Skip to content

Commit

Permalink
Merge pull request #159 from Eswar2103/FIRECERT-2243
Browse files Browse the repository at this point in the history
Implementation of Interaction log service feature
  • Loading branch information
kschrief authored Sep 10, 2024
2 parents 40609cc + b556321 commit 73eef81
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 2 deletions.
6 changes: 6 additions & 0 deletions server/src/configureAPI.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ function configureAPI(app) {
// Revert to the way things were when server started up
app.post('/api/v1/state/revert', stateApi.revertState);

// Start the interaction log service
app.post('/api/v1/state/interactionLogs/start', stateApi.enableInteractionLogs);

// Stop the interaction log service
app.post('/api/v1/state/interactionLogs/stop', stateApi.disableInteractionLogs);

// ======================= State-Related API Routes =======================

app.put('/api/v1/user/:userId?', userApi.addUser);
Expand Down
10 changes: 10 additions & 0 deletions server/src/events.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { logger } from './logger.mjs';
import * as fireboltOpenRpc from './fireboltOpenRpc.mjs';
import { config } from './config.mjs';
import { updateCallWithResponse } from './sessionManagement.mjs';
import { createAndSendInteractionLog } from './interactionLog.mjs';
import { createCaseAgnosticMethod } from './util.mjs';


Expand Down Expand Up @@ -226,6 +227,11 @@ function sendEventListenerAck(userId, ws, metadata) {
const ackMessage = template(metadata);
const parsedAckMessage = JSON.parse(ackMessage);

config.interactionService && config.interactionService.forEach((_, userId) => {
const userWSData = userManagement.getWsForUser(userId);
createAndSendInteractionLog(ackMessage, metadata.method, metadata.registration.params, userWSData, userId); // creating interaction log and send it to the client
});

ws.send(ackMessage);
logger.debug(`Sent registration event ack message for user ${userId}: ${ackMessage}`);
updateCallWithResponse(metadata.method, parsedAckMessage.result, "result", userId)
Expand Down Expand Up @@ -294,6 +300,10 @@ function emitResponse(finalResult, msg, userId, method) {
}
//Update the call with event response
updateCallWithResponse(method, eventMessage, "events", userId);
config.interactionService && config.interactionService.forEach((_, userId) => {
const userWSData = userManagement.getWsForUser(userId);
createAndSendInteractionLog(eventMessage, method, null, userWSData, userId); // creating interaction log and send it to the client
});
wsArr.forEach((ws) => {
ws.send(eventMessage);
// Check if eventType is included in config
Expand Down
64 changes: 64 additions & 0 deletions server/src/interactionLog.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2021 Comcast Cable Communications Management, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/

// InteractionLogs

import { logger } from './logger.mjs';

/**
* @function: createAndSendInteractionLog
* @Description: Create interaction log and send it to the client
* @param {String} response - Response of the method call
* @param {String} method - Name of the method
* @param {String} params - Params of the method call
* @param {Object} ws - WS object to send the interaction log
* @param {String} ws - UserId value
*/
function createAndSendInteractionLog(response, method, params, ws, userId) {
try {
const interactionLog = {
app_id: "mock-firebolt",
method: "",
params: "",
success: true,
response: "",
};

interactionLog.params = params;
interactionLog.method = method;
interactionLog.response = response;
if (ws) {
ws.send(JSON.stringify({ FireboltInteraction: interactionLog }));
logger.debug(
`Sent interaction log for user ${userId}: ${JSON.stringify({
FireboltInteraction: interactionLog,
})}`
);
} else {
logger.error(
`Error in createAndSendInteractionLog: ws object is not provided`
);
}
} catch (error) {
logger.error(`Error in createAndSendInteractionLog: ${error}`);
}
}

// ----exports----

export { createAndSendInteractionLog };
7 changes: 7 additions & 0 deletions server/src/messageHandler.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { addCall, updateCallWithResponse } from './sessionManagement.mjs';
import * as proxyManagement from './proxyManagement.mjs';
import * as conduit from './conduit.mjs';
import { config } from './config.mjs';
import { createAndSendInteractionLog } from './interactionLog.mjs';

const { dotConfig: { eventConfig } } = config;

Expand Down Expand Up @@ -345,9 +346,15 @@ async function handleMessage(message, userId, ws) {
}
const dly = stateManagement.getAppropriateDelay(userId, oMsg.method);
await util.delay(dly);

ws.send(finalResponse);
logger.debug(`Sent message for user ${userId}: ${finalResponse}`);
updateCallWithResponse(oMsg.method, JSON.parse(finalResponse).result, "result", userId)

config.interactionService && config.interactionService.forEach((_, userId) => {
const userWSData = userManagement.getWsForUser(userId);
createAndSendInteractionLog(finalResponse, JSON.parse(message).method, JSON.parse(message).params, userWSData, userId); // creating interaction log and send it to the client
});
}

// --- Exports ---
Expand Down
39 changes: 38 additions & 1 deletion server/src/routes/api/state.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -289,11 +289,48 @@ function revertState(req, res) {
});
}

// POST /api/v1/state/enableInteractionLogs
// Expected body: None
// Expected headers: x-mockfirebolt-userid - The user id of the user making the request
function enableInteractionLogs(req, res) {
const user = getUserIdFromReq(req);
logger.info(`Enabling interaction logs for user ${user}`);
config.interactionService == undefined &&
(config.interactionService = new Map());
config.interactionService.set(user, { enabled: true });
return res.status(200).send({
status: "SUCCESS",
message: "Successfully started interactionService",
});
}

// POST /api/v1/state/disableInteractionLogs
// Expected body: None
// Expected headers: x-mockfirebolt-userid - The user id of the user making the request
function disableInteractionLogs(req, res) {
const user = getUserIdFromReq(req);
logger.info(`Disabling interaction logs for user ${user}`);
// If the user is not found in the interactionService, return an error
if (!config.interactionService.has(user)) {
return res.status(400).send({
status: "ERROR",
errorCode: "USER-NOT-FOUND",
message: "User not found",
});
}
config.interactionService.delete(user);
return res.status(200).send({
status: "SUCCESS",
message: "Successfully stopped interactionService",
});
}

// --- Exports ---

export {
getState,
setLatency, setMode,
setMethodResult, setMethodError,
updateState, revertState
updateState, revertState,
enableInteractionLogs, disableInteractionLogs
};
1 change: 0 additions & 1 deletion server/src/routes/api/user.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ function getUsers(req, res) {
});
}


// --- Exports ---

export {
Expand Down
35 changes: 35 additions & 0 deletions server/test/suite/interactionLogs.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2021 Comcast Cable Communications Management, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/

// InteractionLogs: Tests

import {jest} from '@jest/globals';
import { createAndSendInteractionLog } from "../../src/interactionLog.mjs";
import { logger } from "../../src/logger.mjs";

test(`interactionLogs.createAndSendInteractionLog works properly`, () => {
const debugSpy = jest.spyOn(logger, "debug");
createAndSendInteractionLog('{name: "id"}', "account.id", {}, {send: () => {}}, '12345' );
expect(debugSpy).toHaveBeenCalled();
});

test(`interactionLogs.createAndSendInteractionLog works properly without ws object`, () => {
const errorSpy = jest.spyOn(logger, "error");
createAndSendInteractionLog('{name: "id"}', "account.id", {}, undefined );
expect(errorSpy).toHaveBeenCalled();
});
7 changes: 7 additions & 0 deletions server/test/suite/messageHandler.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import * as messageHandler from "../../src/messageHandler.mjs";
import { logger } from "../../src/logger.mjs";
import * as fireboltOpenRpc from "../../src/fireboltOpenRpc.mjs";
import { methodTriggers } from "../../src/triggers.mjs";
import { config } from "../../src/config.mjs";
import * as userManagement from "../../src/userManagement.mjs";

test(`messageHandler.handleMessage works properly and return when message doesn't have any id`, async () => {
const spy = jest.spyOn(logger, "info");
Expand Down Expand Up @@ -165,6 +167,8 @@ test(`messageHandler.handleMessage works properly, message param is false`, asyn
});

test(`messageHandler.handleMessage works properly, for logger.debug`, async () => {
config.interactionService = new Map();
config.interactionService.set("12345", { enabled: true });
fireboltOpenRpc.testExports.methodMaps["core"] = {
"lifecycle.onInactive": {
name: "lifecycle.onInactive",
Expand Down Expand Up @@ -199,11 +203,14 @@ test(`messageHandler.handleMessage works properly, for logger.debug`, async () =
},
};

userManagement.testExports.associateUserWithWs("12345", { send: () => {} });
const debugSpy = jest.spyOn(logger, "debug");
const dummyMsgFour =
'{"jsonrpc":"2.0","method":"rpc.discover","params":{"listen":true},"id":1}';
await messageHandler.handleMessage(dummyMsgFour, "12345", { send: () => {} });
expect(debugSpy).toHaveBeenCalled();
userManagement.testExports.user2ws.delete("12345");
delete config.interactionService;
});

test(`messageHandler.handleMessage works properly for error scenarios`, async () => {
Expand Down

0 comments on commit 73eef81

Please sign in to comment.