Skip to content

Commit

Permalink
feat: add cds logger
Browse files Browse the repository at this point in the history
* initial commit

* replace console.error with Logger

* add 'non-existing custom ord file' test and small clean-up

* minor changes

* add mock for error log function

* replace template literals with comma-separated values

* minor changes: increase code-coverage in tests

* minor changes: increase code-coverage in tests
  • Loading branch information
aramovic79 authored Nov 15, 2024
1 parent 679ef91 commit b4faec2
Show file tree
Hide file tree
Showing 9 changed files with 71 additions and 46 deletions.
3 changes: 2 additions & 1 deletion __tests__/bookshop/.cdsrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
"description": "this is my custom description",
"policyLevel": "sap:core:v1",
"customOrdContentFile": "./ord/custom.ord.json"
}
},
"DEBUG": false
}
25 changes: 12 additions & 13 deletions __tests__/unittest/extendOrdWithCustom.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,20 @@ const cds = require("@sap/cds");
const path = require('path');
const { extendCustomORDContentIfExists } = require('../../lib/extendOrdWithCustom');

jest.mock('path', () => ({
join: jest.fn(),
}));

jest.mock("@sap/cds", () => {
const actualCds = jest.requireActual('@sap/cds');
return {
...actualCds,
env: {},
log: jest.fn(() => ({
levels: { DEBUG: 0, WARN: 1 },
warn: jest.fn(() => console.warn('Mocked warning')),
error: jest.fn(() => console.error('Mocked error')),
})),
};
});

describe('extendOrdWithCustom', () => {

let appConfig = {};

beforeEach(() => {
Expand All @@ -29,24 +26,26 @@ describe('extendOrdWithCustom', () => {
};
});

afterEach(() => {
jest.resetModules();
jest.clearAllMocks();
});

describe('extendCustomORDContentIfExists', () => {
it('should skip if there is no custom ord file', () => {
it('should skip if there is no customOrdContentFile property in the .cdsrc.json', () => {
const ordContent = {};
appConfig.env.customOrdContentFile = undefined;
const result = extendCustomORDContentIfExists(appConfig, ordContent);
expect(result).toEqual(ordContent);
});

it('should skip if customOrdContentFile property in the .cdsrc.json points to NON-EXISTING custom ord file', () => {
const ordContent = {};
appConfig.env.customOrdContentFile = "./ord/NotExistingCustom.ord.json";
const result = extendCustomORDContentIfExists(appConfig, ordContent);
expect(result).toEqual(ordContent);
});

it('should ignore and log warn if found ord top-level primitive property in customOrdFile', () => {
const ordContent = {};
const warningSpy = jest.spyOn(console, 'warn');
prepareTestEnvironment({ namespace: "sap.sample" }, appConfig, 'testCustomORDContentFileThrowErrors.json');
const result = extendCustomORDContentIfExists(appConfig, ordContent, cds.log());
const result = extendCustomORDContentIfExists(appConfig, ordContent);

expect(warningSpy).toHaveBeenCalledTimes(3);
expect(warningSpy).toHaveBeenCalledWith('Mocked warning');
Expand Down Expand Up @@ -120,5 +119,5 @@ describe('extendOrdWithCustom', () => {
function prepareTestEnvironment(ordEnvVariables, appConfig, testFileName) {
cds.env["ord"] = ordEnvVariables;
appConfig.env.customOrdContentFile = testFileName;
path.join.mockReturnValue(`${__dirname}/utils/${testFileName}`);
jest.spyOn(path, 'join').mockReturnValueOnce(`${__dirname}/utils/${testFileName}`);
}
15 changes: 15 additions & 0 deletions __tests__/unittest/templates.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,21 @@ describe('templates', () => {
};
expect(createGroupsTemplateForService(testServiceName, linkedModel, appConfig)).toEqual(testResult);
});

it('should return default value with a proper Service title when "Service" keyword is missing', () => {
const testServiceName = 'testServName';
const testResult = {
groupId: 'sap.cds:service:customer.testNamespace:testServName',
groupTypeId: 'sap.cds:service',
title: 'testServName Service'
};
expect(createGroupsTemplateForService(testServiceName, linkedModel, appConfig)).toEqual(testResult);
});

it('should return undefined when no service definition', () => {
const testServiceName = 'testServiceName';
expect(createGroupsTemplateForService(testServiceName, null, appConfig)).not.toBeDefined();
});
});

describe('createAPIResourceTemplate', () => {
Expand Down
31 changes: 14 additions & 17 deletions lib/extendOrdWithCustom.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
const { CONTENT_MERGE_KEY } = require('./constants');
const { CONTENT_MERGE_KEY } = require("./constants");
const cds = require("@sap/cds");
const fs = require("fs");
const { Logger } = require("./logger");
const path = require("path");
const _ = require('lodash');


const _ = require("lodash");

function cleanNullProperties(obj) {
for (const key in obj) {
Expand All @@ -29,12 +29,13 @@ function patchGeneratedOrdResources(destinationObj, sourceObj) {
return cleanNullProperties(Object.values(destObj));
}

function compareAndHandleCustomORDContentWithExistingContent(ordContent, customORDContent, logger) {
function compareAndHandleCustomORDContentWithExistingContent(ordContent, customORDContent) {
const clonedOrdContent = structuredClone(ordContent);
for (const key in customORDContent) {
const propertyType = typeof customORDContent[key];
if (propertyType !== 'object' && propertyType !== 'array') {
logger.warn('Found ord top level primitive ord property in customOrdFile:', key, ', please define it in .cdsrc.json.');
Logger.warn('Found ord top level primitive ord property in customOrdFile:', key, '. Please define it in .cdsrc.json.');

continue;
}
if (key in ordContent) {
Expand All @@ -47,21 +48,17 @@ function compareAndHandleCustomORDContentWithExistingContent(ordContent, customO
}

function getCustomORDContent(appConfig) {
let customORDContent;

if (appConfig.env?.customOrdContentFile) {
customORDContent = require(path.join(cds.root, appConfig.env.customOrdContentFile));
if (!appConfig.env?.customOrdContentFile) return;
const pathToCustomORDContent = path.join(cds.root, appConfig.env?.customOrdContentFile);
if (fs.existsSync(pathToCustomORDContent)) {
Logger.error('Custom ORD content file not found at', pathToCustomORDContent);
return require(pathToCustomORDContent);
}
return customORDContent;
}

function extendCustomORDContentIfExists(appConfig, ordContent, logger) {
function extendCustomORDContentIfExists(appConfig, ordContent) {
const customORDContent = getCustomORDContent(appConfig);

if (customORDContent) {
ordContent = compareAndHandleCustomORDContentWithExistingContent(ordContent, customORDContent, logger);
}
return ordContent;
return customORDContent ? compareAndHandleCustomORDContentWithExistingContent(ordContent, customORDContent) : ordContent;
}

module.exports = {
Expand Down
11 changes: 11 additions & 0 deletions lib/logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const cds = require("@sap/cds");

const Logger = cds.log("ord-plugin", {
level: cds.env.DEBUG || process.env.DEBUG
? cds.log.levels?.DEBUG
: cds.log.levels?.WARN,
});

module.exports = {
Logger,
};
7 changes: 4 additions & 3 deletions lib/metaData.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const cds = require('@sap/cds/lib');
const { compile: openapi } = require('@cap-js/openapi')
const { compile: asyncapi } = require('@cap-js/asyncapi');
const { COMPILER_TYPES } = require('./constants');
const { Logger } = require('./logger');

module.exports = async (data) => {
const parts = data?.split("/").pop().replace(/\.json$/, '').split(".");
Expand All @@ -16,23 +17,23 @@ module.exports = async (data) => {
try {
responseFile = openapi(csn, options);
} catch (error) {
console.error("OpenApi error:", error.message);
Logger.error('OpenApi error:', error.message);
throw error;
}
break;
case COMPILER_TYPES.asyncapi2:
try {
responseFile = asyncapi(csn, options);
} catch (error) {
console.error("AsyncApi error:", error.message);
Logger.error('AsyncApi error:', error.message);
throw error;
}
break;
case COMPILER_TYPES.edmx:
try {
responseFile = await cds.compile(csn).to["edmx"](options);
} catch (error) {
console.error("Edmx error:", error.message);
Logger.error('Edmx error:', error.message);
throw error;
}
}
Expand Down
8 changes: 4 additions & 4 deletions lib/ord.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ const {
} = require('./templates');
const { extendCustomORDContentIfExists } = require('./extendOrdWithCustom');
const { getRFC3339Date } = require('./date');
const { Logger } = require('./logger');
const _ = require("lodash");
const cds = require("@sap/cds");
const defaults = require("./defaults");
const logger = cds.log('ord-plugin');
const path = require("path");

const initializeAppConfig = (csn) => {
Expand All @@ -34,7 +34,7 @@ const initializeAppConfig = (csn) => {
const eventApplicationNamespace = cds.env?.export?.asyncapi?.applicationNamespace;

if (eventApplicationNamespace && ordNamespace !== eventApplicationNamespace) {
console.warn("ORD and AsyncAPI namespaces should be the same.");
Logger.warn('ORD and AsyncAPI namespaces should be the same.');
}

for (const key of modelKeys) {
Expand Down Expand Up @@ -123,7 +123,7 @@ function validateNamespace(appConfig) {
let error = new Error(
`Namespace is not defined in cdsrc.json or it is not in the format of ${appConfig.eventApplicationNamespace}.<appName>.<service>`
);
console.error("Namespace error:", error.message);
Logger.error('Namespace error:', error.message);
throw error;
}
}
Expand Down Expand Up @@ -162,7 +162,7 @@ module.exports = (csn) => {
const packageIds = extractPackageIds(ordDocument);
ordDocument.apiResources = _getAPIResources(linkedCsn, appConfig, packageIds);
ordDocument.eventResources = _getEventResources(linkedCsn, appConfig, packageIds);
ordDocument = extendCustomORDContentIfExists(appConfig, ordDocument, logger);
ordDocument = extendCustomORDContentIfExists(appConfig, ordDocument);

return ordDocument;
};
10 changes: 5 additions & 5 deletions lib/plugin.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const { ord, getMetadata, defaults } = require("./");
const cds = require("@sap/cds");
const { Logger } = require("./logger");
const { ord, getMetadata, defaults } = require("./");


cds.on("bootstrap", (app) => {
app.use("/.well-known/open-resource-discovery", async (req, res) => {
Expand All @@ -10,8 +12,7 @@ cds.on("bootstrap", (app) => {
const { contentType, response } = await getMetadata(req.url);
res.status(200).contentType(contentType).send(response);
} catch (error) {
console.log(error);
console.log('Error while generating metadata');
Logger.error(error, 'Error while generating metadata');
res.status(500).send(error.message);
}
}
Expand All @@ -23,8 +24,7 @@ cds.on("bootstrap", (app) => {
const data = ord(csn);
return res.status(200).send(data);
} catch (error) {
console.log(error);
console.log('Error while creating ORD document');
Logger.error(error, 'Error while creating ORD document');
return res.status(500).send(error.message);
}
});
Expand Down
7 changes: 4 additions & 3 deletions lib/templates.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const {
RESOURCE_VISIBILITY,
SHORT_DESCRIPTION_PREFIX
} = require("./constants");
const { Logger } = require("./logger");

function unflatten(flattedObject) {
let result = {}
Expand Down Expand Up @@ -46,12 +47,12 @@ const _generatePaths = (srv, srvDefinition) => {
//removing instances of graphql protocol from paths
for (var index = paths.length - 1; index >= 0; index--) {
if (paths[index].kind === "graphql") {
console.warn("Graphql protocol is not supported.");
Logger.warn('Graphql protocol is not supported.');
paths.splice(index, 1);
}
}

//putting default as odata in case no supported protcol is there
//putting OData as default in case of non-supported protocol
if (paths.length === 0) {
srvDefinition["@odata"] = true;
paths.push({ kind: "odata", path: protocols.path4(srvDefinition) });
Expand Down Expand Up @@ -106,7 +107,7 @@ const createGroupsTemplateForService = (serviceName, serviceDefinition, appConfi
const ordExtensions = readORDExtensions(serviceDefinition);

if (!serviceDefinition) {
console.warn("Unable to find service definition:", serviceName)
Logger.warn('Unable to find service definition:', serviceName)
return undefined
}

Expand Down

0 comments on commit b4faec2

Please sign in to comment.