Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GPII-3529: Report NoConnection user error when no cloud connection. #709

Merged
merged 3 commits into from Nov 19, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 5 additions & 1 deletion gpii/node_modules/flowManager/src/UntrustedFlowManager.js
Expand Up @@ -61,9 +61,13 @@ fluid.defaults("gpii.flowManager.untrusted", {
});

gpii.flowManager.untrusted.reportSaveError = function (userErrorEvent, error) {
fluid.log("The save of preferences to the cloud fails with the error: ", error);

var connectionErrCode = ["ECONNREFUSED", "ETIMEDOUT", "ECONNRESET"];

userErrorEvent.fire({
isError: true,
messageKey: "SaveToCloudFail",
messageKey: connectionErrCode.indexOf(error.code) === -1 ? "SaveToCloudFail" : "NoConnection",
originalError: error
});
};

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion gpii/node_modules/lifecycleManager/src/UserLogonRequest.js
Expand Up @@ -97,7 +97,15 @@ gpii.lifecycleManager.userLogonRequest.handleSuccessRequest = function (that, pa
gpii.lifecycleManager.userLogonRequest.handleFailedRequest = function (that, userErrorEvent, err) {
fluid.log("UserLogonRequest fails with the error: ", err);

if (!err.ignoreUserErrors) {
var connectionErrCode = ["ECONNREFUSED", "ETIMEDOUT", "ECONNRESET"];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put these in a public constant, together with a public checking function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amb26, the ways in my mind in terms of where to put these public constants and public utility functions share by multiple GPII modules:

  1. within "flowManager" module such as flowManager/src/Utility.js;
  2. create a separae GPII module "gpii-utility" with Utility.js in its src/ directory.

Either way, Utility.js will be required by various GPII modules when it's needed. In this fix, these modules are "flowManager" and "lifecycleManager".

Which way would you prefer or do you have other ideas? Thanks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest putting this constant and function in the gpii.userErrors namespace and module


if (connectionErrCode.indexOf(err.code) !== -1) {
userErrorEvent.fire({
isError: true,
messageKey: "NoConnection",
originalError: err
});
} else if (!err.ignoreUserErrors) {
userErrorEvent.fire({
isError: true,
messageKey: "KeyInFail",
Expand Down
2 changes: 1 addition & 1 deletion tests/ProductionConfigTests.js
Expand Up @@ -58,7 +58,7 @@ gpii.tests.productionConfigTesting.testDefs = fluid.transform(gpii.tests.develop
});

// Override the original "kettle.test.testDefToServerEnvironment" function provided by kettle library to boil a new
// aggregate event "onAllReady" that listens to both "onServerReady" and "{flowManager}.events.noUserLoggedIn" events
// aggregate event "onAllReady" that listens to both "onServerReady" and "{flowManager}.events.resetAtStartSuccess" events
kettle.test.testDefToServerEnvironment = function (testDef) {
var configurationName = testDef.configType || kettle.config.createDefaults(testDef.config);
return {
Expand Down
87 changes: 87 additions & 0 deletions tests/UntrustedUserLogonRequestTests.js
Expand Up @@ -13,6 +13,7 @@
"use strict";

var fluid = require("infusion"),
kettle = fluid.registerNamespace("kettle"),
gpii = fluid.registerNamespace("gpii");

fluid.require("%gpii-universal");
Expand All @@ -23,4 +24,90 @@ gpii.loadTestingSupport();

fluid.registerNamespace("gpii.tests.untrusted.userLogonRequest");

// 1. Tests for general user logon request tests
gpii.test.bootstrapServer(gpii.tests.userLogonRequest.buildTestDefs(gpii.tests.userLogonRequest.testDefs, "untrusted"));

// 2. Specific tests for untrusted environment only.
// Test the user report on NoConnection when the cloud cannot be accessed
gpii.tests.untrusted.userLogonRequest.buildTestDefs = function (testDefs) {
var config = {
configName: "gpii.config.untrusted.development",
configPath: "%gpii-universal/gpii/configs"
};

return fluid.transform(testDefs, function (testDef) {
return fluid.extend(true, {
config: config,
gpiiKey: testDefs.gpiiKey || gpii.tests.userLogonRequest.gpiiKey,
distributeOptions: {
"flowManager.escalate": {
"record": {
"resetAtStartSuccess.escalate": "{testEnvironment}.events.resetAtStartSuccess"
},
"target": "{that gpii.flowManager.local}.options.listeners"
}
}
}, gpii.tests.userLogonRequest.commonTestConfig, testDef);
});
};

// Override the original "kettle.test.testDefToServerEnvironment" function provided by kettle library to boil a new
// aggregate event "onAllReady" that listens to both "onServerReady" and "{flowManager}.events.resetAtStartSuccess" events
kettle.test.testDefToServerEnvironment = function (testDef) {
var configurationName = testDef.configType || kettle.config.createDefaults(testDef.config);
return {
type: "kettle.test.serverEnvironment",
options: {
configurationName: configurationName,
components: {
tests: {
options: kettle.test.testDefToCaseHolder(configurationName, testDef)
}
},
events: {
resetAtStartSuccess: null
}
}
};
};

gpii.tests.untrusted.userLogonRequest.untrustedSpecificTests = [{
name: "GPII-3529: report NoConnection user error when no cloud connection",
expect: 2,
sequence: [{
event: "{kettle.test.serverEnvironment}.events.resetAtStartSuccess",
listener: "fluid.identity"
}, {
// standard login without a cloud
func: "gpii.tests.invokePromiseProducer",
args: ["{lifecycleManager}.performLogin", [gpii.tests.userLogonRequest.gpiiKey], "{that}"]
}, {
event: "{that}.events.onError",
listener: "gpii.tests.userLogonRequest.testUserError",
args: ["{arguments}.0",
{
"code": "ECONNREFUSED",
"errno": "ECONNREFUSED",
"syscall": "connect",
"address": "127.0.0.1",
"port": 8084,
"isError": true
},
"{lifecycleManager}.userErrors.options.trackedUserErrors",
{
"isError": true,
"messageKey": "NoConnection",
"originalError": {
"code": "ECONNREFUSED",
"errno": "ECONNREFUSED",
"syscall": "connect",
"address": "127.0.0.1",
"port": 8084,
"isError": true
}
}
]
}]
}];

kettle.test.bootstrapServer(gpii.tests.untrusted.userLogonRequest.buildTestDefs(gpii.tests.untrusted.userLogonRequest.untrustedSpecificTests));
98 changes: 59 additions & 39 deletions tests/shared/UserLogonRequestTestDefs.js
Expand Up @@ -61,13 +61,26 @@ gpii.tests.userLogonRequest.modelChangeChecker = function (trackedLogonChange, e
jqUnit.assertEquals("Checking gpiiKey of model change", expectedGpiiKey, result.gpiiKey);
};

gpii.tests.userLogonRequest.testLogoutError = function (actualError, userError, expectedError) {
jqUnit.assertDeepEq("onError fires with the expected message", expectedError, actualError);
if (actualError.ignoreUserErrors) {
jqUnit.assertDeepEq("User error has not be fired", {}, userError);
} else {
var userErrorMessage = userError.error.originalError;
jqUnit.assertDeepEq("User error has been fired with the expected message", actualError.message, userErrorMessage);
gpii.tests.userLogonRequest.testUserError = function (actualResponse, expectedResponse, userError, expectedUserError) {
jqUnit.assertDeepEq("onError fires with the expected message", expectedResponse, actualResponse);
jqUnit.assertDeepEq("User error has been fired with the expected content", expectedUserError, userError.error);
};

gpii.tests.userLogonRequest.commonTestConfig = {
gradeNames: ["gpii.tests.userLogonRequest.testCaseHolder", "gpii.test.integration.testCaseHolder.linux"],
distributeOptions: {
"lifecycleManager.userErrorsListener": {
"record": {
trackedUserErrors: {},
listeners: {
"userError.trackReportedError": {
listener: "fluid.set",
args: ["{that}.options.trackedUserErrors", "error", "{arguments}.0"]
}
}
},
"target": "{that gpii.flowManager.local userErrors}.options"
}
}
};

Expand All @@ -88,7 +101,6 @@ gpii.tests.userLogonRequest.buildTestDefs = function (testDefs, testType) {
var extraTestDef = testType === "untrusted" ? testDef.untrustedExtras : {};
return fluid.extend(true, {
config: config,
gradeNames: ["gpii.tests.userLogonRequest.testCaseHolder", "gpii.test.integration.testCaseHolder.linux"],
gpiiKey: testDefs.gpiiKey || gpii.tests.userLogonRequest.gpiiKey,
distributeOptions: {
"lifecycleManager.logonChangeListener": {
Expand All @@ -102,21 +114,9 @@ gpii.tests.userLogonRequest.buildTestDefs = function (testDefs, testType) {
}
},
"target": "{that gpii.flowManager.local lifecycleManager}.options"
},
"lifecycleManager.userErrorsListener": {
"record": {
trackedUserErrors: {},
listeners: {
"userError.trackReportedError": {
listener: "fluid.set",
args: ["{that}.options.trackedUserErrors", "error", "{arguments}.0"]
}
}
},
"target": "{that gpii.flowManager.local userErrors}.options"
}
}
}, testDef, extraTestDef);
}, gpii.tests.userLogonRequest.commonTestConfig, testDef, extraTestDef);
});
};

Expand Down Expand Up @@ -491,25 +491,41 @@ gpii.tests.userLogonRequest.testDefs = [{
args: ["{lifecycleManager}.performLogin", [gpii.tests.userLogonRequest.gpiiKey], "{that}"]
}, {
event: "{that}.events.onError",
listener: "gpii.tests.userLogonRequest.testLogoutError",
args: ["{arguments}.0", "{lifecycleManager}.userErrors.options.trackedUserErrors", {
"statusCode": 409,
"message": "Got log in request from user testUser1, but the user testUser1 is already logged in. So ignoring login request.",
"ignoreUserErrors": false
}]
listener: "gpii.tests.userLogonRequest.testUserError",
args: ["{arguments}.0",
{
"statusCode": 409,
"message": "Got log in request from user testUser1, but the user testUser1 is already logged in. So ignoring login request.",
"ignoreUserErrors": false
},
"{lifecycleManager}.userErrors.options.trackedUserErrors",
{
"isError": true,
"messageKey": "KeyInFail",
"originalError": "Got log in request from user testUser1, but the user testUser1 is already logged in. So ignoring login request."
}
]
}, {
// logout of different user
func: "gpii.tests.invokePromiseProducer",
args: ["{lifecycleManager}.performLogout", [gpii.tests.userLogonRequest.anotherGpiiKey], "{that}"]
}, {
event: "{that}.events.onError",
priority: "last",
listener: "gpii.tests.userLogonRequest.testLogoutError",
args: ["{arguments}.0", "{lifecycleManager}.userErrors.options.trackedUserErrors", {
"statusCode": 409,
"message": "Got logout request from user sammy, but the user testUser1 is logged in. So ignoring the request.",
"ignoreUserErrors": false
}]
listener: "gpii.tests.userLogonRequest.testUserError",
args: ["{arguments}.0",
{
"statusCode": 409,
"message": "Got logout request from user sammy, but the user testUser1 is logged in. So ignoring the request.",
"ignoreUserErrors": false
},
"{lifecycleManager}.userErrors.options.trackedUserErrors",
{
"isError": true,
"messageKey": "KeyInFail",
"originalError": "Got logout request from user sammy, but the user testUser1 is logged in. So ignoring the request."
}
]
}, {
// logout of the correct user
func: "gpii.tests.invokePromiseProducer",
Expand Down Expand Up @@ -542,12 +558,16 @@ gpii.tests.userLogonRequest.testDefs = [{
args: ["{lifecycleManager}.performLogout", [gpii.tests.userLogonRequest.gpiiKey], "{that}"]
}, {
event: "{that}.events.onError",
listener: "gpii.tests.userLogonRequest.testLogoutError",
args: ["{arguments}.0", "{lifecycleManager}.userErrors.options.trackedUserErrors", {
"statusCode": 409,
"message": "Got logout request from user testUser1, but the user noUser is logged in. So ignoring the request.",
"ignoreUserErrors": true
}, "{arguments}.0"]
listener: "gpii.tests.userLogonRequest.testUserError",
args: ["{arguments}.0",
{
"statusCode": 409,
"message": "Got logout request from user testUser1, but the user noUser is logged in. So ignoring the request.",
"ignoreUserErrors": true
},
"{lifecycleManager}.userErrors.options.trackedUserErrors",
undefined
]
}]
}, {
name: "Testing standard error handling: invalid user URLs",
Expand Down