| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- /*
- Desktop: backend API surface.
- Exercises every endpoint registered by DesktopInit in src/desktop.go,
- driving the exact request shapes the desktop.html front end uses:
- /system/desktop/host host / device details
- /system/desktop/user self info (quota, groups, admin),
- another user's public info, noicon
- /system/desktop/theme list wallpapers, set + read back
- /system/desktop/preference set / get / remove a preference key
- /system/desktop/files icon location set / get / delete
- /system/desktop/createShortcut create a .shortcut on the desktop
- /system/desktop/listDesktop list desktop objects + shortcut meta
- /system/desktop/opr/renameShortcut rename it, and reject off-desktop
- All backend, so this is the deterministic backbone of the desktop
- coverage; the UI specs (022, 023) drive the same features visually.
- */
- "use strict";
- const h = require("../lib/system-harness");
- const OTHER_USER = "e2edeskother";
- const OTHER_PASS = "e2e-Other-Pass1";
- const SC_NAME = "e2e-shortcut";
- const SC_FILE = "user:/Desktop/" + SC_NAME + ".shortcut";
- h.run("DESKTOP-API", async function (env) {
- const base = env.baseURL;
- const page = await h.newPage(env.browser);
- await h.loginViaAPI(page, base, env.admin.username, env.admin.password);
- // ── 1. /host reports device details ──
- const host = await h.getJSON(page, base + "/system/desktop/host");
- ["Hostname", "DeviceUUID", "BuildVersion", "InternalVersion"].forEach(function (k) {
- if (!(k in host)) h.fail("/system/desktop/host missing field " + k);
- });
- if (host.Hostname.indexOf("E2E ArozOS") === -1) {
- h.fail("/system/desktop/host wrong hostname: " + host.Hostname);
- }
- h.ok("/host returns hostname, device UUID and version fields");
- // ── 2. /user reports the signed-in user's profile ──
- const me = await h.getJSON(page, base + "/system/desktop/user");
- if (me.Username !== env.admin.username) h.fail("/user wrong username: " + me.Username);
- if (me.IsAdmin !== true) h.fail("/user should mark the admin account as admin");
- if (!Array.isArray(me.UserGroups) || me.UserGroups.indexOf("administrator") === -1) {
- h.fail("/user should list the administrator group: " + JSON.stringify(me.UserGroups));
- }
- if (typeof me.StorageQuotaTotal !== "number") h.fail("/user missing StorageQuotaTotal");
- h.ok("/user reports username, admin flag, groups and storage quota");
- // noicon=true (POST param) strips the (potentially large) icon payload.
- const meNoIcon = JSON.parse(await h.postForm(page, base + "/system/desktop/user", { noicon: "true" }));
- if (meNoIcon.UserIcon !== "") h.fail("/user noicon=true should return an empty UserIcon");
- h.ok("/user with noicon=true omits the icon payload");
- // Another user's *public* info via ?target= (create one, query, remove).
- let resp = await h.postForm(page, base + "/system/auth/register", {
- username: OTHER_USER, password: OTHER_PASS, group: "user"
- });
- if (resp.toLowerCase().indexOf("ok") === -1) h.fail("could not create second user: " + resp);
- const other = await h.getJSON(page, base + "/system/desktop/user?target=" + encodeURIComponent(OTHER_USER));
- if (other.Username !== OTHER_USER) h.fail("/user?target did not return the target user");
- if (other.IsAdmin !== false) h.fail("/user?target should not mark a plain user as admin");
- h.ok("/user?target returns another user's public info");
- const missing = await page.request.get(base + "/system/desktop/user?target=nosuchuser____");
- if ((await missing.text()).toLowerCase().indexOf("error") === -1) {
- h.fail("/user?target for a missing user should error");
- }
- h.ok("/user?target for a non-existent user returns an error");
- // ── 3. /theme lists wallpapers and round-trips the user's choice ──
- const themes = await h.getJSON(page, base + "/system/desktop/theme");
- if (!Array.isArray(themes) || themes.length === 0) h.fail("/theme returned no wallpaper themes");
- if (!("Theme" in themes[0]) || !("Bglist" in themes[0])) {
- h.fail("/theme entries missing Theme/Bglist fields: " + JSON.stringify(themes[0]));
- }
- h.ok("/theme lists wallpaper themes with their backgrounds");
- const chosen = themes[0].Theme;
- const setThemeResp = (await (await page.request.get(base + "/system/desktop/theme?set=" +
- encodeURIComponent(chosen))).text()).trim();
- if (setThemeResp.replace(/"/g, "").toLowerCase() !== "ok") h.fail("/theme?set failed: " + setThemeResp);
- const gotTheme = (await (await page.request.get(base + "/system/desktop/theme?get=true")).text()).trim();
- if (gotTheme.replace(/"/g, "") !== chosen) {
- h.fail("/theme?get did not return the theme just set (" + gotTheme + " != " + chosen + ")");
- }
- h.ok("/theme?set then ?get round-trips the selected wallpaper theme");
- // ── 4. /preference set / get / remove ──
- const prefKey = "e2e_pref";
- const prefVal = "value-" + Date.now();
- resp = await h.postForm(page, base + "/system/desktop/preference", { preference: prefKey, value: prefVal });
- if (resp.toLowerCase().indexOf("ok") === -1) h.fail("preference set failed: " + resp);
- let gotPref = JSON.parse(await h.postForm(page, base + "/system/desktop/preference", { preference: prefKey }));
- if (gotPref !== prefVal) h.fail("preference get did not return the stored value: " + gotPref);
- h.ok("/preference stores and returns a preference value");
- resp = await h.postForm(page, base + "/system/desktop/preference", { preference: prefKey, remove: "true" });
- if (resp.toLowerCase().indexOf("ok") === -1) h.fail("preference remove failed: " + resp);
- gotPref = JSON.parse(await h.postForm(page, base + "/system/desktop/preference", { preference: prefKey }));
- if (gotPref !== "") h.fail("preference should be empty after removal, got: " + gotPref);
- h.ok("/preference removes a preference key");
- // ── 5. createShortcut puts a .shortcut on the desktop ──
- resp = await h.postForm(page, base + "/system/desktop/createShortcut", {
- stype: "module", stext: SC_NAME, spath: "Dummy/index.html", sicon: "img/system/favicon.png"
- });
- if (resp.toLowerCase().indexOf("ok") === -1) h.fail("createShortcut failed: " + resp);
- h.ok("/createShortcut writes a shortcut file to the desktop");
- // ── 6. listDesktop reports the shortcut with parsed metadata ──
- let desktop = await h.getJSON(page, base + "/system/desktop/listDesktop");
- let sc = desktop.filter(function (o) { return o.Filename === SC_NAME + ".shortcut"; })[0];
- if (!sc) h.fail("listDesktop did not include the created shortcut");
- if (!sc.IsShortcut || sc.ShortcutType !== "module" || sc.ShortcutName !== SC_NAME) {
- h.fail("listDesktop shortcut metadata wrong: " + JSON.stringify(sc));
- }
- h.ok("/listDesktop returns the shortcut with IsShortcut + parsed name/type");
- // ── 7. icon location set / get / delete via /files ──
- resp = await h.postForm(page, base + "/system/desktop/files", {
- set: SC_NAME + ".shortcut", x: "123", y: "456"
- });
- if (resp.replace(/"/g, "").toLowerCase() !== "ok") h.fail("/files set location failed: " + resp);
- const loc = JSON.parse(await h.postForm(page, base + "/system/desktop/files", { get: SC_NAME + ".shortcut" }));
- if (loc[0] !== 123 || loc[1] !== 456) h.fail("/files get returned wrong location: " + JSON.stringify(loc));
- h.ok("/files stores and returns a desktop icon coordinate");
- await h.postForm(page, base + "/system/desktop/files", { del: SC_NAME + ".shortcut" });
- const locGone = JSON.parse(await h.postForm(page, base + "/system/desktop/files", { get: SC_NAME + ".shortcut" }));
- if (locGone[0] !== -1 || locGone[1] !== -1) h.fail("/files del did not clear the location: " + JSON.stringify(locGone));
- h.ok("/files deletes a desktop icon coordinate");
- // ── 8. renameShortcut updates the shortcut's display name ──
- const newName = "e2e-renamed";
- resp = (await (await page.request.get(base + "/system/desktop/opr/renameShortcut?src=" +
- encodeURIComponent(SC_FILE) + "&new=" + encodeURIComponent(newName))).text()).trim();
- if (resp.toLowerCase().indexOf("ok") === -1) h.fail("renameShortcut failed: " + resp);
- desktop = await h.getJSON(page, base + "/system/desktop/listDesktop");
- sc = desktop.filter(function (o) { return o.Filename === SC_NAME + ".shortcut"; })[0];
- if (!sc || sc.ShortcutName !== newName) {
- h.fail("renameShortcut did not update the display name: " + JSON.stringify(sc));
- }
- h.ok("/opr/renameShortcut updates the shortcut display name");
- // Off-desktop rename must be refused.
- const badRename = (await (await page.request.get(base + "/system/desktop/opr/renameShortcut?src=" +
- encodeURIComponent("user:/Documents/whatever.shortcut") + "&new=x")).text()).trim();
- if (badRename.toLowerCase().indexOf("error") === -1) {
- h.fail("renameShortcut on a non-desktop path should be refused: " + badRename);
- }
- h.ok("/opr/renameShortcut refuses a path outside the desktop");
- // ── Cleanup ──
- const csrft = await h.csrfToken(page, base);
- await h.postForm(page, base + "/system/file_system/fileOpr", {
- opr: "delete", src: JSON.stringify([SC_FILE]), csrft: csrft
- });
- await h.postForm(page, base + "/system/users/removeUser", { username: OTHER_USER });
- await page.close();
- });
|