Skip to content

Commit 4967c03

Browse files
committed
Fix gob encoding on operations
Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
1 parent c3754ea commit 4967c03

File tree

5 files changed

+248
-0
lines changed

5 files changed

+248
-0
lines changed

.golangci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,5 @@ linters:
1919
- maligned
2020
- unparam
2121
- lll
22+
- gochecknoinits
23+
- gochecknoglobals

info_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,13 @@ func TestIntegrationInfo_Deserialize(t *testing.T) {
6363
assert.EqualValues(t, info, actual)
6464
}
6565
}
66+
67+
func TestInfoGobEncoding(t *testing.T) {
68+
var src, dst Info
69+
if assert.NoError(t, json.Unmarshal([]byte(infoJSON), &src)) {
70+
assert.EqualValues(t, src, info)
71+
} else {
72+
t.FailNow()
73+
}
74+
doTestAnyGobEncoding(t, &src, &dst)
75+
}

operation.go

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,20 @@
1515
package spec
1616

1717
import (
18+
"bytes"
19+
"encoding/gob"
1820
"encoding/json"
1921

2022
"github.com/go-openapi/jsonpointer"
2123
"github.com/go-openapi/swag"
2224
)
2325

26+
func init() {
27+
//gob.Register(map[string][]interface{}{})
28+
gob.Register(map[string]interface{}{})
29+
gob.Register([]interface{}{})
30+
}
31+
2432
// OperationProps describes an operation
2533
type OperationProps struct {
2634
Description string `json:"description,omitempty"`
@@ -257,3 +265,126 @@ func (o *Operation) RespondsWith(code int, response *Response) *Operation {
257265
o.Responses.StatusCodeResponses[code] = *response
258266
return o
259267
}
268+
269+
type opsAlias OperationProps
270+
271+
type gobAlias struct {
272+
Security []map[string]struct {
273+
List []string
274+
Pad bool
275+
}
276+
Alias *opsAlias
277+
SecurityIsEmpty bool
278+
}
279+
280+
// GobEncode provides a safe gob encoder for Operation, including empty security requirements
281+
func (o Operation) GobEncode() ([]byte, error) {
282+
raw := struct {
283+
Ext VendorExtensible
284+
Props OperationProps
285+
}{
286+
Ext: o.VendorExtensible,
287+
Props: o.OperationProps,
288+
}
289+
var b bytes.Buffer
290+
err := gob.NewEncoder(&b).Encode(raw)
291+
return b.Bytes(), err
292+
}
293+
294+
// GobDecode provides a safe gob decoder for Operation, including empty security requirements
295+
func (o *Operation) GobDecode(b []byte) error {
296+
var raw struct {
297+
Ext VendorExtensible
298+
Props OperationProps
299+
}
300+
301+
buf := bytes.NewBuffer(b)
302+
err := gob.NewDecoder(buf).Decode(&raw)
303+
if err != nil {
304+
return err
305+
}
306+
o.VendorExtensible = raw.Ext
307+
o.OperationProps = raw.Props
308+
return nil
309+
}
310+
311+
// GobEncode provides a safe gob encoder for Operation, including empty security requirements
312+
func (op OperationProps) GobEncode() ([]byte, error) {
313+
raw := gobAlias{
314+
Alias: (*opsAlias)(&op),
315+
}
316+
317+
var b bytes.Buffer
318+
if op.Security == nil {
319+
// nil security requirement
320+
err := gob.NewEncoder(&b).Encode(raw)
321+
return b.Bytes(), err
322+
}
323+
324+
if len(op.Security) == 0 {
325+
// empty, but non-nil security requirement
326+
raw.SecurityIsEmpty = true
327+
raw.Alias.Security = nil
328+
err := gob.NewEncoder(&b).Encode(raw)
329+
return b.Bytes(), err
330+
}
331+
332+
raw.Security = make([]map[string]struct {
333+
List []string
334+
Pad bool
335+
}, 0, len(op.Security))
336+
for _, req := range op.Security {
337+
v := make(map[string]struct {
338+
List []string
339+
Pad bool
340+
}, len(req))
341+
for k, val := range req {
342+
v[k] = struct {
343+
List []string
344+
Pad bool
345+
}{
346+
List: val,
347+
}
348+
}
349+
raw.Security = append(raw.Security, v)
350+
}
351+
352+
err := gob.NewEncoder(&b).Encode(raw)
353+
return b.Bytes(), err
354+
}
355+
356+
// GobDecode provides a safe gob decoder for Operation, including empty security requirements
357+
func (op *OperationProps) GobDecode(b []byte) error {
358+
var raw gobAlias
359+
360+
buf := bytes.NewBuffer(b)
361+
err := gob.NewDecoder(buf).Decode(&raw)
362+
if err != nil {
363+
return err
364+
}
365+
if raw.Alias == nil {
366+
return nil
367+
}
368+
369+
switch {
370+
case raw.SecurityIsEmpty:
371+
// empty, but non-nil security requirement
372+
raw.Alias.Security = []map[string][]string{}
373+
case len(raw.Alias.Security) == 0:
374+
// nil security requirement
375+
raw.Alias.Security = nil
376+
default:
377+
raw.Alias.Security = make([]map[string][]string, 0, len(raw.Security))
378+
for _, req := range raw.Security {
379+
v := make(map[string][]string, len(req))
380+
for k, val := range req {
381+
v[k] = make([]string, 0, len(val.List))
382+
v[k] = append(v[k], val.List...)
383+
}
384+
raw.Alias.Security = append(raw.Alias.Security, v)
385+
}
386+
}
387+
388+
*op = *(*OperationProps)(raw.Alias)
389+
return nil
390+
}

operation_test.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
package spec
1616

1717
import (
18+
"bytes"
19+
"encoding/gob"
1820
"encoding/json"
1921
"testing"
2022

@@ -103,5 +105,100 @@ func TestSecurityProperty(t *testing.T) {
103105
assert.Equal(t, securityContainsEmptyArray, props)
104106
}
105107
}
108+
}
109+
110+
func TestOperationGobEncoding(t *testing.T) {
111+
// 1. empty scope in security requirements: "security": [ { "apiKey": [] } ],
112+
doTestOperationGobEncoding(t, operationJSON)
113+
114+
// 2. nil security requirements
115+
doTestOperationGobEncoding(t, `{
116+
"description": "operation description",
117+
"x-framework": "go-swagger",
118+
"consumes": [ "application/json", "application/x-yaml" ],
119+
"produces": [ "application/json", "application/x-yaml" ],
120+
"schemes": ["http", "https"],
121+
"tags": ["dogs"],
122+
"summary": "the summary of the operation",
123+
"operationId": "sendCat",
124+
"deprecated": true,
125+
"parameters": [{"$ref":"Cat"}],
126+
"responses": {
127+
"default": {
128+
"description": "void response"
129+
}
130+
}
131+
}`)
106132

133+
// 3. empty security requirement
134+
doTestOperationGobEncoding(t, `{
135+
"description": "operation description",
136+
"x-framework": "go-swagger",
137+
"consumes": [ "application/json", "application/x-yaml" ],
138+
"produces": [ "application/json", "application/x-yaml" ],
139+
"schemes": ["http", "https"],
140+
"tags": ["dogs"],
141+
"security": [],
142+
"summary": "the summary of the operation",
143+
"operationId": "sendCat",
144+
"deprecated": true,
145+
"parameters": [{"$ref":"Cat"}],
146+
"responses": {
147+
"default": {
148+
"description": "void response"
149+
}
150+
}
151+
}`)
152+
153+
// 4. non-empty security requirements
154+
doTestOperationGobEncoding(t, `{
155+
"description": "operation description",
156+
"x-framework": "go-swagger",
157+
"consumes": [ "application/json", "application/x-yaml" ],
158+
"produces": [ "application/json", "application/x-yaml" ],
159+
"schemes": ["http", "https"],
160+
"tags": ["dogs"],
161+
"summary": "the summary of the operation",
162+
"security": [ { "scoped-auth": [ "phone", "email" ] , "api-key": []} ],
163+
"operationId": "sendCat",
164+
"deprecated": true,
165+
"parameters": [{"$ref":"Cat"}],
166+
"responses": {
167+
"default": {
168+
"description": "void response"
169+
}
170+
}
171+
}`)
172+
173+
}
174+
175+
func doTestOperationGobEncoding(t *testing.T, fixture string) {
176+
var src, dst Operation
177+
178+
if !assert.NoError(t, json.Unmarshal([]byte(fixture), &src)) {
179+
t.FailNow()
180+
}
181+
182+
doTestAnyGobEncoding(t, &src, &dst)
183+
}
184+
185+
func doTestAnyGobEncoding(t *testing.T, src, dst interface{}) {
186+
expectedJSON, _ := json.MarshalIndent(src, "", " ")
187+
188+
var b bytes.Buffer
189+
err := gob.NewEncoder(&b).Encode(src)
190+
if !assert.NoError(t, err) {
191+
t.FailNow()
192+
}
193+
194+
err = gob.NewDecoder(&b).Decode(dst)
195+
if !assert.NoError(t, err) {
196+
t.FailNow()
197+
}
198+
199+
jazon, err := json.MarshalIndent(dst, "", " ")
200+
if !assert.NoError(t, err) {
201+
t.FailNow()
202+
}
203+
assert.JSONEq(t, string(expectedJSON), string(jazon))
107204
}

parameters_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,11 @@ func TestParameterSerialization(t *testing.T) {
154154
`{"type":"object","in":"body","schema":{"type":"array","items":{"$ref":"Cat"}}}`)
155155

156156
}
157+
158+
func TestParameterGobEncoding(t *testing.T) {
159+
var src, dst Parameter
160+
if !assert.NoError(t, json.Unmarshal([]byte(parameterJSON), &src)) {
161+
t.FailNow()
162+
}
163+
doTestAnyGobEncoding(t, &src, &dst)
164+
}

0 commit comments

Comments
 (0)