Skip to content

Commit 44b13ac

Browse files
authored
Merge pull request #1834 from rocketstack-matt/getting-started-tests
chore(cli): implement static URL mapping for Getting Started assets and add related tests
2 parents 48f5bb8 + b349a0b commit 44b13ac

File tree

4 files changed

+187
-21
lines changed

4 files changed

+187
-21
lines changed

cli/src/cli.e2e.spec.ts

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,26 @@
11
import { execSync } from 'child_process';
2-
import path, { join } from 'path';
2+
import path from 'path';
33
import * as fs from 'fs';
44
import * as os from 'os';
55
import { execa } from 'execa';
66
import { parseStringPromise } from 'xml2js';
77
import axios from 'axios';
88
import { expectDirectoryMatch, expectFilesMatch } from '@finos/calm-shared';
99
import { spawn } from 'node:child_process';
10+
import { STATIC_GETTING_STARTED_MAPPING_PATH } from './test_helpers/getting-started-url-mapping';
1011

1112
const millisPerSecond = 1000;
1213
const integrationTestPrefix = 'calm-consumer-test';
1314
let tempDir: string;
1415
const repoRoot = path.resolve(__dirname);
16+
const GETTING_STARTED_DIR = path.resolve(
17+
__dirname,
18+
'../../calm/getting-started'
19+
);
20+
const GETTING_STARTED_TEST_FIXTURES_DIR = path.resolve(
21+
__dirname,
22+
'../test_fixtures/getting-started'
23+
);
1524

1625
function run(file: string, args: string[]) {
1726
const cp = execa(file, args, { cwd: tempDir });
@@ -438,30 +447,35 @@ describe('CLI Integration Tests', () => {
438447

439448
await expectDirectoryMatch(expectedOutputDir, actualOutputDir);
440449
});
441-
442-
450+
// Docify widget rendering verifies every template keeps working with the
451+
// getting-started assets bundled in the repo, so we use the static mapping
452+
// to avoid hitting the public site during CI.
443453
describe('calm docify command - widget rendering', () => {
444454
function runTemplateWidgetTest(templateName: string, outputName: string) {
445455
return async () => {
446456

447-
const GETTING_STARTED_TEST_FIXTURES_DIR = join(
448-
__dirname,
449-
'../../cli/test_fixtures/getting-started'
450-
);
451-
452457
const testModelPath = path.resolve(
453458
GETTING_STARTED_TEST_FIXTURES_DIR,
454459
'STEP-3/conference-signup-with-flow.arch.json'
455460
);
456-
457461
const fixtureDir = path.resolve(__dirname, '../test_fixtures/template');
458462
const templatePath = path.join(fixtureDir, `widget-tests/${templateName}`);
459463
const expectedOutputPath = path.join(fixtureDir, `expected-output/widget-tests/${outputName}`);
460464
const outputDir = path.join(tempDir, 'widget-tests');
461465
const outputFile = path.join(outputDir, outputName);
462466

463467
await run(
464-
calm(), ['docify', '--architecture', testModelPath, '--template', templatePath, '--output', outputFile]
468+
calm(), [
469+
'docify',
470+
'--architecture',
471+
testModelPath,
472+
'--template',
473+
templatePath,
474+
'--output',
475+
outputFile,
476+
'--url-to-local-file-mapping',
477+
STATIC_GETTING_STARTED_MAPPING_PATH,
478+
]
465479
);
466480

467481
expect(fs.existsSync(outputFile)).toBe(true);
@@ -488,15 +502,8 @@ describe('CLI Integration Tests', () => {
488502

489503

490504
test('Getting Started Verification - CLI Steps', async () => {
491-
const GETTING_STARTED_DIR = join(
492-
__dirname,
493-
'../../calm/getting-started'
494-
);
495-
const GETTING_STARTED_TEST_FIXTURES_DIR = join(
496-
__dirname,
497-
'../../cli/test_fixtures/getting-started'
498-
);
499-
505+
// This flow mirrors the public Getting Started guide to ensure the
506+
// documentation actually works when the CLI resolves URLs locally.
500507
//STEP 1: Generate Architecture From Pattern
501508
const inputPattern = path.resolve(
502509
GETTING_STARTED_DIR,
@@ -517,7 +524,15 @@ describe('CLI Integration Tests', () => {
517524
//STEP 2: Generate Docify Website From Architecture
518525
const outputWebsite = path.resolve(tempDir, 'website');
519526
await run(
520-
calm(), ['docify', '--architecture', outputArchitecture, '--output', outputWebsite]
527+
calm(), [
528+
'docify',
529+
'--architecture',
530+
outputArchitecture,
531+
'--output',
532+
outputWebsite,
533+
'--url-to-local-file-mapping',
534+
STATIC_GETTING_STARTED_MAPPING_PATH,
535+
]
521536
);
522537

523538
const expectedOutputDocifyWebsite = path.resolve(
@@ -570,7 +585,15 @@ describe('CLI Integration Tests', () => {
570585
'website-with-flow'
571586
);
572587
await run(
573-
calm(), ['docify', '--architecture', outputArchitecture, '--output', outputWebsiteWithFlow]
588+
calm(), [
589+
'docify',
590+
'--architecture',
591+
outputArchitecture,
592+
'--output',
593+
outputWebsiteWithFlow,
594+
'--url-to-local-file-mapping',
595+
STATIC_GETTING_STARTED_MAPPING_PATH,
596+
]
574597
);
575598

576599
const expectedOutputDocifyWebsiteWithFLow = path.resolve(
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import path from 'path';
2+
import fs from 'node:fs';
3+
import { describe, test, expect } from 'vitest';
4+
import {
5+
STATIC_GETTING_STARTED_MAPPING_PATH,
6+
collectGettingStartedUrlsFromFile,
7+
isOptionalGettingStartedUrl,
8+
loadGettingStartedMapping,
9+
resolveLocalPathForUrl,
10+
} from './test_helpers/getting-started-url-mapping';
11+
12+
const FILES_WITH_GETTING_STARTED_URLS = [
13+
path.resolve(
14+
__dirname,
15+
'../test_fixtures/getting-started/STEP-1/conference-signup.arch.json'
16+
),
17+
path.resolve(
18+
__dirname,
19+
'../test_fixtures/getting-started/STEP-3/conference-signup-with-flow.arch.json'
20+
),
21+
path.resolve(
22+
__dirname,
23+
'../../calm/getting-started/conference-signup.pattern.json'
24+
),
25+
];
26+
27+
// Ensures the static mapping the CLI now relies on stays aligned with the
28+
// Getting Started fixtures and that every mapped URL has a local file present.
29+
describe('Getting Started URL mapping', () => {
30+
test('static mapping covers all referenced URLs and files exist', () => {
31+
const mapping = loadGettingStartedMapping();
32+
const urls = new Set<string>();
33+
FILES_WITH_GETTING_STARTED_URLS.forEach((filePath) =>
34+
collectGettingStartedUrlsFromFile(filePath, urls)
35+
);
36+
37+
urls.forEach((url) => {
38+
if (isOptionalGettingStartedUrl(url)) {
39+
return;
40+
}
41+
expect(mapping[url]).toBeDefined();
42+
const localPath = resolveLocalPathForUrl(
43+
url,
44+
mapping,
45+
STATIC_GETTING_STARTED_MAPPING_PATH
46+
);
47+
expect(localPath, `Mapping missing local path for ${url}`).toBeDefined();
48+
expect(
49+
fs.existsSync(localPath!),
50+
`Local file ${localPath} for ${url} does not exist`
51+
).toBe(true);
52+
});
53+
});
54+
});
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import fs from 'node:fs';
2+
import path from 'path';
3+
4+
const GETTING_STARTED_URL_PREFIX = 'https://calm.finos.org/getting-started/';
5+
const OPTIONAL_RELATIVE_PREFIXES = ['flows/'];
6+
7+
export const STATIC_GETTING_STARTED_MAPPING_PATH = path.resolve(
8+
__dirname,
9+
'../../test_fixtures/getting-started/url-to-local-file-mapping.json'
10+
);
11+
12+
export function collectGettingStartedUrlsFromFile(
13+
filePath: string,
14+
urls: Set<string>
15+
): void {
16+
let architecture;
17+
try {
18+
architecture = JSON.parse(fs.readFileSync(filePath, 'utf8'));
19+
} catch (err) {
20+
throw new Error(
21+
`Failed to read or parse JSON from file "${filePath}": ${err instanceof Error ? err.message : String(err)}`
22+
);
23+
}
24+
collectGettingStartedUrls(architecture, urls);
25+
}
26+
27+
export function loadGettingStartedMapping(
28+
mappingPath: string = STATIC_GETTING_STARTED_MAPPING_PATH
29+
): Record<string, string> {
30+
try {
31+
return JSON.parse(fs.readFileSync(mappingPath, 'utf8'));
32+
} catch (err) {
33+
throw new Error(
34+
`Failed to read or parse JSON from mapping file "${mappingPath}": ${err instanceof Error ? err.message : String(err)}`
35+
);
36+
}
37+
}
38+
39+
export function resolveLocalPathForUrl(
40+
url: string,
41+
mapping: Record<string, string>,
42+
mappingPath: string = STATIC_GETTING_STARTED_MAPPING_PATH
43+
): string | undefined {
44+
const relativePath = mapping[url];
45+
if (!relativePath) {
46+
return undefined;
47+
}
48+
const mappingDir = path.dirname(mappingPath);
49+
return path.resolve(mappingDir, relativePath);
50+
}
51+
52+
export function isOptionalGettingStartedUrl(url: string): boolean {
53+
const relativePath = url.slice(GETTING_STARTED_URL_PREFIX.length);
54+
return OPTIONAL_RELATIVE_PREFIXES.some((prefix) =>
55+
relativePath.startsWith(prefix)
56+
);
57+
}
58+
59+
function collectGettingStartedUrls(value: unknown, urls: Set<string>): void {
60+
if (value === null || value === undefined) {
61+
return;
62+
}
63+
64+
if (typeof value === 'string') {
65+
if (value.startsWith(GETTING_STARTED_URL_PREFIX)) {
66+
urls.add(value);
67+
}
68+
return;
69+
}
70+
71+
if (Array.isArray(value)) {
72+
value.forEach((item) => collectGettingStartedUrls(item, urls));
73+
return;
74+
}
75+
76+
if (typeof value === 'object') {
77+
Object.values(value as Record<string, unknown>).forEach((v) =>
78+
collectGettingStartedUrls(v, urls)
79+
);
80+
}
81+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"https://calm.finos.org/getting-started/controls/micro-segmentation.requirement.json": "../../../calm/getting-started/controls/micro-segmentation.requirement.json",
3+
"https://calm.finos.org/getting-started/controls/micro-segmentation.config.json": "../../../calm/getting-started/controls/micro-segmentation.config.json",
4+
"https://calm.finos.org/getting-started/controls/permitted-connection.requirement.json": "../../../calm/getting-started/controls/permitted-connection.requirement.json",
5+
"https://calm.finos.org/getting-started/controls/permitted-connection-http.config.json": "../../../calm/getting-started/controls/permitted-connection-http.config.json",
6+
"https://calm.finos.org/getting-started/controls/permitted-connection-jdbc.config.json": "../../../calm/getting-started/controls/permitted-connection-jdbc.config.json",
7+
"https://calm.finos.org/getting-started/conference-signup.pattern.json": "../../../calm/getting-started/conference-signup.pattern.json"
8+
}

0 commit comments

Comments
 (0)