Skip to content

Commit cbae6a9

Browse files
Merge pull request #1877 from markscott-ms/boolean-properties
CLI validation - permit zero or false properties
2 parents 02a1d3f + 0f0ee5a commit cbae6a9

File tree

6 files changed

+135
-13
lines changed

6 files changed

+135
-13
lines changed

cli/test_fixtures/validate_output_junit.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<testsuite name="Spectral Suite" tests="31"
88
failures="0" errors="0" skipped="0">
99
<testcase name="architecture-has-nodes-relationships" />
10-
<testcase name="architecture-has-no-empty-properties" />
10+
<testcase name="architecture-has-no-empty-string-properties" />
1111
<testcase
1212
name="architecture-has-no-placeholder-properties-numerical" />
1313
<testcase name="architecture-has-no-placeholder-properties-string" />

shared/src/commands/validate/validate.e2e.spec.ts

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,17 @@ const badPatternPath = path.join(
1717
__dirname,
1818
'../../../test_fixtures/bad-schema/bad-json-schema.json'
1919
);
20-
const flowsDir = path.join(
20+
const validationPath = path.join(
2121
__dirname,
22-
'../../../test_fixtures/command/validate/flows/'
22+
'../../../test_fixtures/command/validate/'
2323
);
2424

2525
const schemaDir_10 = path.join(__dirname, '../../../../calm/release/1.0/meta/');
2626
const schemaDir_11 = path.join(__dirname, '../../../../calm/release/1.1/meta/');
2727

2828
describe('validate E2E', () => {
2929
let documentLoader: FileSystemDocumentLoader;
30-
let schemaDirectory : SchemaDirectory;
30+
let schemaDirectory: SchemaDirectory;
3131

3232
beforeEach(async () => {
3333
documentLoader = new FileSystemDocumentLoader([schemaDir_10, schemaDir_11], true);
@@ -63,6 +63,38 @@ describe('validate E2E', () => {
6363
expect(response.jsonSchemaValidationOutputs[0].path).toBe('/');
6464
});
6565

66+
it('reports spectral issue for architecture with empty string property', async () => {
67+
const inputArch = JSON.parse(readFileSync(path.join(validationPath, 'empty-string-property.json'), 'utf-8'));
68+
const pattern = await schemaDirectory.getSchema(inputArch['$schema']);
69+
70+
const response = await validate(inputArch, pattern, schemaDirectory, false);
71+
72+
expect(response.hasErrors).toBeTruthy();
73+
expect(response.spectralSchemaValidationOutputs).toHaveLength(1);
74+
expect(response.spectralSchemaValidationOutputs[0].message).toContain('nonempty value');
75+
expect(response.spectralSchemaValidationOutputs[0].path).toBe('/nodes/0/description');
76+
});
77+
78+
it('does not report spectral issue for architecture with false boolean property', async () => {
79+
// If we prohibit false, then there is no way to represent a boolean property set to false in the architecture.
80+
const inputArch = JSON.parse(readFileSync(path.join(validationPath, 'false-boolean-property.json'), 'utf-8'));
81+
const pattern = await schemaDirectory.getSchema(inputArch['$schema']);
82+
83+
const response = await validate(inputArch, pattern, schemaDirectory, false);
84+
85+
expect(response.hasErrors).toBeFalsy();
86+
});
87+
88+
it('does not report spectral issue for architecture with zero integer property', async () => {
89+
// If we prohibit 0, then there is no way to represent the number zero in the architecture.
90+
const inputArch = JSON.parse(readFileSync(path.join(validationPath, 'zero-integer-property.json'), 'utf-8'));
91+
const pattern = await schemaDirectory.getSchema(inputArch['$schema']);
92+
93+
const response = await validate(inputArch, pattern, schemaDirectory, false);
94+
95+
expect(response.hasErrors).toBeFalsy();
96+
});
97+
6698
describe('applyArchitectureOptionsToPattern', () => {
6799
it('works with one options relationship', async () => {
68100
const architecture = JSON.parse(
@@ -82,7 +114,7 @@ describe('validate E2E', () => {
82114

83115
describe('schema specific validations', () => {
84116
it('fails to report bad flows for schema 1.0', async () => {
85-
const inputArch = JSON.parse(readFileSync(path.join(flowsDir, 'flows-1.0-bad.json'), 'utf-8'));
117+
const inputArch = JSON.parse(readFileSync(path.join(validationPath, 'flows/flows-1.0-bad.json'), 'utf-8'));
86118
const schema = await schemaDirectory.getSchema(inputArch['$schema']);
87119

88120
const response = await validate(inputArch, schema, schemaDirectory, false);
@@ -91,7 +123,7 @@ describe('validate E2E', () => {
91123
});
92124

93125
it('reports bad flows for schema 1.1', async () => {
94-
const inputArch = JSON.parse(readFileSync(path.join(flowsDir, 'flows-1.1-bad.json'), 'utf-8'));
126+
const inputArch = JSON.parse(readFileSync(path.join(validationPath, 'flows/flows-1.1-bad.json'), 'utf-8'));
95127
const schema = await schemaDirectory.getSchema(inputArch['$schema']);
96128

97129
const response = await validate(inputArch, schema, schemaDirectory, false);
@@ -103,7 +135,7 @@ describe('validate E2E', () => {
103135
});
104136

105137
it('accepts good flows for schema 1.1', async () => {
106-
const inputArch = JSON.parse(readFileSync(path.join(flowsDir, 'flows-1.1-good.json'), 'utf-8'));
138+
const inputArch = JSON.parse(readFileSync(path.join(validationPath, 'flows/flows-1.1-good.json'), 'utf-8'));
107139
const schema = await schemaDirectory.getSchema(inputArch['$schema']);
108140

109141
const response = await validate(inputArch, schema, schemaDirectory, false);
@@ -112,7 +144,7 @@ describe('validate E2E', () => {
112144
});
113145

114146
it('error in flow with non-unique sequence numbers', async () => {
115-
const inputArch = JSON.parse(readFileSync(path.join(flowsDir, 'flows-spectral-sequence-non-unique.json'), 'utf-8'));
147+
const inputArch = JSON.parse(readFileSync(path.join(validationPath, 'flows/flows-spectral-sequence-non-unique.json'), 'utf-8'));
116148
const schema = await schemaDirectory.getSchema(inputArch['$schema']);
117149

118150
const response = await validate(inputArch, schema, schemaDirectory, false);
@@ -124,7 +156,7 @@ describe('validate E2E', () => {
124156
});
125157

126158
it('error in flow with unknown relationship', async () => {
127-
const inputArch = JSON.parse(readFileSync(path.join(flowsDir, 'flows-spectral-unknown-relationship.json'), 'utf-8'));
159+
const inputArch = JSON.parse(readFileSync(path.join(validationPath, 'flows/flows-spectral-unknown-relationship.json'), 'utf-8'));
128160
const schema = await schemaDirectory.getSchema(inputArch['$schema']);
129161

130162
const response = await validate(inputArch, schema, schemaDirectory, false);

shared/src/spectral/rules-architecture.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ const architectureRules: RulesetDefinition = {
2929
],
3030
},
3131

32-
'architecture-has-no-empty-properties': {
33-
description: 'Must not contain string properties set to the empty string or numerical properties set to zero',
34-
message: 'All properties must be set to a nonempty, nonzero value.',
32+
'architecture-has-no-empty-string-properties': {
33+
description: 'Must not contain string properties set to the empty string',
34+
message: 'All properties must be set to a nonempty value.',
3535
severity: 'error',
36-
given: '$..*',
36+
given: '$..*@string()',
3737
then: {
3838
function: truthy,
3939
},
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"$schema": "https://calm.finos.org/release/1.0/meta/calm.json",
3+
"nodes": [
4+
{
5+
"unique-id": "node-1",
6+
"name": "Frontend Service with no description",
7+
"node-type": "service",
8+
"description": ""
9+
},
10+
{
11+
"unique-id": "node-2",
12+
"name": "Backend Service",
13+
"node-type": "service",
14+
"description": "Backend Service"
15+
}
16+
],
17+
"relationships": [
18+
{
19+
"unique-id": "node-1-to-node-2",
20+
"relationship-type": {
21+
"connects": {
22+
"source": { "node": "node-1" },
23+
"destination": { "node": "node-2" }
24+
}
25+
}
26+
}
27+
]
28+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"$schema": "https://calm.finos.org/release/1.0/meta/calm.json",
3+
"nodes": [
4+
{
5+
"unique-id": "node-1",
6+
"name": "Frontend Service",
7+
"node-type": "service",
8+
"description": "Frontend Service",
9+
"metadata": {
10+
"is-active": false
11+
}
12+
},
13+
{
14+
"unique-id": "node-2",
15+
"name": "Backend Service",
16+
"node-type": "service",
17+
"description": "Backend Service"
18+
}
19+
],
20+
"relationships": [
21+
{
22+
"unique-id": "node-1-to-node-2",
23+
"relationship-type": {
24+
"connects": {
25+
"source": { "node": "node-1" },
26+
"destination": { "node": "node-2" }
27+
}
28+
}
29+
}
30+
]
31+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"$schema": "https://calm.finos.org/release/1.0/meta/calm.json",
3+
"nodes": [
4+
{
5+
"unique-id": "node-1",
6+
"name": "Frontend Service",
7+
"node-type": "service",
8+
"description": "Frontend Service",
9+
"metadata": {
10+
"minimum-instances": 0
11+
}
12+
},
13+
{
14+
"unique-id": "node-2",
15+
"name": "Backend Service",
16+
"node-type": "service",
17+
"description": "Backend Service"
18+
}
19+
],
20+
"relationships": [
21+
{
22+
"unique-id": "node-1-to-node-2",
23+
"relationship-type": {
24+
"connects": {
25+
"source": { "node": "node-1" },
26+
"destination": { "node": "node-2" }
27+
}
28+
}
29+
}
30+
]
31+
}

0 commit comments

Comments
 (0)