UNPKG

gpii-windows

Version:

Components of the GPII personalization infrastructure for use on Microsoft's "Windows" ™

313 lines (255 loc) 9.41 kB
/* * Windows service handler tests * * Copyright 2017 Raising the Floor - International * * Licensed under the New BSD license. You may not use this file except in * compliance with this License. * * The R&D leading to these results received funding from the * Department of Education - Grant H421A150005 (GPII-APCP). However, * these results do not necessarily represent the policy of the * Department of Education, and you should not assume endorsement by the * Federal Government. * * You may obtain a copy of the License at * https://github.com/GPII/universal/blob/master/LICENSE.txt */ "use strict"; var fluid = require("gpii-universal"), ffi = require("ffi-napi"), net = require("net"); var jqUnit = fluid.require("node-jqunit"); var gpii = fluid.registerNamespace("gpii"); fluid.registerNamespace("gpii.tests.serviceHandler"); process.env.GPII_SERVICE_PIPE_DISABLED = true; require("../index.js"); jqUnit.module("gpii.tests.serviceHandler"); gpii.tests.serviceHandler.kernel32 = ffi.Library("kernel32", { // https://msdn.microsoft.com/library/ms687032 "WaitForSingleObject": [ "ulong", ["uint", "ulong"] ], // https://msdn.microsoft.com/library/ms682396 "CreateEventW": [ "ulong", [ "int", "int", "int", "int" ] ] }); jqUnit.asyncTest("serviceChallenge tests", function () { var badHandles = [ null, "", 0, "0", 123, "123", "text" ]; // Try some invalid data. Nothing is expected to happen, it shouldn't crash. badHandles.forEach(function (handle) { fluid.log("serviceChallenge - trying: ", handle); gpii.windows.service.serviceChallenge(handle); }); // Try a real event handle. var eventHandle = gpii.tests.serviceHandler.kernel32.CreateEventW(0, false, false, 0); var timeout = 5000; gpii.tests.serviceHandler.kernel32.WaitForSingleObject.async(eventHandle, timeout, function (err, result) { if (err) { jqUnit.fail(err); } else { var WAIT_OBJECT_0 = 0; jqUnit.assertEquals("WaitForSingleObject should return WAIT_OBJECT_0", WAIT_OBJECT_0, result); jqUnit.start(); } }); gpii.windows.service.serviceChallenge(eventHandle); }); jqUnit.asyncTest("connectToService failure tests", function () { var tests = [ "aa", 123, "a:", ":a", "pipe:", "pipe:a/b", "pipe:a\\b", "pipe:aa bb", "pipe:aa/bb", "pipe:aa\nbb", "pipe:201-valid-characters-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ]; jqUnit.expect(tests.length * 3 + 4); var serviceHandler = gpii.windows.service.serviceHandler({ listeners: { // Don't auto-connect. "onCreate.connectToService": "fluid.identity" } }); var runTest = function (testIndex) { if (testIndex >= tests.length) { jqUnit.start(); return; } var test = tests[testIndex]; process.env.GPII_SERVICE_PIPE = test; var promise = serviceHandler.connectToService(); jqUnit.assertNotNull("connectToService must return non-null", promise); jqUnit.assertTrue("connectToService must return a promise", fluid.isPromise(promise)); promise.then(function () { jqUnit.fail("connectToService should have rejected"); }, function (e) { jqUnit.assertUndefined("connectToService should reject with undefined", e); runTest(testIndex + 1); }); }; // Test a valid name, but doesn't exist. process.env.GPII_SERVICE_PIPE = "pipe:test-not-exist" + Math.random().toString(36); var promise = serviceHandler.connectToService(); jqUnit.assertNotNull("connectToService must return non-null", promise); jqUnit.assertTrue("connectToService must return a promise", fluid.isPromise(promise)); promise.then(function () { jqUnit.fail("connectToService should have rejected"); }, function (e) { jqUnit.assertTrue("connectToService should reject with an error", e.isError); jqUnit.assertEquals("connectToService should reject with ENOENT", "ENOENT", e.error && e.error.code); runTest(0); }); }); jqUnit.asyncTest("connectToService tests", function () { var tests = [ { data: "challenge:none\nOK\n", expect: "resolve" }, { data: "challenge:1\nOK\n", expect: "resolve" }, { data: "challenge:2\nOK\n", expect: "resolve" }, { data: "challenge:A\nOK\n", expect: "reject" }, { data: "challenge:1\nchallenge:2\nOK\n", expect: "reject" }, { data: "stupid value\n", expect: "reject" }, { data: "OK\n", expect: "resolve" }, { data: null, disconnect: true, expect: "reject" }, { data: "challenge:1\n", disconnect: true, expect: "reject" }, { data: "challenge:none\n", disconnect: true, expect: "reject" }, { data: "challenge:none\nOK\n", disconnect: true, expect: "resolve" } ]; var serviceHandler = gpii.windows.service.serviceHandler({ listeners: { // Don't auto-connect. "onCreate.connectToService": "fluid.identity" }, reconnect: false }); var pipeIdPrefix = "test-connectToService-" + Math.random().toString(36); var runTest = function (testIndex) { if (testIndex >= tests.length) { jqUnit.start(); return; } var test = tests[testIndex]; var pipeId = pipeIdPrefix + testIndex; var pipeName = serviceHandler.options.pipePrefix + pipeId; var pipeServer = net.createServer(); var closed = 0; pipeServer.on("error", jqUnit.fail); pipeServer.listen(pipeName, function () { process.env.GPII_SERVICE_PIPE = "pipe:" + pipeId; var promise = serviceHandler.connectToService(); jqUnit.assertNotNull("connectToService must return non-null", promise); jqUnit.assertTrue("connectToService must return a promise", fluid.isPromise(promise)); promise.then(function () { jqUnit.assertEquals("connectToService must only resolve if expected", test.expect, "resolve"); runTest(testIndex + 1); }, function () { jqUnit.assertEquals("connectToService must only reject if expected", test.expect, "reject"); // Wait for the pipe to close. gpii.windows.waitForCondition(function () { return closed; }, { timeout: 5000, dontReject: true }).then(function (value) { jqUnit.assertNotEquals("connectToService should have closed the pipe", "timeout", value); runTest(testIndex + 1); }, jqUnit.fail); }); }); pipeServer.on("connection", function (pipe) { fluid.log("pipeServer.connection"); pipe.on("data", function (data) { fluid.log("pipeServer.data", data.toString()); }); pipe.on("close", function () { closed = true; }); if (test.data) { fluid.log("Sending ", test.data.replace(/\n/g, "\\n")); pipe.write(test.data); } if (test.disconnect) { fluid.log("Disconnecting"); pipe.destroy(); } }); }; runTest(0); }); jqUnit.test("status request tests", function () { var requestHandler = gpii.windows.service.requestHandler(); var result = requestHandler.status(); jqUnit.assertTrue("status should return an object", fluid.isPlainObject(result)); jqUnit.assertTrue("status should be 'running'", result.isRunning); requestHandler.destroy(); }); jqUnit.test("shutdown request tests", function () { var requestHandler = gpii.windows.service.requestHandler(); var sendMessageCalled = false; // Mock the sendMessage, instead of sending the real shutdown message. var sendMessageOrig = gpii.windows.messages.sendMessage; gpii.windows.messages.sendMessage = function (window, msg) { jqUnit.assertEquals("sendMessage should be called with the correct window", "gpii-message-window", window); jqUnit.assertEquals("sendMessage should be called with the correct message", gpii.windows.API_constants.WM_QUERYENDSESSION, msg); sendMessageCalled = true; }; try { requestHandler.shutdown(); jqUnit.assertTrue("sendMessage should have been invoked", sendMessageCalled); } finally { gpii.windows.messages.sendMessage = sendMessageOrig; } });