Skip to content

Commit c56bb2e

Browse files
committed
fix: Validate processing fields everywhere
1 parent cd093f2 commit c56bb2e

File tree

5 files changed

+180
-46
lines changed

5 files changed

+180
-46
lines changed

json-schema/schema.json

Lines changed: 7 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -54,21 +54,7 @@
5454
"properties": {
5555
"type": {
5656
"const": "Collection"
57-
}
58-
}
59-
},
60-
{
61-
"$ref": "#/definitions/stac_extensions"
62-
}
63-
],
64-
"anyOf": [
65-
{
66-
"$comment": "Validate fields in Collection Providers.",
67-
"type": "object",
68-
"required": [
69-
"providers"
70-
],
71-
"properties": {
57+
},
7258
"providers": {
7359
"type": "array",
7460
"minItems": 1,
@@ -110,16 +96,7 @@
11096
}
11197
]
11298
}
113-
}
114-
}
115-
},
116-
{
117-
"type": "object",
118-
"$comment": "This validates the fields in Collection Assets, but does not require them.",
119-
"required": [
120-
"assets"
121-
],
122-
"properties": {
99+
},
123100
"assets": {
124101
"type": "object",
125102
"not": {
@@ -136,16 +113,7 @@
136113
}
137114
}
138115
}
139-
}
140-
}
141-
},
142-
{
143-
"type": "object",
144-
"$comment": "This is the schema for the fields in Item Asset Definitions. It doesn't require any fields.",
145-
"required": [
146-
"item_assets"
147-
],
148-
"properties": {
116+
},
149117
"item_assets": {
150118
"type": "object",
151119
"not": {
@@ -162,20 +130,14 @@
162130
}
163131
}
164132
}
165-
}
166-
}
167-
},
168-
{
169-
"type": "object",
170-
"$comment": "This is the schema for the fields in Summaries. By default, only checks the existance of the properties, but not the schema of the summaries.",
171-
"required": [
172-
"summaries"
173-
],
174-
"properties": {
133+
},
175134
"summaries": {
176135
"$ref": "#/definitions/require_any_field"
177136
}
178137
}
138+
},
139+
{
140+
"$ref": "#/definitions/stac_extensions"
179141
}
180142
]
181143
}

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22
"name": "stac-extensions",
33
"version": "1.0.0",
44
"scripts": {
5-
"test": "npm run check-markdown && npm run check-examples",
5+
"test": "jest && npm run check-markdown && npm run check-examples",
66
"check-markdown": "remark . -f -r .github/remark.yaml",
77
"check-examples": "stac-node-validator . --lint --verbose --schemaMap https://stac-extensions.github.io/processing/v1.0.0/schema.json=./json-schema/schema.json",
88
"format-examples": "stac-node-validator . --format --schemaMap https://stac-extensions.github.io/processing/v1.0.0/schema.json=./json-schema/schema.json"
99
},
10+
"type": "module",
1011
"dependencies": {
12+
"ajv": "^8.8.2",
13+
"jest": "^27.4.4",
1114
"remark-cli": "^8.0.0",
1215
"remark-lint": "^7.0.0",
1316
"remark-lint-no-html": "^2.0.0",

tests/collection.test.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
const { join } = require('path');
2+
const { promises } = require('fs');
3+
const { AjvOptions, rootDirectory, schemaPath } = require('./validation.js');
4+
const ajv = new (require('ajv'))(AjvOptions);
5+
6+
const examplePath = join(rootDirectory, 'examples/collection.json');
7+
8+
const propertyNames = [
9+
'processing:expression',
10+
'processing:facility',
11+
'processing:level',
12+
'processing:lineage',
13+
'processing:software',
14+
];
15+
16+
let validate;
17+
beforeAll(async () => {
18+
const data = JSON.parse(await promises.readFile(schemaPath));
19+
validate = await ajv.compileAsync(data);
20+
});
21+
22+
describe('Collection example', () => {
23+
it('should pass validation', async () => {
24+
// given
25+
const example = JSON.parse(await promises.readFile(examplePath));
26+
27+
// when
28+
let valid = validate(example);
29+
30+
// then
31+
expect(valid).toBeTruthy()
32+
});
33+
34+
it('should fail validation with invalid providers processing:software value', async () => {
35+
// given
36+
const example = JSON.parse(await promises.readFile(examplePath));
37+
example['providers'][0]['processing:software'] = null;
38+
39+
// when
40+
let valid = validate(example);
41+
42+
// then
43+
expect(valid).toBeFalsy();
44+
expect(
45+
validate.errors.some(
46+
(error) =>
47+
error.instancePath === '/providers/0/processing:software' &&
48+
error.message === 'must be object',
49+
),
50+
).toBeTruthy();
51+
});
52+
53+
it('should fail validation without any summaries processing: properties', async () => {
54+
// given
55+
const example = JSON.parse(await promises.readFile(examplePath));
56+
for (const propertyName of propertyNames) {
57+
delete example['summaries'][propertyName];
58+
}
59+
60+
// when
61+
let valid = validate(example);
62+
63+
// then
64+
expect(valid).toBeFalsy();
65+
for (const propertyName of propertyNames) {
66+
expect(
67+
validate.errors.some(
68+
(error) =>
69+
error.instancePath === "/summaries" &&
70+
error.message === `must have required property '${propertyName}'`,
71+
),
72+
).toBeTruthy();
73+
}
74+
});
75+
});

tests/item.test.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
const { join } = require('path');
2+
const { promises } = require('fs');
3+
const { AjvOptions, rootDirectory, schemaPath } = require('./validation.js');
4+
const ajv = new (require('ajv'))(AjvOptions);
5+
6+
const examplePath = join(rootDirectory, 'examples/item.json');
7+
8+
let validate;
9+
beforeAll(async () => {
10+
const data = JSON.parse(await promises.readFile(schemaPath));
11+
validate = await ajv.compileAsync(data);
12+
});
13+
14+
describe('Item example', () => {
15+
it('should pass validation', async () => {
16+
// given
17+
const example = JSON.parse(await promises.readFile(examplePath));
18+
19+
// when
20+
let valid = validate(example);
21+
22+
// then
23+
expect(valid).toBeTruthy();
24+
});
25+
26+
it('should fail validation with invalid properties processing:software value', async () => {
27+
// given
28+
const example = JSON.parse(await promises.readFile(examplePath));
29+
example['properties']['processing:software'] = null;
30+
31+
// when
32+
let valid = validate(example);
33+
34+
// then
35+
expect(valid).toBeFalsy();
36+
expect(
37+
validate.errors.some(
38+
(error) =>
39+
error.instancePath === '/properties/processing:software' &&
40+
error.message === 'must be object',
41+
),
42+
).toBeTruthy();
43+
});
44+
45+
it('should fail validation with invalid asset processing:software value ', async () => {
46+
// given
47+
const example = JSON.parse(await promises.readFile(examplePath));
48+
example['assets']['manifest']['processing:software'] = null;
49+
50+
// when
51+
let valid = validate(example);
52+
53+
// then
54+
expect(valid).toBeFalsy();
55+
expect(
56+
validate.errors.some(
57+
(error) =>
58+
error.instancePath === '/assets/manifest/processing:software' &&
59+
error.message === 'must be object',
60+
),
61+
).toBeTruthy();
62+
});
63+
});

tests/validation.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
const axios = require('axios');
2+
const { dirname, join } = require('path');
3+
const iriFormats = require('stac-node-validator/iri.js');
4+
5+
// const directory = dirname(fileURLToPath(import.meta.url));
6+
7+
const Schemas = new Map();
8+
const loadSchema = function (uri) {
9+
let existing = Schemas.get(uri);
10+
if (existing == null) {
11+
existing = loadSchemaFromUri(uri);
12+
Schemas.set(uri, existing);
13+
}
14+
return existing;
15+
}
16+
17+
/**
18+
* function passed in to Ajv instance which allows us to load schemas from a url at run time.
19+
*/
20+
module.exports.loadSchemaFromUri = async function (uri) {
21+
try {
22+
let response = await axios.get(uri);
23+
return response.data;
24+
} catch (error) {
25+
throw new Error(`-- Schema at '${uri}' not found. Please ensure all entries in 'stac_extensions' are valid.`);
26+
}
27+
}
28+
29+
module.exports.AjvOptions = {loadSchema, formats: Object.assign(iriFormats)};
30+
module.exports.rootDirectory = dirname(__dirname);
31+
module.exports.schemaPath = join(module.exports.rootDirectory, 'json-schema/schema.json');

0 commit comments

Comments
 (0)