Skip to content

Commit

Permalink
fix: event resources generation
Browse files Browse the repository at this point in the history
  • Loading branch information
aramovic79 committed Sep 12, 2024
2 parents 349a1ce + e8d96ee commit e9d6538
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 35 deletions.
75 changes: 73 additions & 2 deletions __tests__/__snapshots__/ord.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ exports[`Tests for default ORD document Successfully create ORD Documents with d
"partOfGroups": [
"sap.cds:service:capjs.ord:undefined.AdminService",
],
"partOfPackage": undefined,
"partOfPackage": "capjsord:package:undefined:v1",
"releaseStatus": "active",
"resourceDefinitions": [
{
Expand Down Expand Up @@ -69,7 +69,7 @@ exports[`Tests for default ORD document Successfully create ORD Documents with d
"partOfGroups": [
"sap.cds:service:capjs.ord:undefined.CatalogService",
],
"partOfPackage": undefined,
"partOfPackage": "capjsord:package:undefined:v1",
"releaseStatus": "active",
"resourceDefinitions": [
{
Expand Down Expand Up @@ -100,6 +100,64 @@ exports[`Tests for default ORD document Successfully create ORD Documents with d
},
],
"description": "this is an application description",
"eventResources": [
{
"description": "CAP Event resource describing events / messages.",
"extensible": {
"supported": "no",
},
"ordId": "capjs.ord:eventResource:undefined.AdminService:v1",
"partOfGroups": [
"sap.cds:service:capjs.ord:undefined.AdminService",
],
"partOfPackage": "capjsord:package:undefined:v1",
"releaseStatus": "beta",
"resourceDefinitions": [
{
"accessStrategies": [
{
"type": "open",
},
],
"mediaType": "application/json",
"type": "asyncapi-v2",
"url": "/.well-known/open-resource-discovery/v1/api-metadata/AdminService.asyncapi2.json",
},
],
"shortDescription": "Example ODM Event",
"title": "ODM capjsord Events",
"version": "1.0.0",
"visibility": "public",
},
{
"description": "CAP Event resource describing events / messages.",
"extensible": {
"supported": "no",
},
"ordId": "capjs.ord:eventResource:undefined.CatalogService:v1",
"partOfGroups": [
"sap.cds:service:capjs.ord:undefined.CatalogService",
],
"partOfPackage": "capjsord:package:undefined:v1",
"releaseStatus": "beta",
"resourceDefinitions": [
{
"accessStrategies": [
{
"type": "open",
},
],
"mediaType": "application/json",
"type": "asyncapi-v2",
"url": "/.well-known/open-resource-discovery/v1/api-metadata/CatalogService.asyncapi2.json",
},
],
"shortDescription": "Example ODM Event",
"title": "ODM capjsord Events",
"version": "1.0.0",
"visibility": "public",
},
],
"groups": [
{
"groupId": "sap.cds:service:capjs.ord:undefined.AdminService",
Expand All @@ -113,6 +171,19 @@ exports[`Tests for default ORD document Successfully create ORD Documents with d
},
],
"openResourceDiscovery": "1.9",
"packages": [
{
"description": "Description for capjs ord",
"ordId": "capjsord:package:undefined:v1",
"partOfProducts": [
"customer:product:capjs.ord:",
],
"shortDescription": "Short description for capjs ord",
"title": "capjs ord",
"vendor": "customer:vendor:Customer:",
"version": "1.0.0",
},
],
"policyLevel": "none",
"products": [
{
Expand Down
14 changes: 14 additions & 0 deletions __tests__/bookshop/srv/admin-service.cds
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,18 @@ using { sap.capire.bookshop as my } from '../db/schema';
service AdminService @(requires:'authenticated-user') {
entity Books as projection on my.Books;
entity Authors as projection on my.Authors;

event BookCreated : {
ID : Integer;
title : String @title: 'Title';
};

event BookDeleted : {
ID : Integer;
};

event BookUpdated : {
ID : Integer;
title : String @title: 'Title';
}
}
14 changes: 14 additions & 0 deletions __tests__/bookshop/srv/cat-service.cds
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,18 @@ service CatalogService @(path:'/browse') {

@requires: 'authenticated-user'
action submitOrder (book: Books:ID, quantity: Integer);

event BookCreated : {
ID : Integer;
title : String @title: 'Title';
};

event BookDeleted : {
ID : Integer;
};

event BookUpdated : {
ID : Integer;
title : String @title: 'Title';
}
}
33 changes: 33 additions & 0 deletions __tests__/ord.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,37 @@ describe("Tests for default ORD document", () => {
const document = ord(csn);
expect(document).toMatchSnapshot();
});


describe("eventResources", () => {
const GROUP_ID_REGEX = /^([a-z0-9-]+(?:[.][a-z0-9-]+)*):([a-zA-Z0-9._\-/]+):([a-z0-9-]+(?:[.][a-z0-9-]+)*):(?<service>[a-zA-Z0-9._\-/]+)$/

let document;

beforeAll(()=> {
document = ord(csn);
})

test("Assigned to excactly one CDS Service group", () => {
for (const eventResource of document.eventResources) {
expect(eventResource.partOfGroups.length).toEqual(1)
}
});

test("The CDS Service Group ID includes the CDS Service identifier", () => {
for (const eventResource of document.eventResources) {
const [groupId] = eventResource.partOfGroups
expect(groupId).toMatch(GROUP_ID_REGEX)

const match = GROUP_ID_REGEX.exec(groupId)
if (match && match.groups?.service) {
let service = match.groups?.service
if (service.startsWith("undefined")) service = service.replace("undefined.", "")
const definition = csn.definitions[service]
expect(definition).toBeDefined()
expect(definition.kind).toEqual("service")
}
}
})
})
});
8 changes: 0 additions & 8 deletions __tests__/unittest/templates.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,6 @@ describe('templates', () => {
};
expect(templates.fCreateGroupsTemplateForService(testSrv, linkedModel, testGroupIds)).toEqual(testResult);
});

it('should return null when groupIds has groupId', () => {
const testSrv = 'testServiceName';
global.namespace = 'customer';
const testGroupIds = new Set(['sap.cds:service:customer:undefined.testServiceName']);
const testResult = null;
expect(templates.fCreateGroupsTemplateForService(testSrv, linkedModel, testGroupIds)).toEqual(testResult);
});
});

describe('fCreateGroupsTemplateForEvent', () => {
Expand Down
27 changes: 15 additions & 12 deletions lib/ord.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ const {
fCreateAPIResourceTemplate,
fCreateEventResourceTemplate,
fCreateGroupsTemplateForService,
fCreateGroupsTemplateForEvent,
fCreateEntityTypeTemplate
} = require('./templates');

Expand Down Expand Up @@ -110,17 +109,9 @@ const fGetProducts = (global) => global.env?.products || defaults.products(globa
* @returns {Array<object>} The groups array.
*/
const fGetGroups = (csn, global) => {
// storing the group ids in a set to avoid duplicates
let groupIds = new Set();

let serviceGroups = global.aServices
.map((srv) => fCreateGroupsTemplateForService(srv, csn.definitions[srv], groupIds))
.filter((resource) => resource !== null && resource !== undefined);
let eventGroups = global.aEvents
.map((event) => fCreateGroupsTemplateForEvent(event, csn.definitions[event], groupIds))
return global.aServices
.map((srv) => fCreateGroupsTemplateForService(srv, csn.definitions[srv]))
.filter((resource) => resource !== null && resource !== undefined);

return [...serviceGroups, ...eventGroups];
};

/**
Expand Down Expand Up @@ -156,7 +147,19 @@ const fGetAPIResources = (csn, global,packageIds) => {
* @param {Object} csn object
* @returns {Array<object>} The Event Resources array.
*/
const fGetEventResources = (csn, global,packageIds) => global.aEvents.map((srv) => fCreateEventResourceTemplate(srv, csn.definitions[srv], global, packageIds)).filter((resource) => resource !== null && resource !== undefined);
const fGetEventResources = (csn, global, packageIds) => {
if(global.aEvents.length === 0) return []

const services = []
for (const serviceName of global.aServices) {
const hasEvents = global.aEvents.find((eventName) => eventName.startsWith(serviceName));
if (hasEvents) {
services.push(serviceName)
}
}

return services.map((serviceName) => fCreateEventResourceTemplate(serviceName, csn.definitions[serviceName], global, packageIds))
};

module.exports = (csn) => {
const linkedCsn = cds.linked(csn);
Expand Down
26 changes: 13 additions & 13 deletions lib/templates.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,28 +115,28 @@ function _getTitleFromServiceName(srv) {
* @param {Set} groupIds A set of group ids.
* @returns {Object} A group object.
*/
const fCreateGroupsTemplateForService = (srv, srvDefinition, groupIds) => {
const ordExtensions = fReadORDExtensions(srvDefinition);
const fCreateGroupsTemplateForService = (srv, srvDefinition) => {
const ordExtensions = fReadORDExtensions(srvDefinition);

let fullyQualifiedServiceName = srv;
if (!srv.includes(global.capNamespace)) {
fullyQualifiedServiceName = global.capNamespace + "." + srv;
}

if (checkEntityFunctionAction(srvDefinition, global).length > 0) {
let groupId = _getGroupID(fullyQualifiedServiceName, defaults.groupTypeId);
if (groupIds.has(groupId)) {
return null;
} else {
groupIds.add(groupId);
if(!srvDefinition) {
console.warn("Unable to find service definition:", srv)
return undefined
}

if (srvDefinition && checkEntityFunctionAction(srvDefinition, global).length > 0) {
let groupId = _getGroupID(fullyQualifiedServiceName, defaults.groupTypeId);
return {
groupId: groupId,
groupTypeId: `${defaults.groupTypeId}`,
title: ordExtensions.title ?? _getTitleFromServiceName(srv),
groupId: groupId,
groupTypeId: `${defaults.groupTypeId}`,
title: ordExtensions.title ?? _getTitleFromServiceName(srv)
};
}
}
};

/**
*
Expand Down Expand Up @@ -291,7 +291,7 @@ const fCreateEventResourceTemplate = (srv, srvDefinition, global,packageIds) =>
{
type: "asyncapi-v2",
mediaType: "application/json",
url: `/.well-known/open-resource-discovery/v1/api-metadata/${srvDefinition._service.name}.asyncapi2.json`,
url: `/.well-known/open-resource-discovery/v1/api-metadata/${srv}.asyncapi2.json`,
accessStrategies: [
{
type: "open",
Expand Down

0 comments on commit e9d6538

Please sign in to comment.