Skip to content

Commit 27fb53e

Browse files
authored
fix: CF integration tests and sonar issues (#3739)
* test: add cf integration test * refactor: improve create service * test: add tests * chore: add cset * refactor: rename method * refactor: rename method
1 parent b1b87b0 commit 27fb53e

File tree

10 files changed

+474
-222
lines changed

10 files changed

+474
-222
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@sap-ux/generator-adp': patch
3+
'@sap-ux/adp-tooling': patch
4+
---
5+
6+
fix: CF integration tests and sonar issues

packages/adp-tooling/src/cf/app/html5-repo.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type { ToolsLogger } from '@sap-ux/logger';
55
import type { Manifest } from '@sap-ux/project-access';
66

77
import { t } from '../../i18n';
8-
import { createService, getServiceInstanceKeys } from '../services/api';
8+
import { getServiceNameByTags, getServiceInstanceKeys, createServiceInstance } from '../services/api';
99
import type { HTML5Content, ServiceKeys, Uaa, CfAppParams } from '../../types';
1010

1111
const HTML5_APPS_REPO_RUNTIME = 'html5-apps-repo-runtime';
@@ -75,16 +75,10 @@ export async function getHtml5RepoCredentials(spaceGuid: string, logger: ToolsLo
7575
logger
7676
);
7777
if (!serviceKeys?.credentials?.length) {
78-
await createService(
79-
spaceGuid,
80-
'app-runtime',
81-
HTML5_APPS_REPO_RUNTIME,
82-
['html5-apps-repo-rt'],
83-
undefined,
84-
undefined,
85-
undefined,
78+
const serviceName = await getServiceNameByTags(spaceGuid, ['html5-apps-repo-rt']);
79+
await createServiceInstance('app-runtime', HTML5_APPS_REPO_RUNTIME, serviceName, {
8680
logger
87-
);
81+
});
8882
serviceKeys = await getServiceInstanceKeys({ names: [HTML5_APPS_REPO_RUNTIME] }, logger);
8983
if (!serviceKeys?.credentials?.length) {
9084
logger.debug(t('error.noUaaCredentialsFoundForHtml5Repo'));

packages/adp-tooling/src/cf/project/yaml.ts

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ interface AdjustMtaYamlParams {
2828
appRouterType: AppRouterType;
2929
businessSolutionName: string;
3030
businessService: string;
31-
spaceGuid: string;
3231
}
3332

3433
/**
@@ -418,7 +417,7 @@ function adjustMtaYamlFlpModule(yamlContent: MtaYaml, projectName: string, busin
418417
* @returns {Promise<void>} The promise.
419418
*/
420419
export async function adjustMtaYaml(
421-
{ projectPath, moduleName, appRouterType, businessSolutionName, businessService, spaceGuid }: AdjustMtaYamlParams,
420+
{ projectPath, moduleName, appRouterType, businessSolutionName, businessService }: AdjustMtaYamlParams,
422421
memFs: Editor,
423422
templatePathOverwrite?: string,
424423
logger?: ToolsLogger
@@ -456,15 +455,7 @@ export async function adjustMtaYaml(
456455
// should go last since it sorts the modules (workaround, should be removed after fixed in deployment module)
457456
adjustMtaYamlFlpModule(yamlContent, projectName, businessService);
458457

459-
await createServices(
460-
projectPath,
461-
yamlContent,
462-
initialServices,
463-
timestamp,
464-
spaceGuid,
465-
templatePathOverwrite,
466-
logger
467-
);
458+
await createServices(yamlContent, initialServices, timestamp, templatePathOverwrite, logger);
468459

469460
const updatedYamlContent = yaml.dump(yamlContent);
470461

packages/adp-tooling/src/cf/services/api.ts

Lines changed: 49 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ interface FDCResponse {
2828
results: CFApp[];
2929
}
3030

31+
interface CreateServiceOptions {
32+
xsSecurityProjectName?: string;
33+
templatePathOverwrite?: string;
34+
logger?: ToolsLogger;
35+
}
36+
3137
const PARAM_MAP: Map<string, string> = new Map([
3238
['spaceGuids', 'space_guids'],
3339
['planNames', 'service_plan_names'],
@@ -133,57 +139,38 @@ export async function getFDCApps(appHostIds: string[], cfConfig: CfConfig, logge
133139
}
134140

135141
/**
136-
* Creates a service.
142+
* Creates a service instance.
137143
*
138-
* @param {string} spaceGuid - The space GUID.
139-
* @param {string} plan - The plan.
144+
* @param {string} plan - The service plan.
140145
* @param {string} serviceInstanceName - The service instance name.
141-
* @param {string[]} tags - The tags.
142-
* @param {string} [serviceName] - The service name.
143-
* @param {object} [security] - Security configuration.
144-
* @param {string | null} security.filePath - The security file path.
145-
* @param {string} [security.xsappname] - The XS app name.
146-
* @param {string} [templatePathOverwrite] - The template path overwrite.
147-
* @param {ToolsLogger} [logger] - The logger.
146+
* @param {string} serviceName - The service name.
147+
* @param {CreateServiceOptions} [options] - Additional options.
148+
* @returns {Promise<void>} The promise.
148149
*/
149-
export async function createService(
150-
spaceGuid: string,
150+
export async function createServiceInstance(
151151
plan: string,
152152
serviceInstanceName: string,
153-
tags: string[],
154-
serviceName: string | undefined,
155-
security?: {
156-
filePath: string | null;
157-
xsappname?: string;
158-
},
159-
templatePathOverwrite?: string,
160-
logger?: ToolsLogger
153+
serviceName: string,
154+
options?: CreateServiceOptions
161155
): Promise<void> {
156+
const { xsSecurityProjectName, templatePathOverwrite, logger } = options ?? {};
157+
162158
try {
163-
const { filePath, xsappname } = security ?? {};
164-
if (!serviceName) {
165-
const json: CfAPIResponse<CfServiceOffering> = await requestCfApi<CfAPIResponse<CfServiceOffering>>(
166-
`/v3/service_offerings?per_page=1000&space_guids=${spaceGuid}`
167-
);
168-
const serviceOffering = json?.resources?.find(
169-
(resource: CfServiceOffering) => resource.tags && tags.every((tag) => resource.tags?.includes(tag))
170-
);
171-
serviceName = serviceOffering?.name;
172-
}
173159
logger?.log(
174160
`Creating service instance '${serviceInstanceName}' of service '${serviceName}' with '${plan}' plan`
175161
);
176162

177-
const commandParameters: string[] = ['create-service', serviceName ?? '', plan, serviceInstanceName];
178-
if (filePath) {
163+
const commandParameters: string[] = ['create-service', serviceName, plan, serviceInstanceName];
164+
165+
if (xsSecurityProjectName) {
179166
let xsSecurity = null;
180167
try {
181168
const baseTmplPath = path.join(__dirname, '../../../templates');
182169
const templatePath = templatePathOverwrite ?? baseTmplPath;
183170
const filePath = path.resolve(templatePath, 'cf/xs-security.json');
184171
const xsContent = fs.readFileSync(filePath, 'utf-8');
185172
xsSecurity = JSON.parse(xsContent) as unknown as { xsappname?: string };
186-
xsSecurity.xsappname = xsappname;
173+
xsSecurity.xsappname = xsSecurityProjectName;
187174
} catch (err) {
188175
logger?.error(`Failed to parse xs-security.json file: ${err}`);
189176
throw new Error(t('error.xsSecurityJsonCouldNotBeParsed'));
@@ -200,53 +187,64 @@ export async function createService(
200187
}
201188
}
202189

190+
/**
191+
* Gets the service name by tags.
192+
*
193+
* @param {string} spaceGuid - The space GUID.
194+
* @param {string[]} tags - The service tags for discovery.
195+
* @returns {Promise<string>} The service name.
196+
*/
197+
export async function getServiceNameByTags(spaceGuid: string, tags: string[]): Promise<string> {
198+
const json: CfAPIResponse<CfServiceOffering> = await requestCfApi<CfAPIResponse<CfServiceOffering>>(
199+
`/v3/service_offerings?per_page=1000&space_guids=${spaceGuid}`
200+
);
201+
const serviceOffering = json?.resources?.find(
202+
(resource: CfServiceOffering) => resource.tags && tags.every((tag) => resource.tags?.includes(tag))
203+
);
204+
return serviceOffering?.name ?? '';
205+
}
206+
203207
/**
204208
* Creates the services.
205209
*
206-
* @param {string} projectPath - The project path.
207210
* @param {MtaYaml} yamlContent - The YAML content.
208211
* @param {string[]} initialServices - The initial services.
209212
* @param {string} timestamp - The timestamp.
210-
* @param {string} spaceGuid - The space GUID.
211213
* @param {string} [templatePathOverwrite] - The template path overwrite.
212214
* @param {ToolsLogger} logger - The logger.
213215
* @returns {Promise<void>} The promise.
214216
*/
215217
export async function createServices(
216-
projectPath: string,
217218
yamlContent: MtaYaml,
218219
initialServices: string[],
219220
timestamp: string,
220-
spaceGuid: string,
221221
templatePathOverwrite?: string,
222222
logger?: ToolsLogger
223223
): Promise<void> {
224224
const excludeServices = new Set([...initialServices, 'portal', 'html5-apps-repo']);
225-
const xsSecurityPath = path.join(projectPath, 'xs-security.json');
226225
const xsSecurityProjectName = getProjectNameForXsSecurity(yamlContent, timestamp);
227226
for (const resource of yamlContent.resources ?? []) {
228227
if (!excludeServices.has(resource?.parameters?.service ?? '')) {
229228
if (resource?.parameters?.service === 'xsuaa') {
230-
await createService(
231-
spaceGuid,
229+
await createServiceInstance(
232230
resource.parameters['service-plan'] ?? '',
233231
resource.parameters['service-name'] ?? '',
234-
[],
235232
resource.parameters.service,
236-
{ filePath: xsSecurityPath, xsappname: xsSecurityProjectName },
237-
templatePathOverwrite,
238-
logger
233+
{
234+
xsSecurityProjectName,
235+
templatePathOverwrite,
236+
logger
237+
}
239238
);
240239
} else {
241-
await createService(
242-
spaceGuid,
240+
await createServiceInstance(
243241
resource.parameters['service-plan'] ?? '',
244242
resource.parameters['service-name'] ?? '',
245-
[],
246-
resource.parameters.service,
247-
{ filePath: null, xsappname: xsSecurityProjectName },
248-
templatePathOverwrite,
249-
logger
243+
resource.parameters.service ?? '',
244+
{
245+
templatePathOverwrite,
246+
logger
247+
}
250248
);
251249
}
252250
}

packages/adp-tooling/src/writer/cf.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ export async function generateCf(
3838
moduleName: app.id,
3939
appRouterType: cf.approuter,
4040
businessSolutionName: cf.businessSolutionName ?? '',
41-
businessService: cf.businessService,
42-
spaceGuid: cf.space.GUID
41+
businessService: cf.businessService
4342
},
4443
fs,
4544
config.options?.templatePathOverwrite,

packages/adp-tooling/test/unit/cf/app/html5-repo.test.ts

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,22 @@ import type { Manifest } from '@sap-ux/project-access';
66

77
import { initI18n, t } from '../../../../src/i18n';
88
import type { CfAppParams, ServiceKeys, Uaa } from '../../../../src/types';
9-
import { createService, getServiceInstanceKeys } from '../../../../src/cf/services/api';
9+
import { getServiceNameByTags, createServiceInstance, getServiceInstanceKeys } from '../../../../src/cf/services/api';
1010
import { downloadAppContent, downloadZip, getHtml5RepoCredentials, getToken } from '../../../../src/cf/app/html5-repo';
1111

12-
// Mock dependencies
1312
jest.mock('axios');
1413
jest.mock('adm-zip');
1514
jest.mock('../../../../src/cf/services/api', () => ({
1615
...jest.requireActual('../../../../src/cf/services/api'),
17-
createService: jest.fn(),
16+
getServiceNameByTags: jest.fn(),
17+
createServiceInstance: jest.fn(),
1818
getServiceInstanceKeys: jest.fn()
1919
}));
2020

2121
const mockAxios = axios as jest.Mocked<typeof axios>;
2222
const mockAdmZip = AdmZip as jest.MockedClass<typeof AdmZip>;
23-
const mockCreateService = createService as jest.MockedFunction<typeof createService>;
23+
const mockGetServiceNameByTags = getServiceNameByTags as jest.MockedFunction<typeof getServiceNameByTags>;
24+
const mockCreateServiceInstance = createServiceInstance as jest.MockedFunction<typeof createServiceInstance>;
2425
const mockGetServiceInstanceKeys = getServiceInstanceKeys as jest.MockedFunction<typeof getServiceInstanceKeys>;
2526

2627
describe('HTML5 Repository', () => {
@@ -166,27 +167,28 @@ describe('HTML5 Repository', () => {
166167
},
167168
mockLogger
168169
);
169-
expect(mockCreateService).not.toHaveBeenCalled();
170+
expect(mockGetServiceNameByTags).not.toHaveBeenCalled();
171+
expect(mockCreateServiceInstance).not.toHaveBeenCalled();
170172
});
171173

172174
test('should create service when no credentials found', async () => {
173175
mockGetServiceInstanceKeys
174176
.mockResolvedValueOnce({ credentials: [], serviceInstance: { guid: '', name: '' } })
175177
.mockResolvedValueOnce(mockServiceKeys);
176-
mockCreateService.mockResolvedValue(undefined);
178+
mockGetServiceNameByTags.mockResolvedValue('html5-apps-repo-rt');
179+
mockCreateServiceInstance.mockResolvedValue(undefined);
177180

178181
const result = await getHtml5RepoCredentials('test-space-guid', mockLogger);
179182

180183
expect(result).toBe(mockServiceKeys);
181-
expect(mockCreateService).toHaveBeenCalledWith(
182-
'test-space-guid',
184+
expect(mockGetServiceNameByTags).toHaveBeenCalledWith('test-space-guid', ['html5-apps-repo-rt']);
185+
expect(mockCreateServiceInstance).toHaveBeenCalledWith(
183186
'app-runtime',
184187
'html5-apps-repo-runtime',
185-
['html5-apps-repo-rt'],
186-
undefined,
187-
undefined,
188-
undefined,
189-
mockLogger
188+
'html5-apps-repo-rt',
189+
{
190+
logger: mockLogger
191+
}
190192
);
191193
expect(mockGetServiceInstanceKeys).toHaveBeenCalledTimes(2);
192194
});
@@ -195,7 +197,8 @@ describe('HTML5 Repository', () => {
195197
mockGetServiceInstanceKeys
196198
.mockResolvedValueOnce({ credentials: [], serviceInstance: { guid: '', name: '' } })
197199
.mockResolvedValueOnce({ credentials: [], serviceInstance: { guid: '', name: '' } });
198-
mockCreateService.mockResolvedValue(undefined);
200+
mockGetServiceNameByTags.mockResolvedValue('html5-apps-repo-rt');
201+
mockCreateServiceInstance.mockResolvedValue(undefined);
199202

200203
await expect(getHtml5RepoCredentials('test-space-guid', mockLogger)).rejects.toThrow(
201204
t('error.cannotFindHtml5RepoRuntime')

0 commit comments

Comments
 (0)