Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cli/test_fixtures/validate_output_junit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<testsuite name="Spectral Suite" tests="31"
failures="0" errors="0" skipped="0">
<testcase name="architecture-has-nodes-relationships" />
<testcase name="architecture-has-no-empty-properties" />
<testcase name="architecture-has-no-empty-string-properties" />
<testcase
name="architecture-has-no-placeholder-properties-numerical" />
<testcase name="architecture-has-no-placeholder-properties-string" />
Expand Down
48 changes: 40 additions & 8 deletions shared/src/commands/validate/validate.e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,17 @@ const badPatternPath = path.join(
__dirname,
'../../../test_fixtures/bad-schema/bad-json-schema.json'
);
const flowsDir = path.join(
const validationPath = path.join(
__dirname,
'../../../test_fixtures/command/validate/flows/'
'../../../test_fixtures/command/validate/'
);

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

describe('validate E2E', () => {
let documentLoader: FileSystemDocumentLoader;
let schemaDirectory : SchemaDirectory;
let schemaDirectory: SchemaDirectory;

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

it('reports spectral issue for architecture with empty string property', async () => {
const inputArch = JSON.parse(readFileSync(path.join(validationPath, 'empty-string-property.json'), 'utf-8'));
const pattern = await schemaDirectory.getSchema(inputArch['$schema']);

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

expect(response.hasErrors).toBeTruthy();
expect(response.spectralSchemaValidationOutputs).toHaveLength(1);
expect(response.spectralSchemaValidationOutputs[0].message).toContain('nonempty value');
expect(response.spectralSchemaValidationOutputs[0].path).toBe('/nodes/0/description');
});

it('does not report spectral issue for architecture with false boolean property', async () => {
// If we prohibit false, then there is no way to represent a boolean property set to false in the architecture.
const inputArch = JSON.parse(readFileSync(path.join(validationPath, 'false-boolean-property.json'), 'utf-8'));
const pattern = await schemaDirectory.getSchema(inputArch['$schema']);

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

expect(response.hasErrors).toBeFalsy();
});

it('does not report spectral issue for architecture with zero integer property', async () => {
// If we prohibit 0, then there is no way to represent the number zero in the architecture.
const inputArch = JSON.parse(readFileSync(path.join(validationPath, 'zero-integer-property.json'), 'utf-8'));
const pattern = await schemaDirectory.getSchema(inputArch['$schema']);

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

expect(response.hasErrors).toBeFalsy();
});

describe('applyArchitectureOptionsToPattern', () => {
it('works with one options relationship', async () => {
const architecture = JSON.parse(
Expand All @@ -82,7 +114,7 @@ describe('validate E2E', () => {

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

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

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

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

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

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

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

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

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

const response = await validate(inputArch, schema, schemaDirectory, false);
Expand Down
8 changes: 4 additions & 4 deletions shared/src/spectral/rules-architecture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ const architectureRules: RulesetDefinition = {
],
},

'architecture-has-no-empty-properties': {
description: 'Must not contain string properties set to the empty string or numerical properties set to zero',
message: 'All properties must be set to a nonempty, nonzero value.',
'architecture-has-no-empty-string-properties': {
description: 'Must not contain string properties set to the empty string',
message: 'All properties must be set to a nonempty value.',
severity: 'error',
given: '$..*',
given: '$..*@string()',
then: {
function: truthy,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"$schema": "https://calm.finos.org/release/1.0/meta/calm.json",
"nodes": [
{
"unique-id": "node-1",
"name": "Frontend Service with no description",
"node-type": "service",
"description": ""
},
{
"unique-id": "node-2",
"name": "Backend Service",
"node-type": "service",
"description": "Backend Service"
}
],
"relationships": [
{
"unique-id": "node-1-to-node-2",
"relationship-type": {
"connects": {
"source": { "node": "node-1" },
"destination": { "node": "node-2" }
}
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"$schema": "https://calm.finos.org/release/1.0/meta/calm.json",
"nodes": [
{
"unique-id": "node-1",
"name": "Frontend Service",
"node-type": "service",
"description": "Frontend Service",
"metadata": {
"is-active": false
}
},
{
"unique-id": "node-2",
"name": "Backend Service",
"node-type": "service",
"description": "Backend Service"
}
],
"relationships": [
{
"unique-id": "node-1-to-node-2",
"relationship-type": {
"connects": {
"source": { "node": "node-1" },
"destination": { "node": "node-2" }
}
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"$schema": "https://calm.finos.org/release/1.0/meta/calm.json",
"nodes": [
{
"unique-id": "node-1",
"name": "Frontend Service",
"node-type": "service",
"description": "Frontend Service",
"metadata": {
"minimum-instances": 0
}
},
{
"unique-id": "node-2",
"name": "Backend Service",
"node-type": "service",
"description": "Backend Service"
}
],
"relationships": [
{
"unique-id": "node-1-to-node-2",
"relationship-type": {
"connects": {
"source": { "node": "node-1" },
"destination": { "node": "node-2" }
}
}
}
]
}
Loading