Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Response header flat 73980 #89

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 2 additions & 10 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,9 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4

- name: execute unit tests
- name: execute unit tests, build & apitest
shell: bash
run: make test

- name: build executable for test suite
shell: bash
run: make build

- name: execute apitest
shell: bash
run: make apitest
run: make all

- name: Notify slack channel about a failure
if: ${{ failure() }}
Expand Down
38 changes: 5 additions & 33 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,44 +1,16 @@
GOOS ?= linux
GOARCH ?= amd64
GIT_COMMIT_SHA ?= $(shell git rev-list -1 HEAD)
LD_FLAGS = -ldflags="-X main.buildCommit=${GIT_COMMIT_SHA}"

all: test build apitest

deps:
go mod download github.com/clbanning/mxj
go get ./...

vet:
test:
go vet ./...

fmt:
go fmt ./...

test: deps fmt vet
go test -race -cover ./...

webtest:
go test -coverprofile=testcoverage.out
go tool cover -html=testcoverage.out

apitest:
apitest: build
./apitest -c apitest.test.yml --stop-on-fail -d test/

gox: deps
go get github.com/mitchellh/gox
gox ${LDFLAGS} -parallel=4 -output="./bin/apitest_{{.OS}}_{{.Arch}}"

clean:
rm -rfv ./apitest ./bin/* ./testcoverage.out

ci: deps
go build $(LD_FLAGS) -o bin/apitest_$(GOOS)_$(GOARCH) *.go

build: deps
go build $(LD_FLAGS)

build-linux: deps
GOOS=linux GOARCH=amd64 go build -o apitest-linux
build:
go build

.PHONY: all test apitest webtest gox build clean
.PHONY: all test apitest build clean
27 changes: 18 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,14 +224,14 @@ Manifest is loaded as **template**, so you can use variables, Go **range** and *
"query_params_from_store": {
"format": "formatFromDatastore",
// If the datastore key starts with an ?, wo do not throw an error if the key could not be found, but just
// do not set the query param. If the key "a" is not found it datastore, the queryparameter test will not be set
// do not set the query param. If the key "a" is not found it datastore, the query parameter test will not be set
"test": "?a"
},

// Additional headers that should be added to the request
"header": {
"header1": "value",
"header2": "value"
"header2": ["value1", "value2"]
},

// Cookies can be added to the request
Expand Down Expand Up @@ -270,7 +270,7 @@ Manifest is loaded as **template**, so you can use variables, Go **range** and *
}
],

// With header_from_you set a header to the value of the dat astore field
// With header_from_store you set a header to the value of the datastore field
// In this example we set the "Content-Type" header to the value "application/json"
// As "application/json" is stored as string in the datastore on index "contentType"
"header_from_store": {
Expand Down Expand Up @@ -298,13 +298,22 @@ Manifest is loaded as **template**, so you can use variables, Go **range** and *
// Expected http status code. See api documentation vor the right ones
"statuscode": 200,

// If you expect certain response headers, you can define them here. A single key can have mulitble headers (as defined in rfc2616)
// If you expect certain response headers, you can define them here. A single key can have multiple headers (as defined in rfc2616)
"header": {
"key1": [
"val1",
"val2",
"val3"
],

// Headers sharing the same key are concatenated using ";", if the comparison value is a simple string,
// thus "key1" can also be checked like this:
"key1": "val1;val2;val3"

// :control in header is always applied to the flat format
"key1:control": {
// see below, this is not applied against the array
},
"x-easydb-token": [
"csdklmwerf8ßwji02kopwfjko2"
]
Expand Down Expand Up @@ -808,6 +817,9 @@ In the example we use the jsonObject `test` and define some control structures o
}
```

### `body:control`

All controls, which are defined below, can also be applied to the complete response body itself by setting `body:control`. The control check functions work the same as on any other key. This can be combined with other controls inside the body.

## Available controls

Expand Down Expand Up @@ -1931,10 +1943,7 @@ The datastore stores all responses in a list. We can retrieve the response (as a
{
"statuscode": 200,
"header": {
"foo": [
"bar",
"baz"
]
"foo": "bar;baz"
},
"body": "..."
}
Expand Down Expand Up @@ -2658,7 +2667,7 @@ The endpoint `bounce` returns the binary of the request body, as well as the req
"param1": "abc"
},
"header": {
"header1": 123
"header1": "123"
},
"body": {
"file": "@path/to/file.jpg"
Expand Down
10 changes: 5 additions & 5 deletions api_testcase.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ type Case struct {
index int
dataStore *datastore.Datastore

standardHeader map[string]*string
standardHeader map[string]any // can be string or []string
standardHeaderFromStore map[string]string

ServerURL string `json:"server_url"`
Expand Down Expand Up @@ -471,7 +471,7 @@ func (testCase Case) loadRequest() (api.Request, error) {
func (testCase Case) loadExpectedResponse() (res api.Response, err error) {
// unspecified response is interpreted as status_code 200
if testCase.ResponseData == nil {
return api.NewResponse(http.StatusOK, nil, nil, nil, nil, nil, res.Format)
return api.NewResponse(http.StatusOK, nil, nil, nil, nil, res.Format)
}
spec, err := testCase.loadResponseSerialization(testCase.ResponseData)
if err != nil {
Expand Down Expand Up @@ -523,10 +523,10 @@ func (testCase Case) loadRequestSerialization() (api.Request, error) {
spec.ServerURL = testCase.ServerURL
}
if len(spec.Headers) == 0 {
spec.Headers = make(map[string]*string)
spec.Headers = make(map[string]any)
}
for k, v := range testCase.standardHeader {
if spec.Headers[k] == nil {
if _, exist := spec.Headers[k]; !exist {
spec.Headers[k] = v
}
}
Expand All @@ -535,7 +535,7 @@ func (testCase Case) loadRequestSerialization() (api.Request, error) {
spec.HeaderFromStore = make(map[string]string)
}
for k, v := range testCase.standardHeaderFromStore {
if spec.HeaderFromStore[k] == "" {
if _, exist := spec.HeaderFromStore[k]; !exist {
spec.HeaderFromStore[k] = v
}
}
Expand Down
13 changes: 6 additions & 7 deletions api_testsuite.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/url"
"os"
Expand All @@ -14,7 +14,6 @@ import (
"sync/atomic"
"time"

"github.com/pkg/errors"
"github.com/sirupsen/logrus"

"github.com/programmfabrik/apitest/internal/httpproxy"
Expand Down Expand Up @@ -43,8 +42,8 @@ type Suite struct {
Tests []any `json:"tests"`
Store map[string]any `json:"store"`

StandardHeader map[string]*string `yaml:"header" json:"header"`
StandardHeaderFromStore map[string]string `yaml:"header_from_store" json:"header_from_store"`
StandardHeader map[string]any `yaml:"header" json:"header"`
StandardHeaderFromStore map[string]string `yaml:"header_from_store" json:"header_from_store"`

Config TestToolConfig
datastore *datastore.Datastore
Expand Down Expand Up @@ -104,7 +103,7 @@ func NewTestSuite(config TestToolConfig, manifestPath string, manifestDir string
if httpServerReplaceHost != "" {
_, err = url.Parse("//" + httpServerReplaceHost)
if err != nil {
return nil, errors.Wrap(err, "set http_server_host failed (command argument)")
return nil, fmt.Errorf("set http_server_host failed (command argument): %w", err)
}
}
if suitePreload.HttpServer != nil {
Expand All @@ -115,7 +114,7 @@ func NewTestSuite(config TestToolConfig, manifestPath string, manifestDir string
// We need to append it as the golang URL parser is not smart enough to differenciate between hostname and protocol
_, err = url.Parse("//" + preloadHTTPAddrStr)
if err != nil {
return nil, errors.Wrap(err, "set http_server_host failed (manifesr addr)")
return nil, fmt.Errorf("set http_server_host failed (manifesr addr): %w", err)
}
}
suitePreload.HTTPServerHost = httpServerReplaceHost
Expand Down Expand Up @@ -440,7 +439,7 @@ func (ats *Suite) loadManifest() ([]byte, error) {
}
defer manifestFile.Close()

manifestTmpl, err := ioutil.ReadAll(manifestFile)
manifestTmpl, err := io.ReadAll(manifestFile)
if err != nil {
return res, fmt.Errorf("error loading manifest (%s): %s", ats.manifestPath, err)
}
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/programmfabrik/go-test-utils v0.0.0-20191114143449-b8e16b04adb1 h1:NbjvVAvjVfIse7/zgFpP0P93Hj3o4lRJCzGgkNQ87Gc=
github.com/programmfabrik/go-test-utils v0.0.0-20191114143449-b8e16b04adb1/go.mod h1:6Tg7G+t9KYiFa0sU8PpISt9RUgIpgrEI+tXvWz3tSIU=
github.com/programmfabrik/golib v0.0.0-20240226091422-733aede66819 h1:lJ+a0MLo4Dn2UTF0Q/nh9msLqP8MaNEL/RbJLop022g=
github.com/programmfabrik/golib v0.0.0-20240226091422-733aede66819/go.mod h1:qb4pSUhPsZ/UfvM/MBNwKHb6W7xL85uSi4od9emNHHw=
github.com/programmfabrik/golib v0.0.0-20240701125551-843bc5e3be55 h1:VBYGpSvjwHSa5ARrs6uPlUOJF1+n6rFWn49+++h20IU=
github.com/programmfabrik/golib v0.0.0-20240701125551-843bc5e3be55/go.mod h1:qb4pSUhPsZ/UfvM/MBNwKHb6W7xL85uSi4od9emNHHw=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
Expand Down
3 changes: 1 addition & 2 deletions http_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"context"
"encoding/json"
"io"
"io/ioutil"
"net/http"
"net/url"
"path/filepath"
Expand Down Expand Up @@ -155,7 +154,7 @@ func bounceJSON(w http.ResponseWriter, r *http.Request) {
bodyJSON, errorBody any
)

bodyBytes, err = ioutil.ReadAll(r.Body)
bodyBytes, err = io.ReadAll(r.Body)

if utf8.Valid(bodyBytes) {
if len(bodyBytes) > 0 {
Expand Down
16 changes: 7 additions & 9 deletions internal/httpproxy/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@ package httpproxy
import (
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/url"
"strconv"

"github.com/pkg/errors"

"github.com/programmfabrik/apitest/internal/handlerutil"
)

Expand Down Expand Up @@ -63,9 +61,9 @@ func (st *store) write(w http.ResponseWriter, r *http.Request) {
offset := len(st.Data)

if r.Body != nil {
reqData.Body, err = ioutil.ReadAll(r.Body)
reqData.Body, err = io.ReadAll(r.Body)
if err != nil {
handlerutil.RespondWithErr(w, http.StatusInternalServerError, errors.Errorf("Could not read request body: %s", err))
handlerutil.RespondWithErr(w, http.StatusInternalServerError, fmt.Errorf("Could not read request body: %w", err))
return
}
}
Expand All @@ -76,7 +74,7 @@ func (st *store) write(w http.ResponseWriter, r *http.Request) {
Offset int `json:"offset"`
}{offset})
if err != nil {
handlerutil.RespondWithErr(w, http.StatusInternalServerError, errors.Errorf("Could not encode response: %s", err))
handlerutil.RespondWithErr(w, http.StatusInternalServerError, fmt.Errorf("Could not encode response: %w", err))
}
}

Expand All @@ -94,14 +92,14 @@ func (st *store) read(w http.ResponseWriter, r *http.Request) {
if offsetStr != "" {
offset, err = strconv.Atoi(offsetStr)
if err != nil {
handlerutil.RespondWithErr(w, http.StatusBadRequest, errors.Errorf("Invalid offset %s", offsetStr))
handlerutil.RespondWithErr(w, http.StatusBadRequest, fmt.Errorf("Invalid offset %s", offsetStr))
return
}
}

count := len(st.Data)
if offset >= count {
handlerutil.RespondWithErr(w, http.StatusBadRequest, errors.Errorf("Offset (%d) is higher than count (%d)", offset, count))
handlerutil.RespondWithErr(w, http.StatusBadRequest, fmt.Errorf("Offset (%d) is higher than count (%d)", offset, count))
return
}

Expand All @@ -126,6 +124,6 @@ func (st *store) read(w http.ResponseWriter, r *http.Request) {

_, err = w.Write(req.Body)
if err != nil {
handlerutil.RespondWithErr(w, http.StatusInternalServerError, errors.Errorf("Could not encode response: %s", err))
handlerutil.RespondWithErr(w, http.StatusInternalServerError, fmt.Errorf("Could not encode response: %w", err))
}
}
Loading
Loading