Skip to content

Commit

Permalink
preferred header takes precedence over lowest 2xx
Browse files Browse the repository at this point in the history
  • Loading branch information
macyabbey authored and daveshanley committed Apr 3, 2024
1 parent 8b09671 commit 3dc943f
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 6 deletions.
45 changes: 42 additions & 3 deletions mock/mock_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,11 +297,23 @@ func (rme *ResponseMockEngine) runWorkflow(request *http.Request) ([]byte, int,

}

// get the lowest success code
preferred := rme.extractPreferred(request)
lo := rme.findLowestSuccessCode(operation)

// find the lowest success code.
mt, noMT := rme.lookForResponseCodes(operation, request, []string{lo})
var mt *v3.MediaType
var noMT bool = true

if preferred != "" {
// If an explicit preferred header is present, let it have a chance to take precedence
// This can lead to a preferred header leading to a 3xx, 4xx, or 5xx example response.
mt, lo, noMT = rme.findMediaTypeContainingNamedExample(operation, request, preferred)
}

if (noMT) {
// find the lowest success code.
mt, noMT = rme.lookForResponseCodes(operation, request, []string{lo})
}

if mt == nil && noMT {
mtString := rme.extractMediaTypeHeader(request)
return rme.buildError(
Expand All @@ -326,6 +338,33 @@ func (rme *ResponseMockEngine) runWorkflow(request *http.Request) ([]byte, int,
return mock, c, nil
}

func (rme *ResponseMockEngine) findMediaTypeContainingNamedExample(
operation *v3.Operation,
request *http.Request,
preferredExample string) (*v3.MediaType, string, bool) {

mediaTypeString := rme.extractMediaTypeHeader(request)

for codePairs := operation.Responses.Codes.First(); codePairs != nil; codePairs = codePairs.Next() {
resp := codePairs.Value()

if resp.Content != nil {
responseBody := resp.Content.GetOrZero(mediaTypeString)
if responseBody == nil {
responseBody = resp.Content.GetOrZero("application/json")
}

_, present := responseBody.Examples.Get(preferredExample)

if present {
return responseBody, codePairs.Key(), false
}
}
}

return nil, "", true
}

func (rme *ResponseMockEngine) findLowestSuccessCode(operation *v3.Operation) string {
var lowestCode = 299

Expand Down
86 changes: 83 additions & 3 deletions mock/mock_engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ package mock
import (
"bytes"
"encoding/json"
"io"
"net/http"
"testing"

"github.com/pb33f/libopenapi"
"github.com/pb33f/libopenapi-validator/helpers"
v3 "github.com/pb33f/libopenapi/datamodel/high/v3"
"github.com/stretchr/testify/assert"
"io"
"net/http"
"testing"
)

// var doc *v3.Document
Expand Down Expand Up @@ -843,6 +844,85 @@ components:

}

// https://github.com/pb33f/wiretap/issues/84
func TestNewMockEngine_UseExamples_Preferred_From_400(t *testing.T) {

spec := `openapi: 3.1.0
paths:
/test:
get:
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/Thing'
examples:
happyDays:
value:
name: happy days
description: a terrible show from a time that never existed.
robocop:
value:
name: robocop
description: perhaps the best cyberpunk movie ever made.
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorThing'
examples:
sadErrorDays:
value:
name: sad error days
description: a sad error prone show
sadcop:
value:
name: sad cop
description: perhaps the saddest cyberpunk movie ever made.
components:
schemas:
Thing:
type: object
properties:
name:
type: string
example: nameExample
description:
type: string
example: descriptionExample
ErrorThing:
type: object
properties:
name:
type: string
example: errorNameExample
description:
type: string
example: errorDescriptionExample
`

d, _ := libopenapi.NewDocument([]byte(spec))
doc, _ := d.BuildV3Model()

me := NewMockEngine(&doc.Model, false)

request, _ := http.NewRequest(http.MethodGet, "https://api.pb33f.io/test", nil)
request.Header.Set(helpers.Preferred, "sadcop")

b, status, err := me.GenerateResponse(request)

assert.NoError(t, err)
assert.Equal(t, 400, status)

var decoded map[string]any
_ = json.Unmarshal(b, &decoded)

assert.Equal(t, "sad cop", decoded["name"])
assert.Equal(t, "perhaps the saddest cyberpunk movie ever made.", decoded["description"])

}

// https://github.com/pb33f/wiretap/issues/84
func TestNewMockEngine_UseExamples_FromSchema(t *testing.T) {

Expand Down

0 comments on commit 3dc943f

Please sign in to comment.