From 37742f787121d257c23282e4e11b41e047bc0c98 Mon Sep 17 00:00:00 2001 From: Kasper Markus Date: Thu, 6 Aug 2015 22:26:23 +0200 Subject: [PATCH 01/10] GPII-1251: First steps toward implementation of PCP --- documentation/PCPChannel.md | 76 +++++++++ .../flowManager/src/FlowManager.js | 10 +- .../flowManager/src/PCPInterface.js | 108 +++++++++++++ .../flowManager/test/PCPInterfaceTests.js | 153 ++++++++++++++++++ .../test/configs/browserChannel.json | 32 ---- .../test/configs/pcpInterface.json | 15 ++ 6 files changed, 361 insertions(+), 33 deletions(-) create mode 100644 documentation/PCPChannel.md create mode 100644 gpii/node_modules/flowManager/src/PCPInterface.js create mode 100644 gpii/node_modules/flowManager/test/PCPInterfaceTests.js delete mode 100644 gpii/node_modules/flowManager/test/configs/browserChannel.json create mode 100644 gpii/node_modules/flowManager/test/configs/pcpInterface.json diff --git a/documentation/PCPChannel.md b/documentation/PCPChannel.md new file mode 100644 index 000000000..43d7c6723 --- /dev/null +++ b/documentation/PCPChannel.md @@ -0,0 +1,76 @@ +## 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 on login +* Sending messages to be displayed in the PCP +* Receiving responses to messages from PCP + +### API + +This settings handler follows the standard settings handler API and exposes both the .get and .set methods to the rest of the system. +The settings handler is an instance of _gpii.settingsHandler.WebSocketsComponent_, which can be found in _gpii/node_modules/settingsHandlers/src/WebSocketsComponent.js_. + +This component stores the information about clients and keeps a list of settings for every solution that makes use of this settings handler. +Also, this component create notifications for every connected client at any time when the settings change. + +### Usage + +This small and documented client illustrates the workflow. + +```javascript +var io = require("socket.io-client"); + +// The client starts the communication +// +var socket = io.connect("http://localhost:8081/browserChannel"); + +// When the connection is done, the client tells to the flow manager its id +// +socket.on("connect", function () { + console.log("## Socket connected"); + socket.send("org.chrome.cloud4chrome"); +}); + +// Right after sending the id to the flow manager, the server will return back +// the current settings in the system (if any) +// +socket.on("connectionSucceeded", function (settings) { + console.log("## Received the following settings: " + JSON.stringify(settings)); +}); + +// By listening to this signal, the client will be notified when the system has +// new settings to be applied on the client side +// +socket.on("onBrowserSettingsChanged", function (newSettings) { + console.log("## Got newSettings: " + JSON.stringify(newSettings)); +}); +``` + +The _contract API_ between client and server can be resumed as follows: + +* After connecting to the flow manager, the client sends a socket message to the channel, which is basically a string containing the *id* of the client. ie: _org.chrome.cloud4chrome_ +* The client will be registered if the solution's id can be found of the solutions registry, otherwise, the registration will be rejected and the system will emit en error, and the client will disconnected. +* When the flow manager emits either the _connectionSucceeded_ (after being registered) or the _onBrowserSettingsChanged_ (after a user login/logout) signal to the client, it is delivering the current available settings for the client in the following way: +``` +{ + "screenReaderTTSEnabled":false, + "highContrastEnabled":true, + "invertColours":false, + "magnifierEnabled":true, + "magnification":2, + "fontSize":"medium", + "simplifier":false, + "highContrastTheme":"white-black" +} +``` +* When a client disconnects, it'll be removed from the list of registered clients + +## Testing + +This new feature has been tested with [this version of the Cloud4Chrome extension](https://github.com/GutiX/chrome4cloud/commit/3d064bb7efc93bf90fde90b0192c273fb76817e5). diff --git a/gpii/node_modules/flowManager/src/FlowManager.js b/gpii/node_modules/flowManager/src/FlowManager.js index 095093901..701df6dd3 100644 --- a/gpii/node_modules/flowManager/src/FlowManager.js +++ b/gpii/node_modules/flowManager/src/FlowManager.js @@ -13,7 +13,7 @@ * You may obtain a copy of the License at * https://github.com/GPII/universal/blob/master/LICENSE.txt */ - + "use strict"; var fluid = require("infusion"), @@ -28,6 +28,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"); @@ -83,6 +84,9 @@ fluid.defaults("gpii.flowManager", { }, browserChannel: { type: "gpii.flowManager.browserChannel" + }, + pcpInterface: { + type: "gpii.pcpInterface" } }, handlers: { @@ -147,6 +151,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/PCPInterface.js b/gpii/node_modules/flowManager/src/PCPInterface.js new file mode 100644 index 000000000..260bac405 --- /dev/null +++ b/gpii/node_modules/flowManager/src/PCPInterface.js @@ -0,0 +1,108 @@ +/** +* 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: { + socket: null + }, + invokers: { + sendUserMessage: { + funcName: "gpii.pcpInterface.sendUserMessage", + args: ["{that}.socket", "{arguments}.0" ] + }, + notifyLogin: { + funcName: "gpii.pcpInterface.notifyLogin", + args: ["{that}.socket", "{arguments}.0", "{arguments}.1" ] + // user token, adjusters + }, + notifyLogout: { + funcName: "gpii.pcpInterface.notifyLogout", + args: ["{that}.socket" ] + }, + initSocket: { + funcName: "gpii.pcpInterface.initSocket", + args: ["{that}", "{arguments}.0" ] // socket connection + } + }, + events: { + sendUserMessage: null + }, + listeners: { + sendUserMessage: "{that}.sendUserMessage" + } + }); + + gpii.pcpInterface.initSocket = function (that, socket) { + that.socket = socket; + }; + + gpii.pcpInterface.sendUserMessage = function (socket, message) { + if (socket === null) { + fluid.log("No PCP connected, so discarding message: " + message); + return; + } + socket.emit("message", message, fluid.log); + }; + + /** + * Adjusters can be passed to the PCP via the adjusters argument. If + * this is left empty, a ddefault set of adjusters will be passed to + * the PCP. + */ + gpii.pcpInterface.notifyLogin = function (socket, userToken, adjusters) { + if (socket === null) { + fluid.log("No PCP connected, so is not attempting to notify of a loging"); + return; + } + var defaultAdjusters = { + "http://registry.gpii.net/common/highContrastEnabled": false + }; + socket.emit("login", { + settings: adjusters !== undefined ? adjusters : defaultAdjusters, + userToken: userToken + }); + }; + + gpii.pcpInterface.notifyLogout = function (socket) { + if (socket === null) { + fluid.log("No PCP connected, so is not attempting to notify of a log out"); + return; + } + socket.emit("logout"); + }; + + fluid.defaults("kettle.requests.request.handler.pcpChannel", { + gradeNames: ["gpii.request.flowManager.sessionAware", "autoInit"], + invokers: { + handle: { + funcName: "gpii.request.flowManager.pcpChannelHandle", + args: ["{that}", "{request}.socket", "{requestProxy}.events", "{flowManager}.pcpInterface" ], + dynamic: true + } + } + }); + + gpii.request.flowManager.pcpChannelHandle = function (that, socket, events, pcpInterface) { + pcpInterface.initSocket(socket); + events.onSuccess.fire("Client has successfully established connection to the PCP Channel"); + }; +})(); \ No newline at end of file diff --git a/gpii/node_modules/flowManager/test/PCPInterfaceTests.js b/gpii/node_modules/flowManager/test/PCPInterfaceTests.js new file mode 100644 index 000000000..33407b354 --- /dev/null +++ b/gpii/node_modules/flowManager/test/PCPInterfaceTests.js @@ -0,0 +1,153 @@ +/** + * 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("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 + } +}); + +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.onLogin = function (data, userToken, settings) { + jqUnit.assertDeepEq("Testing data on login event", { + "settings": settings, + "userToken": userToken + }, 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 testDef = { + name: "Flow Manager PCPInterface tests", + expect: 5, + config: { + configName: "development", + configPath: configPath + }, + gradeNames: "gpii.tests.flowManager.pcpInterface.testCaseHolder", + components: { + client: { + type: "gpii.tests.flowManager.PCPInterface.basicClient" + } + }, + sequence: [ + { + func: "{client}.send", + args: "{client}.options.solutionId" + }, { + event: "{client}.events.onComplete", + listener: "gpii.tests.flowManager.PCPInterface.checkConnectionRequest", + args: [ "{arguments}.0", "{client}" ] + }, { + // Test regular login notification with no settings passed + func: "{flowManager}.pcpInterface.notifyLogin", + args: [ "someUser" ] + }, { + event: "{client}.events.onLogin", + listener: "gpii.tests.flowManager.PCPInterface.onLogin", + args: [ "{arguments}.0", "someUser", { "http://registry.gpii.net/common/highContrastEnabled": false } ] + }, { + // Test regular login notification with a set of settings passed + func: "{flowManager}.pcpInterface.notifyLogin", + args: [ "someOtherUser", { "http://registry.gpii.net/common/screenResolution": "low" } ] + }, { + event: "{client}.events.onLogin", + listener: "gpii.tests.flowManager.PCPInterface.onLogin", + args: [ "{arguments}.0", "someOtherUser", { "http://registry.gpii.net/common/screenResolution": "low" } ] + }, { + // Test logout notification gets passed to socket client + func: "{flowManager}.pcpInterface.notifyLogout" + }, { + event: "{client}.events.onLogout", + listener: "gpii.tests.flowManager.PCPInterface.onLogout" + }, { + // Test regular messages gets passed to socket client + func: "{flowManager}.pcpInterface.sendUserMessage", + args: [ + [{ + type: "infoMessage", + message: { + dk: "Katte er nogle trælse kræ", + en: "Howdy user! This is a message to you", + es: "¿Hola Pedro, donde esta la biblioteca?" + } + }] + ] + }, { + event: "{client}.events.onMessage", + listener: "gpii.tests.flowManager.PCPInterface.onMessage", + args: [ + "{arguments}.0", [{ + type: "infoMessage", + message: { + dk: "Katte er nogle trælse kræ", + en: "Howdy user! This is a message to you", + es: "¿Hola Pedro, donde esta la biblioteca?" + } + }] + ] + } + ] +}; + +module.exports = kettle.test.bootstrapServer([testDef]); diff --git a/gpii/node_modules/flowManager/test/configs/browserChannel.json b/gpii/node_modules/flowManager/test/configs/browserChannel.json deleted file mode 100644 index 2cdf68e6b..000000000 --- a/gpii/node_modules/flowManager/test/configs/browserChannel.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "typeName": "browserChannel", - "options": { - "gradeNames": ["autoInit", "fluid.littleComponent"], - "distributeOptions": [{ - "source": "{that}.options.port", - "target": "{that server}.options.port" - }, { - "source": "{that}.options.solutionsRegistryUrl", - "target": "{that flowManager}.options.urls.solutionsRegistry" - }, { - "source": "{that}.options.rawPreferencesSourceUrl", - "target": "{that rawPreferencesServer}.options.rawPreferencesSourceUrl" - }, { - "source": "{that}.options.installedSolutionsUrl", - "target": "{that deviceReporter}.options.installedSolutionsUrl" - }], - "rawPreferencesSourceUrl": "file://%root/../flowManager/test/data/%userToken.json", - "solutionsRegistryUrl": "file://%root/../flowManager/test/data/browserChannel_solutionsRegistry.json", - "installedSolutionsUrl": "file://%root/../flowManager/test/data/browserChannel_deviceReporter.json", - "port": 8081 - }, - "includes": [ - "../../configs/io.json", - "../../configs/development.json", - "../../../deviceReporter/configs/development.json", - "../../../flatMatchMaker/configs/development.all.local.json", - "../../../preferencesServer/configs/development.json", - "../../../rawPreferencesServer/configs/development.json", - "../../../solutionsRegistry/configs/development.json" - ] -} diff --git a/gpii/node_modules/flowManager/test/configs/pcpInterface.json b/gpii/node_modules/flowManager/test/configs/pcpInterface.json new file mode 100644 index 000000000..041b12830 --- /dev/null +++ b/gpii/node_modules/flowManager/test/configs/pcpInterface.json @@ -0,0 +1,15 @@ +{ + "typeName": "pcpInterface", + "options": { + "gradeNames": ["autoInit", "fluid.littleComponent"], + "distributeOptions": [{ + "source": "{that}.options.port", + "target": "{that server}.options.port" + }], + "port": 8081 + }, + "includes": [ + "../../configs/io.json", + "../../configs/development.json" + ] +} From 2aa9a82b0fc6b291cd1f180ee25aa6e29632e89d Mon Sep 17 00:00:00 2001 From: Kasper Markus Date: Thu, 20 Aug 2015 13:51:16 +0200 Subject: [PATCH 02/10] GPII-1251: Added integration tests and calls from userlogin/logout --- documentation/PCPChannel.md | 90 +++---- .../flowManager/src/PCPInterface.js | 238 ++++++++++-------- .../node_modules/flowManager/src/UserLogin.js | 38 ++- .../flowManager/src/UserLogout.js | 18 +- .../flowManager/test/PCPInterfaceTests.js | 172 ++++++++----- .../test/configs/pcpInterface.json | 15 -- package.json | 3 +- tests/PCPIntegrationTests.js | 192 ++++++++++++++ tests/all-tests.js | 1 + tests/configs/pcpIntegration.json | 32 +++ 10 files changed, 547 insertions(+), 252 deletions(-) delete mode 100644 gpii/node_modules/flowManager/test/configs/pcpInterface.json create mode 100644 tests/PCPIntegrationTests.js create mode 100644 tests/configs/pcpIntegration.json diff --git a/documentation/PCPChannel.md b/documentation/PCPChannel.md index 43d7c6723..684cd870d 100644 --- a/documentation/PCPChannel.md +++ b/documentation/PCPChannel.md @@ -3,74 +3,66 @@ 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 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 on login +* Sending a list of desired adjusters to the PCP * Sending messages to be displayed in the PCP * Receiving responses to messages from PCP -### API +Message types: +(Info<- default), Error, Warning +{ + type: "infoMessage", + message: { + dk: "Katte er nogle trælse kræ", + en: "Howdy user! This is a message to you", + es: "¿Hola Pedro, donde esta la biblioteca?" + } +} -This settings handler follows the standard settings handler API and exposes both the .get and .set methods to the rest of the system. -The settings handler is an instance of _gpii.settingsHandler.WebSocketsComponent_, which can be found in _gpii/node_modules/settingsHandlers/src/WebSocketsComponent.js_. +### Internal API -This component stores the information about clients and keeps a list of settings for every solution that makes use of this settings handler. -Also, this component create notifications for every connected client at any time when the settings change. +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** Can be either an object with messages keyed by language code, e.g.: `{ "en": "My message", "es": "Mi mensaje"}`, or a simple string, which the system will assume is an english message wrap accordingly + * **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 -### Usage +### External API -This small and documented client illustrates the workflow. -```javascript -var io = require("socket.io-client"); +#### Connection -// The client starts the communication -// -var socket = io.connect("http://localhost:8081/browserChannel"); +Connection to the PCP is done as a socket connection to the URL `/pcpChannel`. -// When the connection is done, the client tells to the flow manager its id -// -socket.on("connect", function () { - console.log("## Socket connected"); - socket.send("org.chrome.cloud4chrome"); -}); -// Right after sending the id to the flow manager, the server will return back -// the current settings in the system (if any) -// -socket.on("connectionSucceeded", function (settings) { - console.log("## Received the following settings: " + JSON.stringify(settings)); -}); +#### On login [`login` signal]: -// By listening to this signal, the client will be notified when the system has -// new settings to be applied on the client side -// -socket.on("onBrowserSettingsChanged", function (newSettings) { - console.log("## Got newSettings: " + JSON.stringify(newSettings)); -}); -``` +When a user logs into the system, it will emit a `login` signal. 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` signal] -The _contract API_ between client and server can be resumed as follows: +When a user logs out of the system, it will emit a `logout` signal to the socket. + + +#### Sending user messages [`message` signal] + +When the system has a message it will emit a `message` signal. It will have the format: -* After connecting to the flow manager, the client sends a socket message to the channel, which is basically a string containing the *id* of the client. ie: _org.chrome.cloud4chrome_ -* The client will be registered if the solution's id can be found of the solutions registry, otherwise, the registration will be rejected and the system will emit en error, and the client will disconnected. -* When the flow manager emits either the _connectionSucceeded_ (after being registered) or the _onBrowserSettingsChanged_ (after a user login/logout) signal to the client, it is delivering the current available settings for the client in the following way: ``` { - "screenReaderTTSEnabled":false, - "highContrastEnabled":true, - "invertColours":false, - "magnifierEnabled":true, - "magnification":2, - "fontSize":"medium", - "simplifier":false, - "highContrastTheme":"white-black" + "type": "infoMessage", + "message": { + "en": "My message", + "es": "Mi mensaje"} + } } ``` -* When a client disconnects, it'll be removed from the list of registered clients - -## Testing -This new feature has been tested with [this version of the Cloud4Chrome extension](https://github.com/GutiX/chrome4cloud/commit/3d064bb7efc93bf90fde90b0192c273fb76817e5). +Where the `"type"` can be either "infoMessage", "warningMessage" or "errorMessage", and `"message"` will contains messages keyed by language codes. diff --git a/gpii/node_modules/flowManager/src/PCPInterface.js b/gpii/node_modules/flowManager/src/PCPInterface.js index 260bac405..5c23c0a34 100644 --- a/gpii/node_modules/flowManager/src/PCPInterface.js +++ b/gpii/node_modules/flowManager/src/PCPInterface.js @@ -1,108 +1,132 @@ -/** -* 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: { - socket: null - }, - invokers: { - sendUserMessage: { - funcName: "gpii.pcpInterface.sendUserMessage", - args: ["{that}.socket", "{arguments}.0" ] - }, - notifyLogin: { - funcName: "gpii.pcpInterface.notifyLogin", - args: ["{that}.socket", "{arguments}.0", "{arguments}.1" ] - // user token, adjusters - }, - notifyLogout: { - funcName: "gpii.pcpInterface.notifyLogout", - args: ["{that}.socket" ] - }, - initSocket: { - funcName: "gpii.pcpInterface.initSocket", - args: ["{that}", "{arguments}.0" ] // socket connection - } - }, - events: { - sendUserMessage: null - }, - listeners: { - sendUserMessage: "{that}.sendUserMessage" - } - }); - - gpii.pcpInterface.initSocket = function (that, socket) { - that.socket = socket; - }; - - gpii.pcpInterface.sendUserMessage = function (socket, message) { - if (socket === null) { - fluid.log("No PCP connected, so discarding message: " + message); - return; - } - socket.emit("message", message, fluid.log); - }; - - /** - * Adjusters can be passed to the PCP via the adjusters argument. If - * this is left empty, a ddefault set of adjusters will be passed to - * the PCP. - */ - gpii.pcpInterface.notifyLogin = function (socket, userToken, adjusters) { - if (socket === null) { - fluid.log("No PCP connected, so is not attempting to notify of a loging"); - return; - } - var defaultAdjusters = { - "http://registry.gpii.net/common/highContrastEnabled": false - }; - socket.emit("login", { - settings: adjusters !== undefined ? adjusters : defaultAdjusters, - userToken: userToken - }); - }; - - gpii.pcpInterface.notifyLogout = function (socket) { - if (socket === null) { - fluid.log("No PCP connected, so is not attempting to notify of a log out"); - return; - } - socket.emit("logout"); - }; - - fluid.defaults("kettle.requests.request.handler.pcpChannel", { - gradeNames: ["gpii.request.flowManager.sessionAware", "autoInit"], - invokers: { - handle: { - funcName: "gpii.request.flowManager.pcpChannelHandle", - args: ["{that}", "{request}.socket", "{requestProxy}.events", "{flowManager}.pcpInterface" ], - dynamic: true - } - } - }); - - gpii.request.flowManager.pcpChannelHandle = function (that, socket, events, pcpInterface) { - pcpInterface.initSocket(socket); - events.onSuccess.fire("Client has successfully established connection to the PCP Channel"); - }; +/** +* 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: { + socket: null + }, + invokers: { + sendUserMessage: { + funcName: "gpii.pcpInterface.sendUserMessage", + args: ["{that}.socket", "{arguments}.0", "{arguments}.1" ] + }, + notifyLogin: { + funcName: "gpii.pcpInterface.notifyLogin", + args: ["{that}.socket", "{arguments}.0", "{arguments}.1" ] + // user token, adjusters + }, + notifyLogout: { + funcName: "gpii.pcpInterface.notifyLogout", + args: ["{that}.socket" ] + }, + initSocket: { + funcName: "gpii.pcpInterface.initSocket", + args: ["{that}", "{arguments}.0" ] // socket connection + } + }, + events: { + sendUserMessage: null + }, + listeners: { + sendUserMessage: "{that}.sendUserMessage" + } + }); + + gpii.pcpInterface.initSocket = function (that, socket) { + that.socket = socket; + }; + + /** + * 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 (socket, text, messageType) { + if (socket === null) { + fluid.log("No PCP connected, so discarding message: " + text); + return; + } + // Default to 'infoMessage' and assume english if the text is a simple string + var message = { + type: (messageType === undefined) ? "infoMessage" : messageType, + message: (typeof text === "string") ? { "en": text } : text + }; + socket.emit("message", message, fluid.log); + }; + + /** + * Notify the PCP client that a user has logged in. + * + * @param socket {Object} client socket connection + * @param userToken {String} the token of the user who has just logged in + * @param adjusters {Object} Adjusters can be passed to the PCP via the adjusters argument. If + * this is left empty, a ddefault set of adjusters will be passed to + * the PCP. The format of the adjusters is a map of settings names as keys and the deafult + * value as values. + */ + gpii.pcpInterface.notifyLogin = function (socket, userToken, adjusters) { + if (socket === null) { + fluid.log("No PCP connected, so is not attempting to notify of a login"); + return; + } + var defaultAdjusters = { + "http://registry.gpii.net/common/highContrastEnabled": false + }; + socket.emit("login", { + settings: adjusters !== undefined ? adjusters : defaultAdjusters, + userToken: userToken + }); + }; + + /** + * Notify the PCP client that a user has logged out. + * + * @param socket {Object} client socket connection + */ + gpii.pcpInterface.notifyLogout = function (socket) { + if (socket === null) { + fluid.log("No PCP connected, so is not attempting to notify of a log out"); + return; + } + socket.emit("logout"); + }; + + fluid.defaults("kettle.requests.request.handler.pcpChannel", { + gradeNames: ["gpii.request.flowManager.sessionAware", "autoInit"], + invokers: { + handle: { + funcName: "gpii.request.flowManager.pcpChannelHandle", + args: ["{request}.socket", "{requestProxy}.events", "{flowManager}.pcpInterface" ], + dynamic: true + } + } + }); + + gpii.request.flowManager.pcpChannelHandle = function (socket, events, pcpInterface) { + pcpInterface.initSocket(socket); + events.onSuccess.fire("Client has successfully established connection to the PCP Channel"); + }; })(); \ No newline at end of file diff --git a/gpii/node_modules/flowManager/src/UserLogin.js b/gpii/node_modules/flowManager/src/UserLogin.js index c302d60b7..77b2606e0 100644 --- a/gpii/node_modules/flowManager/src/UserLogin.js +++ b/gpii/node_modules/flowManager/src/UserLogin.js @@ -22,31 +22,43 @@ var gpii = fluid.registerNamespace("gpii"); fluid.registerNamespace("gpii.request.flowManager"); - gpii.request.flowManager.onUserLogin = function (userToken, handler) { + gpii.request.flowManager.onUserLogin = function (userToken, proxy, handler) { handler.events.onUserToken.fire(userToken); }; - gpii.request.flowManager.startLifecycle = function (lifecycleManager, lifecyclePayload, event) { + gpii.request.flowManager.startLifecycle = function (that, 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."; + var msg = "User with token " + lifecyclePayload.userToken + " was successfully logged in."; + that.notifyLogin(msg, lifecyclePayload.userToken); + return msg; } )); }; - + gpii.request.flowManager.getDeviceContext = function (deviceReporterDataSource, event) { fluid.log("gpii.request.flowManager.getDeviceContext called - fetching device info"); deviceReporterDataSource.get(null, gpii.request.flowManager.logAndNotify( "Fetched device reporter data: ", event)); }; + gpii.request.flowManager.notifyLogin = function (status, userToken, pcpInterface) { + pcpInterface.notifyLogin(userToken); + pcpInterface.sendUserMessage(status); + }; + + gpii.request.flowManager.notifyError = function (status, pcpInterface) { + var message = (status && status.message) ? status.message : status; + pcpInterface.sendUserMessage(message, "errorMessage"); + }; + fluid.defaults("kettle.requests.request.handler.userLogin", { gradeNames: ["fluid.littleComponent", "gpii.request.flowManager.matchMakingRequest", "autoInit"], invokers: { startLifecycle: { funcName: "gpii.request.flowManager.startLifecycle", - args: [ "{flowManager}.lifecycleManager", "{arguments}.0", "{requestProxy}.events.onSuccess" ] + args: [ "{that}", "{flowManager}.lifecycleManager", "{arguments}.0", "{requestProxy}.events.onSuccess" ] // final payload from matchmaking process }, getDeviceContext: { @@ -55,12 +67,24 @@ }, handle: { funcName: "gpii.request.flowManager.onUserLogin", - args: ["{request}.req.params.userToken", "{that}"] + args: ["{request}.req.params.userToken", "{requestProxy}", "{that}"] + }, + notifyLogin: { + funcName: "gpii.request.flowManager.notifyLogin", + args: ["{arguments}.0", "{arguments}.1", "{flowManager}.pcpInterface"] + }, + notifyError: { + funcName: "gpii.request.flowManager.notifyError", + args: ["{arguments}.0", "{flowManager}.pcpInterface"] } }, listeners: { onUserToken: "{that}.getDeviceContext", - onMatchDone: "{that}.startLifecycle" + onMatchDone: "{that}.startLifecycle", + "{request}.events.onError": { + funcName: "{that}.notifyError", + priority: "first" + } } }); diff --git a/gpii/node_modules/flowManager/src/UserLogout.js b/gpii/node_modules/flowManager/src/UserLogout.js index b46fbbf47..442f2786a 100644 --- a/gpii/node_modules/flowManager/src/UserLogout.js +++ b/gpii/node_modules/flowManager/src/UserLogout.js @@ -23,25 +23,35 @@ fluid.registerNamespace("gpii.request.flowManager"); + gpii.request.flowManager.notifyLogout = function (status, pcpInterface) { + pcpInterface.notifyLogout(); + pcpInterface.sendUserMessage(status); + }; + fluid.defaults("kettle.requests.request.handler.userLogout", { gradeNames: ["fluid.littleComponent", "autoInit"], invokers: { handle: { funcName: "gpii.request.flowManager.onUserLogout", - args: ["{requestProxy}", "{request}.req.params.userToken", "{flowManager}.lifecycleManager"], + args: ["{that}", "{requestProxy}", "{request}.req.params.userToken", "{flowManager}.lifecycleManager"], dynamic: true + }, + notifyLogout: { + funcName: "gpii.request.flowManager.notifyLogout", + args: ["{arguments}.0", "{flowManager}.pcpInterface"] } } }); - gpii.request.flowManager.onUserLogout = function (requestProxy, userToken, lifecycleManager) { + gpii.request.flowManager.onUserLogout = function (that, requestProxy, userToken, lifecycleManager) { // TODO: clarify semantics of multiple active start/stop cycles. lifecycleManager.stop({ userToken: userToken }, function onSuccess(response) { + var msg = "User with token " + userToken + " was successfully logged out."; fluid.log("Lifecycle manager returned: ", response); - requestProxy.events.onSuccess.fire("User with token " + userToken + - " was successfully logged out."); + that.notifyLogout(msg); + requestProxy.events.onSuccess.fire(msg); }); }; diff --git a/gpii/node_modules/flowManager/test/PCPInterfaceTests.js b/gpii/node_modules/flowManager/test/PCPInterfaceTests.js index 33407b354..8a67b605f 100644 --- a/gpii/node_modules/flowManager/test/PCPInterfaceTests.js +++ b/gpii/node_modules/flowManager/test/PCPInterfaceTests.js @@ -77,77 +77,113 @@ gpii.tests.flowManager.PCPInterface.onMessage = function (data, expected) { jqUnit.assertDeepEq("Message succusfully received by socket client", expected, data); }; -var testDef = { - name: "Flow Manager PCPInterface tests", - expect: 5, - config: { - configName: "development", - configPath: configPath - }, - gradeNames: "gpii.tests.flowManager.pcpInterface.testCaseHolder", - components: { - client: { - type: "gpii.tests.flowManager.PCPInterface.basicClient" - } - }, - sequence: [ - { - func: "{client}.send", - args: "{client}.options.solutionId" - }, { - event: "{client}.events.onComplete", - listener: "gpii.tests.flowManager.PCPInterface.checkConnectionRequest", - args: [ "{arguments}.0", "{client}" ] - }, { - // Test regular login notification with no settings passed - func: "{flowManager}.pcpInterface.notifyLogin", - args: [ "someUser" ] - }, { - event: "{client}.events.onLogin", - listener: "gpii.tests.flowManager.PCPInterface.onLogin", - args: [ "{arguments}.0", "someUser", { "http://registry.gpii.net/common/highContrastEnabled": false } ] - }, { - // Test regular login notification with a set of settings passed - func: "{flowManager}.pcpInterface.notifyLogin", - args: [ "someOtherUser", { "http://registry.gpii.net/common/screenResolution": "low" } ] - }, { - event: "{client}.events.onLogin", - listener: "gpii.tests.flowManager.PCPInterface.onLogin", - args: [ "{arguments}.0", "someOtherUser", { "http://registry.gpii.net/common/screenResolution": "low" } ] - }, { - // Test logout notification gets passed to socket client - func: "{flowManager}.pcpInterface.notifyLogout" - }, { - event: "{client}.events.onLogout", - listener: "gpii.tests.flowManager.PCPInterface.onLogout" - }, { - // Test regular messages gets passed to socket client - func: "{flowManager}.pcpInterface.sendUserMessage", - args: [ - [{ - type: "infoMessage", - message: { +var testDefs = [ + { + name: "Flow Manager PCPInterface login, logout and standard message tests", + expect: 5, + 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 regular login notification with no settings passed + func: "{flowManager}.pcpInterface.notifyLogin", + args: [ "someUser" ] + }, { + event: "{client}.events.onLogin", + listener: "gpii.tests.flowManager.PCPInterface.onLogin", + args: [ "{arguments}.0", "someUser", { "http://registry.gpii.net/common/highContrastEnabled": false } ] + }, { + // Test regular login notification with a set of settings passed + func: "{flowManager}.pcpInterface.notifyLogin", + args: [ "someOtherUser", { "http://registry.gpii.net/common/screenResolution": "low" } ] + }, { + event: "{client}.events.onLogin", + listener: "gpii.tests.flowManager.PCPInterface.onLogin", + args: [ "{arguments}.0", "someOtherUser", { "http://registry.gpii.net/common/screenResolution": "low" } ] + }, { + // Test logout notification gets passed to socket client + func: "{flowManager}.pcpInterface.notifyLogout" + }, { + event: "{client}.events.onLogout", + listener: "gpii.tests.flowManager.PCPInterface.onLogout" + }, { + // Test regular messages gets passed to socket client + func: "{flowManager}.pcpInterface.sendUserMessage", + args: [ + { dk: "Katte er nogle trælse kræ", en: "Howdy user! This is a message to you", es: "¿Hola Pedro, donde esta la biblioteca?" + }, + "warningMessage" + ] + }, { + event: "{client}.events.onMessage", + listener: "gpii.tests.flowManager.PCPInterface.onMessage", + args: [ + "{arguments}.0", { + type: "warningMessage", + message: { + dk: "Katte er nogle trælse kræ", + en: "Howdy user! This is a message to you", + es: "¿Hola Pedro, donde esta la biblioteca?" + } } - }] - ] - }, { - event: "{client}.events.onMessage", - listener: "gpii.tests.flowManager.PCPInterface.onMessage", - args: [ - "{arguments}.0", [{ - type: "infoMessage", - message: { - dk: "Katte er nogle trælse kræ", - en: "Howdy user! This is a message to you", - es: "¿Hola Pedro, donde esta la biblioteca?" + ] + } + ] + }, { + 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: { + en: "Howdy user! This is a message to you" + } } - }] - ] - } - ] -}; + ] + } + ] + } +]; -module.exports = kettle.test.bootstrapServer([testDef]); +module.exports = kettle.test.bootstrapServer(testDefs); diff --git a/gpii/node_modules/flowManager/test/configs/pcpInterface.json b/gpii/node_modules/flowManager/test/configs/pcpInterface.json deleted file mode 100644 index 041b12830..000000000 --- a/gpii/node_modules/flowManager/test/configs/pcpInterface.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "typeName": "pcpInterface", - "options": { - "gradeNames": ["autoInit", "fluid.littleComponent"], - "distributeOptions": [{ - "source": "{that}.options.port", - "target": "{that server}.options.port" - }], - "port": 8081 - }, - "includes": [ - "../../configs/io.json", - "../../configs/development.json" - ] -} diff --git a/package.json b/package.json index 25747e137..af57aab46 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,7 @@ "node-uuid": "~1.4.0", "semver": "~1.1.4", "xml-mapping": "~1.2.0", - "kettle": "git://github.com/fluid-project/kettle.git#e79bb81196df68c97eaa9f96c485a4321b69af75", - + "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..c78785154 --- /dev/null +++ b/tests/PCPIntegrationTests.js @@ -0,0 +1,192 @@ +/** + * 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); + +}; + +gpii.tests.integration.PCPInterface.softFailureHandler = function (args, activity) { + var messages = ["ASSERTION FAILED: "].concat(args).concat(activity); + fluid.log.apply(null, [fluid.logLevel.FATAL].concat(messages)); + var request = kettle.getCurrentRequest(); + if (request) { + request.events.onError.fire({ + isError: true, + message: "This is system failure triggered for testing" + }); + } +}; + +fluid.defaults("gpii.tests.integration.PCPInterface.mockServer", { + gradeNames: ["autoInit", "fluid.littleComponent"], + invokers: { + set: { + funcName: "gpii.tests.integration.PCPInterface.mockServer.set" + } + } +}); + +gpii.tests.integration.PCPInterface.pushInstrumentedErrors = function () { + fluid.pushSoftFailure(gpii.tests.integration.PCPInterface.softFailureHandler); +}; + +gpii.tests.integration.PCPInterface.popInstrumentedErrors = function () { + fluid.pushSoftFailure(-1); +}; + +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: [ + { + 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: { en: "User with token screenreader_common was successfully 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: { en: "User with token screenreader_common was successfully logged out." }} + ] + } + ] +}, { + name: "Login fails and is it is reported to the PCP channel", + expect: 2, + config: { + configName: "localInstall", + configPath: configPath + }, + userToken: "screenreader_common", + gradeNames: "gpii.test.integration.testCaseHolder.windows", + rawPreferencesDataSourceGradeNames: ["gpii.tests.integration.PCPInterface.mockServer"], + distributeOptions: { + source: "{that}.options.rawPreferencesDataSourceGradeNames", + target: "{that matchMakerService}.options.gradeNames" + }, + components: { + client: { + type: "gpii.tests.integration.PCPInterface.basicClient" + } + }, + sequence: [ + { + funcName: "gpii.tests.integration.PCPInterface.pushInstrumentedErrors" + }, { + 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.onMessage", + listener: "gpii.tests.integration.PCPInterface.onMessage", + args: [ "{arguments}.0", + { type: "errorMessage", message: { en: "This is system failure triggered for testing" }} + ] + }, { + func: "gpii.tests.integration.PCPInterface.popInstrumentedErrors" + } + ] +}]; + +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 cea746800..018f4c7f7 100644 --- a/tests/all-tests.js +++ b/tests/all-tests.js @@ -43,6 +43,7 @@ var testIncludes = [ "../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", diff --git a/tests/configs/pcpIntegration.json b/tests/configs/pcpIntegration.json new file mode 100644 index 000000000..2cdf68e6b --- /dev/null +++ b/tests/configs/pcpIntegration.json @@ -0,0 +1,32 @@ +{ + "typeName": "browserChannel", + "options": { + "gradeNames": ["autoInit", "fluid.littleComponent"], + "distributeOptions": [{ + "source": "{that}.options.port", + "target": "{that server}.options.port" + }, { + "source": "{that}.options.solutionsRegistryUrl", + "target": "{that flowManager}.options.urls.solutionsRegistry" + }, { + "source": "{that}.options.rawPreferencesSourceUrl", + "target": "{that rawPreferencesServer}.options.rawPreferencesSourceUrl" + }, { + "source": "{that}.options.installedSolutionsUrl", + "target": "{that deviceReporter}.options.installedSolutionsUrl" + }], + "rawPreferencesSourceUrl": "file://%root/../flowManager/test/data/%userToken.json", + "solutionsRegistryUrl": "file://%root/../flowManager/test/data/browserChannel_solutionsRegistry.json", + "installedSolutionsUrl": "file://%root/../flowManager/test/data/browserChannel_deviceReporter.json", + "port": 8081 + }, + "includes": [ + "../../configs/io.json", + "../../configs/development.json", + "../../../deviceReporter/configs/development.json", + "../../../flatMatchMaker/configs/development.all.local.json", + "../../../preferencesServer/configs/development.json", + "../../../rawPreferencesServer/configs/development.json", + "../../../solutionsRegistry/configs/development.json" + ] +} From 77551480c20ca75c09deeda5d3ba2f4996672e7c Mon Sep 17 00:00:00 2001 From: Kasper Markus Date: Thu, 20 Aug 2015 14:09:35 +0200 Subject: [PATCH 03/10] GPII-1251: Removed unnused argument from userlogin.js handlers... moved config file that was previously moved by mistake --- gpii/node_modules/flowManager/src/UserLogin.js | 4 ++-- .../node_modules/flowManager/test/configs/browserChannel.json | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename tests/configs/pcpIntegration.json => gpii/node_modules/flowManager/test/configs/browserChannel.json (100%) diff --git a/gpii/node_modules/flowManager/src/UserLogin.js b/gpii/node_modules/flowManager/src/UserLogin.js index 77b2606e0..de380cb56 100644 --- a/gpii/node_modules/flowManager/src/UserLogin.js +++ b/gpii/node_modules/flowManager/src/UserLogin.js @@ -22,7 +22,7 @@ var gpii = fluid.registerNamespace("gpii"); fluid.registerNamespace("gpii.request.flowManager"); - gpii.request.flowManager.onUserLogin = function (userToken, proxy, handler) { + gpii.request.flowManager.onUserLogin = function (userToken, handler) { handler.events.onUserToken.fire(userToken); }; @@ -67,7 +67,7 @@ }, handle: { funcName: "gpii.request.flowManager.onUserLogin", - args: ["{request}.req.params.userToken", "{requestProxy}", "{that}"] + args: ["{request}.req.params.userToken", "{that}"] }, notifyLogin: { funcName: "gpii.request.flowManager.notifyLogin", diff --git a/tests/configs/pcpIntegration.json b/gpii/node_modules/flowManager/test/configs/browserChannel.json similarity index 100% rename from tests/configs/pcpIntegration.json rename to gpii/node_modules/flowManager/test/configs/browserChannel.json From 7ca3464c3391bbde925ee82a305e6b17661e568a Mon Sep 17 00:00:00 2001 From: Kasper Markus Date: Mon, 14 Sep 2015 11:49:04 +0200 Subject: [PATCH 04/10] Update PCPChannel.md --- documentation/PCPChannel.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/PCPChannel.md b/documentation/PCPChannel.md index 684cd870d..02df86217 100644 --- a/documentation/PCPChannel.md +++ b/documentation/PCPChannel.md @@ -60,7 +60,7 @@ When the system has a message it will emit a `message` signal. It will have the "type": "infoMessage", "message": { "en": "My message", - "es": "Mi mensaje"} + "es": "Mi mensaje" } } ``` From d559906fc8c37a0b1bae68e109b3fb9c11af2353 Mon Sep 17 00:00:00 2001 From: Kasper Markus Date: Thu, 15 Oct 2015 19:13:18 +0200 Subject: [PATCH 05/10] GPII-1251: Updated the documentation on the PCP according to review comments --- documentation/PCPChannel.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/documentation/PCPChannel.md b/documentation/PCPChannel.md index 684cd870d..561a28ad8 100644 --- a/documentation/PCPChannel.md +++ b/documentation/PCPChannel.md @@ -38,7 +38,7 @@ The PCPChannel is a component of the Flowmanager, used in the local/hybrid deplo #### Connection -Connection to the PCP is done as a socket connection to the URL `/pcpChannel`. +Connection to the PCP is done as a WebSockets connection to the URL `/pcpChannel`. #### On login [`login` signal]: @@ -53,16 +53,13 @@ When a user logs out of the system, it will emit a `logout` signal to the socket #### Sending user messages [`message` signal] -When the system has a message it will emit a `message` signal. It will have the format: +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": { - "en": "My message", - "es": "Mi mensaje"} - } + "message": "My message" } ``` -Where the `"type"` can be either "infoMessage", "warningMessage" or "errorMessage", and `"message"` will contains messages keyed by language codes. +Where the `"type"` can be either "infoMessage", "warningMessage" or "errorMessage", and `"message"` will contain the message to be displayed From a69ca636e4cda68c6660623e9fd60d95bc37711d Mon Sep 17 00:00:00 2001 From: Kasper Markus Date: Thu, 15 Oct 2015 21:09:34 +0200 Subject: [PATCH 06/10] GPII-1251: Commiting to show stuff to antranig --- documentation/PCPChannel.md | 9 ++-- .../flowManager/src/FlowManager.js | 4 +- .../flowManager/src/FlowManagerUtilities.js | 3 ++ .../flowManager/src/PCPInterface.js | 5 ++- .../flowManager/src/UserLogonStateChange.js | 45 ++++++++++++------- .../flowManager/test/PCPInterfaceTests.js | 16 ++----- tests/PCPIntegrationTests.js | 2 +- tests/all-tests.js | 1 + 8 files changed, 47 insertions(+), 38 deletions(-) diff --git a/documentation/PCPChannel.md b/documentation/PCPChannel.md index 561a28ad8..639013b98 100644 --- a/documentation/PCPChannel.md +++ b/documentation/PCPChannel.md @@ -15,24 +15,21 @@ Message types: (Info<- default), Error, Warning { type: "infoMessage", - message: { - dk: "Katte er nogle trælse kræ", - en: "Howdy user! This is a message to you", - es: "¿Hola Pedro, donde esta la biblioteca?" - } + 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** Can be either an object with messages keyed by language code, e.g.: `{ "en": "My message", "es": "Mi mensaje"}`, or a simple string, which the system will assume is an english message wrap accordingly + * **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 diff --git a/gpii/node_modules/flowManager/src/FlowManager.js b/gpii/node_modules/flowManager/src/FlowManager.js index 8798a96ce..6713be1d7 100644 --- a/gpii/node_modules/flowManager/src/FlowManager.js +++ b/gpii/node_modules/flowManager/src/FlowManager.js @@ -171,7 +171,9 @@ fluid.defaults("gpii.flowManager.io", { onCreate: { funcName: "gpii.flowManager.mountWebSocketsSettingsHandler", args: ["{webSocketsComponent}"] - } + }, + "{that}.events.onLoginComplete": "{lifecycleManager}.notifyLogin" + } }); 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 index 5c23c0a34..ad5cb156f 100644 --- a/gpii/node_modules/flowManager/src/PCPInterface.js +++ b/gpii/node_modules/flowManager/src/PCPInterface.js @@ -69,10 +69,10 @@ fluid.log("No PCP connected, so discarding message: " + text); return; } - // Default to 'infoMessage' and assume english if the text is a simple string + // Default to 'infoMessage' var message = { type: (messageType === undefined) ? "infoMessage" : messageType, - message: (typeof text === "string") ? { "en": text } : text + message: text }; socket.emit("message", message, fluid.log); }; @@ -88,6 +88,7 @@ * value as values. */ gpii.pcpInterface.notifyLogin = function (socket, userToken, adjusters) { + fluid.fail("Kasper, you bloody genious"); if (socket === null) { fluid.log("No PCP connected, so is not attempting to notify of a login"); return; diff --git a/gpii/node_modules/flowManager/src/UserLogonStateChange.js b/gpii/node_modules/flowManager/src/UserLogonStateChange.js index fb96bc0fe..ac344597b 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,9 @@ }, listeners: { onUserToken: "{that}.getDeviceContext", - onMatchDone: "{that}.startLifecycle" + onMatchDone: "{that}.startLifecycle", + onLoginComplete: "{that}.loginComplete", + onLogoutComplete: "{that}.logoutComplete" } }); diff --git a/gpii/node_modules/flowManager/test/PCPInterfaceTests.js b/gpii/node_modules/flowManager/test/PCPInterfaceTests.js index 8a67b605f..ee12a4240 100644 --- a/gpii/node_modules/flowManager/test/PCPInterfaceTests.js +++ b/gpii/node_modules/flowManager/test/PCPInterfaceTests.js @@ -124,11 +124,7 @@ var testDefs = [ // Test regular messages gets passed to socket client func: "{flowManager}.pcpInterface.sendUserMessage", args: [ - { - dk: "Katte er nogle trælse kræ", - en: "Howdy user! This is a message to you", - es: "¿Hola Pedro, donde esta la biblioteca?" - }, + "Howdy user! This is a message to you", "warningMessage" ] }, { @@ -137,11 +133,7 @@ var testDefs = [ args: [ "{arguments}.0", { type: "warningMessage", - message: { - dk: "Katte er nogle trælse kræ", - en: "Howdy user! This is a message to you", - es: "¿Hola Pedro, donde esta la biblioteca?" - } + message: "Howdy user! This is a message to you" } ] } @@ -176,9 +168,7 @@ var testDefs = [ args: [ "{arguments}.0", { type: "infoMessage", - message: { - en: "Howdy user! This is a message to you" - } + message: "Howdy user! This is a message to you" } ] } diff --git a/tests/PCPIntegrationTests.js b/tests/PCPIntegrationTests.js index c78785154..623c6e5a1 100644 --- a/tests/PCPIntegrationTests.js +++ b/tests/PCPIntegrationTests.js @@ -108,7 +108,7 @@ var testDefs = [{ } }, sequence: [ - { + { // connect the PCP client first func: "{client}.send" }, { event: "{client}.events.onComplete", diff --git a/tests/all-tests.js b/tests/all-tests.js index f66b522c4..515307db9 100644 --- a/tests/all-tests.js +++ b/tests/all-tests.js @@ -43,6 +43,7 @@ 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", From 29e59a25d74232d0bb5ab61dbef19a4bc0c333bb Mon Sep 17 00:00:00 2001 From: Kasper Markus Date: Fri, 16 Oct 2015 13:05:18 +0200 Subject: [PATCH 07/10] GPII-1251: Fixed up the code a bit, to remove hard dependency between login/logout actions and PCP. It now uses events instead --- .../flowManager/src/FlowManager.js | 7 +- .../flowManager/src/PCPInterface.js | 51 ++++++--------- .../flowManager/src/UserLogonStateChange.js | 16 ++++- .../flowManager/test/PCPInterfaceTests.js | 43 ++++++------ tests/PCPIntegrationTests.js | 65 +------------------ 5 files changed, 61 insertions(+), 121 deletions(-) diff --git a/gpii/node_modules/flowManager/src/FlowManager.js b/gpii/node_modules/flowManager/src/FlowManager.js index 6713be1d7..c3f349f1b 100644 --- a/gpii/node_modules/flowManager/src/FlowManager.js +++ b/gpii/node_modules/flowManager/src/FlowManager.js @@ -109,6 +109,9 @@ fluid.defaults("gpii.flowManager", { route: "/environmentChanged", type: "put" } + }, + events: { + onLogonStateChangeComplete: null } }); @@ -171,9 +174,7 @@ fluid.defaults("gpii.flowManager.io", { onCreate: { funcName: "gpii.flowManager.mountWebSocketsSettingsHandler", args: ["{webSocketsComponent}"] - }, - "{that}.events.onLoginComplete": "{lifecycleManager}.notifyLogin" - + } } }); diff --git a/gpii/node_modules/flowManager/src/PCPInterface.js b/gpii/node_modules/flowManager/src/PCPInterface.js index ad5cb156f..504aaeeaf 100644 --- a/gpii/node_modules/flowManager/src/PCPInterface.js +++ b/gpii/node_modules/flowManager/src/PCPInterface.js @@ -29,15 +29,11 @@ funcName: "gpii.pcpInterface.sendUserMessage", args: ["{that}.socket", "{arguments}.0", "{arguments}.1" ] }, - notifyLogin: { - funcName: "gpii.pcpInterface.notifyLogin", - args: ["{that}.socket", "{arguments}.0", "{arguments}.1" ] + notifyUserLogonStateChange: { + funcName: "gpii.pcpInterface.notifyUserLogonStateChange", + args: ["{that}", "{that}.socket", "{arguments}.0", "{arguments}.1" ] // user token, adjusters }, - notifyLogout: { - funcName: "gpii.pcpInterface.notifyLogout", - args: ["{that}.socket" ] - }, initSocket: { funcName: "gpii.pcpInterface.initSocket", args: ["{that}", "{arguments}.0" ] // socket connection @@ -47,7 +43,8 @@ sendUserMessage: null }, listeners: { - sendUserMessage: "{that}.sendUserMessage" + sendUserMessage: "{that}.sendUserMessage", + "{flowManager}.events.onLogonStateChangeComplete": "{that}.notifyUserLogonStateChange" } }); @@ -65,6 +62,7 @@ * or "errorMessage"). If this parameter is not given, it defaults to "infoMessage" */ gpii.pcpInterface.sendUserMessage = function (socket, text, messageType) { + console.log("User message sent: " + text); if (socket === null) { fluid.log("No PCP connected, so discarding message: " + text); return; @@ -78,41 +76,34 @@ }; /** - * Notify the PCP client that a user has logged in. + * Notify the PCP client that a user has logged in or out * + * @param that {Object} the pcpInterface * @param socket {Object} client socket connection - * @param userToken {String} the token of the user who has just logged in - * @param adjusters {Object} Adjusters can be passed to the PCP via the adjusters argument. If - * this is left empty, a ddefault set of adjusters will be passed to - * the PCP. The format of the adjusters is a map of settings names as keys and the deafult - * value as values. + * @param action {String} "login" or "logout" + * @param userToken {String} the token of the user who has just logged in or out */ - gpii.pcpInterface.notifyLogin = function (socket, userToken, adjusters) { - fluid.fail("Kasper, you bloody genious"); + gpii.pcpInterface.notifyUserLogonStateChange = function (that, socket, action, userToken) { if (socket === null) { - fluid.log("No PCP connected, so is not attempting to notify of a login"); + fluid.log("No PCP connected, so is not attempting to notify of a logon change"); + return; + } + if (action === "logout") { + socket.emit("logout"); + that.sendUserMessage("The token " + userToken + " was logged out."); return; } + // else A user just logged in var defaultAdjusters = { "http://registry.gpii.net/common/highContrastEnabled": false }; + // send login message socket.emit("login", { - settings: adjusters !== undefined ? adjusters : defaultAdjusters, + settings: defaultAdjusters, userToken: userToken }); - }; + that.sendUserMessage("The token " + userToken + " was logged in."); - /** - * Notify the PCP client that a user has logged out. - * - * @param socket {Object} client socket connection - */ - gpii.pcpInterface.notifyLogout = function (socket) { - if (socket === null) { - fluid.log("No PCP connected, so is not attempting to notify of a log out"); - return; - } - socket.emit("logout"); }; fluid.defaults("kettle.requests.request.handler.pcpChannel", { diff --git a/gpii/node_modules/flowManager/src/UserLogonStateChange.js b/gpii/node_modules/flowManager/src/UserLogonStateChange.js index ac344597b..69e271d13 100644 --- a/gpii/node_modules/flowManager/src/UserLogonStateChange.js +++ b/gpii/node_modules/flowManager/src/UserLogonStateChange.js @@ -146,8 +146,20 @@ listeners: { onUserToken: "{that}.getDeviceContext", onMatchDone: "{that}.startLifecycle", - onLoginComplete: "{that}.loginComplete", - onLogoutComplete: "{that}.logoutComplete" + 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 index ee12a4240..bf3c2b531 100644 --- a/gpii/node_modules/flowManager/test/PCPInterfaceTests.js +++ b/gpii/node_modules/flowManager/test/PCPInterfaceTests.js @@ -62,9 +62,11 @@ gpii.tests.flowManager.pcpInterface.receiveLifecycleManager = function (testCase testCaseHolder.flowManager = flowManager; }; -gpii.tests.flowManager.PCPInterface.onLogin = function (data, userToken, settings) { +gpii.tests.flowManager.PCPInterface.onLogin = function (data, userToken) { jqUnit.assertDeepEq("Testing data on login event", { - "settings": settings, + "settings": { + "http://registry.gpii.net/common/highContrastEnabled": false + }, "userToken": userToken }, data); }; @@ -99,41 +101,36 @@ var testDefs = [ listener: "gpii.tests.flowManager.PCPInterface.checkConnectionRequest", args: [ "{arguments}.0", "{client}" ] }, { - // Test regular login notification with no settings passed - func: "{flowManager}.pcpInterface.notifyLogin", - args: [ "someUser" ] + // Test regular login notification + func: "{flowManager}.pcpInterface.notifyUserLogonStateChange", + args: [ "login", "someUser" ] }, { event: "{client}.events.onLogin", listener: "gpii.tests.flowManager.PCPInterface.onLogin", - args: [ "{arguments}.0", "someUser", { "http://registry.gpii.net/common/highContrastEnabled": false } ] - }, { - // Test regular login notification with a set of settings passed - func: "{flowManager}.pcpInterface.notifyLogin", - args: [ "someOtherUser", { "http://registry.gpii.net/common/screenResolution": "low" } ] + args: [ "{arguments}.0", "someUser" ] }, { - event: "{client}.events.onLogin", - listener: "gpii.tests.flowManager.PCPInterface.onLogin", - args: [ "{arguments}.0", "someOtherUser", { "http://registry.gpii.net/common/screenResolution": "low" } ] + event: "{client}.events.onMessage", + listener: "gpii.tests.flowManager.PCPInterface.onMessage", + args: [ + "{arguments}.0", { + type: "infoMessage", + message: "The token someUser was logged in." + } + ] }, { // Test logout notification gets passed to socket client - func: "{flowManager}.pcpInterface.notifyLogout" + func: "{flowManager}.pcpInterface.notifyUserLogonStateChange", + args: [ "logout", "someUser" ] }, { event: "{client}.events.onLogout", listener: "gpii.tests.flowManager.PCPInterface.onLogout" - }, { - // Test regular messages gets passed to socket client - func: "{flowManager}.pcpInterface.sendUserMessage", - args: [ - "Howdy user! This is a message to you", - "warningMessage" - ] }, { event: "{client}.events.onMessage", listener: "gpii.tests.flowManager.PCPInterface.onMessage", args: [ "{arguments}.0", { - type: "warningMessage", - message: "Howdy user! This is a message to you" + type: "infoMessage", + message: "The token someUser was logged out." } ] } diff --git a/tests/PCPIntegrationTests.js b/tests/PCPIntegrationTests.js index 623c6e5a1..e1460e3ea 100644 --- a/tests/PCPIntegrationTests.js +++ b/tests/PCPIntegrationTests.js @@ -59,18 +59,6 @@ gpii.tests.integration.PCPInterface.onMessage = function (data, expected) { }; -gpii.tests.integration.PCPInterface.softFailureHandler = function (args, activity) { - var messages = ["ASSERTION FAILED: "].concat(args).concat(activity); - fluid.log.apply(null, [fluid.logLevel.FATAL].concat(messages)); - var request = kettle.getCurrentRequest(); - if (request) { - request.events.onError.fire({ - isError: true, - message: "This is system failure triggered for testing" - }); - } -}; - fluid.defaults("gpii.tests.integration.PCPInterface.mockServer", { gradeNames: ["autoInit", "fluid.littleComponent"], invokers: { @@ -80,14 +68,6 @@ fluid.defaults("gpii.tests.integration.PCPInterface.mockServer", { } }); -gpii.tests.integration.PCPInterface.pushInstrumentedErrors = function () { - fluid.pushSoftFailure(gpii.tests.integration.PCPInterface.softFailureHandler); -}; - -gpii.tests.integration.PCPInterface.popInstrumentedErrors = function () { - fluid.pushSoftFailure(-1); -}; - gpii.tests.integration.PCPInterface.mockServer.set = function () { fluid.fail(); return fluid.promise(); @@ -130,7 +110,7 @@ var testDefs = [{ event: "{client}.events.onMessage", listener: "gpii.tests.integration.PCPInterface.onMessage", args: [ "{arguments}.0", - { type: "infoMessage", message: { en: "User with token screenreader_common was successfully logged in." }} + { type: "infoMessage", message: "The token screenreader_common was logged in." } ] }, { // Test logout notification gets passed to socket client @@ -142,51 +122,10 @@ var testDefs = [{ event: "{client}.events.onMessage", listener: "gpii.tests.integration.PCPInterface.onMessage", args: [ "{arguments}.0", - { type: "infoMessage", message: { en: "User with token screenreader_common was successfully logged out." }} + { type: "infoMessage", message: "The token screenreader_common was logged out." } ] } ] -}, { - name: "Login fails and is it is reported to the PCP channel", - expect: 2, - config: { - configName: "localInstall", - configPath: configPath - }, - userToken: "screenreader_common", - gradeNames: "gpii.test.integration.testCaseHolder.windows", - rawPreferencesDataSourceGradeNames: ["gpii.tests.integration.PCPInterface.mockServer"], - distributeOptions: { - source: "{that}.options.rawPreferencesDataSourceGradeNames", - target: "{that matchMakerService}.options.gradeNames" - }, - components: { - client: { - type: "gpii.tests.integration.PCPInterface.basicClient" - } - }, - sequence: [ - { - funcName: "gpii.tests.integration.PCPInterface.pushInstrumentedErrors" - }, { - 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.onMessage", - listener: "gpii.tests.integration.PCPInterface.onMessage", - args: [ "{arguments}.0", - { type: "errorMessage", message: { en: "This is system failure triggered for testing" }} - ] - }, { - func: "gpii.tests.integration.PCPInterface.popInstrumentedErrors" - } - ] }]; module.exports = kettle.test.bootstrapServer(testDefs); \ No newline at end of file From 5b738f25ab77a212954304bde586149321e79393 Mon Sep 17 00:00:00 2001 From: Kasper Markus Date: Fri, 16 Oct 2015 13:21:27 +0200 Subject: [PATCH 08/10] GPII-1251: Updated documentation wording to be more clear on direction of socket communication --- documentation/PCPChannel.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/documentation/PCPChannel.md b/documentation/PCPChannel.md index 639013b98..f80fe8576 100644 --- a/documentation/PCPChannel.md +++ b/documentation/PCPChannel.md @@ -38,17 +38,17 @@ The PCPChannel is a component of the Flowmanager, used in the local/hybrid deplo Connection to the PCP is done as a WebSockets connection to the URL `/pcpChannel`. -#### On login [`login` signal]: +#### On login [`login` message]: -When a user logs into the system, it will emit a `login` signal. 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 }` +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` signal] +#### On logout [`logout` message] -When a user logs out of the system, it will emit a `logout` signal to the socket. +When a user logs out of the GPII system, it will emit a `logout` message to the PCP client. -#### Sending user messages [`message` signal] +#### 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: @@ -59,4 +59,4 @@ When the GPII system has a message that it wants the PCP client to display, the } ``` -Where the `"type"` can be either "infoMessage", "warningMessage" or "errorMessage", and `"message"` will contain the message to be displayed +Where the `"type"` can be either "infoMessage", "warningMessage" or "errorMessage", and `"message"` will contain the message to be displayed. From 53d16d3fd10074d11b861b97e2cca8a8975a2c33 Mon Sep 17 00:00:00 2001 From: Kasper Markus Date: Fri, 16 Oct 2015 13:33:20 +0200 Subject: [PATCH 09/10] GPII-1251: Removed stray comma --- gpii/node_modules/flowManager/src/UserLogonStateChange.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gpii/node_modules/flowManager/src/UserLogonStateChange.js b/gpii/node_modules/flowManager/src/UserLogonStateChange.js index 69e271d13..00d50ec95 100644 --- a/gpii/node_modules/flowManager/src/UserLogonStateChange.js +++ b/gpii/node_modules/flowManager/src/UserLogonStateChange.js @@ -151,7 +151,7 @@ listener: "{flowManager}.events.onLogonStateChangeComplete.fire", args: [ "login", "{arguments}.0" ] }, - "{that}.loginComplete", + "{that}.loginComplete" ], onLogoutComplete: [ { From fe2f56ed74ddc8eaa68c855540b551f5f3494cd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Hern=C3=A1ndez?= Date: Tue, 20 Oct 2015 11:30:09 +0200 Subject: [PATCH 10/10] GPII-1251: Ensuring that the clients will be notified with changes This is a temporary hack for review4, the PCPInterface should be re-implemented before landing master. --- .../flowManager/src/PCPInterface.js | 66 ++++++++++--------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/gpii/node_modules/flowManager/src/PCPInterface.js b/gpii/node_modules/flowManager/src/PCPInterface.js index 504aaeeaf..41d1eb6f8 100644 --- a/gpii/node_modules/flowManager/src/PCPInterface.js +++ b/gpii/node_modules/flowManager/src/PCPInterface.js @@ -19,6 +19,8 @@ fluid.registerNamespace("gpii.request.flowManager"); fluid.registerNamespace("gpii.pcpInterface"); + gpii.pcpInterface.sockets = []; + fluid.defaults("gpii.pcpInterface", { gradeNames: ["autoInit", "fluid.eventedComponent"], members: { @@ -50,6 +52,7 @@ gpii.pcpInterface.initSocket = function (that, socket) { that.socket = socket; + gpii.pcpInterface.sockets.push(socket); }; /** @@ -63,16 +66,18 @@ */ gpii.pcpInterface.sendUserMessage = function (socket, text, messageType) { console.log("User message sent: " + text); - if (socket === null) { - fluid.log("No PCP connected, so discarding message: " + text); - return; - } - // Default to 'infoMessage' - var message = { - type: (messageType === undefined) ? "infoMessage" : messageType, - message: text - }; - socket.emit("message", message, fluid.log); + fluid.each(gpii.pcpInterface.sockets, function (s) { + if ((s === null) || (s.disconnected === true)) { + fluid.log("No PCP connected on this socket, so discarding message: " + text); + } else { + // Default to 'infoMessage' + var message = { + type: (messageType === undefined) ? "infoMessage" : messageType, + message: text + }; + s.emit("message", message, fluid.log); + } + }); }; /** @@ -84,26 +89,27 @@ * @param userToken {String} the token of the user who has just logged in or out */ gpii.pcpInterface.notifyUserLogonStateChange = function (that, socket, action, userToken) { - if (socket === null) { - fluid.log("No PCP connected, so is not attempting to notify of a logon change"); - return; - } - if (action === "logout") { - socket.emit("logout"); - that.sendUserMessage("The token " + userToken + " was logged out."); - return; - } - // else A user just logged in - var defaultAdjusters = { - "http://registry.gpii.net/common/highContrastEnabled": false - }; - // send login message - socket.emit("login", { - settings: defaultAdjusters, - userToken: userToken + fluid.each(gpii.pcpInterface.sockets, function (s) { + if ((s === null) || (s.disconnected === true)) { + fluid.log("No PCP connected, so is not attempting to notify of a logon change on this socket"); + } else { + if (action === "logout") { + s.emit("logout"); + that.sendUserMessage("The token " + userToken + " was logged out."); + return; + } + // else A user just logged in + var defaultAdjusters = { + "http://registry.gpii.net/common/highContrastEnabled": false + }; + // send login message + s.emit("login", { + settings: defaultAdjusters, + userToken: userToken + }); + that.sendUserMessage("The token " + userToken + " was logged in."); + } }); - that.sendUserMessage("The token " + userToken + " was logged in."); - }; fluid.defaults("kettle.requests.request.handler.pcpChannel", { @@ -121,4 +127,4 @@ pcpInterface.initSocket(socket); events.onSuccess.fire("Client has successfully established connection to the PCP Channel"); }; -})(); \ No newline at end of file +})();