Skip to content

Commit 90fb641

Browse files
authored
openapi2conv: Set externalDocs for Operations (#1070)
1 parent d4bdebd commit 90fb641

File tree

2 files changed

+223
-12
lines changed

2 files changed

+223
-12
lines changed

openapi2conv/issue1069_test.go

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
package openapi2conv
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/getkin/kin-openapi/openapi2"
8+
"github.com/getkin/kin-openapi/openapi3"
9+
"github.com/oasdiff/yaml"
10+
"github.com/stretchr/testify/assert"
11+
"github.com/stretchr/testify/require"
12+
)
13+
14+
func TestIssue1069V2ToV3(t *testing.T) {
15+
tests := []struct {
16+
name string
17+
v2Spec string
18+
validate func(t *testing.T, v3 *openapi3.T)
19+
}{
20+
{
21+
name: "root level externalDocs",
22+
v2Spec: `
23+
swagger: '2.0'
24+
info:
25+
version: 1.0.0
26+
title: title
27+
externalDocs:
28+
url: https://example/root
29+
description: Root level documentation
30+
paths:
31+
/test:
32+
get:
33+
responses:
34+
'200':
35+
description: description
36+
`,
37+
validate: func(t *testing.T, v3 *openapi3.T) {
38+
require.NotNil(t, v3.ExternalDocs)
39+
assert.Equal(t, "https://example/root", v3.ExternalDocs.URL)
40+
assert.Equal(t, "Root level documentation", v3.ExternalDocs.Description)
41+
},
42+
},
43+
{
44+
name: "operation level externalDocs",
45+
v2Spec: `
46+
swagger: '2.0'
47+
info:
48+
version: 1.0.0
49+
title: title
50+
paths:
51+
/test:
52+
get:
53+
externalDocs:
54+
url: https://example/operation
55+
description: Operation level documentation
56+
responses:
57+
'200':
58+
description: description
59+
`,
60+
validate: func(t *testing.T, v3 *openapi3.T) {
61+
op := v3.Paths.Value("/test").Get
62+
require.NotNil(t, op.ExternalDocs)
63+
assert.Equal(t, "https://example/operation", op.ExternalDocs.URL)
64+
assert.Equal(t, "Operation level documentation", op.ExternalDocs.Description)
65+
},
66+
},
67+
{
68+
name: "schema level externalDocs",
69+
v2Spec: `
70+
swagger: '2.0'
71+
info:
72+
version: 1.0.0
73+
title: title
74+
definitions:
75+
TestSchema:
76+
type: object
77+
externalDocs:
78+
url: https://example/schema
79+
description: Schema level documentation
80+
paths:
81+
/test:
82+
get:
83+
responses:
84+
'200':
85+
description: description
86+
schema:
87+
$ref: '#/definitions/TestSchema'
88+
`,
89+
validate: func(t *testing.T, v3 *openapi3.T) {
90+
schema := v3.Components.Schemas["TestSchema"].Value
91+
require.NotNil(t, schema.ExternalDocs)
92+
assert.Equal(t, "https://example/schema", schema.ExternalDocs.URL)
93+
assert.Equal(t, "Schema level documentation", schema.ExternalDocs.Description)
94+
},
95+
},
96+
}
97+
98+
for _, tt := range tests {
99+
t.Run(tt.name, func(t *testing.T) {
100+
v3, err := v2v3YAML([]byte(tt.v2Spec))
101+
require.NoError(t, err)
102+
err = v3.Validate(context.Background())
103+
require.NoError(t, err)
104+
tt.validate(t, v3)
105+
})
106+
}
107+
}
108+
109+
func TestIssue1069V3ToV2(t *testing.T) {
110+
tests := []struct {
111+
name string
112+
v3Spec string
113+
validate func(t *testing.T, v2 *openapi2.T)
114+
}{
115+
{
116+
name: "root level externalDocs",
117+
v3Spec: `
118+
openapi: 3.0.3
119+
info:
120+
version: 1.0.0
121+
title: title
122+
externalDocs:
123+
url: https://example/root
124+
description: Root level documentation
125+
components: {}
126+
paths:
127+
/test:
128+
get:
129+
responses:
130+
'200':
131+
description: description
132+
`,
133+
validate: func(t *testing.T, v2 *openapi2.T) {
134+
require.NotNil(t, v2.ExternalDocs)
135+
assert.Equal(t, "https://example/root", v2.ExternalDocs.URL)
136+
assert.Equal(t, "Root level documentation", v2.ExternalDocs.Description)
137+
},
138+
},
139+
{
140+
name: "operation level externalDocs",
141+
v3Spec: `
142+
openapi: 3.0.3
143+
info:
144+
version: 1.0.0
145+
title: title
146+
components: {}
147+
paths:
148+
/test:
149+
get:
150+
externalDocs:
151+
url: https://example/operation
152+
description: Operation level documentation
153+
responses:
154+
'200':
155+
description: description
156+
`,
157+
validate: func(t *testing.T, v2 *openapi2.T) {
158+
op := v2.Paths["/test"].Get
159+
require.NotNil(t, op.ExternalDocs)
160+
assert.Equal(t, "https://example/operation", op.ExternalDocs.URL)
161+
assert.Equal(t, "Operation level documentation", op.ExternalDocs.Description)
162+
},
163+
},
164+
{
165+
name: "schema level externalDocs",
166+
v3Spec: `
167+
openapi: 3.0.3
168+
info:
169+
version: 1.0.0
170+
title: title
171+
components:
172+
schemas:
173+
TestSchema:
174+
type: object
175+
externalDocs:
176+
url: https://example/schema
177+
description: Schema level documentation
178+
paths:
179+
/test:
180+
get:
181+
responses:
182+
'200':
183+
description: description
184+
content:
185+
application/json:
186+
schema:
187+
$ref: '#/components/schemas/TestSchema'
188+
`,
189+
validate: func(t *testing.T, v2 *openapi2.T) {
190+
schema := v2.Definitions["TestSchema"].Value
191+
require.NotNil(t, schema.ExternalDocs)
192+
assert.Equal(t, "https://example/schema", schema.ExternalDocs.URL)
193+
assert.Equal(t, "Schema level documentation", schema.ExternalDocs.Description)
194+
},
195+
},
196+
}
197+
198+
for _, tt := range tests {
199+
t.Run(tt.name, func(t *testing.T) {
200+
var doc3 openapi3.T
201+
err := yaml.Unmarshal([]byte(tt.v3Spec), &doc3)
202+
require.NoError(t, err)
203+
204+
v2, err := FromV3(&doc3)
205+
require.NoError(t, err)
206+
tt.validate(t, v2)
207+
})
208+
}
209+
}

openapi2conv/openapi2_conv.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -149,12 +149,13 @@ func ToV3Operation(doc2 *openapi2.T, components *openapi3.Components, pathItem *
149149
return nil, nil
150150
}
151151
doc3 := &openapi3.Operation{
152-
OperationID: operation.OperationID,
153-
Summary: operation.Summary,
154-
Description: operation.Description,
155-
Deprecated: operation.Deprecated,
156-
Tags: operation.Tags,
157-
Extensions: stripNonExtensions(operation.Extensions),
152+
OperationID: operation.OperationID,
153+
Summary: operation.Summary,
154+
Description: operation.Description,
155+
Deprecated: operation.Deprecated,
156+
Tags: operation.Tags,
157+
Extensions: stripNonExtensions(operation.Extensions),
158+
ExternalDocs: operation.ExternalDocs,
158159
}
159160
if v := operation.Security; v != nil {
160161
doc3Security := ToV3SecurityRequirements(*v)
@@ -1065,12 +1066,13 @@ func FromV3Operation(doc3 *openapi3.T, operation *openapi3.Operation) (*openapi2
10651066
return nil, nil
10661067
}
10671068
result := &openapi2.Operation{
1068-
OperationID: operation.OperationID,
1069-
Summary: operation.Summary,
1070-
Description: operation.Description,
1071-
Deprecated: operation.Deprecated,
1072-
Tags: operation.Tags,
1073-
Extensions: stripNonExtensions(operation.Extensions),
1069+
OperationID: operation.OperationID,
1070+
Summary: operation.Summary,
1071+
Description: operation.Description,
1072+
Deprecated: operation.Deprecated,
1073+
Tags: operation.Tags,
1074+
Extensions: stripNonExtensions(operation.Extensions),
1075+
ExternalDocs: operation.ExternalDocs,
10741076
}
10751077
if v := operation.Security; v != nil {
10761078
resultSecurity := FromV3SecurityRequirements(*v)

0 commit comments

Comments
 (0)