Skip to content

Commit e70839d

Browse files
committed
Add tests and address comments
1 parent a3e29e9 commit e70839d

File tree

12 files changed

+159
-42
lines changed

12 files changed

+159
-42
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ require (
1010
github.com/getkin/kin-openapi v0.76.0
1111
github.com/go-openapi/jsonreference v0.19.3
1212
github.com/go-openapi/swag v0.19.5
13+
github.com/go-test/deep v1.0.8
1314
github.com/golang/protobuf v1.5.2
1415
github.com/google/gnostic v0.5.7-v3refs
1516
github.com/google/go-cmp v0.5.5

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+j
3232
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
3333
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
3434
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
35+
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
36+
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
3537
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
3638
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
3739
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=

pkg/builder3/openapi.go

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ type openAPI struct {
3939
definitions map[string]common.OpenAPIDefinition
4040
}
4141

42-
4342
func groupRoutesByPath(routes []common.Route) map[string][]common.Route {
4443
pathToRoutes := make(map[string][]common.Route)
4544
for _, r := range routes {
@@ -52,7 +51,6 @@ func (o *openAPI) buildResponse(model interface{}, description string, content [
5251
response := &spec3.Response{
5352
ResponseProps: spec3.ResponseProps{
5453
Description: description,
55-
Headers: make(map[string]*spec3.Header),
5654
Content: make(map[string]*spec3.MediaType),
5755
},
5856
}
@@ -83,6 +81,15 @@ func (o *openAPI) buildOperations(route common.Route, inPathCommonParamsMap map[
8381
},
8482
},
8583
}
84+
for k, v := range route.Metadata() {
85+
if strings.HasPrefix(k, common.ExtensionPrefix) {
86+
if ret.Extensions == nil {
87+
ret.Extensions = spec.Extensions{}
88+
}
89+
ret.Extensions.Add(k, v)
90+
}
91+
}
92+
8693
var err error
8794
if ret.OperationId, ret.Tags, err = o.config.GetOperationIDAndTagsFromRoute(route); err != nil {
8895
return ret, err
@@ -115,7 +122,6 @@ func (o *openAPI) buildOperations(route common.Route, inPathCommonParamsMap map[
115122
ret.Responses.Default = o.config.DefaultResponse
116123
}
117124

118-
ret.Parameters = make([]*spec3.Parameter, 0)
119125
params := route.Parameters()
120126
for _, param := range params {
121127
_, isCommon := inPathCommonParamsMap[mapKeyFromParam(param)]
@@ -128,7 +134,7 @@ func (o *openAPI) buildOperations(route common.Route, inPathCommonParamsMap map[
128134
}
129135
}
130136

131-
body, err := o.buildRequestBody(params, route.RequestPayloadSample())
137+
body, err := o.buildRequestBody(params, route.Consumes(), route.RequestPayloadSample())
132138
if err != nil {
133139
return nil, err
134140
}
@@ -139,7 +145,7 @@ func (o *openAPI) buildOperations(route common.Route, inPathCommonParamsMap map[
139145
return ret, nil
140146
}
141147

142-
func (o *openAPI) buildRequestBody(parameters []common.Parameter, bodySample interface{}) (*spec3.RequestBody, error) {
148+
func (o *openAPI) buildRequestBody(parameters []common.Parameter, consumes []string, bodySample interface{}) (*spec3.RequestBody, error) {
143149
for _, param := range parameters {
144150
if param.Kind() == common.BodyParameterKind && bodySample != nil {
145151
schema, err := o.toSchema(util.GetCanonicalTypeName(bodySample))
@@ -148,15 +154,16 @@ func (o *openAPI) buildRequestBody(parameters []common.Parameter, bodySample int
148154
}
149155
r := &spec3.RequestBody{
150156
RequestBodyProps: spec3.RequestBodyProps{
151-
Content: map[string]*spec3.MediaType{
152-
"application/json": &spec3.MediaType{
153-
MediaTypeProps: spec3.MediaTypeProps{
154-
Schema: schema,
155-
},
156-
},
157-
},
157+
Content: map[string]*spec3.MediaType{},
158158
},
159159
}
160+
for _, consume := range consumes {
161+
r.Content[consume] = &spec3.MediaType{
162+
MediaTypeProps: spec3.MediaTypeProps{
163+
Schema: schema,
164+
},
165+
}
166+
}
160167
return r, nil
161168
}
162169
}
@@ -174,15 +181,25 @@ func newOpenAPI(config *common.Config) openAPI {
174181
},
175182
Components: &spec3.Components{
176183
Schemas: map[string]*spec.Schema{},
177-
SecuritySchemes: make(spec3.SecuritySchemes),
178-
Responses: make(map[string]*spec3.Response),
179184
},
180185
},
181186
}
187+
if len(o.config.ResponseDefinitions) > 0 {
188+
o.spec.Components.Responses = make(map[string]*spec3.Response)
189+
190+
}
182191
for k, response := range o.config.ResponseDefinitions {
183192
o.spec.Components.Responses[k] = response
184193
}
185194

195+
if len(o.config.SecuritySchemes) > 0 {
196+
o.spec.Components.SecuritySchemes = make(spec3.SecuritySchemes)
197+
198+
}
199+
for k, securityScheme := range o.config.SecuritySchemes {
200+
o.spec.Components.SecuritySchemes[k] = securityScheme
201+
}
202+
186203
if o.config.GetOperationIDAndTagsFromRoute == nil {
187204
// Map the deprecated handler to the common interface, if provided.
188205
if o.config.GetOperationIDAndTags != nil {
@@ -249,9 +266,7 @@ func (o *openAPI) buildOpenAPISpec(webServices []common.RouteContainer) error {
249266
}
250267

251268
pathItem = &spec3.Path{
252-
PathProps: spec3.PathProps{
253-
Parameters: make([]*spec3.Parameter, 0),
254-
},
269+
PathProps: spec3.PathProps{},
255270
}
256271

257272
// add web services's parameters as well as any parameters appears in all ops, as common parameters
@@ -263,6 +278,7 @@ func (o *openAPI) buildOpenAPISpec(webServices []common.RouteContainer) error {
263278

264279
for _, route := range routes {
265280
op, _ := o.buildOperations(route, inPathCommonParamsMap)
281+
sortParameters(op.Parameters)
266282

267283
switch strings.ToUpper(route.Method()) {
268284
case "GET":

pkg/openapiconv/convert.go

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -54,18 +54,23 @@ func ConvertExternalDocumentation(v2ED *spec.ExternalDocumentation) *spec3.Exter
5454
}
5555

5656
func ConvertComponents(v2SecurityDefinitions spec.SecurityDefinitions, v2Definitions spec.Definitions, v2Responses map[string]spec.Response, produces []string) *spec3.Components {
57-
components := &spec3.Components{
58-
Schemas: make(map[string]*spec.Schema),
59-
SecuritySchemes: make(spec3.SecuritySchemes),
60-
Responses: make(map[string]*spec3.Response),
57+
components := &spec3.Components{}
58+
59+
if len(v2Definitions) > 0 {
60+
components.Schemas = make(map[string]*spec.Schema)
6161
}
6262
for s, schema := range v2Definitions {
6363
components.Schemas[s] = ConvertSchema(&schema)
6464
}
65-
65+
if len(v2SecurityDefinitions) > 0 {
66+
components.SecuritySchemes = make(spec3.SecuritySchemes)
67+
}
6668
for s, securityScheme := range v2SecurityDefinitions {
6769
components.SecuritySchemes[s] = ConvertSecurityScheme(securityScheme)
6870
}
71+
if len(v2Responses) > 0 {
72+
components.Responses = make(map[string]*spec3.Response)
73+
}
6974
for r, response := range v2Responses {
7075
components.Responses[r] = ConvertResponse(&response, produces)
7176
}
@@ -144,9 +149,11 @@ func ConvertPaths(v2Paths *spec.Paths) *spec3.Paths {
144149
}
145150
paths := &spec3.Paths{
146151
VendorExtensible: v2Paths.VendorExtensible,
147-
Paths: make(map[string]*spec3.Path),
148152
}
149153

154+
if len(v2Paths.Paths) > 0 {
155+
paths.Paths = make(map[string]*spec3.Path)
156+
}
150157
for k, v := range v2Paths.Paths {
151158
paths.Paths[k] = ConvertPathItem(v)
152159
}
@@ -157,14 +164,13 @@ func ConvertPathItem(v2pathItem spec.PathItem) *spec3.Path {
157164
path := &spec3.Path{
158165
Refable: v2pathItem.Refable,
159166
PathProps: spec3.PathProps{
160-
Get: ConvertOperation(v2pathItem.Get),
161-
Put: ConvertOperation(v2pathItem.Put),
162-
Post: ConvertOperation(v2pathItem.Post),
163-
Delete: ConvertOperation(v2pathItem.Delete),
164-
Options: ConvertOperation(v2pathItem.Options),
165-
Head: ConvertOperation(v2pathItem.Head),
166-
Patch: ConvertOperation(v2pathItem.Patch),
167-
Parameters: []*spec3.Parameter{},
167+
Get: ConvertOperation(v2pathItem.Get),
168+
Put: ConvertOperation(v2pathItem.Put),
169+
Post: ConvertOperation(v2pathItem.Post),
170+
Delete: ConvertOperation(v2pathItem.Delete),
171+
Options: ConvertOperation(v2pathItem.Options),
172+
Head: ConvertOperation(v2pathItem.Head),
173+
Patch: ConvertOperation(v2pathItem.Patch),
168174
},
169175
VendorExtensible: v2pathItem.VendorExtensible,
170176
}
@@ -187,16 +193,16 @@ func ConvertOperation(v2Operation *spec.Operation) *spec3.Operation {
187193
Summary: v2Operation.Summary,
188194
Deprecated: v2Operation.Deprecated,
189195
OperationId: v2Operation.ID,
190-
Parameters: []*spec3.Parameter{},
191196
},
192197
}
193198

194199
for _, param := range v2Operation.Parameters {
195200
if param.ParamProps.Name == "body" && param.ParamProps.Schema != nil {
196201
operation.OperationProps.RequestBody = &spec3.RequestBody{
197-
RequestBodyProps: spec3.RequestBodyProps{
198-
Content: make(map[string]*spec3.MediaType),
199-
},
202+
RequestBodyProps: spec3.RequestBodyProps{},
203+
}
204+
if len(v2Operation.Consumes) > 0 {
205+
operation.RequestBody.Content = make(map[string]*spec3.MediaType)
200206
}
201207
for _, consumer := range v2Operation.Consumes {
202208
operation.RequestBody.Content[consumer] = &spec3.MediaType{
@@ -205,17 +211,20 @@ func ConvertOperation(v2Operation *spec.Operation) *spec3.Operation {
205211
},
206212
}
207213
}
214+
} else {
215+
operation.Parameters = append(operation.Parameters, ConvertParameter(param))
208216
}
209-
operation.Parameters = append(operation.Parameters, ConvertParameter(param))
210217
}
211218

212219
operation.Responses = &spec3.Responses{ResponsesProps: spec3.ResponsesProps{
213220
Default: ConvertResponse(v2Operation.Responses.Default, v2Operation.Produces),
214-
StatusCodeResponses: make(map[int]*spec3.Response),
215221
},
216-
VendorExtensible: v2Operation.VendorExtensible,
222+
VendorExtensible: v2Operation.Responses.VendorExtensible,
217223
}
218224

225+
if len(v2Operation.Responses.StatusCodeResponses) > 0 {
226+
operation.Responses.StatusCodeResponses = make(map[int]*spec3.Response)
227+
}
219228
for k, v := range v2Operation.Responses.StatusCodeResponses {
220229
operation.Responses.StatusCodeResponses[k] = ConvertResponse(&v, v2Operation.Produces)
221230
}
@@ -231,12 +240,13 @@ func ConvertResponse(v2Response *spec.Response, produces []string) *spec3.Respon
231240
VendorExtensible: v2Response.VendorExtensible,
232241
ResponseProps: spec3.ResponseProps{
233242
Description: v2Response.Description,
234-
Headers: make(map[string]*spec3.Header),
235-
Content: make(map[string]*spec3.MediaType),
236243
},
237244
}
238245

239246
if v2Response.Schema != nil {
247+
if len(produces) > 0 {
248+
response.Content = make(map[string]*spec3.MediaType)
249+
}
240250
for _, producer := range produces {
241251
response.ResponseProps.Content[producer] = &spec3.MediaType{
242252
MediaTypeProps: spec3.MediaTypeProps{
@@ -261,6 +271,17 @@ func ConvertParameter(v2Param spec.Parameter) *spec3.Parameter {
261271
AllowEmptyValue: v2Param.AllowEmptyValue,
262272
},
263273
}
274+
// Convert SimpleSchema into Schema
275+
if param.Schema == nil {
276+
param.Schema = &spec.Schema{
277+
SchemaProps: spec.SchemaProps{
278+
Type: []string{v2Param.Type},
279+
Format: v2Param.Format,
280+
UniqueItems: v2Param.UniqueItems,
281+
},
282+
}
283+
}
284+
264285
return param
265286
}
266287

pkg/openapiconv/convert_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
Copyright 2022 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package openapiconv
18+
19+
import (
20+
"encoding/json"
21+
"io/ioutil"
22+
"path/filepath"
23+
"reflect"
24+
"testing"
25+
26+
"k8s.io/kube-openapi/pkg/spec3"
27+
"k8s.io/kube-openapi/pkg/validation/spec"
28+
)
29+
30+
func TestConvert(t *testing.T) {
31+
32+
tcs := []struct {
33+
groupVersion string
34+
}{{
35+
"batch.v1",
36+
}, {
37+
"api.v1",
38+
}, {
39+
"apiextensions.k8s.io.v1",
40+
}}
41+
42+
for _, tc := range tcs {
43+
44+
spec2JSON, err := ioutil.ReadFile(filepath.Join("testdata/v2_" + tc.groupVersion + ".json"))
45+
if err != nil {
46+
t.Fatal(err)
47+
}
48+
var swaggerSpec spec.Swagger
49+
err = json.Unmarshal(spec2JSON, &swaggerSpec)
50+
if err != nil {
51+
t.Fatal(err)
52+
}
53+
54+
convertedV3Spec := ConvertV2ToV3(&swaggerSpec)
55+
if err != nil {
56+
t.Fatal(err)
57+
}
58+
spec3JSON, err := ioutil.ReadFile(filepath.Join("testdata/v3_" + tc.groupVersion + ".json"))
59+
if err != nil {
60+
t.Fatal(err)
61+
}
62+
var V3Spec spec3.OpenAPI
63+
json.Unmarshal(spec3JSON, &V3Spec)
64+
65+
if !reflect.DeepEqual(V3Spec, *convertedV3Spec) {
66+
t.Error("Expected specs to be equal")
67+
}
68+
}
69+
}

pkg/openapiconv/testdata/v2_api.v1.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

pkg/openapiconv/testdata/v2_apiextensions.k8s.io.v1.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

pkg/openapiconv/testdata/v2_batch.v1.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

pkg/openapiconv/testdata/v3_api.v1.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

pkg/openapiconv/testdata/v3_apiextensions.k8s.io.v1.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)