diff --git a/README.md b/README.md index 59ac4d922..59fe3a42c 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,8 @@ To execute the certification suite against any platform, the following setup mus | healthCheckRetries | number | 8 | Health check retry count | | communicationMode | string | 'SDK' or 'Transport' | Set communicationMode as SDK/transport. Default mode is SDK | | performanceMetrics | boolean | true | Makes a call to platform to start/stop the recording of performance metrics if value is true | +| pubSubUrl | string | ws://127.0.0.1:8081 | Sets the the url to use for a PubSub server which will be used for 3rd party app communication. + - Provide the specPattern mapping details. @@ -370,5 +372,21 @@ Example Usage: logger.info('This is an informational message', 'moduleName'); logger.debug('This is a debugging message'); logger.error('This is an error message'); +``` - ``` +## Using Simple PubSub + +If you want to use simplePubSub server as the means of communication for 3rd party app calls follow these steps: + +1. Clone SimplePubSub [server](https://github.com/comcast-firebolt/simplePubSub). +2. Setup SimplePubSub server (i.e. `npm install`) and start (i.e. `npm start`). +3. Clone [firebolt-certification-app](https://github.com/rdkcentral/firebolt-certification-app). +5. In FCA hange the `host` in /webpack.dev.js to . +6. Setup firebolt-certification-app (FCA) (i.e. `npm install`) and start (i.e. `npm start`). +7. Point your device to use your local instance of FCA (i.e. `http://:8081`). +8. When running FCS include env variables: + - deviceMac: `` + - pubSubUrl: `ws://:8080` + + + diff --git a/cypress.config.js b/cypress.config.js index 63cc7f5c2..b0ed13e6e 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -42,6 +42,7 @@ const env = { thirdPartyMockUser: '456~A', MFOS_base_url: 'http://localhost:3333/api/v1/', firstPartyAppId: 'firstPartyAppId', + failOnPubSubConnectionError: false, certification: false, reportType: 'cucumber', deleteReport: false, diff --git a/cypress/plugins/common.js b/cypress/plugins/common.js index 640696ec5..1aa892bf8 100644 --- a/cypress/plugins/common.js +++ b/cypress/plugins/common.js @@ -23,41 +23,40 @@ const CONSTANTS = require('../support/constants/constants'); // If "genericSupport" is set to a falsy value (false, null, etc), take no further action. Simply "return" function genericSupport(config) { + let data; // Read additional config. try { - const data = JSON.parse(fs.readFileSync('supportConfig.json')); - - // Get the arguments passed from command line during run time. - const commandLineArgs = Object.entries(config.resolved.env) - .filter(([key, value]) => value.from === 'cli') - .reduce((acc, [key, value]) => { - acc[key] = value.value; - return acc; - }, {}); - - // fireboltCalls JSON - generateIndexFile(CONSTANTS.FIREBOLTCALLS_FROM_FCS, 'fireboltCalls'); - generateIndexFile(CONSTANTS.FIREBOLTCALLS_FROM_CONFIGMODULE, 'fireboltCalls'); - // fireboltMocks JSON - generateIndexFile(CONSTANTS.FIREBOLTMOCK_FROM_FCS, 'fireboltMocks'); - generateIndexFile(CONSTANTS.FIREBOLTMOCK_FROM_CONFIGMODULE, 'fireboltMocks'); - - // The sequence of override - the default config in the config.js file, overriden by supportConfig.json and then by the command line arguments. - config.env = { - ...config.env, - ...data, - ...commandLineArgs, - }; - // To read device data JSON - preprocessDeviceData(config); - const testDataEnv = testDataProcessor.testDataProcessor(config.env); - Object.assign(config.env, testDataEnv); - - return config; + data = JSON.parse(fs.readFileSync('supportConfig.json')); } catch (error) { logger.error('Received following error while trying to read supportConfig json', error); - return config; } + // Get the arguments passed from command line during run time. + const commandLineArgs = Object.entries(config.resolved.env) + .filter(([key, value]) => value.from === 'cli') + .reduce((acc, [key, value]) => { + acc[key] = value.value; + return acc; + }, {}); + + // fireboltCalls JSON + generateIndexFile(CONSTANTS.FIREBOLTCALLS_FROM_FCS, 'fireboltCalls'); + generateIndexFile(CONSTANTS.FIREBOLTCALLS_FROM_CONFIGMODULE, 'fireboltCalls'); + // fireboltMocks JSON + generateIndexFile(CONSTANTS.FIREBOLTMOCK_FROM_FCS, 'fireboltMocks'); + generateIndexFile(CONSTANTS.FIREBOLTMOCK_FROM_CONFIGMODULE, 'fireboltMocks'); + + // The sequence of override - the default config in the config.js file, overriden by supportConfig.json and then by the command line arguments. + config.env = { + ...config.env, + ...data, + ...commandLineArgs, + }; + // To read device data JSON + preprocessDeviceData(config); + const testDataEnv = testDataProcessor.testDataProcessor(config.env); + Object.assign(config.env, testDataEnv); + + return config; } module.exports = { diff --git a/cypress/support/constants/constants.js b/cypress/support/constants/constants.js index 506ac57df..42ab08886 100644 --- a/cypress/support/constants/constants.js +++ b/cypress/support/constants/constants.js @@ -115,7 +115,7 @@ module.exports = { EVENT_SCHEMA_RESULT: 'eventSchemaResult', EXCEPTION_ERROR_OBJECT: 'exceptionErrorObject', EXCEPTION_METHODS: 'exceptionMethods', - EXCLUDED_METHODS: [], + EXCLUDED_METHODS: ['Lifecycle.close'], EXCLUDED_MODULES: [], EXCLUDED_VALUES: [null, undefined], EXECUTE_SHELL: 'executeShell', @@ -134,6 +134,7 @@ module.exports = { EXTERNAL_PREREQUISITE_DATA: './cypress/fixtures/external/PreRequisiteData.json', EXTRACTEDAPI_PATH: 'extractedApiObject.response.', FAIL: 'FAIL', + FAIL_ON_PUBSUB_CONNECTION_ERROR: 'failOnPubSubConnectionError', FAILED_TO_PARSE_LIEFECYCLE_ERROR: 'Failed to parse error object from response while setting lifecycle state. Response received : ', FAILED_TO_SET_LIFECYCLE_STATE: @@ -226,6 +227,7 @@ module.exports = { LIMITADTRACKING_OFF: 'limitAdTrackingOFF', LIMITADTRACKING_ON: 'limitAdTrackingON', LONGPOLL_TIMEOUT: 15000, + MACADDRESS_PARAM: 'macaddress', MESSAGE_QUEUE: 'messageQueue', MESSAGE_QUEUE_SIZE: 100, MESSAGE_QUEUE_TIME_DIFF: 150000, @@ -289,6 +291,7 @@ module.exports = { 'Platform returned response in invalid format, which could lead to failures in validations. Response must be an object', PLATFORM_NOT_SUPPORT_LOG: 'Platform does not support method', PREREQUISITE_DATA: 'PreRequisiteData.json', + PUB_SUB_URL: 'pubSubUrl', // Env Var for the URL for the Default Module's pubSub implementation SETUPCHECK: 'Setup Check', SETUPVALUES: 'external/setupValues.json', SETUPVALUES_FILEPATH: 'cypress/fixtures/external/setupValues.json', diff --git a/cypress/support/cypress-commands/commands.js b/cypress/support/cypress-commands/commands.js index 9b5068bb2..fcb119a8f 100644 --- a/cypress/support/cypress-commands/commands.js +++ b/cypress/support/cypress-commands/commands.js @@ -17,7 +17,7 @@ */ const CONSTANTS = require('../constants/constants'); const { _ } = Cypress; -import UTILS from '../cypress-support/src/utils'; +import UTILS, { getEnvVariable } from '../cypress-support/src/utils'; const logger = require('../Logger')('command.js'); /** @@ -653,12 +653,12 @@ Cypress.Commands.add('launchApp', (appType, appCallSign) => { ? UTILS.getEnvVariable(CONSTANTS.APP_TYPE) : CONSTANTS.FIREBOLT; // appType defines in which mode app should be launched data = { - query: JSON.stringify({ + query: { params: { [CONSTANTS.APP_ID]: appId, [CONSTANTS.APP_TYPE]: appCategory, }, - }), + }, }; const messageIntent = { action: CONSTANTS.SEARCH, @@ -676,17 +676,28 @@ Cypress.Commands.add('launchApp', (appType, appCallSign) => { Cypress.env(CONSTANTS.TEST_TYPE).toLowerCase() == CONSTANTS.MODULE_NAMES.LIFECYCLE ) { data = { - query: JSON.stringify({ + query: { params: { [CONSTANTS.APP_ID]: appId, [CONSTANTS.LIFECYCLE_VALIDATION]: true, [CONSTANTS.APP_TYPE]: appCategory, }, - }), + }, }; requestMap.params.intent.data = data; } + // Add the PubSub URL if required + if (getEnvVariable(CONSTANTS.PUB_SUB_URL, false)) { + data.query.params[CONSTANTS.PUB_SUB_URL] = getEnvVariable(CONSTANTS.PUB_SUB_URL); + if (getEnvVariable(CONSTANTS.DEVICE_MAC, false) { + data.query.params[CONSTANTS.MACADDRESS_PARAM] = getEnvVariable(CONSTANTS.DEVICE_MAC); + } + } + + // Stringify the query (The intent requires it be a string) + data.query = JSON.stringify(data.query); + Cypress.env(CONSTANTS.CURRENT_APP_ID, appId); const requestTopic = UTILS.getTopic(appId); diff --git a/cypress/support/cypress-support/src/utils.js b/cypress/support/cypress-support/src/utils.js index 7b9477227..28635875e 100644 --- a/cypress/support/cypress-support/src/utils.js +++ b/cypress/support/cypress-support/src/utils.js @@ -168,7 +168,7 @@ function overideParamsFromConfigModule(overrideParams) { : CONSTANTS.EXCLUDED_METHODS; overrideParams.modulesToBeExcluded = getEnvVariable('excludedModules', false) ? getEnvVariable('excludedModules') - : CONSTANTS.EXCLUDED_METHODS; + : CONSTANTS.EXCLUDED_MODULES; return overrideParams; } @@ -547,8 +547,12 @@ function pubSubClientCreation(appTransport) { clientCreated = true; resolve(true); } catch (error) { - // If an error occurs, reject the promise with the error - reject('Failed to initiate PubSubClient' + error); + if (getEnvVariable(CONSTANTS.FAIL_ON_PUBSUB_CONNECTION_ERROR, false)) { + // If an error occurs, reject the promise with the error + reject('Failed to initiate PubSubClient' + error); + } else { + resolve(false); + } } } else { resolve(false); diff --git a/defaultModule/appTransport/index.js b/defaultModule/appTransport/index.js index 4fb2870e8..c2b609b0f 100644 --- a/defaultModule/appTransport/index.js +++ b/defaultModule/appTransport/index.js @@ -16,6 +16,8 @@ * SPDX-License-Identifier: Apache-2.0 */ const logger = require('../../../cypress/support/Logger')('index.js'); +const constants = require('../../cypress/support/constants/constants'); +const { getEnvVariable } = require('../../cypress/support/cypress-support/src/utils'); const client = { ws: null, @@ -37,9 +39,12 @@ const client = { function init() { logger.info('Establishing pubsub connection'); - return new Promise((resolve, reject) => { + return new Promise((resolve) => { // Enter a valid WebSocket URL - client.ws = new WebSocket('ws://your-ws-url-here.com'); + const url = getEnvVariable(constants.PUB_SUB_URL, false) + ? getEnvVariable(constants.PUB_SUB_URL) + : 'ws://localhost:8080'; + client.ws = new WebSocket(url); const websocket = client.ws; @@ -48,14 +53,14 @@ function init() { websocket.removeEventListener('error', openCallback); resolve(event.data); }; + // if WebSocket connection fails (error or close event), the errorHandler logs the error and resolves the promise with a default message instead of rejecting it. + const errorHandler = function (event) { + logger.info('WebSocket connection failed. Continuing execution...', event.data); + reject('Default: Connection could not be established'); + }; - client.ws.addEventListener('error', function (event) { - reject(event.data); - }); - - client.ws.addEventListener('close', function (event) { - reject(event.data); - }); + client.ws.addEventListener('error', errorHandler); + client.ws.addEventListener('close', errorHandler); client.ws.addEventListener('open', openCallback); }); @@ -129,19 +134,18 @@ function subscribe(topic, callback) { const formattedMsg = { operation: data.operation, topic: data.topic, - headers: data.payload?.headers, - payload: data.payload.message, + payload: data.payload?.message, }; // Add headers to top level of formatted message if they exist - if (data.payload.headers) { + if (data.payload?.headers) { formattedMsg.headers = data.payload.headers; } // If a callback function is provided, call it with the formattedMsg payload and headers if (typeof callback == 'function') { logger.info( 'Incoming notification is valid. Calling callback:' + JSON.stringify(data), - 'sunscribe' + 'subscribe' ); callback(formattedMsg.payload, formattedMsg.headers); } @@ -171,4 +175,4 @@ function unsubscribe(topic) { } // Uncomment the line below to get app transport working -// module.exports = { init, publish, subscribe, unsubscribe }; +module.exports = { init, publish, subscribe, unsubscribe };