Skip to content

Commit a90feb7

Browse files
committed
fix: Validate processing fields everywhere
1 parent b47551e commit a90feb7

File tree

5 files changed

+157
-44
lines changed

5 files changed

+157
-44
lines changed

json-schema/schema.json

Lines changed: 8 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -53,21 +53,7 @@
5353
"properties": {
5454
"type": {
5555
"const": "Collection"
56-
}
57-
}
58-
},
59-
{
60-
"$ref": "#/definitions/stac_extensions"
61-
}
62-
],
63-
"anyOf": [
64-
{
65-
"$comment": "Validate fields in Collection Providers.",
66-
"type": "object",
67-
"required": [
68-
"providers"
69-
],
70-
"properties": {
56+
},
7157
"providers": {
7258
"type": "array",
7359
"minItems": 1,
@@ -108,15 +94,7 @@
10894
}
10995
]
11096
}
111-
}
112-
}
113-
},
114-
{
115-
"$comment": "This validates the fields in Collection Assets, but does not require them.",
116-
"required": [
117-
"assets"
118-
],
119-
"properties": {
97+
},
12098
"assets": {
12199
"type": "object",
122100
"not": {
@@ -133,15 +111,7 @@
133111
}
134112
}
135113
}
136-
}
137-
}
138-
},
139-
{
140-
"$comment": "This is the schema for the fields in Item Asset Definitions. It doesn't require any fields.",
141-
"required": [
142-
"item_assets"
143-
],
144-
"properties": {
114+
},
145115
"item_assets": {
146116
"type": "object",
147117
"not": {
@@ -158,19 +128,14 @@
158128
}
159129
}
160130
}
161-
}
162-
}
163-
},
164-
{
165-
"$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.",
166-
"required": [
167-
"summaries"
168-
],
169-
"properties": {
131+
},
170132
"summaries": {
171133
"$ref": "#/definitions/require_any_field"
172134
}
173135
}
136+
},
137+
{
138+
"$ref": "#/definitions/stac_extensions"
174139
}
175140
]
176141
}
@@ -264,4 +229,4 @@
264229
"additionalProperties": false
265230
}
266231
}
267-
}
232+
}

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": "npx ospec && 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+
"@types/ospec": "^4.0.2",
13+
"ospec": "^4.1.1",
1114
"remark-cli": "^8.0.0",
1215
"remark-lint": "^7.0.0",
1316
"remark-lint-no-html": "^2.0.0",

tests/template_collection.test.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import o from 'ospec';
2+
import Ajv from 'ajv';
3+
import { join } from 'path';
4+
import { promises as fs } from 'fs';
5+
import { AjvOptions, rootDirectory, schemaPath } from './validation.js';
6+
7+
const examplePath = join(rootDirectory, 'examples/collection.json');
8+
9+
o.spec('Collection', () => {
10+
let validate;
11+
const ajv = new Ajv(AjvOptions);
12+
13+
o.before(async () => {
14+
const data = JSON.parse(await fs.readFile(schemaPath));
15+
validate = await ajv.compileAsync(data);
16+
});
17+
18+
o('Example should pass validation', async () => {
19+
// given
20+
const example = JSON.parse(await fs.readFile(examplePath));
21+
22+
// when
23+
let valid = validate(example);
24+
25+
// then
26+
o(valid).equals(true)(JSON.stringify(validate.errors, null, 2));
27+
});
28+
29+
o("Example with invalid providers processing:software value should fail validation", async () => {
30+
// given
31+
const example = JSON.parse(await fs.readFile(examplePath));
32+
example['providers'][0]['processing:software'] = null;
33+
34+
// when
35+
let valid = validate(example);
36+
37+
// then
38+
o(valid).equals(false);
39+
o(
40+
validate.errors.some(
41+
(error) =>
42+
error.dataPath === ".providers[0]['processing:software']" &&
43+
error.message === 'should be object',
44+
),
45+
).equals(true)(JSON.stringify(validate.errors));
46+
});
47+
});

tests/template_item.test.js

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

tests/validation.js

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

0 commit comments

Comments
 (0)