summaryrefslogtreecommitdiffstatshomepage
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/fixtures/panel-lifecycle.js112
-rw-r--r--tests/test_canonical.py2
-rw-r--r--tests/test_canonical_desktop.py24
-rw-r--r--tests/test_canonical_panel.py89
4 files changed, 227 insertions, 0 deletions
diff --git a/tests/fixtures/panel-lifecycle.js b/tests/fixtures/panel-lifecycle.js
new file mode 100644
index 0000000..d035289
--- /dev/null
+++ b/tests/fixtures/panel-lifecycle.js
@@ -0,0 +1,112 @@
+import assert from "node:assert/strict";
+
+const callbacks = [];
+let killed = 0;
+let removed = 0;
+class Actor {
+ constructor(props = {}) {
+ Object.assign(this, props);
+ }
+ add_child() {}
+ set_text(text) {
+ this.text = text;
+ }
+ set_style_class_name(name) {
+ this.style = name;
+ }
+ destroy() {
+ this.destroyed = true;
+ }
+}
+class Button extends Actor {
+ menu = { addMenuItem() {}, addAction() {} };
+}
+class Item {
+ label = new Actor();
+}
+class Extension {
+ uuid = "test";
+}
+const St = { BoxLayout: Actor, Label: Actor };
+const Clutter = { ActorAlign: { CENTER: 0 } };
+const PanelMenu = { Button };
+const PopupMenu = { PopupMenuItem: Item };
+const Main = { panel: { addToStatusArea() {} }, notifyError() {} };
+const GLib = {
+ PRIORITY_DEFAULT: 0,
+ SOURCE_CONTINUE: true,
+ timeout_add_seconds: () => 1,
+ Source: {
+ remove() {
+ removed++;
+ },
+ },
+ get_home_dir: () => "/home/test",
+ build_filenamev: (parts) => parts.join("/"),
+};
+const Gio = {
+ Cancellable: class {
+ cancelled = false;
+ cancel() {
+ this.cancelled = true;
+ }
+ is_cancelled() {
+ return this.cancelled;
+ }
+ },
+ SubprocessFlags: { NONE: 0, STDOUT_PIPE: 1, STDERR_PIPE: 2 },
+ Subprocess: {
+ new() {
+ return {
+ communicate_utf8_async(_input, _token, callback) {
+ callbacks.push(callback);
+ },
+ force_exit() {
+ killed++;
+ },
+ };
+ },
+ },
+};
+
+// EXTENSION
+
+const panel = new CorporatePanel();
+panel.enable();
+panel._refresh();
+assert.equal(callbacks.length, 1, "Do not overlap status processes");
+panel._render({
+ displays: "EXT 1",
+ updates: "APT 3",
+ failed: "FAIL 1",
+ reboot: "",
+ errors: "",
+});
+assert.equal(panel._labels.failed.style, "corporate-critical");
+assert.equal(panel._labels.updates.style, "corporate-warning");
+assert.equal(panel._labels.reboot.visible, false);
+const button = panel._button;
+panel.disable();
+assert.equal(killed, 1);
+assert.equal(removed, 1);
+assert.equal(button.destroyed, true);
+panel.enable();
+callbacks[0]({}, {});
+assert.ok(panel._process, "Old callbacks cannot clear the new process");
+const data = {
+ displays: "EXT 0",
+ updates: "APT 0",
+ failed: "FAIL 0",
+ reboot: "REBOOT",
+ errors: "",
+};
+callbacks[1](
+ {
+ communicate_utf8_finish: () => [true, JSON.stringify(data), ""],
+ get_successful: () => true,
+ },
+ {},
+);
+assert.equal(panel._labels.reboot.visible, true);
+assert.equal(panel._process, null);
+panel.disable();
diff --git a/tests/test_canonical.py b/tests/test_canonical.py
index e1c825c..27fd199 100644
--- a/tests/test_canonical.py
+++ b/tests/test_canonical.py
@@ -132,6 +132,7 @@ class RoleTests(unittest.TestCase):
".config/git/config",
".config/ghostty/config",
".local/bin/rqr",
+ ".local/share/gnome-shell/extensions/corporate-panel@dotfiles/extension.js",
]:
self.assertIn(required, files)
for path in files:
@@ -203,6 +204,7 @@ class RoleTests(unittest.TestCase):
)
self.assertNotIn(".config/autostart/dotfiles-", files)
self.assertNotIn("gpg-agent.service.d/canonical.conf", files)
+ self.assertNotIn("corporate-panel@dotfiles", files)
if __name__ == "__main__":
diff --git a/tests/test_canonical_desktop.py b/tests/test_canonical_desktop.py
index cdbc812..9bdace1 100644
--- a/tests/test_canonical_desktop.py
+++ b/tests/test_canonical_desktop.py
@@ -14,6 +14,30 @@ SPEC.loader.exec_module(desktop)
class DesktopTests(unittest.TestCase):
+ def test_clipboard_shortcut_preserves_other_display_bindings(self):
+ settings = MagicMock()
+ settings.get_strv.return_value = ["<Super>p", "XF86Display", "<Super>x"]
+ with (
+ patch.object(desktop, "settings_object", return_value=settings),
+ patch.object(desktop, "write_key") as write,
+ ):
+ desktop.shortcuts({})
+ write.assert_any_call(
+ "org.gnome.mutter.keybindings",
+ "switch-monitor",
+ ["XF86Display", "<Super>x"],
+ {},
+ )
+
+ def test_panel_settings_disable_external_ip_lookup(self):
+ with patch.object(desktop, "write_key") as write:
+ desktop.panel({})
+ write.assert_any_call(
+ "org.gnome.shell.extensions.vitals", "include-public-ip", False, {}
+ )
+ self.assertIn("corporate-panel@dotfiles", desktop.EXTENSIONS)
+ self.assertIn("ubuntu-appindicators@ubuntu.com", desktop.EXTENSIONS)
+
def test_unknown_keys_fail_without_writing(self):
settings = MagicMock()
settings.props.settings_schema.list_keys.return_value = []
diff --git a/tests/test_canonical_panel.py b/tests/test_canonical_panel.py
new file mode 100644
index 0000000..efdf7a5
--- /dev/null
+++ b/tests/test_canonical_panel.py
@@ -0,0 +1,89 @@
+import importlib.util
+import json
+import subprocess
+import tempfile
+import unittest
+from pathlib import Path
+from unittest.mock import patch
+
+ROOT = Path(__file__).resolve().parents[1]
+SPEC = importlib.util.spec_from_file_location(
+ "panel", ROOT / "dot_local/lib/dotfiles/canonical_panel.py"
+)
+assert SPEC and SPEC.loader
+panel = importlib.util.module_from_spec(SPEC)
+SPEC.loader.exec_module(panel)
+
+
+class PanelTests(unittest.TestCase):
+ def test_extension_lifecycle(self):
+ source = (
+ ROOT
+ / "dot_local/share/gnome-shell/extensions/corporate-panel@dotfiles/extension.js"
+ )
+ code = "\n".join(
+ line
+ for line in source.read_text().splitlines()
+ if not line.startswith("import ")
+ )
+ code = code.replace("export default class", "class")
+ harness = (ROOT / "tests/fixtures/panel-lifecycle.js").read_text()
+ subprocess.run(
+ ["node", "--input-type=module"],
+ input=harness.replace("// EXTENSION", code),
+ text=True,
+ check=True,
+ )
+
+ def test_failed_units_use_both_scopes(self):
+ with patch.object(
+ panel, "output", side_effect=['[{"unit":"a.service"}]', "[]"]
+ ):
+ self.assertEqual(panel.failed_units(), "FAIL 1")
+
+ def test_failed_query_does_not_report_healthy(self):
+ with patch.object(panel, "output", side_effect=RuntimeError("offline")):
+ status = panel.collect()
+ self.assertEqual(status["failed"], "FAIL ?")
+ self.assertIn("offline", status["errors"])
+
+ def test_updates_ignore_header(self):
+ with patch.object(
+ panel,
+ "output",
+ return_value="Listing...\na/stable 1 amd64 [upgradable from: 0]\n",
+ ):
+ self.assertEqual(panel.apt_updates(), "APT 1")
+
+ def test_displays_do_not_depend_on_personal_connector_names(self):
+ with tempfile.TemporaryDirectory() as directory:
+ root = Path(directory)
+ for name, value in [
+ ("card1-DP-9", "connected"),
+ ("card0-eDP-1", "connected"),
+ ("card1-HDMI-A-1", "disconnected"),
+ ]:
+ (root / name).mkdir()
+ (root / name / "status").write_text(value)
+ self.assertEqual(panel.displays(root), "EXT 1")
+
+ def test_update_action_quotes_source_directory(self):
+ with patch.object(panel, "output", return_value="/tmp/work tree'quoted\n"):
+ command = panel.action_command("update")
+ self.assertEqual(command[:2], ["/snap/bin/ghostty", "-e"])
+ self.assertIn("just update", command[-1])
+ self.assertIn("'\"'\"'", command[-1])
+
+ def test_extension_metadata_targets_corporate_gnome(self):
+ metadata = json.loads(
+ (
+ ROOT
+ / "dot_local/share/gnome-shell/extensions/corporate-panel@dotfiles/metadata.json"
+ ).read_text()
+ )
+ self.assertEqual(metadata["uuid"], "corporate-panel@dotfiles")
+ self.assertIn("50", metadata["shell-version"])
+
+
+if __name__ == "__main__":
+ unittest.main()