diff --git a/documentation/PCPChannel.md b/documentation/PCPChannel.md new file mode 100644 index 000000000..f80fe8576 --- /dev/null +++ b/documentation/PCPChannel.md @@ -0,0 +1,62 @@ +## The PCP Interface + +This document describes how the __PCP Interface__ works and what its API is. + +### Introduction +The PCP stands for the Personal Control Panel and can be considered the GPIIs main place for displaying messages to the user as well as providing the user with a place to adjust some of their settings, along with other useful controls + +The PCP Interface can be connected to via the web socket: `http://localhost:8081/pcpChannel` and its API provide functionality for: +* Notifying when a user is logging in and logging out +* Sending a list of desired adjusters to the PCP +* Sending messages to be displayed in the PCP +* Receiving responses to messages from PCP + +Message types: +(Info<- default), Error, Warning +{ + type: "infoMessage", + message: "Howdy user! This is a message to you" +} + +### Internal API + +The PCPChannel is a component of the Flowmanager, used in the local/hybrid deployment on the local device. Its 3 main invokers are: +* `sendUserMessage`: This will send a message to be displayed in the PCP and takes a 'message' and a 'messageType' argument. + * **message** A string to display to the user + * **messageType** (optional) should be either "infoMessage", "warningMessage" or "errorMessage" - and will default to "infoMessage" if no second argument is given. +* `notifyLogin`: Should be called when notifying the PCP of a new user login. It takes two arguments; userToken and adjusters: + * **userToken** should be the token of the user logging in + * **adjusters** (optional) An object of the adjusters to display as keys and the value to show for the given adjuster as value. Will default to `{ "http://registry.gpii.net/common/highContrastEnabled": false }` +* `notifyLogout`: Should be called when notifying the PCP of a user logout. Does not take any arguments + + +### External API + + +#### Connection + +Connection to the PCP is done as a WebSockets connection to the URL `/pcpChannel`. + + +#### On login [`login` message]: + +When a user logs into the GPII system, it will emit a `login` message to the PCP client. The body of this will be a JSON object with a key `userToken` for the userToken of the user logging in, and a `settings` key with the adjusters to be displayed. An example of a `settings` value is: `{ "http://registry.gpii.net/common/highContrastEnabled": false }` + + +#### On logout [`logout` message] + +When a user logs out of the GPII system, it will emit a `logout` message to the PCP client. + + +#### Sending user messages [`message` message] + +When the GPII system has a message that it wants the PCP client to display, the system will emit a `message` message. It will have the format: + +``` +{ + "type": "infoMessage", + "message": "My message" +} +``` + +Where the `"type"` can be either "infoMessage", "warningMessage" or "errorMessage", and `"message"` will contain the message to be displayed. diff --git a/gpii/node_modules/flowManager/src/FlowManager.js b/gpii/node_modules/flowManager/src/FlowManager.js index e408222eb..c3f349f1b 100644 --- a/gpii/node_modules/flowManager/src/FlowManager.js +++ b/gpii/node_modules/flowManager/src/FlowManager.js @@ -27,6 +27,7 @@ require("./UserSave.js"); require("./GetUserToken.js"); require("./UserUpdate.js"); require("./BrowserChannel.js"); +require("./PCPInterface.js"); require("./CloudBasedFlowManager.js"); // TODO: move this include to be operated by a config require("lifecycleManager"); @@ -82,6 +83,9 @@ fluid.defaults("gpii.flowManager", { }, browserChannel: { type: "gpii.flowManager.browserChannel" + }, + pcpInterface: { + type: "gpii.pcpInterface" } }, handlers: { @@ -105,6 +109,9 @@ fluid.defaults("gpii.flowManager", { route: "/environmentChanged", type: "put" } + }, + events: { + onLogonStateChangeComplete: null } }); @@ -152,6 +159,10 @@ fluid.defaults("gpii.flowManager.io", { browserChannel: { route: "/browserChannel", type: "io" + }, + pcpChannel: { + route: "/pcpChannel", + type: "io" } }, components: { diff --git a/gpii/node_modules/flowManager/src/FlowManagerUtilities.js b/gpii/node_modules/flowManager/src/FlowManagerUtilities.js index e23bb2255..109d9c989 100644 --- a/gpii/node_modules/flowManager/src/FlowManagerUtilities.js +++ b/gpii/node_modules/flowManager/src/FlowManagerUtilities.js @@ -142,6 +142,9 @@ processMatch: null, // Output of the matching process - listeners in derived grades onMatchDone: null, + // Events signalling successful login and logout, respectively + onLoginComplete: null, + onLogoutComplete: null, // Boiled event which initiates the match process onReadyToMatch: { events: { diff --git a/gpii/node_modules/flowManager/src/PCPInterface.js b/gpii/node_modules/flowManager/src/PCPInterface.js new file mode 100644 index 000000000..ca2a62bb0 --- /dev/null +++ b/gpii/node_modules/flowManager/src/PCPInterface.js @@ -0,0 +1,145 @@ +/** +* GPII PCP Render Handler +* +* Copyright 2014 Astea +* Copyright 2015 Raising the Floor - International +* +* Licensed under the New BSD license. You may not use this file except in +* compliance with this License. +* +* You may obtain a copy of the License at +* https://github.com/gpii/universal/LICENSE.txt +*/ +(function () { + "use strict"; + + var fluid = require("infusion"); + var gpii = fluid.registerNamespace("gpii"); + + fluid.registerNamespace("gpii.request.flowManager"); + fluid.registerNamespace("gpii.pcpInterface"); + + fluid.defaults("gpii.pcpInterface", { + gradeNames: ["autoInit", "fluid.eventedComponent"], + members: { + clients: {} + }, + model: {}, + invokers: { + sendUserMessage: { + funcName: "gpii.pcpInterface.sendUserMessage", + args: ["{that}.clients", "{arguments}.0", "{arguments}.1" ] + }, + notifyUserLogonStateChange: { + funcName: "gpii.pcpInterface.notifyUserLogonStateChange", + args: ["{that}", "{that}.clients", "{arguments}.0", "{arguments}.1" ] + // user token, adjusters + }, + addClient: { + funcName: "gpii.pcpInterface.addClient", + args: [ "{that}", "{arguments}.0" ] // socket connection + }, + removeClient: { + funcName: "gpii.pcpInterface.removeClient", + args: [ "{that}", "{arguments}.0" ] + } + }, + events: { + sendUserMessage: null + }, + listeners: { + sendUserMessage: "{that}.sendUserMessage", + "{flowManager}.events.onLogonStateChangeComplete": "{that}.notifyUserLogonStateChange" + } + }); + + gpii.pcpInterface.addClient = function (that, client) { + var currentValue = fluid.get(that.clients, client.id); + if (!currentValue) { + fluid.set(that.clients, client.id, client); + // notify of current logon state: + client.emit("connectionSucceeded", that.model); + + client.on("disconnect", function () { + if (!fluid.isDestroyed(that)) { + that.removeClient(client); + } + }); + } + }; + + gpii.pcpInterface.removeClient = function (that, client) { + delete that.clients[client.id]; + }; + + /** + * Send a message to the PCP client. If no client is connected, the message is discarded. + * + * @param socket {Object} client socket connection + * @param text {String or Object} The text that the client should display. This should either + * be a simple string of English text or an object with texts, each keyed by a language code. + * @param messageType {String} A string denoting the option type ("infoMessage", "warningMessage" + * or "errorMessage"). If this parameter is not given, it defaults to "infoMessage" + */ + gpii.pcpInterface.sendUserMessage = function (clients, text, messageType) { + fluid.log("User message emitted from the PCP: " + text); + // Default to 'infoMessage' + var message = { + type: (messageType === undefined) ? "infoMessage" : messageType, + message: text + }; + + fluid.each(clients, function (client) { + client.emit("message", message, fluid.log); + }); + }; + + /** + * Notify the PCP client that a user has logged in or out + * + * @param that {Object} the pcpInterface + * @param socket {Object} client socket connection + * @param action {String} "login" or "logout" + * @param userToken {String} the token of the user who has just logged in or out + */ + gpii.pcpInterface.notifyUserLogonStateChange = function (that, clients, action, userToken) { + if (action === "logout") { + that.sendUserMessage("The token " + userToken + " was logged out."); + that.model = {}; + fluid.each(clients, function (client) { + client.emit("logout"); + }); + } else { + // else a user just logging in + var defaultAdjusters = { + "http://registry.gpii.net/common/highContrastEnabled": false + }; + that.model = { + settings: defaultAdjusters, + userToken: userToken + }; + + fluid.each(clients, function (client) { + // send login message + client.emit("login", that.model); + }); + that.sendUserMessage("The token " + userToken + " was logged in."); + } + }; + + fluid.defaults("kettle.requests.request.handler.pcpChannel", { + gradeNames: ["gpii.request.flowManager.sessionAware", "autoInit"], + invokers: { + handle: { + funcName: "gpii.request.flowManager.pcpChannelHandle", + args: ["{request}", "{requestProxy}.events", "{flowManager}.pcpInterface" ], + dynamic: true + } + } + }); + + gpii.request.flowManager.pcpChannelHandle = function (request, events, pcpInterface) { + events.onSuccess.fire("Client has successfully established connection to the PCP Channel"); + pcpInterface.addClient(request.socket); + }; +})(); \ No newline at end of file diff --git a/gpii/node_modules/flowManager/src/UserLogonStateChange.js b/gpii/node_modules/flowManager/src/UserLogonStateChange.js index fb96bc0fe..00d50ec95 100644 --- a/gpii/node_modules/flowManager/src/UserLogonStateChange.js +++ b/gpii/node_modules/flowManager/src/UserLogonStateChange.js @@ -68,25 +68,19 @@ }); }; - gpii.request.flowManager.userLogonStateChange.startLifecycle = function (lifecycleManager, lifecyclePayload, event) { - console.log("Got final payload " + JSON.stringify(lifecyclePayload, null, 2)); - lifecycleManager.start(lifecyclePayload, - gpii.request.flowManager.logAndNotify("Lifecycle manager returned: ", event, function () { - return "User with token " + lifecyclePayload.userToken + " was successfully logged in."; - } - )); - }; - - gpii.request.flowManager.userLogonStateChange.logoutUser = function (requestProxy, lifecycleManager, userToken) { + gpii.request.flowManager.userLogonStateChange.logoutUser = function (lifecycleManager, event, userToken) { lifecycleManager.stop({ userToken: userToken }, function onSuccess(response) { fluid.log("Lifecycle manager returned: ", response); - requestProxy.events.onSuccess.fire("User with token " + userToken + - " was successfully logged out."); + event.fire(userToken); }); }; + gpii.request.flowManager.userLogonStateChange.logoutComplete = function (requestEvent, userToken) { + requestEvent.fire("User with token " + userToken + " was successfully logged out."); + }; + gpii.request.flowManager.userLogonStateChange.loginUser = function (that, userToken) { that.events.onUserToken.fire(userToken); }; @@ -103,12 +97,23 @@ }); }; + gpii.request.flowManager.userLogonStateChange.startLifecycle = function (lifecycleManager, lifecyclePayload, event) { + console.log("Got final payload " + JSON.stringify(lifecyclePayload, null, 2)); + lifecycleManager.start(lifecyclePayload, function () { + event.fire(lifecyclePayload.userToken); + }); + }; + + gpii.request.flowManager.userLogonStateChange.loginComplete = function (requestEvent, userToken) { + requestEvent.fire("User with token " + userToken + " was successfully logged in."); + }; + fluid.defaults("gpii.request.flowManager.userLogonStateChange.stateChangeHandler", { gradeNames: ["fluid.littleComponent", "gpii.request.flowManager.matchMakingRequest", "autoInit"], invokers: { startLifecycle: { funcName: "gpii.request.flowManager.userLogonStateChange.startLifecycle", - args: [ "{flowManager}.lifecycleManager", "{arguments}.0", "{requestProxy}.events.onSuccess" ] + args: [ "{flowManager}.lifecycleManager", "{arguments}.0", "{that}.events.onLoginComplete" ] // final payload from matchmaking process }, getDeviceContext: { @@ -117,7 +122,7 @@ }, logoutUser: { funcName: "gpii.request.flowManager.userLogonStateChange.logoutUser", - args: ["{requestProxy}", "{flowManager}.lifecycleManager", "{arguments}.0"], + args: ["{flowManager}.lifecycleManager", "{that}.events.onLogoutComplete", "{arguments}.0"], dynamic: true }, loginUser: { @@ -125,6 +130,14 @@ args: ["{that}", "{arguments}.0"], dynamic: true }, + loginComplete: { + funcName: "gpii.request.flowManager.userLogonStateChange.loginComplete", + args: ["{requestProxy}.events.onSuccess", "{arguments}.0"] // userToken + }, + logoutComplete: { + funcName: "gpii.request.flowManager.userLogonStateChange.logoutComplete", + args: ["{requestProxy}.events.onSuccess", "{arguments}.0"] // userToken + }, errorResponse: { funcName: "gpii.request.flowManager.userLogonStateChange.errorResponse", args: ["{request}", "{arguments}.0", "{arguments}.1"] @@ -132,7 +145,21 @@ }, listeners: { onUserToken: "{that}.getDeviceContext", - onMatchDone: "{that}.startLifecycle" + onMatchDone: "{that}.startLifecycle", + onLoginComplete: [ + { + listener: "{flowManager}.events.onLogonStateChangeComplete.fire", + args: [ "login", "{arguments}.0" ] + }, + "{that}.loginComplete" + ], + onLogoutComplete: [ + { + listener: "{flowManager}.events.onLogonStateChangeComplete.fire", + args: [ "logout", "{arguments}.0" ] + }, + "{that}.logoutComplete" + ] } }); diff --git a/gpii/node_modules/flowManager/test/PCPInterfaceTests.js b/gpii/node_modules/flowManager/test/PCPInterfaceTests.js new file mode 100644 index 000000000..215a030fa --- /dev/null +++ b/gpii/node_modules/flowManager/test/PCPInterfaceTests.js @@ -0,0 +1,347 @@ +/** + * GPII PCP Interface Tests + * + * Copyright 2015 Raising the Floor - International + * + * Licensed under the New BSD license. You may not use this file except in + * compliance with this License. + * + * You may obtain a copy of the License at + * https://github.com/GPII/kettle/LICENSE.txt + */ + +"use strict"; + +var fluid = require("infusion"), + path = require("path"), + jqUnit = fluid.require("jqUnit"), + configPath = path.resolve(__dirname, "../configs"), + kettle = require("kettle"), + gpii = fluid.registerNamespace("gpii"); + +require("universal"); + +kettle.loadTestingSupport(); + +fluid.registerNamespace("gpii.tests.flowManager.PCPInterface"); + +gpii.tests.flowManager.PCPInterface.checkConnectionRequest = function (data, client) { + jqUnit.assertEquals("Connection succeeded", "Client has successfully established connection to the PCP Channel", data); + + // connect socket events to the client events so we can test it + client.socket.on("login", client.events.onLogin.fire); + client.socket.on("logout", client.events.onLogout.fire); + client.socket.on("connectionSucceeded", client.events.connectionSucceeded.fire); + // client.socket.on("message", client.events.onMessage.fire); +}; + +fluid.defaults("gpii.tests.flowManager.PCPInterface.basicClient", { + gradeNames: ["kettle.test.request.io", "autoInit"], + path: "/pcpChannel", + port: 8081, + listenOnInit: true, + events: { + onLogin: null, + onLogout: null, + onMessage: null, + connectionSucceeded: null + }, + listeners: { + onLogin: { + funcName: "gpii.tests.flowManager.PCPInterface.onLogin", + args: [ "{arguments}.0" ] + } + } +}); + +fluid.defaults("gpii.tests.flowManager.pcpInterface.testCaseHolder", { + gradeNames: ["kettle.test.testCaseHolder", "autoInit"], + distributeOptions: { + record: { + funcName: "gpii.tests.flowManager.pcpInterface.receiveLifecycleManager", + args: ["{testCaseHolder}", "{arguments}.0"] + }, + target: "{that flowManager}.options.listeners.onCreate" + } +}); + + +gpii.tests.flowManager.pcpInterface.receiveLifecycleManager = function (testCaseHolder, flowManager) { + testCaseHolder.flowManager = flowManager; +}; + +gpii.tests.flowManager.PCPInterface.checkConnectionSucceeded = function (data, expected) { + jqUnit.assertDeepEq("Checking data received on connection success: ", expected, data); +}; + +gpii.tests.flowManager.PCPInterface.onLogin = function (data) { + jqUnit.assertDeepEq("Testing data on login event", { + "settings": { + "http://registry.gpii.net/common/highContrastEnabled": false + }, + "userToken": "someUser" + }, data); +}; + +gpii.tests.flowManager.PCPInterface.onLogout = function () { + jqUnit.assertTrue("Logout event received on client side of socket", true); +}; + +gpii.tests.flowManager.PCPInterface.onMessage = function (data, expected) { + jqUnit.assertDeepEq("Message succusfully received by socket client", expected, data); +}; + +var testDefs = [ + { + name: "Flow Manager PCPInterface simple messagetests", + expect: 2, + config: { + configName: "development", + configPath: configPath + }, + gradeNames: "gpii.tests.flowManager.pcpInterface.testCaseHolder", + components: { + client: { + type: "gpii.tests.flowManager.PCPInterface.basicClient" + } + }, + sequence: [ + { + func: "{client}.send" + }, { + event: "{client}.events.onComplete", + listener: "gpii.tests.flowManager.PCPInterface.checkConnectionRequest", + args: [ "{arguments}.0", "{client}" ] + }, { + // Test simpe messages gets passed to socket client + func: "{flowManager}.pcpInterface.sendUserMessage", + args: [ "Howdy user! This is a message to you" ] + }, { + event: "{client}.events.onMessage", + listener: "gpii.tests.flowManager.PCPInterface.onMessage", + args: [ + "{arguments}.0", { + type: "infoMessage", + message: "Howdy user! This is a message to you" + } + ] + } + ] + }, { + name: "Flow Manager PCPInterface with single client login, logout and standard message tests", + expect: 7, + config: { + configName: "development", + configPath: configPath + }, + gradeNames: "gpii.tests.flowManager.pcpInterface.testCaseHolder", + components: { + client: { + type: "gpii.tests.flowManager.PCPInterface.basicClient" + } + }, + sequence: [ + { + func: "{client}.send" + }, { + event: "{client}.events.onComplete", + listener: "gpii.tests.flowManager.PCPInterface.checkConnectionRequest", + args: [ "{arguments}.0", "{client}" ] + }, { + funcName: "fluid.identity" + }, { + event: "{client}.events.connectionSucceeded", + listener: "gpii.tests.flowManager.PCPInterface.checkConnectionSucceeded", + args: [ "{arguments}.0", {} ] + }, { + // Test regular login notification + func: "{flowManager}.pcpInterface.notifyUserLogonStateChange", + args: [ "login", "someUser" ] + }, { + event: "{client}.events.onMessage", + listener: "gpii.tests.flowManager.PCPInterface.onMessage", + args: [ + "{arguments}.0", { + type: "infoMessage", + message: "The token someUser was logged in." + } + ] + }, { + // Test simpe messages gets passed to socket client when logged in + func: "{flowManager}.pcpInterface.sendUserMessage", + args: [ "Howdy user! This is a message to you" ] + }, { + event: "{client}.events.onMessage", + listener: "gpii.tests.flowManager.PCPInterface.onMessage", + args: [ + "{arguments}.0", { + type: "infoMessage", + message: "Howdy user! This is a message to you" + } + ] + }, { + // Test logout notification gets passed to socket client + func: "{flowManager}.pcpInterface.notifyUserLogonStateChange", + args: [ "logout", "someUser" ] + }, { + event: "{client}.events.onMessage", + listener: "gpii.tests.flowManager.PCPInterface.onMessage", + args: [ + "{arguments}.0", { + type: "infoMessage", + message: "The token someUser was logged out." + } + ] + }, { + funcName: "fluid.identity" + }, { + event: "{client}.events.onLogout", + listener: "gpii.tests.flowManager.PCPInterface.onLogout" + } + ] + }, { + name: "Flow Manager PCPInterface with single client checking connection succeeded after login", + expect: 4, + config: { + configName: "development", + configPath: configPath + }, + gradeNames: "gpii.tests.flowManager.pcpInterface.testCaseHolder", + components: { + client: { + type: "gpii.tests.flowManager.PCPInterface.basicClient" + } + }, + sequence: [ + { + // First login + func: "{flowManager}.pcpInterface.notifyUserLogonStateChange", + args: [ "login", "someUser" ] + }, { // connect client and check that we get info about logged in user: + func: "{client}.send" + }, { + event: "{client}.events.onComplete", + listener: "gpii.tests.flowManager.PCPInterface.checkConnectionRequest", + args: [ "{arguments}.0", "{client}" ] + }, { + funcName: "fluid.identity" + }, { + event: "{client}.events.connectionSucceeded", + listener: "gpii.tests.flowManager.PCPInterface.checkConnectionSucceeded", + args: [ "{arguments}.0", { + "settings": { + "http://registry.gpii.net/common/highContrastEnabled": false + }, + "userToken": "someUser" + }] + }, { + // Test logout notification gets passed to socket client + func: "{flowManager}.pcpInterface.notifyUserLogonStateChange", + args: [ "logout", "someUser" ] + }, { + event: "{client}.events.onMessage", + listener: "gpii.tests.flowManager.PCPInterface.onMessage", + args: [ + "{arguments}.0", { + type: "infoMessage", + message: "The token someUser was logged out." + } + ] + }, { + funcName: "fluid.identity" + }, { + event: "{client}.events.onLogout", + listener: "gpii.tests.flowManager.PCPInterface.onLogout" + } + ] + }, { + name: "Flow Manager PCPInterface with multiple clients", + expect: 8, + config: { + configName: "development", + configPath: configPath + }, + gradeNames: "gpii.tests.flowManager.pcpInterface.testCaseHolder", + components: { + client1: { + type: "gpii.tests.flowManager.PCPInterface.basicClient" + }, + client2: { + type: "gpii.tests.flowManager.PCPInterface.basicClient" + } + }, + sequence: [ + { // connect first client + func: "{client1}.send" + }, { + event: "{client1}.events.onComplete", + listener: "gpii.tests.flowManager.PCPInterface.checkConnectionRequest", + args: [ "{arguments}.0", "{client1}" ] + }, { + funcName: "fluid.identity" + }, { + event: "{client1}.events.connectionSucceeded", + listener: "gpii.tests.flowManager.PCPInterface.checkConnectionSucceeded", + args: [ "{arguments}.0", {} ] + }, { // log user in + func: "{flowManager}.pcpInterface.notifyUserLogonStateChange", + args: [ "login", "someUser" ] + }, { + event: "{client1}.events.onMessage", + listener: "gpii.tests.flowManager.PCPInterface.onMessage", + args: [ + "{arguments}.0", { + type: "infoMessage", + message: "The token someUser was logged in." + } + ] + }, { // connect second client + func: "{client2}.send" + }, { + event: "{client2}.events.onComplete", + listener: "gpii.tests.flowManager.PCPInterface.checkConnectionRequest", + args: [ "{arguments}.0", "{client2}" ] + }, { + funcName: "fluid.identity" + }, { + event: "{client2}.events.connectionSucceeded", + listener: "gpii.tests.flowManager.PCPInterface.checkConnectionSucceeded", + args: [ "{arguments}.0", { + "settings": { + "http://registry.gpii.net/common/highContrastEnabled": false + }, + "userToken": "someUser" + }] + }, { // Send message (which should be retrieved by both clients) + func: "{flowManager}.pcpInterface.sendUserMessage", + args: [ "Howdy user! This is a message to you" ] + }, { + event: "{client2}.events.onMessage", + listener: "gpii.tests.flowManager.PCPInterface.onMessage", + args: [ + "{arguments}.0", { + type: "infoMessage", + message: "Howdy user! This is a message to you" + } + ] + }, { + funcName: "fluid.identity" + }, { + event: "{client1}.events.onMessage", + listener: "gpii.tests.flowManager.PCPInterface.onMessage", + args: [ + "{arguments}.0", { + type: "infoMessage", + message: "Howdy user! This is a message to you" + } + ] + }, { + // Test logout notification gets passed to socket client + func: "{flowManager}.pcpInterface.notifyUserLogonStateChange", + args: [ "logout", "someUser" ] + } + ] + } +]; + +module.exports = kettle.test.bootstrapServer(testDefs); \ No newline at end of file diff --git a/package.json b/package.json index 29cba692f..2a21157a9 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,6 @@ "semver": "~1.1.4", "xml-mapping": "~1.2.0", "kettle": "git://github.com/fluid-project/kettle.git#ef796237b7b157df6837a970a8b798370ef14144", - "express": "~3.4.3", "body-parser": "^1.9.2", "connect-ensure-login": "^0.1.1", diff --git a/tests/PCPIntegrationTests.js b/tests/PCPIntegrationTests.js new file mode 100644 index 000000000..e1460e3ea --- /dev/null +++ b/tests/PCPIntegrationTests.js @@ -0,0 +1,131 @@ +/** + * GPII PCP Integration Tests + * + * Copyright 2015 Raising the Floor - International + * + * Licensed under the New BSD license. You may not use this file except in + * compliance with this License. + * + * You may obtain a copy of the License at + * https://github.com/GPII/kettle/LICENSE.txt + */ + +"use strict"; + +var fluid = require("infusion"), + path = require("path"), + jqUnit = fluid.require("jqUnit"), + configPath = path.resolve(__dirname, "configs"), + kettle = require("kettle"), + gpii = fluid.registerNamespace("gpii"); + +require("universal"); + +gpii.loadTestingSupport(); + +fluid.registerNamespace("gpii.tests.integration.PCPInterface"); + +gpii.tests.integration.PCPInterface.checkConnectionRequest = function (data, client) { + jqUnit.assertEquals("Connection succeeded", "Client has successfully established connection to the PCP Channel", data); + + // connect socket events to the client events so we can test it + client.socket.on("login", client.events.onLogin.fire); + client.socket.on("logout", client.events.onLogout.fire); + client.socket.on("message", client.events.onMessage.fire); +}; + +fluid.defaults("gpii.tests.integration.PCPInterface.basicClient", { + gradeNames: ["kettle.test.request.io", "autoInit"], + path: "/pcpChannel", + port: 8081, + listenOnInit: true, + events: { + onLogin: null, + onLogout: null, + onMessage: null + } +}); + +gpii.tests.integration.PCPInterface.checkPCPLoginEvent = function (data, expected) { + jqUnit.assertDeepEq("Testing login event on PCP client", expected, data); +}; + +gpii.tests.integration.PCPInterface.onLogout = function () { + jqUnit.assertTrue("Logout event received on client side of socket", true); +}; + +gpii.tests.integration.PCPInterface.onMessage = function (data, expected) { + jqUnit.assertDeepEq("Message succusfully received by socket client", expected, data); + +}; + +fluid.defaults("gpii.tests.integration.PCPInterface.mockServer", { + gradeNames: ["autoInit", "fluid.littleComponent"], + invokers: { + set: { + funcName: "gpii.tests.integration.PCPInterface.mockServer.set" + } + } +}); + +gpii.tests.integration.PCPInterface.mockServer.set = function () { + fluid.fail(); + return fluid.promise(); +}; + +var testDefs = [{ + name: "Flow Manager PCPInterface tests", + expect: 5, + config: { + configName: "localInstall", + configPath: configPath + }, + userToken: "screenreader_common", + gradeNames: "gpii.test.integration.testCaseHolder.windows", + components: { + client: { + type: "gpii.tests.integration.PCPInterface.basicClient" + } + }, + sequence: [ + { // connect the PCP client first + func: "{client}.send" + }, { + event: "{client}.events.onComplete", + listener: "gpii.tests.integration.PCPInterface.checkConnectionRequest", + args: [ "{arguments}.0", "{client}" ] + }, { + // Test login notification on user login + func: "{loginRequest}.send" + }, { + event: "{client}.events.onLogin", + listener: "gpii.tests.integration.PCPInterface.checkPCPLoginEvent", + args: [ "{arguments}.0", { + "userToken": "screenreader_common", + "settings": { + "http://registry.gpii.net/common/highContrastEnabled": false + } + }] + }, { + event: "{client}.events.onMessage", + listener: "gpii.tests.integration.PCPInterface.onMessage", + args: [ "{arguments}.0", + { type: "infoMessage", message: "The token screenreader_common was logged in." } + ] + }, { + // Test logout notification gets passed to socket client + func: "{logoutRequest}.send" + }, { + event: "{client}.events.onLogout", + listener: "gpii.tests.integration.PCPInterface.onLogout" + }, { + event: "{client}.events.onMessage", + listener: "gpii.tests.integration.PCPInterface.onMessage", + args: [ "{arguments}.0", + { type: "infoMessage", message: "The token screenreader_common was logged out." } + ] + } + ] +}]; + +module.exports = kettle.test.bootstrapServer(testDefs); \ No newline at end of file diff --git a/tests/all-tests.js b/tests/all-tests.js index f920b56a9..515307db9 100644 --- a/tests/all-tests.js +++ b/tests/all-tests.js @@ -43,10 +43,12 @@ var testIncludes = [ "./ContextIntegrationTests.js", "./DeviceReporterErrorTests.js", "./PreferencesServerErrorTests.js", + "./PCPIntegrationTests.js", "../gpii/node_modules/flowManager/test/SaveTests.js", "../gpii/node_modules/flowManager/test/UpdateTests.js", "../gpii/node_modules/flowManager/test/BrowserChannelTests.js", "../gpii/node_modules/flowManager/test/GetUserTokenTests.js", + "../gpii/node_modules/flowManager/test/PCPInterfaceTests.js", "../gpii/node_modules/matchMakerFramework/test/InverseCapabilitiesTests.js", "../gpii/node_modules/matchMakerFramework/test/MatchMakerFrameworkTests.js", "../gpii/node_modules/flatMatchMaker/test/FlatMatchMakerTests.js",