From f563822a09ac194f3a3903c78493099a59ed9f90 Mon Sep 17 00:00:00 2001 From: regeter <2320305+regeter@users.noreply.github.com> Date: Wed, 27 Nov 2024 18:20:43 -0800 Subject: [PATCH] refactor: Remove some nesting and simplify code, add tests. (#195) * test: Add test cases for logs processing and logs merging. * refactor: Removing extra nesting, plus better code for solutiontype that works with both Cloud Logging and Bigquery. --- src/localStorage.js | 102 +++++++++++++++++---------------------- src/localStorage.test.js | 83 +++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+), 57 deletions(-) create mode 100644 src/localStorage.test.js diff --git a/src/localStorage.js b/src/localStorage.js index 304a688..9d4f5cb 100644 --- a/src/localStorage.js +++ b/src/localStorage.js @@ -76,7 +76,7 @@ async function processJsonFile(file) { }); } -function parseJsonContent(content) { +export function parseJsonContent(content) { console.log("Parsing JSON content"); try { return JSON.parse(content); @@ -91,7 +91,7 @@ function parseJsonContent(content) { } } -function removeEmptyObjects(obj) { +export function removeEmptyObjects(obj) { Object.keys(obj).forEach((key) => { if (obj[key] && typeof obj[key] === "object") { if (Object.keys(obj[key]).length === 0) { @@ -108,70 +108,58 @@ function isRestrictedLog(log) { return log.jsonPayload?.["@type"]?.includes("Restricted") || false; } -function ensureCorrectFormat(data) { +export function ensureCorrectFormat(data) { if (data && Array.isArray(data.rawLogs)) { return { ...data, APIKEY: data.APIKEY || DEFAULT_API_KEY, }; - } else { - const logsArray = Array.isArray(data) ? data : [data]; - - const restrictedLogsMap = new Map(); - logsArray.forEach((log) => { - if (isRestrictedLog(log)) { - removeEmptyObjects(log.jsonPayload); - restrictedLogsMap.set(log.jsonPayload.parentInsertId, log); - } - }); + } + const logsArray = Array.isArray(data) ? data : [data]; - // Filter out restricted logs while merging their TOS-restricted attributes into their parent logs. - const mergedLogs = logsArray.filter((log) => { - if (isRestrictedLog(log)) { - return false; - } - const restrictedLog = restrictedLogsMap.get(log.insertId)?.jsonPayload; - if (restrictedLog) { - ["request", "response"].forEach((section) => { - if (restrictedLog[section] && log.jsonPayload[section]) { - TOS_RESTRICTED_ATTRIBUTES.forEach((attr) => { - if (restrictedLog[section][attr] !== undefined) { - log.jsonPayload[section][attr] = restrictedLog[section][attr]; - } - }); - } - }); - } - return true; - }); - - // Determine the solution type based on the resource type of the first log entry - const firstLog = mergedLogs[0]; - const resourceType = firstLog?.resource?.type; - let solutionType; - - if (resourceType === "fleetengine.googleapis.com/DeliveryFleet") { - solutionType = "LMFS"; - } else if (resourceType === "fleetengine.googleapis.com/Fleet") { - solutionType = "ODRD"; - } else { - console.warn( - `Unknown resource type: ${resourceType}, defaulting to ODRD` - ); - solutionType = "ODRD"; + const restrictedLogsMap = new Map(); + logsArray.forEach((log) => { + if (isRestrictedLog(log)) { + removeEmptyObjects(log.jsonPayload); + restrictedLogsMap.set(log.jsonPayload.parentInsertId, log); } + }); - console.log(`Determined solution type: ${solutionType}`); + // Filter out restricted logs while merging their TOS-restricted attributes into their parent logs. + const mergedLogs = logsArray.filter((log) => { + if (isRestrictedLog(log)) { + return false; + } + const restrictedLog = restrictedLogsMap.get(log.insertId)?.jsonPayload; + if (restrictedLog) { + ["request", "response"].forEach((section) => { + if (restrictedLog[section] && log.jsonPayload[section]) { + TOS_RESTRICTED_ATTRIBUTES.forEach((attr) => { + if (restrictedLog[section][attr] !== undefined) { + log.jsonPayload[section][attr] = restrictedLog[section][attr]; + } + }); + } + }); + } + return true; + }); - return { - APIKEY: DEFAULT_API_KEY, - vehicle: "", - projectId: "", - logSource: "Direct Cloud Logging", - solutionType: solutionType, - rawLogs: mergedLogs, - }; - } + // Determine the solution type based on the presence of _delivery_vehicle logs + const isLMFS = mergedLogs.some((log) => + log.logName?.includes("_delivery_vehicle") + ); + const solutionType = isLMFS ? "LMFS" : "ODRD"; + console.log(`Determined solution type: ${solutionType}`); + + return { + APIKEY: DEFAULT_API_KEY, + vehicle: "", + projectId: "", + logSource: "Direct Cloud Logging", + solutionType: solutionType, + rawLogs: mergedLogs, + }; } async function saveToIndexedDB(data, index) { diff --git a/src/localStorage.test.js b/src/localStorage.test.js new file mode 100644 index 0000000..704f63e --- /dev/null +++ b/src/localStorage.test.js @@ -0,0 +1,83 @@ +// localStorage.test.js +import fs from "fs"; +import { parseJsonContent, removeEmptyObjects, ensureCorrectFormat } from "./localStorage"; + +// Helper function to load test data +function loadTestData(filename) { + return JSON.parse(fs.readFileSync(`./datasets/${filename}`)); +} + +test("parseJsonContent handles valid JSON", () => { + const validJson = JSON.stringify({ test: "data" }); + const result = parseJsonContent(validJson); + expect(result).toStrictEqual({ test: "data" }); +}); + +test("parseJsonContent handles multiple JSON objects", () => { + const multipleJson = '{"test": "data1"},{"test": "data2"}'; + const result = parseJsonContent(multipleJson); + expect(result).toHaveLength(2); + expect(result[0]).toStrictEqual({ test: "data1" }); + expect(result[1]).toStrictEqual({ test: "data2" }); +}); + +test("parseJsonContent handles JSON array", () => { + const arrayJson = '[{"key": "value1"},{"test": "data2"}]'; + const result = parseJsonContent(arrayJson); + expect(result).toHaveLength(2); + expect(result[0]).toStrictEqual({ key: "value1" }); + expect(result[1]).toStrictEqual({ test: "data2" }); +}); + +test("parseJsonContent throws error for invalid JSON", () => { + const invalidJson = "{invalid}"; + expect(() => parseJsonContent(invalidJson)).toThrow("Invalid JSON content"); +}); + +test("removeEmptyObjects removes empty nested objects", () => { + const input = { + a: {}, + b: { c: {}, d: { e: 1 } } + }; + const expected = { + b: { d: { e: 1 } } + }; + expect(removeEmptyObjects(input)).toStrictEqual(expected); +}); + +test("ensureCorrectFormat handles LMFS logs", () => { + const lmfsData = loadTestData("lmfs.json"); + const result = ensureCorrectFormat(lmfsData.rawLogs); + expect(result.solutionType).toBe("LMFS"); +}); + +test("ensureCorrectFormat handles ODRD logs", () => { + const odrdData = loadTestData("jump-demo.json"); + const result = ensureCorrectFormat(odrdData.rawLogs); + expect(result.solutionType).toBe("ODRD"); +}); + +test("ensureCorrectFormat merges restricted attributes", () => { + const parentLog = { + insertId: "parent", + jsonPayload: { + "@type": "type.googleapis.com/Normal", + request: {}, + response: {} + } + }; + + const restrictedLog = { + jsonPayload: { + "@type": "type.googleapis.com/Restricted", + parentInsertId: "parent", + request: { + waypoints: ["point1", "point2"] + } + } + }; + + const result = ensureCorrectFormat([parentLog, restrictedLog]); + expect(result.rawLogs[0].jsonPayload.request.waypoints).toStrictEqual(["point1", "point2"]); + expect(result.rawLogs.length).toBe(1); +});