Merge quattro into clock-calendar
Both sides tightened the same center-layout assertion. Taking quattro's: it asserts the weather/update adjacency the test name is about instead of pinning the whole row, which is what kept breaking it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -16,14 +16,14 @@ pass "default shell.json is valid JSON"
|
||||
jq -e '.version == 1 and (.bar.layout.left | type == "array") and (.bar.layout.center | type == "array") and (.bar.layout.right | type == "array")' "$ROOT/config/omarchy/shell.json" >/dev/null
|
||||
pass "default shell.json has versioned bar layout"
|
||||
|
||||
# Pinning the whole row made this fail every time an unrelated widget moved,
|
||||
# so assert the adjacency the name is about and let the rest of the row change.
|
||||
jq -e '
|
||||
def ids: map(.id // .);
|
||||
.bar.layout.center | ids == [
|
||||
"omarchy.indicators",
|
||||
"omarchy.clock",
|
||||
"omarchy.weather",
|
||||
"omarchy.system-update"
|
||||
]
|
||||
(.bar.layout.center | ids) as $ids |
|
||||
($ids | index("omarchy.weather")) as $weather |
|
||||
($ids | index("omarchy.system-update")) as $update |
|
||||
$weather != null and $update == $weather + 1
|
||||
' "$ROOT/config/omarchy/shell.json" >/dev/null
|
||||
pass "default center layout keeps update next to weather"
|
||||
|
||||
@@ -94,12 +94,29 @@ import sys
|
||||
from pathlib import Path
|
||||
|
||||
root = Path(os.environ["ROOT"])
|
||||
home = Path.home()
|
||||
pkgs_candidates = [
|
||||
root.parent / "omarchy-pkgs/pkgbuilds",
|
||||
root.parent / "omarchy/omarchy-pkgs/pkgbuilds",
|
||||
root.parent.parent / "omarchy-pkgs/pkgbuilds",
|
||||
root.parent / "omacom/omarchy-pkgs/pkgbuilds",
|
||||
root.parent.parent / "omacom/omarchy-pkgs/pkgbuilds",
|
||||
home / "Work/omacom/omarchy-pkgs/pkgbuilds",
|
||||
]
|
||||
pkgs_root = next((path for path in pkgs_candidates if path.exists()), pkgs_candidates[0])
|
||||
# Checkouts differ per machine, so allow an explicit pointer at the sibling repo.
|
||||
# Accepts either the omarchy-pkgs checkout or its pkgbuilds/ directory.
|
||||
override = os.environ.get("OMARCHY_PKGS_PATH")
|
||||
if override:
|
||||
pkgs_candidates = [Path(override) / "pkgbuilds", Path(override)] + pkgs_candidates
|
||||
pkgs_root = next((path for path in pkgs_candidates if path.exists()), None)
|
||||
if pkgs_root is None:
|
||||
print("not ok - omarchy-pkgs checkout found for PKGBUILD coverage", file=sys.stderr)
|
||||
print(
|
||||
"looked in:\n " + "\n ".join(str(path) for path in pkgs_candidates) +
|
||||
"\nset OMARCHY_PKGS_PATH to the omarchy-pkgs checkout",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
settings_pkgbuild_path = pkgs_root / "omarchy-settings/PKGBUILD"
|
||||
omarchy_pkgbuild_path = pkgs_root / "omarchy/PKGBUILD"
|
||||
if not settings_pkgbuild_path.exists():
|
||||
@@ -120,8 +137,8 @@ package_defaults = [
|
||||
("default/systemd/user/bt-agent.service", "/usr/lib/systemd/user/bt-agent.service", "systemd/user/bt-agent.service"),
|
||||
("default/systemd/user/omarchy-sleep-lock.service", "/usr/lib/systemd/user/omarchy-sleep-lock.service", "systemd/user/omarchy-sleep-lock.service"),
|
||||
("default/systemd/user/omarchy-recover-internal-monitor.service", "/usr/lib/systemd/user/omarchy-recover-internal-monitor.service", "systemd/user/omarchy-recover-internal-monitor.service"),
|
||||
("default/systemd/user/omarchy-update-user-notify.service", "/usr/lib/systemd/user/omarchy-update-user-notify.service", "systemd/user/omarchy-update-user-notify.service"),
|
||||
("default/systemd/user/omarchy-update-user-notify.path", "/usr/lib/systemd/user/omarchy-update-user-notify.path", "systemd/user/omarchy-update-user-notify.path"),
|
||||
("default/systemd/user/omarchy-migrate-notify.service", "/usr/lib/systemd/user/omarchy-migrate-notify.service", "systemd/user/omarchy-migrate-notify.service"),
|
||||
("default/systemd/user/omarchy-tailscale-receive.service", "/usr/lib/systemd/user/omarchy-tailscale-receive.service", "systemd/user/omarchy-tailscale-receive.service"),
|
||||
("default/systemd/zram-generator.conf.d/90-omarchy.conf", "/usr/lib/systemd/zram-generator.conf.d/90-omarchy.conf", "systemd/zram-generator.conf.d/90-omarchy.conf"),
|
||||
("default/fonts/omarchy/omarchy.ttf", "/usr/share/fonts/omarchy/omarchy.ttf", "omarchy.ttf"),
|
||||
("default/snapper/root", "/etc/snapper/config-templates/omarchy", "snapper/root"),
|
||||
@@ -135,6 +152,16 @@ for source, destination, legacy in package_defaults:
|
||||
if destination and (source not in pkgbuild or destination not in pkgbuild):
|
||||
errors.append(f"PKGBUILD does not explicitly install {source} -> {destination}")
|
||||
|
||||
# Existing users have an absolute wants symlink to the old unit path, and the
|
||||
# migration that repoints it only runs for users who run an update -- the
|
||||
# opposite of who the notifier is for. Dropping this alias strands them.
|
||||
notify_alias = 'ln -sfn omarchy-migrate-notify.service "$pkgdir/usr/lib/systemd/user/omarchy-update-user-notify.service"'
|
||||
if notify_alias not in pkgbuild:
|
||||
errors.append(
|
||||
"PKGBUILD does not ship the omarchy-update-user-notify.service compatibility "
|
||||
"alias, so users who have not run migration 1785095882 lose the login notifier"
|
||||
)
|
||||
|
||||
alpm_hooks = [
|
||||
"00-omarchy-update-guard.hook",
|
||||
"10-omarchy-hyprland-reload-pause.hook",
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
#!/bin/bash
|
||||
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/base-test.sh"
|
||||
|
||||
require_command lua
|
||||
|
||||
resolved_input() {
|
||||
OMARCHY_PATH="$ROOT" OMARCHY_VCONSOLE="${1-}" lua <<'LUA'
|
||||
package.path = os.getenv("OMARCHY_PATH") .. "/?.lua;" .. package.path
|
||||
|
||||
local vconsole = os.getenv("OMARCHY_VCONSOLE")
|
||||
local real_open = io.open
|
||||
|
||||
io.open = function(path, mode)
|
||||
if path ~= "/etc/vconsole.conf" then
|
||||
return real_open(path, mode)
|
||||
end
|
||||
|
||||
if not vconsole then
|
||||
return nil
|
||||
end
|
||||
|
||||
local file = io.tmpfile()
|
||||
file:write(vconsole)
|
||||
file:seek("set")
|
||||
return file
|
||||
end
|
||||
|
||||
hl = {
|
||||
config = function(config)
|
||||
local input = config.input
|
||||
print(("[%s] [%s] [%s]"):format(input.kb_layout, input.kb_variant, input.kb_options))
|
||||
end,
|
||||
}
|
||||
|
||||
o = { window = function() end }
|
||||
|
||||
require("default.hypr.input")
|
||||
LUA
|
||||
}
|
||||
|
||||
assert_input() {
|
||||
local description="$1"
|
||||
local expected="$2"
|
||||
local actual
|
||||
|
||||
if (( $# > 2 )); then
|
||||
actual=$(resolved_input "$3")
|
||||
else
|
||||
actual=$(resolved_input)
|
||||
fi
|
||||
|
||||
[[ $actual == "$expected" ]] ||
|
||||
fail "$description" "expected: $expected"$'\n'"actual: $actual"
|
||||
pass "$description"
|
||||
}
|
||||
|
||||
base_options="compose:caps,shift:both_capslock"
|
||||
toggle_options="$base_options,grp:alts_toggle"
|
||||
|
||||
assert_input "missing vconsole.conf falls back to us" "[us] [] [$base_options]"
|
||||
assert_input "us layout passes through" "[us] [intl] [$base_options]" 'XKBLAYOUT=us
|
||||
XKBVARIANT=intl
|
||||
'
|
||||
assert_input "latin layouts are left alone" "[de] [nodeadkeys] [$base_options]" 'XKBLAYOUT=de
|
||||
XKBVARIANT=nodeadkeys
|
||||
'
|
||||
assert_input "non-latin layout gains us in front" "[us,ara] [,] [$toggle_options]" 'XKBLAYOUT=ara
|
||||
'
|
||||
assert_input "prepended us keeps variants aligned" "[us,ru] [,phonetic] [$toggle_options]" 'XKBLAYOUT=ru
|
||||
XKBVARIANT=phonetic
|
||||
'
|
||||
assert_input "non-latin layout in front gains us even when us trails" "[us,il,us] [,] [$toggle_options]" 'XKBLAYOUT=il,us
|
||||
'
|
||||
|
||||
hooks_conf="$ROOT/etc/mkinitcpio.conf.d/omarchy_hooks.conf"
|
||||
input_lua="$ROOT/default/hypr/input.lua"
|
||||
|
||||
hooks_layouts=$(awk -F')' '/\) ;;$/ { gsub(/[[:space:]|]+/, "\n", $1); print $1 }' "$hooks_conf" | grep '^[a-z]\+$' | sort)
|
||||
lua_layouts=$(sed -n '/^local non_latin_layouts =/,+1p' "$input_lua" | grep -o '"[^"]*"' | tr -d '"' | tr ' ' '\n' | grep '^[a-z]\+$' | sort)
|
||||
|
||||
[[ -n $hooks_layouts ]] || fail "non-latin layout list is readable from omarchy_hooks.conf"
|
||||
[[ $hooks_layouts == "$lua_layouts" ]] ||
|
||||
fail "non-latin layout lists stay in sync" "$(diff <(echo "$hooks_layouts") <(echo "$lua_layouts"))"
|
||||
pass "non-latin layout lists stay in sync with the initramfs hook"
|
||||
@@ -0,0 +1,169 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
|
||||
|
||||
config_script="$ROOT/install/config/locate.sh"
|
||||
|
||||
test_tmp=$(mktemp -d)
|
||||
trap 'rm -rf "$test_tmp"' EXIT
|
||||
|
||||
stock_conf() {
|
||||
cat >"$1" <<'CONF'
|
||||
PRUNE_BIND_MOUNTS = "yes"
|
||||
PRUNEFS = "9p afs autofs cifs fuse nfs nfs4 proc sysfs tmpfs"
|
||||
PRUNENAMES = ".git .hg .svn"
|
||||
PRUNEPATHS = "/afs /media /mnt /net /sfs /tmp /udev /var/cache /var/lib/pacman/local /var/lock /var/run /var/spool /var/tmp"
|
||||
CONF
|
||||
}
|
||||
|
||||
# updatedb dies on a config that defines a variable twice, so hand every
|
||||
# rewritten file to the real parser rather than trusting the greps below.
|
||||
empty_tree="$test_tmp/empty-tree"
|
||||
mkdir -p "$empty_tree"
|
||||
|
||||
assert_conf_parses() {
|
||||
command -v updatedb >/dev/null || return 0
|
||||
|
||||
local errors
|
||||
errors=$(updatedb --config-file "$1" -U "$empty_tree" -o "$test_tmp/plocate.db" 2>&1 >/dev/null | grep -F "$1:" || true)
|
||||
[[ -z $errors ]] || fail "updatedb accepts the rewritten config" "$errors"
|
||||
}
|
||||
|
||||
conf="$test_tmp/updatedb.conf"
|
||||
stock_conf "$conf"
|
||||
|
||||
OMARCHY_UPDATEDB_CONF_PATH="$conf" bash -euo pipefail "$config_script" >/dev/null
|
||||
|
||||
grep -qFx 'PRUNE_BIND_MOUNTS = "no"' "$conf" || fail "locate config indexes Btrfs subvolume mounts like /home"
|
||||
grep -qF 'PRUNEPATHS = "/.snapshots /afs' "$conf" || fail "locate config prunes /.snapshots"
|
||||
assert_conf_parses "$conf"
|
||||
pass "locate config skips Btrfs snapshots and indexes Btrfs subvolumes"
|
||||
|
||||
OMARCHY_UPDATEDB_CONF_PATH="$conf" bash -euo pipefail "$config_script" >/dev/null
|
||||
|
||||
[[ $(grep -o '/\.snapshots' "$conf" | wc -l) -eq 1 ]] || fail "locate config is idempotent"
|
||||
assert_conf_parses "$conf"
|
||||
pass "locate config leaves an already-configured file alone"
|
||||
|
||||
OMARCHY_UPDATEDB_CONF_PATH="$test_tmp/missing.conf" bash -euo pipefail "$config_script" >/dev/null
|
||||
pass "locate config tolerates a missing updatedb.conf"
|
||||
|
||||
# A hand-edited updatedb.conf may drop the settings entirely, or write them
|
||||
# without the spaces around the "=" or the quotes that the stock Arch file uses.
|
||||
conf="$test_tmp/sparse-updatedb.conf"
|
||||
printf '%s\n' 'PRUNENAMES = ".git .hg .svn"' >"$conf"
|
||||
|
||||
OMARCHY_UPDATEDB_CONF_PATH="$conf" bash -euo pipefail "$config_script" >/dev/null
|
||||
|
||||
grep -qFx 'PRUNE_BIND_MOUNTS = "no"' "$conf" || fail "locate config adds a missing PRUNE_BIND_MOUNTS"
|
||||
grep -qFx 'PRUNEPATHS = "/.snapshots"' "$conf" || fail "locate config adds a missing PRUNEPATHS"
|
||||
assert_conf_parses "$conf"
|
||||
pass "locate config adds settings a hand-edited updatedb.conf is missing"
|
||||
|
||||
conf="$test_tmp/unspaced-updatedb.conf"
|
||||
printf '%s\n' 'PRUNE_BIND_MOUNTS="yes"' 'PRUNEPATHS="/tmp /var/tmp"' >"$conf"
|
||||
|
||||
OMARCHY_UPDATEDB_CONF_PATH="$conf" bash -euo pipefail "$config_script" >/dev/null
|
||||
|
||||
grep -qFx 'PRUNE_BIND_MOUNTS = "no"' "$conf" || fail "locate config rewrites an unspaced PRUNE_BIND_MOUNTS"
|
||||
grep -qFx 'PRUNEPATHS = "/.snapshots /tmp /var/tmp"' "$conf" || fail "locate config prunes /.snapshots in an unspaced PRUNEPATHS"
|
||||
[[ $(grep -c 'PRUNEPATHS' "$conf") -eq 1 ]] || fail "locate config keeps a single PRUNEPATHS setting"
|
||||
assert_conf_parses "$conf"
|
||||
pass "locate config handles updatedb.conf written without spaces around ="
|
||||
|
||||
# updatedb allows a comment after a value and indented settings, and defining
|
||||
# either setting twice makes it refuse to run at all.
|
||||
conf="$test_tmp/commented-updatedb.conf"
|
||||
printf '%s\n' ' PRUNE_BIND_MOUNTS = "yes" # subvolumes look like bind mounts' \
|
||||
'PRUNEPATHS = "/tmp" # scratch' >"$conf"
|
||||
|
||||
OMARCHY_UPDATEDB_CONF_PATH="$conf" bash -euo pipefail "$config_script" >/dev/null
|
||||
|
||||
grep -qFx 'PRUNE_BIND_MOUNTS = "no"' "$conf" || fail "locate config rewrites an indented PRUNE_BIND_MOUNTS"
|
||||
grep -qFx 'PRUNEPATHS = "/.snapshots /tmp"' "$conf" || fail "locate config keeps the paths a commented PRUNEPATHS already prunes"
|
||||
[[ $(grep -c 'PRUNEPATHS' "$conf") -eq 1 ]] || fail "locate config replaces a commented PRUNEPATHS instead of adding a second one"
|
||||
assert_conf_parses "$conf"
|
||||
pass "locate config handles indented settings and trailing comments"
|
||||
|
||||
# A hand-edited file may have dropped the quotes updatedb requires, which
|
||||
# leaves it unparseable until something writes the setting out properly.
|
||||
conf="$test_tmp/unquoted-updatedb.conf"
|
||||
printf '%s\n' 'PRUNEPATHS = /tmp' >"$conf"
|
||||
|
||||
OMARCHY_UPDATEDB_CONF_PATH="$conf" bash -euo pipefail "$config_script" >/dev/null
|
||||
|
||||
grep -qFx 'PRUNEPATHS = "/.snapshots"' "$conf" || fail "locate config repairs an unquoted PRUNEPATHS"
|
||||
[[ $(grep -c 'PRUNEPATHS' "$conf") -eq 1 ]] || fail "locate config replaces an unquoted PRUNEPATHS instead of adding a second one"
|
||||
assert_conf_parses "$conf"
|
||||
pass "locate config handles updatedb.conf written without quotes"
|
||||
|
||||
# A path that merely ends in /.snapshots is not the root snapshot directory.
|
||||
conf="$test_tmp/nested-snapshots-updatedb.conf"
|
||||
printf '%s\n' 'PRUNEPATHS = "/var/lib/machines/.snapshots"' >"$conf"
|
||||
|
||||
OMARCHY_UPDATEDB_CONF_PATH="$conf" bash -euo pipefail "$config_script" >/dev/null
|
||||
|
||||
grep -qFx 'PRUNEPATHS = "/.snapshots /var/lib/machines/.snapshots"' "$conf" || fail "locate config prunes /.snapshots alongside a path that ends in it"
|
||||
assert_conf_parses "$conf"
|
||||
pass "locate config tells /.snapshots apart from a path that ends in it"
|
||||
|
||||
locate_migration=$(grep -rl 'Configure locate to skip Btrfs snapshots' "$ROOT/migrations" | head -n 1 || true)
|
||||
[[ -n $locate_migration ]] || fail "locate migration exists"
|
||||
|
||||
fake_bin="$test_tmp/bin"
|
||||
mkdir -p "$fake_bin"
|
||||
|
||||
cat >"$fake_bin/sudo" <<'STUB'
|
||||
#!/bin/bash
|
||||
exec "$@"
|
||||
STUB
|
||||
chmod +x "$fake_bin/sudo"
|
||||
|
||||
cat >"$fake_bin/systemctl" <<'STUB'
|
||||
#!/bin/bash
|
||||
printf 'systemctl %s\n' "$*" >>"$TEST_LOG"
|
||||
STUB
|
||||
chmod +x "$fake_bin/systemctl"
|
||||
|
||||
conf="$test_tmp/migration-updatedb.conf"
|
||||
stock_conf "$conf"
|
||||
|
||||
TEST_LOG="$test_tmp/calls.log" \
|
||||
PATH="$fake_bin:$PATH" \
|
||||
OMARCHY_PATH="$ROOT" \
|
||||
OMARCHY_UPDATEDB_CONF_PATH="$conf" \
|
||||
bash -euo pipefail "$locate_migration" >/dev/null
|
||||
|
||||
grep -qFx 'PRUNE_BIND_MOUNTS = "no"' "$conf" || fail "locate migration rewrites updatedb.conf"
|
||||
grep -qF 'PRUNEPATHS = "/.snapshots /afs' "$conf" || fail "locate migration prunes /.snapshots"
|
||||
grep -qFx 'systemctl restart --no-block plocate-updatedb.service' "$test_tmp/calls.log" || fail "locate migration replaces an in-flight run and rebuilds the index without blocking"
|
||||
pass "locate migration fixes existing installs and rebuilds the index"
|
||||
|
||||
: >"$test_tmp/calls.log"
|
||||
|
||||
TEST_LOG="$test_tmp/calls.log" \
|
||||
PATH="$fake_bin:$PATH" \
|
||||
OMARCHY_PATH="$ROOT" \
|
||||
OMARCHY_UPDATEDB_CONF_PATH="$conf" \
|
||||
bash -euo pipefail "$locate_migration" >/dev/null
|
||||
|
||||
[[ ! -s $test_tmp/calls.log ]] || fail "locate migration skips already-configured installs"
|
||||
pass "locate migration is a no-op once updatedb.conf is configured"
|
||||
|
||||
# A dev checkout carries migrations from a release whose install scripts the
|
||||
# checked-out tree may not have yet, and omarchy-migrate runs under set -e.
|
||||
: >"$test_tmp/calls.log"
|
||||
conf="$test_tmp/no-config-script-updatedb.conf"
|
||||
stock_conf "$conf"
|
||||
|
||||
TEST_LOG="$test_tmp/calls.log" \
|
||||
PATH="$fake_bin:$PATH" \
|
||||
OMARCHY_PATH="$test_tmp/empty" \
|
||||
OMARCHY_UPDATEDB_CONF_PATH="$conf" \
|
||||
bash -euo pipefail "$locate_migration" >/dev/null ||
|
||||
fail "locate migration survives a tree without the locate config script"
|
||||
|
||||
[[ ! -s $test_tmp/calls.log ]] || fail "locate migration touches nothing without the locate config script"
|
||||
pass "locate migration is a no-op when the locate config script is missing"
|
||||
@@ -109,6 +109,25 @@ assertDeepEqual(
|
||||
|
||||
const defaultItems = menu.parseMenuJsonc(defaultMenuJsonc)
|
||||
const defaultById = Object.fromEntries(defaultItems.map(item => [item.id, item]))
|
||||
|
||||
// Needs the real menu: app rows sort after all menu items, and only at that
|
||||
// item count does the order tiebreak alone bury an installed app.
|
||||
const rankBase = menu.mergeMenuSources(defaultItems, [])
|
||||
const ranked = menu.mergeAppRows(rankBase.items, rankBase.itemOrder, [
|
||||
{ id: 'apps.brave', parent: 'apps', kind: 'app', label: 'Brave', description: '', aliases: [] },
|
||||
{ id: 'apps.fontforge', parent: 'apps', kind: 'app', label: 'FontForge', description: '', aliases: [] }
|
||||
])
|
||||
const rankScore = (id, query) => menu.searchScore(ranked.items, ranked.items[id], query)
|
||||
assert(
|
||||
['install.browser.brave', 'remove.browser.brave', 'setup.default.browser.brave'].every(
|
||||
id => rankScore('apps.brave', 'brave') < rankScore(id, 'brave')
|
||||
),
|
||||
'menu ranks an installed app above menu entries matching the query equally well'
|
||||
)
|
||||
assert(
|
||||
rankScore('style.font', 'font') < rankScore('apps.fontforge', 'font'),
|
||||
'menu keeps a better-matching menu entry above a weaker app match'
|
||||
)
|
||||
const triggerItems = defaultItems.filter(item => item.parent === 'trigger')
|
||||
assertEqual(
|
||||
triggerItems[0].id,
|
||||
|
||||
@@ -33,6 +33,12 @@ bash -c "$command"
|
||||
SH
|
||||
chmod +x "$stub_bin/systemd-run"
|
||||
|
||||
cat >"$stub_bin/omarchy-notification-wait" <<'SH'
|
||||
#!/bin/bash
|
||||
exit 0
|
||||
SH
|
||||
chmod +x "$stub_bin/omarchy-notification-wait"
|
||||
|
||||
cat >"$stub_bin/omarchy-notification-send" <<'SH'
|
||||
#!/bin/bash
|
||||
printf '%s\n' "$@" >"$OMARCHY_TEST_NOTIFY_ARGS"
|
||||
|
||||
@@ -45,6 +45,8 @@ SH
|
||||
chmod +x "$stub_bin"/*
|
||||
|
||||
export PATH="$stub_bin:$ROOT/bin:$PATH"
|
||||
# The resize helper anchors to a region file here, so keep it out of the real one
|
||||
export XDG_RUNTIME_DIR="$tmp_dir"
|
||||
export OMARCHY_TEST_MENU_ARGS="$tmp_dir/menu-args"
|
||||
export OMARCHY_TEST_RECORDER_ARGS="$tmp_dir/recorder-args"
|
||||
export OMARCHY_TEST_NOTIFICATION_ARGS="$tmp_dir/notification-args"
|
||||
@@ -153,6 +155,59 @@ if [[ -s $OMARCHY_TEST_HYPRCTL_ARGS ]]; then
|
||||
fi
|
||||
pass "webcam resize ignores other windows"
|
||||
|
||||
region_file="$XDG_RUNTIME_DIR/omarchy-screenrecord-region"
|
||||
|
||||
: >"$OMARCHY_TEST_HYPRCTL_ARGS"
|
||||
echo "800x600+100+100" >"$region_file"
|
||||
"$ROOT/bin/omarchy-capture-webcam-resize" reset
|
||||
|
||||
printf '%s\n' \
|
||||
'dispatch hl.dsp.window.resize({ window = "address:0xabc", x = 133, y = 150 })' \
|
||||
'dispatch hl.dsp.window.move({ window = "address:0xabc", x = 727, y = 510 })' >"$expected_hyprctl_args"
|
||||
|
||||
if ! cmp -s "$OMARCHY_TEST_HYPRCTL_ARGS" "$expected_hyprctl_args"; then
|
||||
fail "webcam anchors to the recorded region" "$(diff -u "$expected_hyprctl_args" "$OMARCHY_TEST_HYPRCTL_ARGS")"
|
||||
fi
|
||||
pass "webcam anchors to the recorded region"
|
||||
|
||||
printf '%s\n' \
|
||||
'dispatch hl.dsp.window.resize({ window = "address:0xabc", x = 178, y = 200 })' \
|
||||
'dispatch hl.dsp.window.move({ window = "address:0xabc", x = 2342, y = 460 })' >"$expected_hyprctl_args"
|
||||
|
||||
for region in "not-a-region" ""; do
|
||||
: >"$OMARCHY_TEST_HYPRCTL_ARGS"
|
||||
printf '%s' "$region" >"$region_file"
|
||||
"$ROOT/bin/omarchy-capture-webcam-resize" reset
|
||||
|
||||
if ! cmp -s "$OMARCHY_TEST_HYPRCTL_ARGS" "$expected_hyprctl_args"; then
|
||||
fail "webcam falls back to the monitor for an unusable region" "$(diff -u "$expected_hyprctl_args" "$OMARCHY_TEST_HYPRCTL_ARGS")"
|
||||
fi
|
||||
done
|
||||
pass "webcam falls back to the monitor for an unusable region"
|
||||
|
||||
# A region too narrow for presets scaled from its height shrinks the whole
|
||||
# ladder, so the three sizes stay distinct and each one fits inside the margins
|
||||
: >"$OMARCHY_TEST_HYPRCTL_ARGS"
|
||||
echo "200x1200+0+0" >"$region_file"
|
||||
for size in small medium large; do
|
||||
"$ROOT/bin/omarchy-capture-webcam-resize" "$size"
|
||||
done
|
||||
|
||||
printf '%s\n' \
|
||||
'dispatch hl.dsp.window.resize({ window = "address:0xabc", x = 64, y = 72 })' \
|
||||
'dispatch hl.dsp.window.move({ window = "address:0xabc", x = 96, y = 1088 })' \
|
||||
'dispatch hl.dsp.window.resize({ window = "address:0xabc", x = 89, y = 100 })' \
|
||||
'dispatch hl.dsp.window.move({ window = "address:0xabc", x = 71, y = 1060 })' \
|
||||
'dispatch hl.dsp.window.resize({ window = "address:0xabc", x = 120, y = 135 })' \
|
||||
'dispatch hl.dsp.window.move({ window = "address:0xabc", x = 40, y = 1025 })' >"$expected_hyprctl_args"
|
||||
|
||||
if ! cmp -s "$OMARCHY_TEST_HYPRCTL_ARGS" "$expected_hyprctl_args"; then
|
||||
fail "webcam sizes stay distinct and inside a narrow region" "$(diff -u "$expected_hyprctl_args" "$OMARCHY_TEST_HYPRCTL_ARGS")"
|
||||
fi
|
||||
pass "webcam sizes stay distinct and inside a narrow region"
|
||||
|
||||
rm -f "$region_file"
|
||||
|
||||
grep -F 'o.bind("SUPER + ALT + code:34", "Make webcam overlay smaller", "omarchy-capture-webcam-resize smaller")' \
|
||||
"$ROOT/default/hypr/bindings/utilities.lua" >/dev/null || fail "webcam smaller hotkey is configured"
|
||||
grep -F 'o.bind("SUPER + ALT + code:35", "Make webcam overlay larger", "omarchy-capture-webcam-resize larger")' \
|
||||
|
||||
@@ -72,7 +72,10 @@ grep -Fx 'systemctl enable --now snapper-cleanup.timer limine-snapper-sync.servi
|
||||
pass "snapshot configure normalizes Snapper policy and services"
|
||||
|
||||
setup_system="$ROOT/bin/omarchy-setup-system"
|
||||
grep -F 'config/snapper.sh' "$setup_system" >/dev/null
|
||||
grep -F 'config/all.sh' "$setup_system" >/dev/null ||
|
||||
fail "system setup runs the config phase"
|
||||
grep -F 'config/snapper.sh' "$ROOT/install/config/all.sh" >/dev/null ||
|
||||
fail "config phase normalizes Snapper"
|
||||
pass "system setup normalizes Snapper during fresh installs"
|
||||
|
||||
migration=$(grep -rl 'Normalize Snapper snapshot services' "$ROOT/migrations" | head -n 1 || true)
|
||||
@@ -84,12 +87,18 @@ grep -F 'as_root env OMARCHY_PATH="$OMARCHY_PATH" bash -euo pipefail "$snapper_c
|
||||
! grep -F 'NUMBER_LIMIT="5"' "$migration" >/dev/null || fail "Snapper service migration does not overwrite working custom retention"
|
||||
pass "Snapper service migration only repairs broken services idempotently"
|
||||
|
||||
# Checkouts differ per machine, so allow an explicit pointer at the sibling repo.
|
||||
# Accepts either the omarchy-pkgs checkout or its pkgbuilds/ directory.
|
||||
find_omarchy_pks_root() {
|
||||
local candidate
|
||||
for candidate in \
|
||||
${OMARCHY_PKGS_PATH:+"$OMARCHY_PKGS_PATH/pkgbuilds" "$OMARCHY_PKGS_PATH"} \
|
||||
"$ROOT/../omarchy-pkgs/pkgbuilds" \
|
||||
"$ROOT/../omarchy/omarchy-pkgs/pkgbuilds" \
|
||||
"$ROOT/../../omarchy-pkgs/pkgbuilds"; do
|
||||
"$ROOT/../../omarchy-pkgs/pkgbuilds" \
|
||||
"$ROOT/../omacom/omarchy-pkgs/pkgbuilds" \
|
||||
"$ROOT/../../omacom/omarchy-pkgs/pkgbuilds" \
|
||||
"$HOME/Work/omacom/omarchy-pkgs/pkgbuilds"; do
|
||||
if [[ -d $candidate ]]; then
|
||||
cd "$candidate" && pwd
|
||||
return 0
|
||||
@@ -111,12 +120,17 @@ grep -F 'cp -a install "$pkgdir/usr/share/omarchy/"' "$omarchy_pkgbuild" >/dev/n
|
||||
grep -F 'cp -a migrations "$pkgdir/usr/share/omarchy/"' "$omarchy_pkgbuild" >/dev/null || fail "omarchy package bundles migrations"
|
||||
pass "omarchy-pkgs packages Snapper template, setup, and migration coverage"
|
||||
|
||||
# Same per-machine checkout problem as omarchy-pkgs; OMARCHY_ISO_PATH points at it.
|
||||
find_omarchy_iso_root() {
|
||||
local candidate
|
||||
for candidate in \
|
||||
${OMARCHY_ISO_PATH:+"$OMARCHY_ISO_PATH"} \
|
||||
"$ROOT/../omarchy-iso" \
|
||||
"$ROOT/../omarchy/omarchy-iso" \
|
||||
"$ROOT/../../omarchy-iso"; do
|
||||
"$ROOT/../../omarchy-iso" \
|
||||
"$ROOT/../omacom/omarchy-iso" \
|
||||
"$ROOT/../../omacom/omarchy-iso" \
|
||||
"$HOME/Work/omacom/omarchy-iso"; do
|
||||
if [[ -d $candidate ]]; then
|
||||
cd "$candidate" && pwd
|
||||
return 0
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
|
||||
|
||||
leak_migration=$(grep -rl 'timeline snapshots leaked by earlier defaults' "$ROOT/migrations" | head -n 1 || true)
|
||||
[[ -n $leak_migration ]] || fail "Snapper timeline leak migration exists"
|
||||
|
||||
test_tmp=$(mktemp -d)
|
||||
trap 'rm -rf "$test_tmp"' EXIT
|
||||
|
||||
fake_bin="$test_tmp/bin"
|
||||
mkdir -p "$fake_bin"
|
||||
|
||||
cat >"$fake_bin/sudo" <<'STUB'
|
||||
#!/bin/bash
|
||||
printf 'sudo %s\n' "$*" >>"$TEST_LOG"
|
||||
exec "$@"
|
||||
STUB
|
||||
chmod +x "$fake_bin/sudo"
|
||||
|
||||
cat >"$fake_bin/snapper" <<'STUB'
|
||||
#!/bin/bash
|
||||
printf 'snapper %s\n' "$*" >>"$TEST_LOG"
|
||||
if [[ "$*" == *"--csvout list"* ]]; then
|
||||
echo "number,cleanup"
|
||||
for i in $(seq 1 45); do
|
||||
echo "$i,timeline"
|
||||
done
|
||||
echo "100,number"
|
||||
echo "101,"
|
||||
fi
|
||||
STUB
|
||||
chmod +x "$fake_bin/snapper"
|
||||
|
||||
snapper_config="$test_tmp/root"
|
||||
printf '%s\n' 'TIMELINE_CREATE="no"' 'NUMBER_CLEANUP="yes"' >"$snapper_config"
|
||||
|
||||
TEST_LOG="$test_tmp/calls.log" \
|
||||
PATH="$fake_bin:$PATH" \
|
||||
OMARCHY_SNAPPER_CONFIG_PATH="$snapper_config" \
|
||||
bash -euo pipefail "$leak_migration" >/dev/null
|
||||
|
||||
deletes=$(grep -c '^snapper -c root delete ' "$test_tmp/calls.log" || true)
|
||||
[[ $deletes -eq 3 ]] || fail "leak migration deletes snapshots in batches" "expected 3 delete calls, got $deletes"
|
||||
|
||||
first_batch=$(grep -m1 '^snapper -c root delete ' "$test_tmp/calls.log")
|
||||
[[ $first_batch == "snapper -c root delete $(seq -s ' ' 1 20)" ]] || fail "leak migration caps delete batches at 20 snapshots" "$first_batch"
|
||||
|
||||
last_batch=$(grep '^snapper -c root delete ' "$test_tmp/calls.log" | tail -n 1)
|
||||
[[ $last_batch == "snapper -c root delete $(seq -s ' ' 41 45)" ]] || fail "leak migration deletes the final partial batch" "$last_batch"
|
||||
|
||||
! grep -E '^snapper -c root delete .*\b(100|101)\b' "$test_tmp/calls.log" || fail "leak migration only deletes timeline snapshots"
|
||||
pass "leak migration removes leaked timeline snapshots in batches and keeps the rest"
|
||||
|
||||
# omarchy-migrate runs under set -e, so a batch that dies on a DBus timeout
|
||||
# would otherwise abort the run and skip every migration queued behind it.
|
||||
: >"$test_tmp/calls.log"
|
||||
printf '%s\n' 'TIMELINE_CREATE="no"' 'NUMBER_CLEANUP="yes"' >"$snapper_config"
|
||||
|
||||
cat >"$fake_bin/snapper" <<'STUB'
|
||||
#!/bin/bash
|
||||
printf 'snapper %s\n' "$*" >>"$TEST_LOG"
|
||||
if [[ "$*" == *"--csvout list"* ]]; then
|
||||
echo "number,cleanup"
|
||||
for i in $(seq 1 45); do
|
||||
echo "$i,timeline"
|
||||
done
|
||||
exit 0
|
||||
fi
|
||||
echo "failure: dbus timeout" >&2
|
||||
exit 1
|
||||
STUB
|
||||
|
||||
output=$(TEST_LOG="$test_tmp/calls.log" \
|
||||
PATH="$fake_bin:$PATH" \
|
||||
OMARCHY_SNAPPER_CONFIG_PATH="$snapper_config" \
|
||||
bash -euo pipefail "$leak_migration" 2>/dev/null) ||
|
||||
fail "leak migration survives a failed delete batch"
|
||||
|
||||
deletes=$(grep -c '^snapper -c root delete ' "$test_tmp/calls.log" || true)
|
||||
[[ $deletes -eq 3 ]] || fail "leak migration keeps draining after a failed batch" "expected 3 delete calls, got $deletes"
|
||||
|
||||
# omarchy-migrate writes the completion marker even when the drain gave up, so
|
||||
# what is left has to be said out loud rather than left for a rerun.
|
||||
grep -qF '45 snapshots could not be deleted' <<<"$output" || fail "leak migration reports the snapshots it could not delete" "$output"
|
||||
pass "leak migration tolerates a batch that fails partway"
|
||||
|
||||
: >"$test_tmp/calls.log"
|
||||
printf '%s\n' 'TIMELINE_CREATE="yes"' >"$snapper_config"
|
||||
|
||||
TEST_LOG="$test_tmp/calls.log" \
|
||||
PATH="$fake_bin:$PATH" \
|
||||
OMARCHY_SNAPPER_CONFIG_PATH="$snapper_config" \
|
||||
bash -euo pipefail "$leak_migration" >/dev/null
|
||||
|
||||
[[ ! -s $test_tmp/calls.log ]] || fail "leak migration leaves deliberate timeline setups alone"
|
||||
pass "leak migration skips systems where timeline snapshots are intentional"
|
||||
|
||||
: >"$test_tmp/calls.log"
|
||||
|
||||
TEST_LOG="$test_tmp/calls.log" \
|
||||
PATH="$fake_bin:$PATH" \
|
||||
OMARCHY_SNAPPER_CONFIG_PATH="$test_tmp/missing" \
|
||||
bash -euo pipefail "$leak_migration" >/dev/null
|
||||
|
||||
[[ ! -s $test_tmp/calls.log ]] || fail "leak migration skips systems without a Snapper root config"
|
||||
pass "leak migration is a no-op without Snapper configured"
|
||||
|
||||
# Snapper's create-config writes a root-only config, and a config this user
|
||||
# cannot read says nothing about whether timeline snapshots are wanted.
|
||||
: >"$test_tmp/calls.log"
|
||||
printf '%s\n' 'TIMELINE_CREATE="no"' >"$snapper_config"
|
||||
chmod 000 "$snapper_config"
|
||||
|
||||
TEST_LOG="$test_tmp/calls.log" \
|
||||
PATH="$fake_bin:$PATH" \
|
||||
OMARCHY_SNAPPER_CONFIG_PATH="$snapper_config" \
|
||||
bash -euo pipefail "$leak_migration" >/dev/null 2>&1
|
||||
|
||||
chmod 600 "$snapper_config"
|
||||
|
||||
grep -qF "sudo grep -qFx TIMELINE_CREATE=\"no\" $snapper_config" "$test_tmp/calls.log" ||
|
||||
fail "leak migration reads a root-only Snapper config as root" "$(cat "$test_tmp/calls.log")"
|
||||
pass "leak migration does not mistake an unreadable Snapper config for an intentional one"
|
||||
@@ -28,12 +28,19 @@ grep -F 'ExecStart=/usr/bin/omarchy-system-sleep-monitor' "$upgrade_to_quattro"
|
||||
grep -F 'reset-failed omarchy-sleep-lock.service' "$upgrade_to_quattro" >/dev/null
|
||||
pass "Omarchy 4 upgrade repairs the legacy sleep lock unit path"
|
||||
|
||||
notify_path="$ROOT/default/systemd/user/omarchy-update-user-notify.path"
|
||||
! grep -q 'PathExistsGlob' "$notify_path"
|
||||
grep -Fx 'PathModified=/usr/share/omarchy/migrations' "$notify_path" >/dev/null
|
||||
pass "migration watcher is edge-triggered so applied migrations on disk cannot re-trigger it"
|
||||
[[ -e $ROOT/default/systemd/user/omarchy-update-user-notify.path ]] &&
|
||||
fail "the retired migration watcher is back; pacman writing the migration directory during omarchy update would notify about migrations that update is already applying"
|
||||
grep -rlE '^(Path[A-Za-z]+|DirectoryNotEmpty)=.*/usr/share/omarchy/migrations' "$ROOT/default/systemd/user" >/dev/null 2>&1 &&
|
||||
fail "a user unit watches the migration directory again; the notifier must stay login-only"
|
||||
pass "no unit watches the migration directory, so package updates cannot trigger the notifier"
|
||||
|
||||
notify_service="$ROOT/default/systemd/user/omarchy-update-user-notify.service"
|
||||
! grep -q 'StartLimit' "$notify_service"
|
||||
notify_service="$ROOT/default/systemd/user/omarchy-migrate-notify.service"
|
||||
grep -Fx 'ExecStart=/usr/bin/omarchy-migrate-notify' "$notify_service" >/dev/null
|
||||
grep -Fx 'WantedBy=graphical-session.target' "$notify_service" >/dev/null
|
||||
pass "migration notifier keeps its start-rate limit and still runs once per login"
|
||||
pass "migration notifier only checks once per login"
|
||||
|
||||
grep -F 'omarchy-migrate-notify.service' "$first_run_units" >/dev/null ||
|
||||
fail "first-run does not enable the login migration notifier"
|
||||
grep -F 'omarchy-update-user-notify' "$first_run_units" >/dev/null &&
|
||||
fail "first-run still enables the retired notifier units"
|
||||
pass "first-run enables the login-only migration notifier"
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
|
||||
|
||||
WORKDIR=$(mktemp -d)
|
||||
cleanup() { rm -rf "$WORKDIR"; }
|
||||
trap cleanup EXIT
|
||||
|
||||
downloads="$WORKDIR/downloads"
|
||||
mkdir -p "$WORKDIR/bin" "$downloads" "$WORKDIR/outbox"
|
||||
printf 'mine' >"$downloads/unrelated.txt"
|
||||
|
||||
# Stands in for the daemon handing over whatever is waiting in the inbox. A
|
||||
# decoy is whatever else drops into the downloads directory while Taildrop is
|
||||
# still blocking on the next delivery.
|
||||
cat >"$WORKDIR/bin/tailscale" <<SH
|
||||
#!/bin/bash
|
||||
target="\${*: -1}"
|
||||
[[ -n \${DECOY:-} ]] && printf 'iso' >"$downloads/\$DECOY"
|
||||
mv "$WORKDIR/outbox/"* "\$target/"
|
||||
SH
|
||||
|
||||
cat >"$WORKDIR/bin/omarchy-notification-send" <<SH
|
||||
#!/bin/bash
|
||||
printf '%s\n' "\$*" >>"$WORKDIR/notifications"
|
||||
# Only the photo notification gets clicked.
|
||||
[[ \$* == *photo.png* ]] && echo default
|
||||
exit 0
|
||||
SH
|
||||
|
||||
cat >"$WORKDIR/bin/xdg-open" <<SH
|
||||
#!/bin/bash
|
||||
printf '%s\n' "\$1" >>"$WORKDIR/opened"
|
||||
SH
|
||||
|
||||
chmod +x "$WORKDIR/bin/"*
|
||||
|
||||
receive() {
|
||||
local expected="$1"
|
||||
shift
|
||||
|
||||
: >"$WORKDIR/notifications"
|
||||
PATH="$WORKDIR/bin:$PATH" "$@" "$ROOT/bin/omarchy-tailscale-receive" --once "$downloads"
|
||||
|
||||
for _ in {1..50}; do
|
||||
(($(wc -l <"$WORKDIR/notifications") >= expected)) && break
|
||||
sleep 0.1
|
||||
done
|
||||
}
|
||||
|
||||
printf 'png' >"$WORKDIR/outbox/photo.png"
|
||||
printf 'pdf' >"$WORKDIR/outbox/notes with space.pdf"
|
||||
receive 2 env
|
||||
|
||||
notifications=$(<"$WORKDIR/notifications")
|
||||
|
||||
[[ -f $downloads/photo.png && -f "$downloads/notes with space.pdf" ]] ||
|
||||
fail "taildrop receive saves incoming files" "$(ls "$downloads")"
|
||||
pass "taildrop receive saves incoming files"
|
||||
|
||||
grep -qF -- "Received photo.png Saved to $downloads --image $downloads/photo.png" <<<"$notifications" ||
|
||||
fail "taildrop receive previews received images" "$notifications"
|
||||
pass "taildrop receive previews received images"
|
||||
|
||||
grep -q "^Received notes with space.pdf .* -g " <<<"$notifications" ||
|
||||
fail "taildrop receive announces other files with a glyph" "$notifications"
|
||||
pass "taildrop receive announces other files with a glyph"
|
||||
|
||||
grep -qxF "$downloads/photo.png" "$WORKDIR/opened" ||
|
||||
fail "taildrop receive opens a clicked file" "$(cat "$WORKDIR/opened" 2>/dev/null)"
|
||||
pass "taildrop receive opens a clicked file"
|
||||
|
||||
grep -q "unrelated.txt" <<<"$notifications" &&
|
||||
fail "taildrop receive leaves the rest of the downloads directory alone" "$notifications"
|
||||
pass "taildrop receive leaves the rest of the downloads directory alone"
|
||||
|
||||
# A second delivery of the same name, alongside a download that arrives while
|
||||
# Taildrop is waiting.
|
||||
printf 'png' >"$WORKDIR/outbox/photo.png"
|
||||
receive 1 env DECOY=browser-download.iso
|
||||
|
||||
notifications=$(<"$WORKDIR/notifications")
|
||||
|
||||
[[ -f $downloads/photo-1.png ]] || fail "taildrop receive keeps both files on a name clash" "$(ls "$downloads")"
|
||||
grep -q "^Received photo-1.png " <<<"$notifications" ||
|
||||
fail "taildrop receive keeps both files on a name clash" "$notifications"
|
||||
pass "taildrop receive keeps both files on a name clash"
|
||||
|
||||
grep -q "browser-download.iso" <<<"$notifications" &&
|
||||
fail "taildrop receive ignores downloads that arrive while it waits" "$notifications"
|
||||
pass "taildrop receive ignores downloads that arrive while it waits"
|
||||
|
||||
[[ -z $(ls -A "$downloads/.omarchy-taildrop") ]] ||
|
||||
fail "taildrop receive empties its staging directory" "$(ls -A "$downloads/.omarchy-taildrop")"
|
||||
pass "taildrop receive empties its staging directory"
|
||||
@@ -28,7 +28,9 @@ const status = tailscale.parseStatus(JSON.stringify({
|
||||
Self: {
|
||||
HostName: 'dhh-fd',
|
||||
DNSName: 'dhh-fd.tail32f559.ts.net.',
|
||||
TailscaleIPs: ['100.74.97.73']
|
||||
TailscaleIPs: ['100.74.97.73'],
|
||||
UserID: 1001,
|
||||
CapMap: { 'https://tailscale.com/cap/file-sharing': null }
|
||||
},
|
||||
Peer: {
|
||||
onlineB: {
|
||||
@@ -38,7 +40,9 @@ const status = tailscale.parseStatus(JSON.stringify({
|
||||
Online: true,
|
||||
OS: 'linux',
|
||||
ExitNodeOption: true,
|
||||
ExitNode: true
|
||||
ExitNode: true,
|
||||
UserID: 1002,
|
||||
TaildropTarget: 5
|
||||
},
|
||||
offline: {
|
||||
HostName: 'offline',
|
||||
@@ -61,7 +65,9 @@ const status = tailscale.parseStatus(JSON.stringify({
|
||||
DNSName: 'alpha.tail32f559.ts.net.',
|
||||
TailscaleIPs: ['100.1.1.1', 'fd7a:115c:a1e0::1901:334b'],
|
||||
Online: true,
|
||||
OS: 'macos'
|
||||
OS: 'macos',
|
||||
UserID: 1001,
|
||||
TaildropTarget: 1
|
||||
},
|
||||
mullvadExit: {
|
||||
HostName: 'al-tia-wg-003',
|
||||
@@ -83,6 +89,20 @@ assert(status.peers[1].ExitNodeOption && status.peers[1].ExitNode, 'tailscale pr
|
||||
assertDeepEqual(status.exitNodes.map(peer => peer.HostName), ['zed'], 'tailscale lists only online tailnet exit nodes')
|
||||
assert(tailscale.isMullvadPeer({ HostName: 'al-tia-wg-003', DNSName: 'al-tia-wg-003.mullvad.ts.net.' }), 'tailscale detects Mullvad status peers')
|
||||
|
||||
assert(status.fileSharing, 'tailscale reads Taildrop capability from the status capability map')
|
||||
assertEqual(status.selfUserId, '1001', 'tailscale records the owning user of this machine')
|
||||
assertDeepEqual(status.peers.map(peer => peer.UserID), ['1001', '1002'], 'tailscale records the owning user of each peer')
|
||||
assert(
|
||||
tailscale.hasFileSharing({ Capabilities: ['https://tailscale.com/cap/file-sharing'] }),
|
||||
'tailscale reads Taildrop capability from the legacy capability list'
|
||||
)
|
||||
assert(!tailscale.hasFileSharing({ CapMap: { funnel: null } }), 'tailscale reports no Taildrop without the capability')
|
||||
assertDeepEqual(status.peers.map(peer => peer.TaildropTarget), [1, 5], 'tailscale records how Tailscale grades each Taildrop target')
|
||||
assert(tailscale.isTaildropTarget({ TaildropTarget: 1, UserID: '1001' }, '2002'), 'tailscale trusts an available Taildrop target')
|
||||
assert(!tailscale.isTaildropTarget({ TaildropTarget: 7, UserID: '1001' }, '1001'), 'tailscale skips peers Tailscale rules out')
|
||||
assert(tailscale.isTaildropTarget({ UserID: '1001' }, '1001'), 'tailscale falls back to same-owner peers without a grade')
|
||||
assert(!tailscale.isTaildropTarget({ UserID: '1002' }, '1001'), 'tailscale skips other owners without a grade')
|
||||
|
||||
const mullvadNodes = tailscale.parseExitNodeList(`
|
||||
IP HOSTNAME COUNTRY CITY STATUS
|
||||
100.65.216.13 au-adl-wg-301.mullvad.ts.net Australia Any -
|
||||
|
||||
@@ -26,11 +26,17 @@ STUB
|
||||
|
||||
chmod +x "$stub_bin/pacman" "$stub_bin/sudo"
|
||||
|
||||
# The migration removes the /etc copy only once the drop-in that replaces it is
|
||||
# installed. Point that at a fixture so the result does not depend on whether
|
||||
# the machine running the tests happens to carry the real one.
|
||||
dropin="$TMPDIR/90-omarchy.conf"
|
||||
: >"$dropin"
|
||||
|
||||
# omarchy-migrate runs each migration with `bash -euo pipefail` and stops the
|
||||
# whole chain on a non-zero exit, so match that invocation exactly.
|
||||
run_migration() {
|
||||
local conf="$1"
|
||||
PATH="$stub_bin:$PATH" OMARCHY_ZRAM_CONF="$conf" \
|
||||
PATH="$stub_bin:$PATH" OMARCHY_ZRAM_CONF="$conf" OMARCHY_ZRAM_DROPIN="$dropin" \
|
||||
bash -euo pipefail "$migration" >/dev/null ||
|
||||
fail "migration exits clean for $(basename "$conf")"
|
||||
}
|
||||
@@ -74,7 +80,7 @@ pass "migration keeps a locally edited config"
|
||||
# them.
|
||||
conf="$TMPDIR/owned.conf"
|
||||
printf '[zram0]\ncompression-algorithm = zstd\n' >"$conf"
|
||||
PATH="$stub_bin:$PATH" PACMAN_OWNS=1 OMARCHY_ZRAM_CONF="$conf" \
|
||||
PATH="$stub_bin:$PATH" PACMAN_OWNS=1 OMARCHY_ZRAM_CONF="$conf" OMARCHY_ZRAM_DROPIN="$dropin" \
|
||||
bash -euo pipefail "$migration" >/dev/null ||
|
||||
fail "migration exits clean for a package-owned config"
|
||||
[[ -f $conf ]] || fail "migration keeps a package-owned config"
|
||||
@@ -85,3 +91,14 @@ conf="$TMPDIR/absent.conf"
|
||||
run_migration "$conf"
|
||||
run_migration "$conf"
|
||||
pass "migration no-ops when the config is already gone"
|
||||
|
||||
# Without the drop-in installed, the /etc copy is the only thing configuring
|
||||
# zram at all. Removing it would leave the machine with no zram device, so the
|
||||
# migration has to leave it alone and stay clean doing it.
|
||||
conf="$TMPDIR/no-dropin.conf"
|
||||
printf '[zram0]\ncompression-algorithm = zstd\n' >"$conf"
|
||||
PATH="$stub_bin:$PATH" OMARCHY_ZRAM_CONF="$conf" OMARCHY_ZRAM_DROPIN="$TMPDIR/absent-dropin.conf" \
|
||||
bash -euo pipefail "$migration" >/dev/null ||
|
||||
fail "migration exits clean when the drop-in is missing"
|
||||
[[ -f $conf ]] || fail "migration keeps the config when the drop-in is missing"
|
||||
pass "migration keeps the config until the drop-in is installed"
|
||||
|
||||
@@ -50,7 +50,15 @@ desired_bytes=$((8192 * 1024 * 1024))
|
||||
run_migration() {
|
||||
local disksize="$1" used="$2" fail_reload="${3:-0}"
|
||||
|
||||
printf '%s' "$disksize" >"$TMPDIR/disksize"
|
||||
# A machine with no zram device has no /sys/block/zram0 at all, so an empty
|
||||
# size means the file is gone rather than blank; the migration tells those
|
||||
# two apart now.
|
||||
if [[ -n $disksize ]]; then
|
||||
printf '%s' "$disksize" >"$TMPDIR/disksize"
|
||||
else
|
||||
rm -f "$TMPDIR/disksize"
|
||||
fi
|
||||
|
||||
printf 'Filename\tType\tSize\tUsed\tPriority\n' >"$TMPDIR/swaps"
|
||||
[[ -n $used ]] &&
|
||||
printf '/dev/zram0 partition 8388604 %s 100\n' "$used" >>"$TMPDIR/swaps"
|
||||
@@ -101,6 +109,15 @@ run_migration "" ""
|
||||
did "systemctl restart dev-zram0.swap" || fail "absent device is created"
|
||||
pass "absent device is created"
|
||||
|
||||
# A device that exists but is swapped off reads empty too, and there the
|
||||
# restart resets it, which fails against whatever still holds it open. Nothing
|
||||
# to gain over the reboot that would have resized it anyway.
|
||||
run_migration $((4096 * 1024 * 1024)) ""
|
||||
did "systemctl restart" && fail "swapped-off device is not restarted"
|
||||
did "omarchy-state set reboot-required" || fail "swapped-off device asks for a reboot"
|
||||
pass "swapped-off device is not restarted"
|
||||
pass "swapped-off device asks for a reboot"
|
||||
|
||||
# A failed daemon-reload must fall back to asking for a reboot.
|
||||
run_migration $((4096 * 1024 * 1024)) 0 1
|
||||
did "systemctl restart" && fail "failed reload does not restart"
|
||||
|
||||
Reference in New Issue
Block a user