test: the wallpaper repair, on Tiny Pebbles' own file, in the lab and on a real install
Unit: Tiny Pebbles' file (desktop 10, panel 1), a healthy River Kids file left byte for byte, a late desktop beside a good one, idempotence, the refusal under a running shell. Lab: Plasma makes a bare desktop itself through a new activity, and the screen is read, not the file. Container gate: the installed package's fallback is the package, and its repair fixes the room's file and leaves the panel alone. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
7b4ac39cd2
commit
9fc86f9d4c
@@ -182,6 +182,12 @@ check "no discover or system settings" 0 \
|
||||
"$(in_lab "grep -cE 'discover.desktop|systemsettings.desktop' $APPLETS")"
|
||||
check "the packaged wallpaper" 1 \
|
||||
"$(in_lab "grep -c 'Image=file:///usr/share/backgrounds/ekklesia/classroom-calm.png' $APPLETS")"
|
||||
# And the one a desktop gets when nothing wrote it, which is what Tiny
|
||||
# Pebbles showed: a package name, and the package there to be found.
|
||||
check "a desktop nobody configured defaults to it" EkklesiaClassroom \
|
||||
"$(in_lab 'sed -n "/^\[Wallpaper\]/,/^\[/s/^Image=//p" /usr/share/plasma/look-and-feel/org.ekklesia.classroom.desktop/contents/defaults')"
|
||||
check "and that package is the same picture" /usr/share/backgrounds/ekklesia/classroom-calm.png \
|
||||
"$(in_lab 'readlink -f /usr/share/wallpapers/EkklesiaClassroom/contents/images/*.png')"
|
||||
|
||||
section "it will not strand a teacher"
|
||||
check "no automatic lock" false "$(session_config --file kscreenlockerrc --group Daemon --key Autolock)"
|
||||
|
||||
Executable
+238
@@ -0,0 +1,238 @@
|
||||
#!/bin/bash
|
||||
# Does every desktop show the classroom's wallpaper — including one Plasma
|
||||
# makes by itself after the layout has run?
|
||||
#
|
||||
# Tiny Pebbles came through the 0.2.2 upgrade with its desktop numbered 10
|
||||
# and nothing configured on it, and showed Plasma's own purple wallpaper.
|
||||
# The layout only reaches the desktops that exist while it runs, and a
|
||||
# room whose updater reboots it at three in the morning with the
|
||||
# television off has none then. The lab cannot switch a television on, so
|
||||
# it makes Plasma create a desktop the other way it does, through a new
|
||||
# activity: the same code in the shell, and measured to give the same
|
||||
# bare containment.
|
||||
#
|
||||
# tools/lab/wallpaper-check against the running lab session
|
||||
#
|
||||
# Each answer is read off the screen, not out of a file: a configuration
|
||||
# can say anything, and the question is what the room sees. The sky at the
|
||||
# top of the classroom's picture is pale blue; Plasma's is purple.
|
||||
set -uo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
LAB="$ROOT/tools/lab/lab"
|
||||
NAME="${LAB_NAME:-classroom-v2-lab}"
|
||||
APPLETS=/home/classroom/.config/plasma-org.kde.plasma.desktop-appletsrc
|
||||
|
||||
PASS=0
|
||||
FAIL=0
|
||||
|
||||
check() {
|
||||
if [[ "$2" == "$3" ]]; then
|
||||
printf ' \033[32mPASS\033[0m %-58s %s\n' "$1" "$3"
|
||||
PASS=$((PASS + 1))
|
||||
else
|
||||
printf ' \033[31mFAIL\033[0m %-58s got [%s] want [%s]\n' "$1" "$3" "$2"
|
||||
FAIL=$((FAIL + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
section() { printf '\n%s\n' "$1"; }
|
||||
in_lab() { docker exec "$NAME" bash -c "$1" 2>/dev/null; }
|
||||
# The same, with this script's input handed through — for a program on a
|
||||
# here-document. Without -i docker gives it nothing to read, and it runs
|
||||
# on nothing and says nothing.
|
||||
in_lab_fed() { docker exec -i "$NAME" bash -c "$1"; }
|
||||
user() { "$LAB" run "$@" 2>/dev/null; }
|
||||
activities() {
|
||||
user busctl --user call org.kde.ActivityManager /ActivityManager/Activities \
|
||||
org.kde.ActivityManager.Activities "$@"
|
||||
}
|
||||
|
||||
# What is on the screen at the top middle, where the classroom's picture
|
||||
# is sky and Plasma's is purple: "classroom", "plasma", or the colour.
|
||||
screen() {
|
||||
"$LAB" outer grim -t ppm - 2>/dev/null | python3 -c '
|
||||
import sys
|
||||
data = sys.stdin.buffer.read()
|
||||
fields, at = [], 0
|
||||
while len(fields) < 4:
|
||||
while data[at:at + 1].isspace():
|
||||
at += 1
|
||||
end = at
|
||||
while not data[end:end + 1].isspace():
|
||||
end += 1
|
||||
fields.append(data[at:end])
|
||||
at = end
|
||||
width, height = int(fields[1]), int(fields[2])
|
||||
pixels = data[at + 1:]
|
||||
total = [0, 0, 0]
|
||||
count = 0
|
||||
for y in range(20, 140, 4):
|
||||
for x in range(width * 2 // 5, width * 3 // 5, 8):
|
||||
offset = (y * width + x) * 3
|
||||
for channel in range(3):
|
||||
total[channel] += pixels[offset + channel]
|
||||
count += 1
|
||||
r, g, b = (value / count for value in total)
|
||||
if b > r + 25 and g > r + 10:
|
||||
print("classroom")
|
||||
elif r > g + 25 and b > g + 25:
|
||||
print("plasma")
|
||||
else:
|
||||
print(f"rgb({r:.0f},{g:.0f},{b:.0f})")
|
||||
'
|
||||
}
|
||||
|
||||
# The shell writes its file a few seconds after a change, not at once.
|
||||
settle() { sleep "${1:-35}"; }
|
||||
|
||||
# The shell's file, read as groups rather than grepped, so nothing here
|
||||
# can pick a line out of the wrong containment.
|
||||
#
|
||||
# applets panels each panel's number, its applets' numbers and plugins
|
||||
# and their order. Not the panel's text: the shell adds
|
||||
# keys of its own to applets as soon as it runs (popup
|
||||
# sizes, the volume's migration), and that is Plasma,
|
||||
# not the repair. tests/ checks the repair's own
|
||||
# output byte for byte.
|
||||
# applets desktops the desktop containments as "id:image" or "id:none",
|
||||
# found by plugin and never by number
|
||||
applets() {
|
||||
in_lab_fed "python3 - $1 $APPLETS" <<'PY'
|
||||
import re, sys
|
||||
mode, path = sys.argv[1], sys.argv[2]
|
||||
groups, name = {}, None
|
||||
for line in open(path).read().splitlines():
|
||||
if line.startswith("[") and line.endswith("]"):
|
||||
name = line
|
||||
groups[name] = []
|
||||
elif name and line:
|
||||
groups[name].append(line)
|
||||
def top(cid):
|
||||
return groups.get(f"[Containments][{cid}]", [])
|
||||
ids = [m.group(1) for g in groups for m in [re.match(r"^\[Containments\]\[(\d+)\]$", g)] if m]
|
||||
if mode == "panels":
|
||||
for c in ids:
|
||||
if "plugin=org.kde.panel" not in top(c):
|
||||
continue
|
||||
applets = sorted(
|
||||
(int(m.group(1)), line[len("plugin=org.kde.plasma."):])
|
||||
for g in groups
|
||||
for m in [re.match(r"^\[Containments\]\[%s\]\[Applets\]\[(\d+)\]$" % c, g)] if m
|
||||
for line in groups[g] if line.startswith("plugin=")
|
||||
)
|
||||
order = [l[len("AppletOrder="):] for l in groups.get(f"[Containments][{c}][General]", [])
|
||||
if l.startswith("AppletOrder=")]
|
||||
print(f"panel {c}:", " ".join(f"{n}={name}" for n, name in applets), "order", *order)
|
||||
else:
|
||||
image = "Image=file:///usr/share/backgrounds/ekklesia/classroom-calm.png"
|
||||
out = []
|
||||
for c in ids:
|
||||
if {"plugin=org.kde.plasma.folder", "plugin=org.kde.desktopcontainment"} & set(top(c)):
|
||||
wallpaper = groups.get(f"[Containments][{c}][Wallpaper][org.kde.image][General]", [])
|
||||
out.append(f"{c}:{'image' if image in wallpaper else 'none'}")
|
||||
print(" ".join(out))
|
||||
PY
|
||||
}
|
||||
|
||||
panel_groups() { applets panels; }
|
||||
desktops() { applets desktops; }
|
||||
|
||||
last_repair() {
|
||||
user journalctl --user -u plasma-plasmashell.service --no-pager -o cat \
|
||||
| grep '^classroom-desktop-wallpaper:' | tail -1
|
||||
}
|
||||
|
||||
restart_shell() {
|
||||
user systemctl --user restart plasma-plasmashell.service
|
||||
for _ in $(seq 1 30); do
|
||||
in_lab 'pgrep -x plasmashell >/dev/null' && break
|
||||
sleep 1
|
||||
done
|
||||
sleep 10
|
||||
}
|
||||
|
||||
section "the package"
|
||||
check "the look and feel's default names a package" EkklesiaClassroom \
|
||||
"$(in_lab 'sed -n "/^\[Wallpaper\]/,/^\[/s/^Image=//p" /usr/share/plasma/look-and-feel/org.ekklesia.classroom.desktop/contents/defaults')"
|
||||
check "which is installed, and is the classroom's picture" /usr/share/backgrounds/ekklesia/classroom-calm.png \
|
||||
"$(in_lab 'readlink -f /usr/share/wallpapers/EkklesiaClassroom/contents/images/*.png')"
|
||||
check "the repair runs before every shell start" 1 \
|
||||
"$(in_lab 'grep -c "^ExecStartPre=-/usr/local/bin/classroom-desktop-wallpaper" /etc/systemd/user/plasma-plasmashell.service.d/ekklesia-classroom.conf')"
|
||||
|
||||
section "the session as it came up"
|
||||
check "the room shows the classroom's picture" classroom "$(screen)"
|
||||
original=$(activities CurrentActivity | cut -d'"' -f2)
|
||||
|
||||
section "a desktop Plasma makes by itself (Tiny Pebbles' television)"
|
||||
panels_before=$(panel_groups)
|
||||
late=$(activities AddActivity s "Late screen" | cut -d'"' -f2)
|
||||
activities SetCurrentActivity s "$late" >/dev/null
|
||||
settle
|
||||
now=$(desktops)
|
||||
check "Plasma made a second desktop" 2 "$(wc -w <<< "$now")"
|
||||
check "and wrote no wallpaper into it, as on Tiny Pebbles" 1 "$(grep -o ':none' <<< "$now" | wc -l)"
|
||||
check "the room still shows the classroom's picture" classroom "$(screen)"
|
||||
|
||||
section "the shell restarted, without a login"
|
||||
restart_shell
|
||||
check "the repair wrote it in" "classroom-desktop-wallpaper: the wallpaper is now configured on desktop $(tr ' ' '\n' <<< "$now" | cut -d: -f1 | paste -sd, | sed 's/,/, /g')" \
|
||||
"$(last_repair)"
|
||||
check "every desktop now names the picture" 0 "$(desktops | grep -o ':none' | wc -l)"
|
||||
check "the panel keeps its numbers, applets and order" "$panels_before" "$(panel_groups)"
|
||||
check "the room shows the classroom's picture" classroom "$(screen)"
|
||||
restart_shell
|
||||
check "a second restart finds nothing to do" \
|
||||
"classroom-desktop-wallpaper: desktop $(desktops | tr ' ' '\n' | cut -d: -f1 | paste -sd, | sed 's/,/, /g'): the classroom wallpaper already" \
|
||||
"$(last_repair)"
|
||||
check "and still does" "$panels_before" "$(panel_groups)"
|
||||
|
||||
activities SetCurrentActivity s "$original" >/dev/null
|
||||
activities RemoveActivity s "$late" >/dev/null
|
||||
sleep 3
|
||||
|
||||
section "Tiny Pebbles' own file: desktop 10, panel 1, no wallpaper"
|
||||
user systemctl --user stop plasma-plasmashell.service
|
||||
in_lab_fed "python3 - '$original' $APPLETS" <<'PY'
|
||||
import sys
|
||||
activity, path = sys.argv[1], sys.argv[2]
|
||||
applets = ["quicklaunch", "panelspacer", "icontasks", "panelspacer",
|
||||
"networkmanagement", "volume", "notifications", "digitalclock"]
|
||||
out = ["[Containments][1]", "activityId=", "formfactor=2", "immutability=1",
|
||||
"lastScreen=0", "location=4", "plugin=org.kde.panel",
|
||||
"wallpaperplugin=org.kde.image", ""]
|
||||
for number, applet in enumerate(applets, start=2):
|
||||
out += [f"[Containments][1][Applets][{number}]", "immutability=1",
|
||||
f"plugin=org.kde.plasma.{applet}", ""]
|
||||
out += ["[Containments][1][Applets][4][Configuration][General]",
|
||||
"launchers=applications:ekklesia-wonderink.desktop,applications:google-chrome.desktop,applications:ekklesia-dvd.desktop",
|
||||
"sortingStrategy=1", "",
|
||||
"[Containments][1][General]", "AppletOrder=2;3;4;5;6;7;8;9", "",
|
||||
"[Containments][10]", f"activityId={activity}", "formfactor=0",
|
||||
"immutability=1", "lastScreen=0", "location=0",
|
||||
"plugin=org.kde.plasma.folder", "wallpaperplugin=org.kde.image", "",
|
||||
"[Containments][10][General]", 'positions={"1920x1080":[]}', ""]
|
||||
open(path, "w").write("\n".join(out))
|
||||
PY
|
||||
in_lab "chown classroom:classroom $APPLETS"
|
||||
panels_before=$(panel_groups)
|
||||
user systemctl --user start plasma-plasmashell.service
|
||||
sleep 12
|
||||
check "the repair found desktop 10 and wrote it" \
|
||||
"classroom-desktop-wallpaper: the wallpaper is now configured on desktop 10" "$(last_repair)"
|
||||
check "desktop 10 names the picture" "10:image" "$(desktops)"
|
||||
check "the panel is still containment 1, applets 2 to 9, in order" "$panels_before" "$(panel_groups)"
|
||||
check "the room shows the classroom's picture" classroom "$(screen)"
|
||||
|
||||
section "and at the next login"
|
||||
"$LAB" plasma-down >/dev/null
|
||||
"$LAB" plasma-up >/dev/null
|
||||
settle 10
|
||||
check "the reset left the repair nothing to do" \
|
||||
"classroom-desktop-wallpaper: no desktop configuration yet; the layout writes the wallpaper" \
|
||||
"$(last_repair)"
|
||||
check "the layout rebuilt one desktop with the picture" 1 "$(desktops | grep -o ':image' | wc -l)"
|
||||
check "the room shows the classroom's picture" classroom "$(screen)"
|
||||
|
||||
printf '\n%s passed, %s failed\n' "$PASS" "$FAIL"
|
||||
[[ "$FAIL" -eq 0 ]]
|
||||
@@ -499,6 +499,71 @@ if [[ -n "$previous" ]]; then
|
||||
grep -q 'var PRESENTATIONS = false;' \
|
||||
/usr/share/plasma/look-and-feel/org.ekklesia.classroom.desktop/contents/layouts/org.kde.plasma.desktop-layout.js
|
||||
|
||||
# TINY PEBBLES, 0.2.2 -> 0.2.6.4: THE DESKTOP WITH NO WALLPAPER.
|
||||
#
|
||||
# The room's desktop was containment 10, made by Plasma after the
|
||||
# layout had run, with nothing configured on it; it showed Plasma's
|
||||
# own wallpaper. What a desktop gets when nothing wrote it is the look
|
||||
# and feel's default, and that has to be a package Plasma can find.
|
||||
lnf=/usr/share/plasma/look-and-feel/org.ekklesia.classroom.desktop/contents/defaults
|
||||
[[ "$(sed -n '/^\[Wallpaper\]/,/^\[/s/^Image=//p' "$lnf")" == EkklesiaClassroom ]]
|
||||
grep -q '"Id": "EkklesiaClassroom"' /usr/share/wallpapers/EkklesiaClassroom/metadata.json
|
||||
[[ "$(readlink -f /usr/share/wallpapers/EkklesiaClassroom/contents/images/*.png)" \
|
||||
== /usr/share/backgrounds/ekklesia/classroom-calm.png ]]
|
||||
grep -qx 'ExecStartPre=-/usr/local/bin/classroom-desktop-wallpaper' \
|
||||
/etc/systemd/user/plasma-plasmashell.service.d/ekklesia-classroom.conf
|
||||
|
||||
# And the repair the package installed, on that room's own file: the
|
||||
# panel built with no screen took 1 and its applets 2 to 9.
|
||||
wallpaper_home=$(mktemp -d)
|
||||
cat > "$wallpaper_home/plasma-org.kde.plasma.desktop-appletsrc" <<'APPLETS'
|
||||
[Containments][1]
|
||||
formfactor=2
|
||||
location=4
|
||||
plugin=org.kde.panel
|
||||
wallpaperplugin=org.kde.image
|
||||
|
||||
[Containments][1][Applets][2]
|
||||
plugin=org.kde.plasma.quicklaunch
|
||||
|
||||
[Containments][1][Applets][9]
|
||||
plugin=org.kde.plasma.digitalclock
|
||||
|
||||
[Containments][1][General]
|
||||
AppletOrder=2;3;4;5;6;7;8;9
|
||||
|
||||
[Containments][10]
|
||||
activityId=62d3d55d-bd31-4fc8-9a7b-a5b9b2b99b60
|
||||
formfactor=0
|
||||
immutability=1
|
||||
lastScreen=0
|
||||
location=0
|
||||
plugin=org.kde.plasma.folder
|
||||
wallpaperplugin=org.kde.image
|
||||
|
||||
[Containments][10][General]
|
||||
positions={"1920x1080":[]}
|
||||
APPLETS
|
||||
applets="$wallpaper_home/plasma-org.kde.plasma.desktop-appletsrc"
|
||||
panel_before=$(sed -n '/^\[Containments\]\[1\]/,/^$/p' "$applets")
|
||||
|
||||
! XDG_CONFIG_HOME="$wallpaper_home" classroom-desktop-wallpaper --check >/dev/null
|
||||
XDG_CONFIG_HOME="$wallpaper_home" classroom-desktop-wallpaper \
|
||||
| grep -q 'configured on desktop 10'
|
||||
sed -n '/^\[Containments\]\[10\]\[Wallpaper\]\[org.kde.image\]\[General\]$/,/^$/p' "$applets" \
|
||||
| grep -qx 'Image=file:///usr/share/backgrounds/ekklesia/classroom-calm.png'
|
||||
[[ "$(sed -n '/^\[Containments\]\[1\]/,/^$/p' "$applets")" == "$panel_before" ]]
|
||||
[[ "$(grep -c '^\[Containments\]\[[0-9]*\]$' "$applets")" -eq 2 ]]
|
||||
|
||||
# Twice changes nothing, and a room that was already right is not
|
||||
# written at all.
|
||||
repaired=$(sha256sum < "$applets")
|
||||
XDG_CONFIG_HOME="$wallpaper_home" classroom-desktop-wallpaper \
|
||||
| grep -q 'the classroom wallpaper already'
|
||||
[[ "$(sha256sum < "$applets")" == "$repaired" ]]
|
||||
XDG_CONFIG_HOME="$wallpaper_home" classroom-desktop-wallpaper --check >/dev/null
|
||||
rm -rf "$wallpaper_home"
|
||||
|
||||
# And a room that was carried through the experiment on its own
|
||||
# channel comes home, because that channel is the obsolete one now.
|
||||
sed -i 's/^CHANNEL=.*/CHANNEL=classroom-v2/' /etc/ekklesia-classroom/device.conf
|
||||
|
||||
Reference in New Issue
Block a user