cockpit/pkg/shell/machines/test-machines.js

257 lines
9.7 KiB
JavaScript

import cockpit from "cockpit";
import QUnit from "qunit-tests";
import { machines } from "./machines";
const dbus = cockpit.dbus(null, { bus: "internal" });
let configDir;
QUnit.module("machines.d parsing tests", {
beforeEach: () => cockpit.spawn(["mkdir", "-p", configDir + "/cockpit/machines.d"]),
afterEach: () => cockpit.spawn(["rm", "-rf", configDir + "/cockpit/machines.d"]),
after: () => cockpit.spawn(["rm", "-r", configDir]),
});
/***
* Tests for parsing on-disk JSON configuration
*/
function machinesParseTest(assert, machines_defs, expectedProperty) {
const done = assert.async();
assert.expect(3);
const setup = [];
for (const fname in machines_defs) {
let path = fname;
if (fname.indexOf('/') < 0)
path = configDir + "/cockpit/machines.d/" + fname;
setup.push(cockpit.file(path).replace(machines_defs[fname]));
}
Promise.all(setup).then(function() {
dbus.call("/machines", "org.freedesktop.DBus.Properties",
"Get", ["cockpit.Machines", "Machines"],
{ type: "ss" })
.done(function(reply) {
assert.equal(reply[0].t, "a{sa{sv}}", "expected return type");
assert.deepEqual(reply[0].v, expectedProperty, "expected property value");
})
.always(function() {
assert.equal(this.state(), "resolved", "finished successfully");
done();
});
});
}
QUnit.test("no machine definitions", function (assert) {
machinesParseTest(assert, {}, {});
});
QUnit.test("empty json", function (assert) {
machinesParseTest(assert, { "01.json": "" }, {});
});
QUnit.test("two definitions", function (assert) {
machinesParseTest(assert,
{
"01.json": '{"green": {"visible": true, "address": "1.2.3.4"}, ' +
' "9.8.7.6": {"visible": false, "address": "9.8.7.6", "user": "admin"}}'
},
{
green: {
address: { t: "s", v: "1.2.3.4" },
visible: { t: "b", v: true }
},
"9.8.7.6": {
address: { t: "s", v: "9.8.7.6" },
user: { t: "s", v: "admin" },
visible: { t: "b", v: false }
}
});
});
QUnit.test("invalid json", function (assert) {
machinesParseTest(assert, { "01.json": '{"green":' }, {});
});
QUnit.test("invalid data types", function (assert) {
machinesParseTest(assert, { "01.json": '{"green": []}' }, {});
});
QUnit.test("merge several JSON files", function (assert) {
/* 99-webui.json changes a property in green, adds a
* property to blue, and adds an entire new host yellow */
machinesParseTest(
assert,
{
"01-green.json": '{"green": {"visible": true, "address": "1.2.3.4"}}',
"02-blue.json": '{"blue": {"address": "9.8.7.6"}}',
"09-webui.json": '{"green": {"visible": false}, ' +
' "blue": {"user": "joe"}, ' +
' "yellow": {"address": "fe80::1", "user": "sue"}}'
},
{
green: {
address: { t: "s", v: "1.2.3.4" },
visible: { t: "b", v: false }
},
blue: {
address: { t: "s", v: "9.8.7.6" },
user: { t: "s", v: "joe" },
},
yellow: {
address: { t: "s", v: "fe80::1" },
user: { t: "s", v: "sue" },
}
}
);
});
QUnit.test("merge JSON files with errors", function (assert) {
machinesParseTest(
assert,
{
"01-valid.json": '{"green": {"visible": true, "address": "1.2.3.4"}}',
"02-syntax.json": '[a',
"03-toptype.json": '["green"]',
"04-toptype.json": '{"green": ["visible"]}',
"05-valid.json": '{"blue": {"address": "fe80::1"}}',
// goodprop should still be considered
"06-proptype.json": '{"green": {"visible": [], "address": {"bar": null}, "goodprop": "yeah"}}',
"07-valid.json": '{"green": {"user": "joe"}}',
"08-empty.json": ''
},
{
green: {
address: { t: "s", v: "1.2.3.4" },
visible: { t: "b", v: true },
user: { t: "s", v: "joe" },
goodprop: { t: "s", v: "yeah" },
},
blue: {
address: { t: "s", v: "fe80::1" }
}
}
);
});
/***
* Tests for Update()
*/
function machinesUpdateTest(assert, origJson, host, props, expectedJson) {
const done = assert.async();
assert.expect(3);
const f = configDir + "/cockpit/machines.d/99-webui.json";
cockpit.file(f).replace(origJson)
.done(function(tag) {
dbus.call("/machines", "cockpit.Machines", "Update", ["99-webui.json", host, props], { type: "ssa{sv}" })
.then(function(reply) {
assert.deepEqual(reply, [], "no expected return value");
return cockpit.file(f, { syntax: JSON }).read()
.done(function(content, tag) {
assert.deepEqual(content, expectedJson, "expected file content");
})
.fail(function(err) {
assert.equal(err, undefined, "expected no error");
});
})
.always(function() {
assert.equal(this.state(), "resolved", "finished successfully");
done();
});
});
}
QUnit.test("no config files", function (assert) {
machinesUpdateTest(assert, null, "green", { visible: cockpit.variant('b', true), address: cockpit.variant('s', "1.2.3.4") },
{ green: { address: "1.2.3.4", visible: true } });
});
QUnit.test("add host to existing map", function (assert) {
machinesUpdateTest(assert,
'{"green": {"visible": true, "address": "1.2.3.4"}}',
"blue",
{ visible: cockpit.variant('b', false), address: cockpit.variant('s', "9.8.7.6") },
{
green: { address: "1.2.3.4", visible: true },
blue: { address: "9.8.7.6", visible: false }
});
});
QUnit.test("change bool host property", function (assert) {
machinesUpdateTest(assert,
'{"green": {"visible": true, "address": "1.2.3.4"}}',
"green",
{ visible: cockpit.variant('b', false) },
{ green: { address: "1.2.3.4", visible: false } });
});
QUnit.test("change string host property", function (assert) {
machinesUpdateTest(assert,
'{"green": {"visible": true, "address": "1.2.3.4"}}',
"green",
{ address: cockpit.variant('s', "fe80::1") },
{ green: { address: "fe80::1", visible: true } });
});
QUnit.test("add host property", function (assert) {
machinesUpdateTest(assert,
'{"green": {"visible": true, "address": "1.2.3.4"}}',
"green",
{ color: cockpit.variant('s', "pitchblack") },
{ green: { address: "1.2.3.4", visible: true, color: "pitchblack" } });
});
QUnit.test("Update() only writes delta", function (assert) {
const done = assert.async();
cockpit.file(configDir + "/cockpit/machines.d/01-green.json")
.replace('{"green": {"address": "1.2.3.4"}, "blue": {"address": "fe80::1"}}')
.done(function(tag) {
machinesUpdateTest(assert,
null,
"green",
{ color: cockpit.variant('s', "pitchblack") },
{ green: { color: "pitchblack" } });
done();
});
});
QUnit.test("updating and existing delta file", function (assert) {
const done = assert.async();
cockpit.file(configDir + "/cockpit/machines.d/01-green.json")
.replace('{"green": {"address": "1.2.3.4"}, "blue": {"address": "fe80::1"}}')
.done(function(tag) {
machinesUpdateTest(assert,
'{"green": {"address": "9.8.7.6", "user": "joe"}}',
"green",
{ color: cockpit.variant('s', "pitchblack") },
{ green: { address: "9.8.7.6", user: "joe", color: "pitchblack" } });
done();
});
});
QUnit.test("colors.parse()", function (assert) {
const colors = [
["#960064", "rgb(150, 0, 100)"],
["rgb(150, 0, 100)", "rgb(150, 0, 100)"],
["#ccc", "rgb(204, 204, 204)"],
];
assert.expect(colors.length);
colors.forEach(function(color) {
assert.equal(machines.colors.parse(color[0]), color[1], "parsed color " + color[0]);
});
});
/* The test cockpit-bridge gets started with temp $XDG_CONFIG_DIRS instead of defaulting to /etc/.
* Read it from the bridge so that we can put our test files into it. */
const proxy = dbus.proxy("cockpit.Environment", "/environment");
proxy.wait(function () {
configDir = proxy.Variables.XDG_CONFIG_DIRS;
QUnit.start();
});