Protect live state during restore and reset
This commit is contained in:
@@ -48,19 +48,21 @@ run save >/dev/null 2>&1 && fail 'backing up a missing settings file reported su
|
||||
[[ "$(run list)" == "[]" ]] || fail 'an empty backup directory did not list as empty'
|
||||
|
||||
# ── A snapshot round-trips ───────────────────────────────────────────────────
|
||||
printf '{"gapsOut":24,"windowRounding":6}' >"$settings"
|
||||
printf '{"gapsOut":24,"windowRounding":6,"displays":{"DP-2":{"mode":"3840x2160@60","scale":2,"transform":0}}}' >"$settings"
|
||||
mkdir -p "$(dirname "$home")"
|
||||
printf '{"initialized":true,"favorites":[{"id":"light.desk","alias":"Desk"}]}' >"$home"
|
||||
run save >/dev/null || fail 'save failed on a valid settings file'
|
||||
name="$(run list | jq -r '.[0].name')"
|
||||
[[ "$name" =~ ^settings-[0-9]{8}-[0-9]{9}\.json$ ]] || fail "unexpected snapshot name: $name"
|
||||
[[ "$(run list | jq -r '.[0].keys')" == "2" ]] || fail 'snapshot key count is wrong'
|
||||
[[ "$(run list | jq -r '.[0].keys')" == "3" ]] || fail 'snapshot key count is wrong'
|
||||
|
||||
printf '{"gapsOut":99}' >"$settings"
|
||||
printf '{"gapsOut":99,"displays":{"DP-2":{"mode":"4500x3000@60","scale":1.5,"transform":0}}}' >"$settings"
|
||||
printf '{"initialized":false,"favorites":[]}' >"$home"
|
||||
restore_result="$(run restore "$name")" || fail 'restore failed'
|
||||
[[ "$(jq -r .gapsOut "$settings")" == "24" ]] || fail 'restore did not bring back the snapshot contents'
|
||||
[[ "$(jq -r .windowRounding "$settings")" == "6" ]] || fail 'restore lost a key'
|
||||
[[ "$(jq -r '.displays["DP-2"].scale' "$settings")" == "1.5" ]] \
|
||||
|| fail 'restore bypassed display confirmation by applying snapshot geometry'
|
||||
[[ "$(jq -r '.favorites[0].id' "$home")" == "light.desk" ]] || fail 'restore did not bring back Home favourites'
|
||||
[[ "$(jq -r '.favorites[0].alias' "$home")" == "Desk" ]] || fail 'restore lost a Home alias'
|
||||
jq -e '.home.present == true and .home.data.favorites[0].id == "light.desk"' <<<"$restore_result" >/dev/null \
|
||||
|
||||
@@ -43,6 +43,8 @@ for mapping in \
|
||||
'HomePreferences.initialize(ids);' \
|
||||
'HomePreferences.setAlias(id, alias);' \
|
||||
'DesktopPreferences.reload();' \
|
||||
'DesktopPreferences.set("displays", value);' \
|
||||
'Displays.externalChangeBlocked = blocked;' \
|
||||
'SystemSettings.applyPersistedDisplayPolicy();' \
|
||||
'Keybinds.applyReload();' \
|
||||
'Wallpaper.set(path);' \
|
||||
@@ -82,9 +84,11 @@ jq -e '
|
||||
"home.alias:light.desk=Desk",
|
||||
"home.alias:light.office=Office",
|
||||
"desktop.reload",
|
||||
"display.protect:{\"DP-2\":{\"mode\":\"4500x3000@60\",\"scale\":1.5,\"transform\":0}}",
|
||||
"system.apply",
|
||||
"keybinds.reload",
|
||||
"wallpaper.set:/tmp/restored-wallpaper.jpg",
|
||||
"display.block:false",
|
||||
"shell.reload"
|
||||
]
|
||||
and .initialized == true
|
||||
@@ -118,15 +122,26 @@ jq -e '
|
||||
.calls == [
|
||||
"home.reset",
|
||||
"desktop.reload",
|
||||
"display.protect:{\"DP-2\":{\"mode\":\"4500x3000@60\",\"scale\":1.5,\"transform\":0}}",
|
||||
"system.apply",
|
||||
"keybinds.reload",
|
||||
"wallpaper.set:/tmp/restored-wallpaper.jpg",
|
||||
"display.block:false",
|
||||
"shell.reload"
|
||||
]
|
||||
and .initialized == false
|
||||
and .favorites == []
|
||||
' <<<"$status" >/dev/null || fail "absent Home handoff was wrong: $status"
|
||||
|
||||
# Restore refuses before launching the helper while a display apply/recovery is
|
||||
# active, so no snapshot can race the confirmation boundary.
|
||||
qs_test ipc call settings-backup-behavior reset >/dev/null
|
||||
[[ "$(qs_test ipc call settings-backup-behavior restoreWhileDisplayBusy)" == "false" ]] \
|
||||
|| fail 'snapshot restore started during an active display operation'
|
||||
status="$(qs_test ipc call settings-backup-behavior status)"
|
||||
jq -e '.calls == [] and (.lastError | contains("display change"))' <<<"$status" >/dev/null \
|
||||
|| fail "display-busy restore refusal was not clean: $status"
|
||||
|
||||
trap - EXIT
|
||||
cleanup
|
||||
printf 'settings backup live contract: PASS\n'
|
||||
|
||||
@@ -20,6 +20,7 @@ set -euo pipefail
|
||||
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
harness="$repo_dir/config/dot/quickshell/settings-system-harness.qml"
|
||||
system_settings="$repo_dir/config/dot/quickshell/services/SystemSettings.qml"
|
||||
wallpaper_service="$repo_dir/config/dot/quickshell/services/Wallpaper.qml"
|
||||
|
||||
# Preferences are committed to $XDG_CONFIG_HOME, and the Home store lives under
|
||||
# $XDG_STATE_HOME. Both are isolated so this contract cannot touch the real
|
||||
@@ -37,6 +38,16 @@ rg -Fq 'HomePreferences.resetHomeDefaults();' "$system_settings" \
|
||||
if rg -q 'HomePreferences\.(favorites|initialized)\s*=' "$system_settings"; then
|
||||
fail 'restoreDefaults mutates Home aliases instead of using resetHomeDefaults'
|
||||
fi
|
||||
rg -Fq 'root.protectDisplays(protectedDisplays)' "$system_settings" \
|
||||
|| fail 'restoreDefaults can apply unconfirmed display geometry during reload'
|
||||
rg -Fq 'Keybinds.applyReload();' "$system_settings" \
|
||||
|| fail 'restoreDefaults does not replay shipped keybindings'
|
||||
rg -Fq 'root.applyWallpaper(String(DesktopPreferences.get("wallpaperPath") ?? ""));' "$system_settings" \
|
||||
|| fail 'restoreDefaults does not visibly reapply the shipped wallpaper'
|
||||
rg -Fq 'const effectivePath = path === "" ? root.shippedPath : path;' "$wallpaper_service" \
|
||||
|| fail 'clearing wallpaper preference leaves the old image visible'
|
||||
rg -Fq 'property string storedValue:' "$wallpaper_service" \
|
||||
|| fail 'the shipped wallpaper cannot remain represented by the default empty preference'
|
||||
|
||||
qs_for_harness() {
|
||||
XDG_CONFIG_HOME="$config_home" XDG_STATE_HOME="$state_home" qs -p "$harness" "$@"
|
||||
@@ -92,6 +103,9 @@ before="$(qs_for_harness ipc call settings-system-test stored windowRounding)"
|
||||
# ── Reset spans every store, not just the schema one ─────────────────────────
|
||||
qs_for_harness ipc call settings-system-test seedHome >/dev/null
|
||||
qs_for_harness ipc call settings-system-test commit dockHideDelayMs 900 >/dev/null
|
||||
display_fixture='{"DP-2":{"mode":"4500x3000@60","scale":1.5,"transform":0}}'
|
||||
[[ "$(qs_for_harness ipc call settings-system-test commit displays "$display_fixture")" == "true" ]] \
|
||||
|| fail 'the protected display fixture did not apply'
|
||||
sleep 0.4
|
||||
|
||||
home_before="$(qs_for_harness ipc call settings-system-test homeState)"
|
||||
@@ -100,11 +114,24 @@ jq -e '.count == 1 and .initialized == true' <<<"$home_before" >/dev/null \
|
||||
[[ "$(qs_for_harness ipc call settings-system-test stored dockHideDelayMs)" == "900" ]] \
|
||||
|| fail 'the dock fixture did not apply'
|
||||
|
||||
qs_for_harness ipc call settings-system-test restoreDefaults >/dev/null
|
||||
[[ "$(qs_for_harness ipc call settings-system-test restoreDefaults)" == "true" ]] \
|
||||
|| fail 'restoreDefaults refused a safe reset'
|
||||
sleep 0.6
|
||||
|
||||
reset_state="$(qs_for_harness ipc call settings-system-test resetState)"
|
||||
jq -e '.calls == [
|
||||
"display.block:true",
|
||||
"display.protect",
|
||||
"keybinds.reload",
|
||||
"wallpaper.set:",
|
||||
"display.block:false"
|
||||
] and .displayBlocked == false' <<<"$reset_state" >/dev/null \
|
||||
|| fail "reset did not safely replay non-reactive state: $reset_state"
|
||||
|
||||
[[ "$(qs_for_harness ipc call settings-system-test stored dockHideDelayMs)" == "250" ]] \
|
||||
|| fail 'reset did not restore a schema default'
|
||||
[[ "$(qs_for_harness ipc call settings-system-test stored displays | jq -cS .)" == "$(jq -cS . <<<"$display_fixture")" ]] \
|
||||
|| fail 'reset replaced confirmed display geometry without confirmation'
|
||||
|
||||
home_after="$(qs_for_harness ipc call settings-system-test homeState)"
|
||||
jq -e '.count == 0 and .initialized == false' <<<"$home_after" >/dev/null \
|
||||
|
||||
Reference in New Issue
Block a user