Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,47 @@ testRule('xgen-IPA-113-reset-method-not-on-readonly-singleton', [
},
errors: [],
},
{
name: 'valid reset when base path returns list response shape',
document: {
paths: {
'/resource/{exampleId}/listSingleton': {
get: {
responses: {
200: {
content: {
'application/json': {
schema: {
type: 'object',
properties: {
results: {
type: 'array',
readOnly: true,
items: {
type: 'object',
properties: {
id: { type: 'string', readOnly: true },
status: { type: 'string', readOnly: true },
},
},
},
totalCount: { type: 'integer', readOnly: true },
},
required: ['results'],
},
},
},
},
},
},
},
'/resource/{exampleId}/listSingleton:reset': {
post: {},
},
},
},
errors: [],
},
{
name: 'invalid reset on read-only singleton',
document: {
Expand Down
173 changes: 170 additions & 3 deletions tools/spectral/ipa/__tests__/IPA113SingletonHasUpdateMethod.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,164 @@ testRule('xgen-IPA-113-singleton-should-have-update-method', [
errors: [],
},
{
name: 'read-only singleton with List response',
name: 'read-only singleton with referenced nested schema does not require update method',
document: {
paths: {
'/resource/{exampleId}/readOnlySingleton': {
get: {
responses: {
200: {
content: {
'application/json': {
schema: {
$ref: '#/components/schemas/ReadOnlySingleton',
},
},
},
},
},
},
},
},
components: {
schemas: {
ReadOnlySingleton: {
type: 'object',
properties: {
status: { type: 'string', readOnly: true },
metadata: {
$ref: '#/components/schemas/ReadOnlyMetadata',
},
},
},
ReadOnlyMetadata: {
type: 'object',
properties: {
createdAt: { type: 'string', readOnly: true },
updatedAt: { type: 'string', readOnly: true },
},
},
},
},
},
errors: [],
},
{
name: 'singleton with writable property in referenced nested schema requires update method',
document: {
paths: {
'/resource/{exampleId}/writableSingleton': {
get: {
responses: {
200: {
content: {
'application/json': {
schema: {
$ref: '#/components/schemas/WritableSingleton',
},
},
},
},
},
},
},
},
components: {
schemas: {
WritableSingleton: {
type: 'object',
properties: {
status: { type: 'string', readOnly: true },
metadata: {
$ref: '#/components/schemas/WritableMetadata',
},
},
},
WritableMetadata: {
type: 'object',
properties: {
createdAt: { type: 'string', readOnly: true },
displayName: { type: 'string' },
},
},
},
},
},
errors: [
{
code: 'xgen-IPA-113-singleton-should-have-update-method',
message:
'Singleton resources should define the Update method. If this is not a singleton resource, please implement all CRUDL methods.',
path: ['paths', '/resource/{exampleId}/writableSingleton'],
severity: DiagnosticSeverity.Error,
},
],
},
...['allOf', 'anyOf', 'oneOf'].flatMap((composition) =>
[
{ description: 'read-only branches', withProperties: false, writable: false },
{ description: 'a writable branch', withProperties: false, writable: true },
{ description: 'read-only branches alongside properties', withProperties: true, writable: false },
{ description: 'a writable branch alongside read-only properties', withProperties: true, writable: true },
].map(({ description, withProperties, writable }) => ({
name: `singleton with referenced nested ${composition} containing ${description}`,
document: {
paths: {
'/resource/{exampleId}/singleton': {
get: {
responses: {
200: {
content: {
'application/json': {
schema: { $ref: '#/components/schemas/Singleton' },
},
},
},
},
},
},
},
components: {
schemas: {
Singleton: {
type: 'object',
properties: {
metadata: { $ref: '#/components/schemas/Metadata' },
},
},
Metadata: {
...(withProperties ? { properties: { id: { type: 'string', readOnly: true } } } : {}),
[composition]: [
{ $ref: '#/components/schemas/ReadOnlyMetadataPart' },
{ $ref: '#/components/schemas/OtherMetadataPart' },
],
},
ReadOnlyMetadataPart: {
type: 'object',
properties: { createdAt: { type: 'string', readOnly: true } },
},
OtherMetadataPart: {
type: 'object',
properties: { displayName: { type: 'string', readOnly: !writable } },
},
},
},
},
errors: writable
? [
{
code: 'xgen-IPA-113-singleton-should-have-update-method',
message:
'Singleton resources should define the Update method. If this is not a singleton resource, please implement all CRUDL methods.',
path: ['paths', '/resource/{exampleId}/singleton'],
severity: DiagnosticSeverity.Error,
},
]
: [],
}))
),
{
name: 'list response shape does not prove singleton is read-only',
document: {
paths: {
'/resource/{exampleId}/readOnlyListSingleton': {
Expand All @@ -109,6 +266,7 @@ testRule('xgen-IPA-113-singleton-should-have-update-method', [
properties: {
results: {
type: 'array',
readOnly: true,
items: {
type: 'object',
properties: {
Expand All @@ -118,8 +276,9 @@ testRule('xgen-IPA-113-singleton-should-have-update-method', [
},
},
},
totalCount: { type: 'integer' },
totalCount: { type: 'integer', readOnly: true },
},
required: ['results'],
},
},
},
Expand All @@ -129,7 +288,15 @@ testRule('xgen-IPA-113-singleton-should-have-update-method', [
},
},
},
errors: [],
errors: [
{
code: 'xgen-IPA-113-singleton-should-have-update-method',
message:
'Singleton resources should define the Update method. If this is not a singleton resource, please implement all CRUDL methods.',
path: ['paths', '/resource/{exampleId}/readOnlyListSingleton'],
severity: DiagnosticSeverity.Error,
},
],
},
{
name: 'writable singleton with List response',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import testRule from './__helpers__/testRule';
import { DiagnosticSeverity } from '@stoplight/types';

const READ_ONLY_SCHEMA_ERROR_MESSAGE =
'The Operation resource must be read-only. All properties of the GET response schema must be marked as readOnly: true.';
'The Operation resource must be read-only. All properties of the GET response schema must be marked as readOnly: true or contain only read-only properties.';

const readOnlyGet = {
responses: {
Expand Down
Loading
Loading