105 строки
3.6 KiB
JavaScript
105 строки
3.6 KiB
JavaScript
// Check conformance to Azure guidelines for 202 responses:
|
|
// - A 202 response should have a response body schema
|
|
// - The response body schema should contain `id`, `status`, and `error` properties.
|
|
// - The `id`, `status`, and `error` properties should be required.
|
|
// - The `id` property should be type: string.
|
|
// - The `status` property should be type: string and enum with values:
|
|
// - "Running", "Succeeded", "Failed", "Cancelled".
|
|
// - The `error` property should be type: object and not required.
|
|
|
|
// Rule target is a 202 response
|
|
module.exports = (lroResponse, _opts, context) => {
|
|
// defensive programming - make sure we have an object
|
|
if (lroResponse === null || typeof lroResponse !== 'object') {
|
|
return [];
|
|
}
|
|
|
|
const lroResponseSchema = lroResponse.schema;
|
|
|
|
// A 202 response should include a schema for the operation status monitor.
|
|
if (!lroResponseSchema) {
|
|
return [{
|
|
message: 'A 202 response should include a schema for the operation status monitor.',
|
|
path: context.path || [],
|
|
}];
|
|
}
|
|
|
|
const path = [...(context.path || []), 'schema'];
|
|
|
|
const errors = [];
|
|
|
|
// - The `id`, `status`, and `error` properties should be required.
|
|
const requiredProperties = new Set(lroResponseSchema.required || []);
|
|
const checkRequiredProperty = (prop) => {
|
|
if (!requiredProperties.has(prop)) {
|
|
errors.push({
|
|
message: `\`${prop}\` property in LRO response should be required`,
|
|
path: [...path, 'required'],
|
|
});
|
|
}
|
|
};
|
|
|
|
// Check id property
|
|
if (lroResponseSchema.properties && 'id' in lroResponseSchema.properties) {
|
|
if (lroResponseSchema.properties.id.type !== 'string') {
|
|
errors.push({
|
|
message: '\'id\' property in LRO response should be type: string',
|
|
path: [...path, 'properties', 'id', 'type'],
|
|
});
|
|
}
|
|
checkRequiredProperty('id');
|
|
} else {
|
|
errors.push({
|
|
message: 'LRO response should contain top-level property `id`',
|
|
path: [...path, 'properties'],
|
|
});
|
|
}
|
|
|
|
// Check status property
|
|
if (lroResponseSchema.properties && 'status' in lroResponseSchema.properties) {
|
|
if (lroResponseSchema.properties.status.type !== 'string') {
|
|
errors.push({
|
|
message: '`status` property in LRO response should be type: string',
|
|
path: [...path, 'properties', 'status', 'type'],
|
|
});
|
|
}
|
|
checkRequiredProperty('status');
|
|
const statusValues = new Set(lroResponseSchema.properties.status.enum || []);
|
|
const requiredStatusValues = ['Running', 'Succeeded', 'Failed', 'Canceled'];
|
|
if (!requiredStatusValues.every((value) => statusValues.has(value))) {
|
|
errors.push({
|
|
message: `'status' property enum in LRO response should contain values: ${requiredStatusValues.join(', ')}`,
|
|
path: [...path, 'properties', 'status', 'enum'],
|
|
});
|
|
}
|
|
} else {
|
|
errors.push({
|
|
message: 'LRO response should contain top-level property `status`',
|
|
path: [...path, 'properties'],
|
|
});
|
|
}
|
|
|
|
// Check error property
|
|
if (lroResponseSchema.properties && 'error' in lroResponseSchema.properties) {
|
|
if (lroResponseSchema.properties.error.type !== 'object') {
|
|
errors.push({
|
|
message: '`error` property in LRO response should be type: object',
|
|
path: [...path, 'properties', 'error', 'type'],
|
|
});
|
|
}
|
|
if (requiredProperties.has('error')) {
|
|
errors.push({
|
|
message: '`error` property in LRO response should not be required',
|
|
path: [...path, 'required'],
|
|
});
|
|
}
|
|
} else {
|
|
errors.push({
|
|
message: 'LRO response should contain top-level property `error`',
|
|
path: [...path, 'properties'],
|
|
});
|
|
}
|
|
|
|
return errors;
|
|
};
|