Skip to content

Commit

Permalink
Add SetStringResponse (#38)
Browse files Browse the repository at this point in the history
  • Loading branch information
vearutop authored Jul 29, 2022
1 parent 473314e commit af6d025
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 57 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/gorelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ jobs:
with:
path: |
~/go/bin/gorelease
key: ${{ runner.os }}-gorelease-fork
key: ${{ runner.os }}-gorelease-generic
- name: Gorelease
id: gorelease
run: |
test -e ~/go/bin/gorelease || (rm -rf /tmp/gorelease && mkdir -p /tmp/gorelease && cd /tmp/gorelease && go mod init foo && go mod edit -replace golang.org/x/exp=github.com/vearutop/golang-exp@gorelease-generic && go get golang.org/x/exp/cmd/gorelease && go install golang.org/x/exp/cmd/gorelease)
test -e ~/go/bin/gorelease || go install golang.org/x/exp/cmd/gorelease@latest
OUTPUT=$(gorelease 2>&1 || exit 0)
echo "${OUTPUT}"
OUTPUT="${OUTPUT//$'\n'/%0A}"
Expand Down
71 changes: 49 additions & 22 deletions .github/workflows/test-unit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,20 @@ env:
GO111MODULE: "on"
RUN_BASE_COVERAGE: "on" # Runs test for PR base in case base test coverage is missing.
COV_GO_VERSION: 1.18.x # Version of Go to collect coverage
TARGET_DELTA_COV: 90 # Target coverage of changed lines, in percents
jobs:
test:
strategy:
matrix:
go-version: [ 1.13.x, 1.14.x, 1.15.x, 1.16.x, 1.17.x, 1.18.x ]
go-version: [ 1.16.x, 1.17.x, 1.18.x ]
runs-on: ubuntu-latest
steps:
- name: Install Go stable
if: matrix.go-version != 'tip'
uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go-version }}

- name: Install Go tip
if: matrix.go-version == 'tip'
run: |
Expand All @@ -37,8 +39,10 @@ jobs:
tar -C ~/sdk/gotip -xzf gotip.tar.gz
~/sdk/gotip/bin/go version
echo "PATH=$HOME/go/bin:$HOME/sdk/gotip/bin/:$PATH" >> $GITHUB_ENV
- name: Checkout code
uses: actions/checkout@v2

- name: Go cache
uses: actions/cache@v2
with:
Expand All @@ -51,58 +55,81 @@ jobs:
key: ${{ runner.os }}-go-cache-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-cache
- name: Restore base test coverage
id: base-coverage
if: matrix.go-version == env.COV_GO_VERSION
if: matrix.go-version == env.COV_GO_VERSION && github.event.pull_request.base.sha != ''
uses: actions/cache@v2
with:
path: |
unit-base.txt
# Use base sha for PR or new commit hash for master/main push in test result key.
key: ${{ runner.os }}-unit-test-coverage-${{ (github.event.pull_request.base.sha != github.event.after) && github.event.pull_request.base.sha || github.event.after }}
- name: Checkout base code
if: matrix.go-version == env.COV_GO_VERSION && env.RUN_BASE_COVERAGE == 'on' && steps.base-coverage.outputs.cache-hit != 'true' && github.event.pull_request.base.sha != ''
uses: actions/checkout@v2
with:
ref: ${{ github.event.pull_request.base.sha }}
path: __base

- name: Run test for base code
if: matrix.go-version == env.COV_GO_VERSION && env.RUN_BASE_COVERAGE == 'on' && steps.base-coverage.outputs.cache-hit != 'true' && github.event.pull_request.base.sha != ''
run: |
cd __base
make | grep test-unit && (make test-unit && go tool cover -func=./unit.coverprofile | sed -e 's/.go:[0-9]*:\t/.go\t/g' | sed -e 's/\t\t*/\t/g' > ../unit-base.txt) || echo "No test-unit in base"
git fetch origin master ${{ github.event.pull_request.base.sha }}
HEAD=$(git rev-parse HEAD)
git reset --hard ${{ github.event.pull_request.base.sha }}
(make test-unit && go tool cover -func=./unit.coverprofile > unit-base.txt) || echo "No test-unit in base"
git reset --hard $HEAD
- name: Test
id: test
run: |
make test-unit
go tool cover -func=./unit.coverprofile | sed -e 's/.go:[0-9]*:\t/.go\t/g' | sed -e 's/\t\t*/\t/g' > unit.txt
OUTPUT=$(test -e unit-base.txt && (diff unit-base.txt unit.txt || exit 0) || cat unit.txt)
echo "${OUTPUT}"
OUTPUT="${OUTPUT//$'\n'/%0A}"
go tool cover -func=./unit.coverprofile > unit.txt
TOTAL=$(grep 'total:' unit.txt)
echo "${TOTAL}"
echo "::set-output name=diff::$OUTPUT"
echo "::set-output name=total::$TOTAL"
- name: Store base coverage
if: ${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' }}
run: cp unit.txt unit-base.txt
- name: Annotate missing test coverage
id: annotate
if: matrix.go-version == env.COV_GO_VERSION && github.event.pull_request.base.sha != ''
run: |
curl -sLO https://github.com/vearutop/gocovdiff/releases/download/v1.3.6/linux_amd64.tar.gz && tar xf linux_amd64.tar.gz
gocovdiff_hash=$(git hash-object ./gocovdiff)
[ "$gocovdiff_hash" == "8e507e0d671d4d6dfb3612309b72b163492f28eb" ] || (echo "::error::unexpected hash for gocovdiff, possible tampering: $gocovdiff_hash" && exit 1)
git fetch origin master ${{ github.event.pull_request.base.sha }}
REP=$(./gocovdiff -cov unit.coverprofile -gha-annotations gha-unit.txt -delta-cov-file delta-cov-unit.txt -target-delta-cov ${TARGET_DELTA_COV})
echo "${REP}"
REP="${REP//$'\n'/%0A}"
cat gha-unit.txt
DIFF=$(test -e unit-base.txt && ./gocovdiff -func-cov unit.txt -func-base-cov unit-base.txt || echo "Missing base coverage file")
DIFF="${DIFF//$'\n'/%0A}"
TOTAL=$(cat delta-cov-unit.txt)
echo "::set-output name=rep::$REP"
echo "::set-output name=diff::$DIFF"
echo "::set-output name=total::$TOTAL"
- name: Comment Test Coverage
continue-on-error: true
if: matrix.go-version == env.COV_GO_VERSION
if: matrix.go-version == env.COV_GO_VERSION && github.event.pull_request.base.sha != ''
uses: marocchino/sticky-pull-request-comment@v2
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
header: unit-test
message: |
### Unit Test Coverage
${{ steps.test.outputs.total }}
${{ steps.annotate.outputs.total }}
<details><summary>Coverage of changed lines</summary>
${{ steps.annotate.outputs.rep }}
</details>
<details><summary>Coverage diff with base branch</summary>
```diff
${{ steps.test.outputs.diff }}
```
${{ steps.annotate.outputs.diff }}
</details>
- name: Store base coverage
if: ${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' }}
run: cp unit.txt unit-base.txt

- name: Upload code coverage
if: matrix.go-version == env.COV_GO_VERSION
uses: codecov/codecov-action@v1
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ module github.com/swaggest/openapi-go
go 1.17

require (
github.com/bool64/dev v0.2.12
github.com/stretchr/testify v1.7.1
github.com/bool64/dev v0.2.18
github.com/stretchr/testify v1.8.0
github.com/swaggest/assertjson v1.7.0
github.com/swaggest/jsonschema-go v0.3.35
github.com/swaggest/refl v1.0.2
github.com/swaggest/refl v1.1.0
gopkg.in/yaml.v2 v2.4.0
)

Expand Down
12 changes: 8 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ github.com/bool64/dev v0.1.25/go.mod h1:cTHiTDNc8EewrQPy3p1obNilpMpdmlUesDkFTF2z
github.com/bool64/dev v0.1.41/go.mod h1:cTHiTDNc8EewrQPy3p1obNilpMpdmlUesDkFTF2zRWU=
github.com/bool64/dev v0.2.5/go.mod h1:cTHiTDNc8EewrQPy3p1obNilpMpdmlUesDkFTF2zRWU=
github.com/bool64/dev v0.2.10/go.mod h1:/csLrm+4oDSsKJRIVS0mrywAonLnYKFG8RvGT7Jh9b8=
github.com/bool64/dev v0.2.12 h1:XXXE1Eh2//Dmp1hr+SqjxIXOEjq6D3Y5SwbGowpIK4I=
github.com/bool64/dev v0.2.12/go.mod h1:/csLrm+4oDSsKJRIVS0mrywAonLnYKFG8RvGT7Jh9b8=
github.com/bool64/dev v0.2.16/go.mod h1:/csLrm+4oDSsKJRIVS0mrywAonLnYKFG8RvGT7Jh9b8=
github.com/bool64/dev v0.2.18 h1:FPXZxR4+bgNgBKtORwCr7W/s46bY/LkKFwVy8f63cqI=
github.com/bool64/dev v0.2.18/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
github.com/bool64/shared v0.1.3/go.mod h1:RF1p1Oi29ofgOvinBpetbF5mceOUP3kpMkvLbWOmtm0=
github.com/bool64/shared v0.1.4 h1:zwtb1dl2QzDa9TJOq2jzDTdb5IPf9XlxTGKN8cySWT0=
github.com/bool64/shared v0.1.4/go.mod h1:ryGjsnQFh6BnEXClfVlEJrzjwzat7CmA8PNS5E+jPp0=
Expand Down Expand Up @@ -55,16 +56,19 @@ github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNX
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/swaggest/assertjson v1.6.8/go.mod h1:Euf0upn9Vlaf1/llYHTs+Kx5K3vVbpMbsZhth7zlN7M=
github.com/swaggest/assertjson v1.7.0 h1:SKw5Rn0LQs6UvmGrIdaKQbMR1R3ncXm5KNon+QJ7jtw=
github.com/swaggest/assertjson v1.7.0/go.mod h1:vxMJMehbSVJd+dDWFCKv3QRZKNTpy/ktZKTz9LOEDng=
github.com/swaggest/jsonschema-go v0.3.35 h1:LW5DC0WgR5YdQXyTRc5e8gLdKT0wkACg4aVJyaseU+4=
github.com/swaggest/jsonschema-go v0.3.35/go.mod h1:JAF1nm+uIaMOXktuQepmkiRcgQ5yJk4Ccwx9HVt2cXw=
github.com/swaggest/refl v1.0.2 h1:VmP8smuDS1EzUPn31++TzMi13CAaVJdlWpIxzj0up88=
github.com/swaggest/refl v1.0.2/go.mod h1:DoiPoBJPYHU6Z9fIA6zXQ9uI6VRL6M8BFX5YFT+ym9g=
github.com/swaggest/refl v1.1.0 h1:a+9a75Kv6ciMozPjVbOfcVTEQe81t2R3emvaD9oGQGc=
github.com/swaggest/refl v1.1.0/go.mod h1:g3Qa6ki0A/L2yxiuUpT+cuBURuRaltF5SDQpg1kMZSY=
github.com/yosuke-furukawa/json5 v0.1.2-0.20201207051438-cf7bb3f354ff/go.mod h1:sw49aWDqNdRJ6DYUtIQiaA3xyj2IL9tjeNYmX2ixwcU=
github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
Expand Down
5 changes: 4 additions & 1 deletion openapi3/_testdata/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,10 @@
"schema":{"type":"string","description":"Sample header response."}
}
},
"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Openapi3TestResp"}}}}
"content":{
"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Openapi3TestResp"}}},
"text/html":{"schema":{"type":"string"}}
}
}
}
}
Expand Down
33 changes: 24 additions & 9 deletions openapi3/reflect.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,15 @@ func (r *Reflector) parseResponseHeader(resp *Response, oc OperationContext) err
return nil
}

// SetStringResponse sets unstructured response.
func (r *Reflector) SetStringResponse(o *Operation, httpStatus int, contentType string) error {
return r.SetupResponse(OperationContext{
Operation: o,
HTTPStatus: httpStatus,
RespContentType: contentType,
})
}

// SetJSONResponse sets up operation JSON response.
func (r *Reflector) SetJSONResponse(o *Operation, output interface{}, httpStatus int) error {
return r.SetupResponse(OperationContext{
Expand Down Expand Up @@ -443,32 +452,37 @@ func (r *Reflector) hasJSONBody(output interface{}) (bool, error) {

// SetupResponse sets up operation response.
func (r *Reflector) SetupResponse(oc OperationContext) error {
resp := Response{}
httpStatus := strconv.Itoa(oc.HTTPStatus)
resp := oc.Operation.Responses.MapOfResponseOrRefValues[httpStatus].Response

if resp == nil {
resp = &Response{}
}

if oc.Output != nil {
oc.RespContentType = strings.Split(oc.RespContentType, ";")[0]

err := r.parseJSONResponse(&resp, oc)
err := r.parseJSONResponse(resp, oc)
if err != nil {
return err
}

err = r.parseResponseHeader(&resp, oc)
err = r.parseResponseHeader(resp, oc)
if err != nil {
return err
}
}

if oc.RespContentType != "" {
r.ensureResponseContentType(&resp, oc.RespContentType)
}
if oc.RespContentType != "" {
r.ensureResponseContentType(resp, oc.RespContentType)
}

if resp.Description == "" {
resp.Description = http.StatusText(oc.HTTPStatus)
}

oc.Operation.Responses.WithMapOfResponseOrRefValuesItem(strconv.Itoa(oc.HTTPStatus), ResponseOrRef{
Response: &resp,
oc.Operation.Responses.WithMapOfResponseOrRefValuesItem(httpStatus, ResponseOrRef{
Response: resp,
})

return nil
Expand All @@ -480,8 +494,9 @@ func (r *Reflector) ensureResponseContentType(resp *Response, contentType string
resp.Content = map[string]MediaType{}
}

typeString := SchemaTypeString
resp.Content[contentType] = MediaType{
Schema: &SchemaOrRef{Schema: &Schema{}},
Schema: &SchemaOrRef{Schema: &Schema{Type: &typeString}},
}
}
}
Expand Down
45 changes: 29 additions & 16 deletions openapi3/reflect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,14 +191,10 @@ func TestReflector_SetJSONResponse(t *testing.T) {

op := openapi3.Operation{}

err := reflector.SetRequest(&op, new(Req), http.MethodPost)
assert.NoError(t, err)

err = reflector.SetJSONResponse(&op, new(WeirdResp), http.StatusOK)
assert.NoError(t, err)

err = reflector.SetJSONResponse(&op, new([]WeirdResp), http.StatusConflict)
assert.NoError(t, err)
assert.NoError(t, reflector.SetRequest(&op, new(Req), http.MethodPost))
assert.NoError(t, reflector.SetJSONResponse(&op, new(WeirdResp), http.StatusOK))
assert.NoError(t, reflector.SetJSONResponse(&op, new([]WeirdResp), http.StatusConflict))
assert.NoError(t, reflector.SetStringResponse(&op, http.StatusConflict, "text/html"))

pathItem := openapi3.PathItem{}
pathItem.
Expand All @@ -217,12 +213,8 @@ func TestReflector_SetJSONResponse(t *testing.T) {

op = openapi3.Operation{}

err = reflector.SetRequest(&op, new(GetReq), http.MethodGet)
assert.NoError(t, err)

err = reflector.SetJSONResponse(&op, new(Resp), http.StatusOK)
assert.NoError(t, err)

assert.NoError(t, reflector.SetRequest(&op, new(GetReq), http.MethodGet))
assert.NoError(t, reflector.SetJSONResponse(&op, new(Resp), http.StatusOK))
assert.NoError(t, s.AddOperation(http.MethodGet, "/somewhere/{in_path}", op))

js = op.Responses.MapOfResponseOrRefValues[strconv.Itoa(http.StatusOK)].Response.Content["application/json"].
Expand Down Expand Up @@ -255,7 +247,7 @@ func TestReflector_SetJSONResponse(t *testing.T) {
expected, err = ioutil.ReadFile("_testdata/openapi.json")
require.NoError(t, err)

assertjson.Equal(t, expected, b)
assertjson.EqualMarshal(t, expected, s)
}

type Identity struct {
Expand Down Expand Up @@ -379,7 +371,7 @@ func TestReflector_SetupResponse(t *testing.T) {
"X-Value-1":{"style":"simple","schema":{"type":"integer"}},
"X-Value-2":{"style":"simple","schema":{"type":"string"}}
},
"content":{"text/csv":{"schema":{}}}
"content":{"text/csv":{"schema":{"type":"string"}}}
}
}
}
Expand Down Expand Up @@ -753,3 +745,24 @@ func TestOperationCtx(t *testing.T) {
"resp:header": true,
}, visited)
}

func TestReflector_SetStringResponse(t *testing.T) {
reflector := openapi3.Reflector{}

s := reflector.SpecEns()
s.Info.Title = apiName
s.Info.Version = apiVersion

reflector.AddTypeMapping(new(WeirdResp), new(Resp))

op := openapi3.Operation{}

err := reflector.SetRequest(&op, new(Req), http.MethodPost)
assert.NoError(t, err)

err = reflector.SetJSONResponse(&op, new(WeirdResp), http.StatusOK)
assert.NoError(t, err)

err = reflector.SetJSONResponse(&op, new([]WeirdResp), http.StatusConflict)
assert.NoError(t, err)
}

0 comments on commit af6d025

Please sign in to comment.