From 9c6558e8265879d8821b3ec07b3cad6c29758ddc Mon Sep 17 00:00:00 2001 From: Sergei Makarov <33636772+siller174@users.noreply.github.com> Date: Mon, 12 Feb 2024 12:19:35 +0100 Subject: [PATCH] [ISSUE-44] add broken validation (#61) * [ISSUE-44] add broken validation * [ISSUE-44] add wrappers for errors, fix docs and linter * [ISSUE-44] fix docs, test * [ISSUE-44] fix linter --- .github/workflows/main.yml | 2 +- Makefile | 2 +- README.MD | 20 +- assert_broken.go | 69 ++++++ assert_broken_test.go | 98 ++++++++ assert_optional.go | 2 +- assert_test.go => assert_optional_test.go | 12 +- assert_require.go | 2 +- assert_require_test.go | 98 ++++++++ builder.go | 277 ++------------------- builder_asserts.go | 289 ++++++++++++++++++++++ builder_request.go | 30 +++ cute.go | 18 +- errors/broken.go | 47 ++++ errors/error.go | 19 +- errors/optional.go | 18 +- errors/require.go | 18 +- examples/single_test.go | 49 ++++ interface.go | 24 +- json_marshaler.go | 20 ++ jsonschema.go | 2 +- provider.go | 2 + result.go | 56 +++++ results_test.go => result_test.go | 9 +- results.go | 37 --- roundtripper.go | 3 +- step.go | 6 + test.go | 41 +-- test_test.go | 1 + 29 files changed, 925 insertions(+), 346 deletions(-) create mode 100644 assert_broken.go create mode 100644 assert_broken_test.go rename assert_test.go => assert_optional_test.go (89%) create mode 100644 assert_require_test.go create mode 100644 builder_asserts.go create mode 100644 builder_request.go create mode 100644 errors/broken.go create mode 100644 json_marshaler.go create mode 100644 result.go rename results_test.go => result_test.go (79%) delete mode 100644 results.go diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 93b3aa9..94febea 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -35,7 +35,7 @@ jobs: with: only-new-issues: true # golangci-lint command line arguments - args: --timeout=5m0s + args: --timeout=5m0s --new-from-rev=origin/master examples: name: examples diff --git a/Makefile b/Makefile index 632f383..074157b 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ install: # run full lint like in pipeline .PHONY: lint lint: install-lint - $(GOLANGCI_BIN) run --config=.golangci.yaml ./... --build-tags=examples,allure_go,provider + $(GOLANGCI_BIN) run --config=.golangci.yaml ./... --new-from-rev=origin/master --build-tags=examples,allure_go,provider .PHONY: install-lint diff --git a/README.MD b/README.MD index e050299..51be6d2 100644 --- a/README.MD +++ b/README.MD @@ -39,7 +39,7 @@ Three steps for testing your HTTP service: ## Installation ```bash -go get -u github.com/ozontech/cute + go get -u github.com/ozontech/cute ``` ## Requirements @@ -58,16 +58,16 @@ go get -u github.com/ozontech/cute 1) Install allure ```bash - $ brew install allure + brew install allure ``` 2) Run example ```bash - $ make example + make example ``` 3) Run allure ```bash - $ allure serve ./examples/allure-results + allure serve ./examples/allure-results ``` ## Examples @@ -447,9 +447,9 @@ You can implement [3 type of asserts](assert.go): Types for creating custom assertions. ```go -type AssertBody func(body []byte) error -type AssertHeaders func(headers http.Header) error -type AssertResponse func(response *http.Response) error + type AssertBody func(body []byte) error + type AssertHeaders func(headers http.Header) error + type AssertResponse func(response *http.Response) error ``` **Example:** @@ -473,9 +473,9 @@ You can log some information to Allure. \ Also you can log error on Allure yourself or just return error. ```go -type AssertBodyT func(t cute.T, body []byte) error -type AssertHeadersT func(t cute.T, headers http.Header) error -type AssertResponseT func(t cute.T, response *http.Response) error + type AssertBodyT func(t cute.T, body []byte) error + type AssertHeadersT func(t cute.T, headers http.Header) error + type AssertResponseT func(t cute.T, response *http.Response) error ``` **Example with T:** diff --git a/assert_broken.go b/assert_broken.go new file mode 100644 index 0000000..d64383e --- /dev/null +++ b/assert_broken.go @@ -0,0 +1,69 @@ +package cute + +import ( + "net/http" + + "github.com/ozontech/cute/errors" +) + +func brokenAssertHeaders(assert AssertHeaders) AssertHeaders { + return func(headers http.Header) error { + err := assert(headers) + + return wrapBrokenError(err) + } +} + +func brokenAssertBody(assert AssertBody) AssertBody { + return func(body []byte) error { + err := assert(body) + + return wrapBrokenError(err) + } +} + +func brokenAssertResponse(assert AssertResponse) AssertResponse { + return func(resp *http.Response) error { + err := assert(resp) + + return wrapBrokenError(err) + } +} + +func brokenAssertHeadersT(assert AssertHeadersT) AssertHeadersT { + return func(t T, headers http.Header) error { + err := assert(t, headers) + + return wrapBrokenError(err) + } +} + +func brokenAssertBodyT(assert AssertBodyT) AssertBodyT { + return func(t T, body []byte) error { + err := assert(t, body) + + return wrapBrokenError(err) + } +} + +func brokenAssertResponseT(assert AssertResponseT) AssertResponseT { + return func(t T, resp *http.Response) error { + err := assert(t, resp) + + return wrapBrokenError(err) + } +} + +func wrapBrokenError(err error) error { + if err == nil { + return nil + } + + if tErr, ok := err.(errors.BrokenError); ok { + tErr.SetBroken(true) + + return tErr.(error) + } + + return errors.WrapBrokenError(err) +} diff --git a/assert_broken_test.go b/assert_broken_test.go new file mode 100644 index 0000000..03dc766 --- /dev/null +++ b/assert_broken_test.go @@ -0,0 +1,98 @@ +package cute + +import ( + "errors" + "net/http" + "testing" + + cuteErrors "github.com/ozontech/cute/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestBrokenAssertResponse(t *testing.T) { + v := &http.Response{} + f := func(_ *http.Response) error { + return errors.New("test error") + } + + err := brokenAssertResponse(f)(v) + + if BrokenError, ok := err.(cuteErrors.BrokenError); assert.True(t, ok) { + require.True(t, BrokenError.IsBroken()) + } +} + +func TestBrokenAssertResponseT(t *testing.T) { + v := &http.Response{} + f := func(T, *http.Response) error { + return errors.New("test error") + } + + err := brokenAssertResponseT(f)(nil, v) + + if BrokenError, ok := err.(cuteErrors.BrokenError); assert.True(t, ok) { + require.True(t, BrokenError.IsBroken()) + } +} + +func TestBrokenAssertHeaders(t *testing.T) { + h := http.Header{} + f := func(_ http.Header) error { + return errors.New("test error") + } + + err := brokenAssertHeaders(f)(h) + + if BrokenError, ok := err.(cuteErrors.BrokenError); assert.True(t, ok) { + require.True(t, BrokenError.IsBroken()) + } +} + +func TestBrokenAssertHeadersT(t *testing.T) { + h := http.Header{} + f := func(T, http.Header) error { + return errors.New("test error") + } + + err := brokenAssertHeadersT(f)(nil, h) + + if BrokenError, ok := err.(cuteErrors.BrokenError); assert.True(t, ok) { + require.True(t, BrokenError.IsBroken()) + } +} + +func TestBrokenAssertBody(t *testing.T) { + v := []byte{} + f := func(_ []byte) error { + return errors.New("test error") + } + + err := brokenAssertBody(f)(v) + + if BrokenError, ok := err.(cuteErrors.BrokenError); assert.True(t, ok) { + require.True(t, BrokenError.IsBroken()) + } +} + +func TestBrokenAssertBodyT(t *testing.T) { + v := []byte{} + f := func(T, []byte) error { + return errors.New("test error") + } + + err := brokenAssertBodyT(f)(nil, v) + + if BrokenError, ok := err.(cuteErrors.BrokenError); assert.True(t, ok) { + require.True(t, BrokenError.IsBroken()) + } +} + +func TestWrapBrokenError(t *testing.T) { + err := errors.New("test error") + + optError := wrapBrokenError(err) + if BrokenError, ok := optError.(cuteErrors.BrokenError); assert.True(t, ok) { + require.True(t, BrokenError.IsBroken()) + } +} diff --git a/assert_optional.go b/assert_optional.go index 93c1ac6..e95fa12 100644 --- a/assert_optional.go +++ b/assert_optional.go @@ -65,5 +65,5 @@ func wrapOptionalError(err error) error { return tErr.(error) } - return errors.NewOptionalError(err.Error()) + return errors.WrapOptionalError(err) } diff --git a/assert_test.go b/assert_optional_test.go similarity index 89% rename from assert_test.go rename to assert_optional_test.go index 7defd13..2933212 100644 --- a/assert_test.go +++ b/assert_optional_test.go @@ -12,7 +12,7 @@ import ( func TestOptionalAssertResponse(t *testing.T) { v := &http.Response{} - f := func(resp *http.Response) error { + f := func(*http.Response) error { return errors.New("test error") } @@ -25,7 +25,7 @@ func TestOptionalAssertResponse(t *testing.T) { func TestOptionalAssertResponseT(t *testing.T) { v := &http.Response{} - f := func(t T, resp *http.Response) error { + f := func(T, *http.Response) error { return errors.New("test error") } @@ -38,7 +38,7 @@ func TestOptionalAssertResponseT(t *testing.T) { func TestOptionalAssertHeaders(t *testing.T) { h := http.Header{} - f := func(headers http.Header) error { + f := func(http.Header) error { return errors.New("test error") } @@ -51,7 +51,7 @@ func TestOptionalAssertHeaders(t *testing.T) { func TestOptionalAssertHeadersT(t *testing.T) { h := http.Header{} - f := func(t T, headers http.Header) error { + f := func(T, http.Header) error { return errors.New("test error") } @@ -64,7 +64,7 @@ func TestOptionalAssertHeadersT(t *testing.T) { func TestOptionalAssertBody(t *testing.T) { v := []byte{} - f := func(body []byte) error { + f := func([]byte) error { return errors.New("test error") } @@ -77,7 +77,7 @@ func TestOptionalAssertBody(t *testing.T) { func TestOptionalAssertBodyT(t *testing.T) { v := []byte{} - f := func(t T, body []byte) error { + f := func(T, []byte) error { return errors.New("test error") } diff --git a/assert_require.go b/assert_require.go index bf760af..1a206bf 100644 --- a/assert_require.go +++ b/assert_require.go @@ -65,5 +65,5 @@ func wrapRequireError(err error) error { return tErr.(error) } - return errors.NewRequireError(err.Error()) + return errors.WrapRequireError(err) } diff --git a/assert_require_test.go b/assert_require_test.go new file mode 100644 index 0000000..8b46b49 --- /dev/null +++ b/assert_require_test.go @@ -0,0 +1,98 @@ +package cute + +import ( + "errors" + "net/http" + "testing" + + cuteErrors "github.com/ozontech/cute/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestRequireAssertResponse(t *testing.T) { + v := &http.Response{} + f := func(_ *http.Response) error { + return errors.New("test error") + } + + err := requireAssertResponse(f)(v) + + if RequireError, ok := err.(cuteErrors.RequireError); assert.True(t, ok) { + require.True(t, RequireError.IsRequire()) + } +} + +func TestRequireAssertResponseT(t *testing.T) { + v := &http.Response{} + f := func(T, *http.Response) error { + return errors.New("test error") + } + + err := requireAssertResponseT(f)(nil, v) + + if RequireError, ok := err.(cuteErrors.RequireError); assert.True(t, ok) { + require.True(t, RequireError.IsRequire()) + } +} + +func TestRequireAssertHeaders(t *testing.T) { + h := http.Header{} + f := func(http.Header) error { + return errors.New("test error") + } + + err := requireAssertHeaders(f)(h) + + if RequireError, ok := err.(cuteErrors.RequireError); assert.True(t, ok) { + require.True(t, RequireError.IsRequire()) + } +} + +func TestRequireAssertHeadersT(t *testing.T) { + h := http.Header{} + f := func(T, http.Header) error { + return errors.New("test error") + } + + err := requireAssertHeadersT(f)(nil, h) + + if RequireError, ok := err.(cuteErrors.RequireError); assert.True(t, ok) { + require.True(t, RequireError.IsRequire()) + } +} + +func TestRequireAssertBody(t *testing.T) { + v := []byte{} + f := func([]byte) error { + return errors.New("test error") + } + + err := requireAssertBody(f)(v) + + if RequireError, ok := err.(cuteErrors.RequireError); assert.True(t, ok) { + require.True(t, RequireError.IsRequire()) + } +} + +func TestRequireAssertBodyT(t *testing.T) { + v := []byte{} + f := func(T, []byte) error { + return errors.New("test error") + } + + err := requireAssertBodyT(f)(nil, v) + + if RequireError, ok := err.(cuteErrors.RequireError); assert.True(t, ok) { + require.True(t, RequireError.IsRequire()) + } +} + +func TestWrapRequireError(t *testing.T) { + err := errors.New("test error") + + optError := wrapRequireError(err) + if RequireError, ok := optError.(cuteErrors.RequireError); assert.True(t, ok) { + require.True(t, RequireError.IsRequire()) + } +} diff --git a/builder.go b/builder.go index a27cb7d..5afabcc 100644 --- a/builder.go +++ b/builder.go @@ -16,10 +16,9 @@ var ( // HTTPTestMaker is a creator tests type HTTPTestMaker struct { - httpClient *http.Client - middleware *Middleware - - // todo add marshaler + httpClient *http.Client + middleware *Middleware + jsonMarshaler JSONMarshaler } type options struct { @@ -27,6 +26,8 @@ type options struct { httpTimeout time.Duration httpRoundTripper http.RoundTripper + jsonMarshaler JSONMarshaler + middleware *Middleware } @@ -40,6 +41,13 @@ func WithHTTPClient(client *http.Client) Option { } } +// WithJSONMarshaler is a function for set custom json marshaler +func WithJSONMarshaler(m JSONMarshaler) Option { + return func(o *options) { + o.jsonMarshaler = m + } +} + // WithCustomHTTPTimeout is a function for set custom http client timeout func WithCustomHTTPTimeout(t time.Duration) Option { return func(o *options) { @@ -89,8 +97,9 @@ func NewHTTPTestMaker(opts ...Option) *HTTPTestMaker { middleware: new(Middleware), } - timeout = defaultHTTPTimeout * time.Second - roundTripper = http.DefaultTransport + timeout = defaultHTTPTimeout * time.Second + roundTripper = http.DefaultTransport + jsMarshaler JSONMarshaler = &jsonMarshaler{} ) for _, opt := range opts { @@ -114,9 +123,14 @@ func NewHTTPTestMaker(opts ...Option) *HTTPTestMaker { httpClient = o.httpClient } + if o.jsonMarshaler != nil { + jsMarshaler = o.jsonMarshaler + } + m := &HTTPTestMaker{ - httpClient: httpClient, - middleware: o.middleware, + httpClient: httpClient, + jsonMarshaler: jsMarshaler, + middleware: o.middleware, } return m @@ -165,9 +179,10 @@ func createDefaultTest(m *HTTPTestMaker) *Test { } return &Test{ - httpClient: m.httpClient, - Middleware: middleware, - AllureStep: new(AllureStep), + httpClient: m.httpClient, + jsonMarshaler: m.jsonMarshaler, + Middleware: middleware, + AllureStep: new(AllureStep), Request: &Request{ Repeat: new(RequestRepeatPolitic), }, @@ -421,30 +436,6 @@ func (qt *cute) AfterTestExecuteT(fs ...AfterExecuteT) NextTestBuilder { return qt } -func (qt *cute) RequestRepeat(count int) RequestHTTPBuilder { - qt.tests[qt.countTests].Request.Repeat.Count = count - - return qt -} - -func (qt *cute) RequestRepeatDelay(delay time.Duration) RequestHTTPBuilder { - qt.tests[qt.countTests].Request.Repeat.Delay = delay - - return qt -} - -func (qt *cute) Request(r *http.Request) ExpectHTTPBuilder { - qt.tests[qt.countTests].Request.Base = r - - return qt -} - -func (qt *cute) RequestBuilder(r ...RequestBuilder) ExpectHTTPBuilder { - qt.tests[qt.countTests].Request.Builders = append(qt.tests[qt.countTests].Request.Builders, r...) - - return qt -} - func (qt *cute) ExpectExecuteTimeout(t time.Duration) ExpectHTTPBuilder { qt.tests[qt.countTests].Expect.ExecuteTime = t @@ -475,222 +466,6 @@ func (qt *cute) ExpectJSONSchemaFile(filePath string) ExpectHTTPBuilder { return qt } -func (qt *cute) AssertBody(asserts ...AssertBody) ExpectHTTPBuilder { - for _, assert := range asserts { - if assert == nil { - panic(errorAssertIsNil) - } - } - - qt.tests[qt.countTests].Expect.AssertBody = append(qt.tests[qt.countTests].Expect.AssertBody, asserts...) - - return qt -} - -func (qt *cute) OptionalAssertBody(asserts ...AssertBody) ExpectHTTPBuilder { - for _, assert := range asserts { - if assert == nil { - panic(errorAssertIsNil) - } - - qt.tests[qt.countTests].Expect.AssertBody = append(qt.tests[qt.countTests].Expect.AssertBody, optionalAssertBody(assert)) - } - - return qt -} - -func (qt *cute) RequireBody(asserts ...AssertBody) ExpectHTTPBuilder { - for _, assert := range asserts { - if assert == nil { - panic(errorAssertIsNil) - } - - qt.tests[qt.countTests].Expect.AssertBody = append(qt.tests[qt.countTests].Expect.AssertBody, requireAssertBody(assert)) - } - - return qt -} - -func (qt *cute) AssertHeaders(asserts ...AssertHeaders) ExpectHTTPBuilder { - for _, assert := range asserts { - if assert == nil { - panic(errorAssertIsNil) - } - } - - qt.tests[qt.countTests].Expect.AssertHeaders = append(qt.tests[qt.countTests].Expect.AssertHeaders, asserts...) - - return qt -} - -func (qt *cute) OptionalAssertHeaders(asserts ...AssertHeaders) ExpectHTTPBuilder { - for _, assert := range asserts { - if assert == nil { - panic(errorAssertIsNil) - } - - qt.tests[qt.countTests].Expect.AssertHeaders = append(qt.tests[qt.countTests].Expect.AssertHeaders, optionalAssertHeaders(assert)) - } - - return qt -} - -func (qt *cute) RequireHeaders(asserts ...AssertHeaders) ExpectHTTPBuilder { - for _, assert := range asserts { - if assert == nil { - panic(errorAssertIsNil) - } - - qt.tests[qt.countTests].Expect.AssertHeaders = append(qt.tests[qt.countTests].Expect.AssertHeaders, requireAssertHeaders(assert)) - } - - return qt -} - -func (qt *cute) AssertResponse(asserts ...AssertResponse) ExpectHTTPBuilder { - for _, assert := range asserts { - if assert == nil { - panic(errorAssertIsNil) - } - } - - qt.tests[qt.countTests].Expect.AssertResponse = append(qt.tests[qt.countTests].Expect.AssertResponse, asserts...) - - return qt -} - -func (qt *cute) OptionalAssertResponse(asserts ...AssertResponse) ExpectHTTPBuilder { - for _, assert := range asserts { - if assert == nil { - panic(errorAssertIsNil) - } - - qt.tests[qt.countTests].Expect.AssertResponse = append(qt.tests[qt.countTests].Expect.AssertResponse, optionalAssertResponse(assert)) - } - - return qt -} - -func (qt *cute) RequireResponse(asserts ...AssertResponse) ExpectHTTPBuilder { - for _, assert := range asserts { - if assert == nil { - panic(errorAssertIsNil) - } - - qt.tests[qt.countTests].Expect.AssertResponse = append(qt.tests[qt.countTests].Expect.AssertResponse, requireAssertResponse(assert)) - } - - return qt -} - -func (qt *cute) AssertBodyT(asserts ...AssertBodyT) ExpectHTTPBuilder { - for _, assert := range asserts { - if assert == nil { - panic(errorAssertIsNil) - } - } - - qt.tests[qt.countTests].Expect.AssertBodyT = append(qt.tests[qt.countTests].Expect.AssertBodyT, asserts...) - - return qt -} - -func (qt *cute) OptionalAssertBodyT(asserts ...AssertBodyT) ExpectHTTPBuilder { - for _, assert := range asserts { - if assert == nil { - panic(errorAssertIsNil) - } - - qt.tests[qt.countTests].Expect.AssertBodyT = append(qt.tests[qt.countTests].Expect.AssertBodyT, optionalAssertBodyT(assert)) - } - - return qt -} - -func (qt *cute) RequireBodyT(asserts ...AssertBodyT) ExpectHTTPBuilder { - for _, assert := range asserts { - if assert == nil { - panic(errorAssertIsNil) - } - - qt.tests[qt.countTests].Expect.AssertBodyT = append(qt.tests[qt.countTests].Expect.AssertBodyT, requireAssertBodyT(assert)) - } - - return qt -} - -func (qt *cute) AssertHeadersT(asserts ...AssertHeadersT) ExpectHTTPBuilder { - for _, assert := range asserts { - if assert == nil { - panic(errorAssertIsNil) - } - } - - qt.tests[qt.countTests].Expect.AssertHeadersT = append(qt.tests[qt.countTests].Expect.AssertHeadersT, asserts...) - - return qt -} - -func (qt *cute) OptionalAssertHeadersT(asserts ...AssertHeadersT) ExpectHTTPBuilder { - for _, assert := range asserts { - if assert == nil { - panic(errorAssertIsNil) - } - - qt.tests[qt.countTests].Expect.AssertHeadersT = append(qt.tests[qt.countTests].Expect.AssertHeadersT, optionalAssertHeadersT(assert)) - } - - return qt -} - -func (qt *cute) RequireHeadersT(asserts ...AssertHeadersT) ExpectHTTPBuilder { - for _, assert := range asserts { - if assert == nil { - panic(errorAssertIsNil) - } - - qt.tests[qt.countTests].Expect.AssertHeadersT = append(qt.tests[qt.countTests].Expect.AssertHeadersT, requireAssertHeadersT(assert)) - } - - return qt -} - -func (qt *cute) AssertResponseT(asserts ...AssertResponseT) ExpectHTTPBuilder { - for _, assert := range asserts { - if assert == nil { - panic(errorAssertIsNil) - } - } - - qt.tests[qt.countTests].Expect.AssertResponseT = append(qt.tests[qt.countTests].Expect.AssertResponseT, asserts...) - - return qt -} - -func (qt *cute) OptionalAssertResponseT(asserts ...AssertResponseT) ExpectHTTPBuilder { - for _, assert := range asserts { - if assert == nil { - panic(errorAssertIsNil) - } - - qt.tests[qt.countTests].Expect.AssertResponseT = append(qt.tests[qt.countTests].Expect.AssertResponseT, optionalAssertResponseT(assert)) - } - - return qt -} - -func (qt *cute) RequireResponseT(asserts ...AssertResponseT) ExpectHTTPBuilder { - for _, assert := range asserts { - if assert == nil { - panic(errorAssertIsNil) - } - - qt.tests[qt.countTests].Expect.AssertResponseT = append(qt.tests[qt.countTests].Expect.AssertResponseT, requireAssertResponseT(assert)) - } - - return qt -} - func (qt *cute) CreateTableTest() MiddlewareTable { qt.isTableTest = true diff --git a/builder_asserts.go b/builder_asserts.go new file mode 100644 index 0000000..31c55d4 --- /dev/null +++ b/builder_asserts.go @@ -0,0 +1,289 @@ +package cute + +func (qt *cute) AssertBody(asserts ...AssertBody) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + } + + qt.tests[qt.countTests].Expect.AssertBody = append(qt.tests[qt.countTests].Expect.AssertBody, asserts...) + + return qt +} + +func (qt *cute) OptionalAssertBody(asserts ...AssertBody) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + + qt.tests[qt.countTests].Expect.AssertBody = append(qt.tests[qt.countTests].Expect.AssertBody, optionalAssertBody(assert)) + } + + return qt +} + +func (qt *cute) BrokenAssertBody(asserts ...AssertBody) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + + qt.tests[qt.countTests].Expect.AssertBody = append(qt.tests[qt.countTests].Expect.AssertBody, brokenAssertBody(assert)) + } + + return qt +} + +func (qt *cute) RequireBody(asserts ...AssertBody) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + + qt.tests[qt.countTests].Expect.AssertBody = append(qt.tests[qt.countTests].Expect.AssertBody, requireAssertBody(assert)) + } + + return qt +} + +func (qt *cute) AssertHeaders(asserts ...AssertHeaders) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + } + + qt.tests[qt.countTests].Expect.AssertHeaders = append(qt.tests[qt.countTests].Expect.AssertHeaders, asserts...) + + return qt +} + +func (qt *cute) OptionalAssertHeaders(asserts ...AssertHeaders) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + + qt.tests[qt.countTests].Expect.AssertHeaders = append(qt.tests[qt.countTests].Expect.AssertHeaders, optionalAssertHeaders(assert)) + } + + return qt +} + +func (qt *cute) RequireHeaders(asserts ...AssertHeaders) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + + qt.tests[qt.countTests].Expect.AssertHeaders = append(qt.tests[qt.countTests].Expect.AssertHeaders, requireAssertHeaders(assert)) + } + + return qt +} + +func (qt *cute) BrokenAssertHeaders(asserts ...AssertHeaders) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + + qt.tests[qt.countTests].Expect.AssertHeaders = append(qt.tests[qt.countTests].Expect.AssertHeaders, brokenAssertHeaders(assert)) + } + + return qt +} + +func (qt *cute) AssertResponse(asserts ...AssertResponse) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + } + + qt.tests[qt.countTests].Expect.AssertResponse = append(qt.tests[qt.countTests].Expect.AssertResponse, asserts...) + + return qt +} + +func (qt *cute) OptionalAssertResponse(asserts ...AssertResponse) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + + qt.tests[qt.countTests].Expect.AssertResponse = append(qt.tests[qt.countTests].Expect.AssertResponse, optionalAssertResponse(assert)) + } + + return qt +} + +func (qt *cute) RequireResponse(asserts ...AssertResponse) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + + qt.tests[qt.countTests].Expect.AssertResponse = append(qt.tests[qt.countTests].Expect.AssertResponse, requireAssertResponse(assert)) + } + + return qt +} + +func (qt *cute) BrokenAssertResponse(asserts ...AssertResponse) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + + qt.tests[qt.countTests].Expect.AssertResponse = append(qt.tests[qt.countTests].Expect.AssertResponse, brokenAssertResponse(assert)) + } + + return qt +} + +func (qt *cute) AssertBodyT(asserts ...AssertBodyT) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + } + + qt.tests[qt.countTests].Expect.AssertBodyT = append(qt.tests[qt.countTests].Expect.AssertBodyT, asserts...) + + return qt +} + +func (qt *cute) OptionalAssertBodyT(asserts ...AssertBodyT) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + + qt.tests[qt.countTests].Expect.AssertBodyT = append(qt.tests[qt.countTests].Expect.AssertBodyT, optionalAssertBodyT(assert)) + } + + return qt +} + +func (qt *cute) BrokenAssertBodyT(asserts ...AssertBodyT) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + + qt.tests[qt.countTests].Expect.AssertBodyT = append(qt.tests[qt.countTests].Expect.AssertBodyT, brokenAssertBodyT(assert)) + } + + return qt +} + +func (qt *cute) RequireBodyT(asserts ...AssertBodyT) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + + qt.tests[qt.countTests].Expect.AssertBodyT = append(qt.tests[qt.countTests].Expect.AssertBodyT, requireAssertBodyT(assert)) + } + + return qt +} + +func (qt *cute) AssertHeadersT(asserts ...AssertHeadersT) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + } + + qt.tests[qt.countTests].Expect.AssertHeadersT = append(qt.tests[qt.countTests].Expect.AssertHeadersT, asserts...) + + return qt +} + +func (qt *cute) OptionalAssertHeadersT(asserts ...AssertHeadersT) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + + qt.tests[qt.countTests].Expect.AssertHeadersT = append(qt.tests[qt.countTests].Expect.AssertHeadersT, optionalAssertHeadersT(assert)) + } + + return qt +} + +func (qt *cute) RequireHeadersT(asserts ...AssertHeadersT) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + + qt.tests[qt.countTests].Expect.AssertHeadersT = append(qt.tests[qt.countTests].Expect.AssertHeadersT, requireAssertHeadersT(assert)) + } + + return qt +} + +func (qt *cute) BrokenAssertHeadersT(asserts ...AssertHeadersT) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + + qt.tests[qt.countTests].Expect.AssertHeadersT = append(qt.tests[qt.countTests].Expect.AssertHeadersT, brokenAssertHeadersT(assert)) + } + + return qt +} + +func (qt *cute) AssertResponseT(asserts ...AssertResponseT) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + } + + qt.tests[qt.countTests].Expect.AssertResponseT = append(qt.tests[qt.countTests].Expect.AssertResponseT, asserts...) + + return qt +} + +func (qt *cute) OptionalAssertResponseT(asserts ...AssertResponseT) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + + qt.tests[qt.countTests].Expect.AssertResponseT = append(qt.tests[qt.countTests].Expect.AssertResponseT, optionalAssertResponseT(assert)) + } + + return qt +} + +func (qt *cute) BrokenAssertResponseT(asserts ...AssertResponseT) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + + qt.tests[qt.countTests].Expect.AssertResponseT = append(qt.tests[qt.countTests].Expect.AssertResponseT, brokenAssertResponseT(assert)) + } + + return qt +} + +func (qt *cute) RequireResponseT(asserts ...AssertResponseT) ExpectHTTPBuilder { + for _, assert := range asserts { + if assert == nil { + panic(errorAssertIsNil) + } + + qt.tests[qt.countTests].Expect.AssertResponseT = append(qt.tests[qt.countTests].Expect.AssertResponseT, requireAssertResponseT(assert)) + } + + return qt +} diff --git a/builder_request.go b/builder_request.go new file mode 100644 index 0000000..772b468 --- /dev/null +++ b/builder_request.go @@ -0,0 +1,30 @@ +package cute + +import ( + "net/http" + "time" +) + +func (qt *cute) RequestRepeat(count int) RequestHTTPBuilder { + qt.tests[qt.countTests].Request.Repeat.Count = count + + return qt +} + +func (qt *cute) RequestRepeatDelay(delay time.Duration) RequestHTTPBuilder { + qt.tests[qt.countTests].Request.Repeat.Delay = delay + + return qt +} + +func (qt *cute) Request(r *http.Request) ExpectHTTPBuilder { + qt.tests[qt.countTests].Request.Base = r + + return qt +} + +func (qt *cute) RequestBuilder(r ...RequestBuilder) ExpectHTTPBuilder { + qt.tests[qt.countTests].Request.Builders = append(qt.tests[qt.countTests].Request.Builders, r...) + + return qt +} diff --git a/cute.go b/cute.go index 31f6723..343da88 100644 --- a/cute.go +++ b/cute.go @@ -172,15 +172,21 @@ func (qt *cute) executeSingleTest(ctx context.Context, allureProvider allureProv allureProvider.Logf("Test start %v", currentTest.Name) resT := currentTest.executeInsideAllure(ctx, allureProvider) - if resT.IsFailed() { - allureProvider.Fail() - allureProvider.Logf("Test was failed %v", currentTest.Name) - return resT + switch resT.GetResultState() { + case ResultStateBroken: + allureProvider.BrokenNow() + allureProvider.Logf("Test broken %v", currentTest.Name) + case ResultStateFail: + allureProvider.Fail() + allureProvider.Logf("Test failed %v", currentTest.Name) + case resultStateFailNow: + allureProvider.FailNow() + allureProvider.Logf("Test failed %v", currentTest.Name) + case ResultStateSuccess: + allureProvider.Logf("Test finished %v", currentTest.Name) } - allureProvider.Logf("Test finished %v", currentTest.Name) - // Remove from base struct all asserts currentTest.clearFields() diff --git a/errors/broken.go b/errors/broken.go new file mode 100644 index 0000000..4e20d8a --- /dev/null +++ b/errors/broken.go @@ -0,0 +1,47 @@ +package errors + +import "errors" + +// BrokenError is an interface for set errors like Broken errors. +// If the function returns an error, which implements this interface, the allure step will has a broken status +type BrokenError interface { + IsBroken() bool + SetBroken(bool) + Error() string +} + +type brokenError struct { + err error + broken bool +} + +// NewBrokenError ... +func NewBrokenError(err string) error { + return &brokenError{ + broken: true, + err: errors.New(err), + } +} + +// WrapBrokenError returns error with a Broken tag for Allure +func WrapBrokenError(err error) error { + return &brokenError{ + broken: true, + err: err, + } +} + +// Error .. +func (o *brokenError) Error() string { + return o.err.Error() +} + +// IsBroken ... +func (o *brokenError) IsBroken() bool { + return o.broken +} + +// SetBroken ... +func (o *brokenError) SetBroken(broken bool) { + o.broken = broken +} diff --git a/errors/error.go b/errors/error.go index cac490c..d53f94c 100644 --- a/errors/error.go +++ b/errors/error.go @@ -43,6 +43,7 @@ type WithAttachments interface { type assertError struct { optional bool require bool + broken bool name string message string @@ -50,7 +51,7 @@ type assertError struct { attachments []*Attachment } -// NewAssertError ... +// NewAssertError is the function, which creates error with "Actual" and "Expected" for allure func NewAssertError(name string, message string, actual interface{}, expected interface{}) error { return &assertError{ name: name, @@ -62,6 +63,14 @@ func NewAssertError(name string, message string, actual interface{}, expected in } } +// NewAssertErrorWithMessage ... +func NewAssertErrorWithMessage(name string, message string) error { + return &assertError{ + name: name, + message: message, + } +} + // NewEmptyAssertError ... func NewEmptyAssertError(name string, message string) CuteError { return &assertError{ @@ -116,3 +125,11 @@ func (a *assertError) IsRequire() bool { func (a *assertError) SetRequire(b bool) { a.require = b } + +func (a *assertError) IsBroken() bool { + return a.broken +} + +func (a *assertError) SetBroken(b bool) { + a.broken = b +} diff --git a/errors/optional.go b/errors/optional.go index 892d66e..52a62d9 100644 --- a/errors/optional.go +++ b/errors/optional.go @@ -1,19 +1,29 @@ package errors -// OptionalError is interface for set error like optional error. -// If function returns error, which implement this interface, allure step will have skip status +import "errors" + +// OptionalError is an interface for set errors like optional errors. +// If the function returns an error, which implements this interface, the allure step will has to skip status type OptionalError interface { IsOptional() bool SetOptional(bool) } type optionalError struct { - err string + err error optional bool } // NewOptionalError ... func NewOptionalError(err string) error { + return &optionalError{ + optional: true, + err: errors.New(err), + } +} + +// WrapOptionalError returns error with an Optional tag for Allure +func WrapOptionalError(err error) error { return &optionalError{ optional: true, err: err, @@ -21,7 +31,7 @@ func NewOptionalError(err string) error { } func (o *optionalError) Error() string { - return o.err + return o.err.Error() } func (o *optionalError) IsOptional() bool { diff --git a/errors/require.go b/errors/require.go index 0ca8d8f..ddb192e 100644 --- a/errors/require.go +++ b/errors/require.go @@ -1,19 +1,29 @@ package errors -// RequireError is interface for set error like require error. -// If function returns error, which implement this interface, allure step will have failed status +import "errors" + +// RequireError is an interface for set errors like require error. +// If the function returns an error, which implements this interface, the allure step will has failed status type RequireError interface { IsRequire() bool SetRequire(bool) } type requireError struct { - err string + err error require bool } // NewRequireError ... func NewRequireError(err string) error { + return &requireError{ + require: true, + err: errors.New(err), + } +} + +// WrapRequireError returns error with flag for execute t.FailNow() and finish test after this error +func WrapRequireError(err error) error { return &requireError{ require: true, err: err, @@ -22,7 +32,7 @@ func NewRequireError(err string) error { // Error .. func (o *requireError) Error() string { - return o.err + return o.err.Error() } // IsRequire ... diff --git a/examples/single_test.go b/examples/single_test.go index e66984d..565dcbc 100644 --- a/examples/single_test.go +++ b/examples/single_test.go @@ -5,6 +5,7 @@ package examples import ( "context" + "errors" "fmt" "io" "net/http" @@ -16,6 +17,7 @@ import ( "github.com/ozontech/allure-go/pkg/allure" "github.com/ozontech/allure-go/pkg/framework/provider" "github.com/ozontech/allure-go/pkg/framework/runner" + cuteErrors "github.com/ozontech/cute/errors" "github.com/ozontech/cute" "github.com/ozontech/cute/asserts/json" @@ -73,6 +75,53 @@ func Test_Single_1(t *testing.T) { ExecuteTest(context.Background(), t) } +func Test_Single_Broken(t *testing.T) { + cute.NewTestBuilder(). + Title("Test_Single_Broken"). + Create(). + RequestBuilder( + cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"), + ). + BrokenAssertBodyT(func(t cute.T, body []byte) error { + return errors.New("example broken error") + }). + ExpectStatus(http.StatusOK). + NextTest(). + Create(). + RequestBuilder( + cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"), + ). + AssertBody(func(body []byte) error { + return errors.New("it's NOT must be run") + }, + ). + ExecuteTest(context.Background(), t) +} + +func Test_Single_Broken_2(t *testing.T) { + cute.NewTestBuilder(). + Title("Test_Single_Broken_2"). + Create(). + RequestBuilder( + cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"), + ). + AssertBodyT(func(t cute.T, body []byte) error { + err := errors.New("example broken error") + return cuteErrors.WrapBrokenError(err) + }). + ExpectStatus(http.StatusOK). + NextTest(). + Create(). + RequestBuilder( + cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"), + ). + AssertBody(func(body []byte) error { + return errors.New("it's NOT must be run") + }, + ). + ExecuteTest(context.Background(), t) +} + func Test_Single_2_AllureRunner(t *testing.T) { runner.Run(t, "Single test with allure-go Runner", func(t provider.T) { var ( diff --git a/interface.go b/interface.go index bafe34b..06e8bf3 100644 --- a/interface.go +++ b/interface.go @@ -215,6 +215,9 @@ type ExpectHTTPBuilder interface { // OptionalAssertBody is not a mandatory assert. // Mark in allure as Skipped OptionalAssertBody(asserts ...AssertBody) ExpectHTTPBuilder + // BrokenAssertBody is function for validate response, if it's failed, then test will be Broken. + // Mark in allure as Broken + BrokenAssertBody(asserts ...AssertBody) ExpectHTTPBuilder // AssertBodyT is function for validate response body with help testing.TB and allure allureProvider. // You may create allure step inside assert, add attachment, log information, etc. AssertBodyT(asserts ...AssertBodyT) ExpectHTTPBuilder @@ -223,6 +226,9 @@ type ExpectHTTPBuilder interface { // OptionalAssertBodyT is not a mandatory assert. // Mark in allure as Skipped OptionalAssertBodyT(asserts ...AssertBodyT) ExpectHTTPBuilder + // BrokenAssertBodyT is function for validate response, if it's failed, then test will be Broken. + // Mark in allure as Broken + BrokenAssertBodyT(asserts ...AssertBodyT) ExpectHTTPBuilder // AssertHeaders is function for validate response headers // Available asserts from asserts/headers/headers.go: @@ -235,6 +241,9 @@ type ExpectHTTPBuilder interface { // OptionalAssertHeaders is not a mandatory assert. // Mark in allure as Skipped OptionalAssertHeaders(asserts ...AssertHeaders) ExpectHTTPBuilder + // BrokenAssertHeaders is function for validate response, if it's failed, then test will be Broken. + // Mark in allure as Broken + BrokenAssertHeaders(asserts ...AssertHeaders) ExpectHTTPBuilder // AssertHeadersT is function for validate headers body with help testing.TB and allure allureProvider. // You may create allure step inside assert, add attachment, log information, etc. AssertHeadersT(asserts ...AssertHeadersT) ExpectHTTPBuilder @@ -243,14 +252,20 @@ type ExpectHTTPBuilder interface { // OptionalAssertHeadersT is not a mandatory assert. // Mark in allure as Skipped OptionalAssertHeadersT(asserts ...AssertHeadersT) ExpectHTTPBuilder + // BrokenAssertHeadersT is function for validate response, if it's failed, then test will be Broken. + // Mark in allure as Broken + BrokenAssertHeadersT(asserts ...AssertHeadersT) ExpectHTTPBuilder - // AssertResponse is function for validate response + // AssertResponse is function for validate response. AssertResponse(asserts ...AssertResponse) ExpectHTTPBuilder // RequireResponse implements the same assertions as the `AssertResponse`, but stops test execution when a test fails. RequireResponse(asserts ...AssertResponse) ExpectHTTPBuilder // OptionalAssertResponse is not a mandatory assert. // Mark in allure as Skipped OptionalAssertResponse(asserts ...AssertResponse) ExpectHTTPBuilder + // BrokenAssertResponse is function for validate response, if it's failed, then test will be Broken. + // Mark in allure as Broken + BrokenAssertResponse(asserts ...AssertResponse) ExpectHTTPBuilder // AssertResponseT is function for validate response with help testing.TB. // You may create allure step inside assert, add attachment, log information, etc. AssertResponseT(asserts ...AssertResponseT) ExpectHTTPBuilder @@ -259,6 +274,9 @@ type ExpectHTTPBuilder interface { // OptionalAssertResponseT is not a mandatory assert. // Mark in allure as Skipped OptionalAssertResponseT(asserts ...AssertResponseT) ExpectHTTPBuilder + // BrokenAssertResponseT is function for validate response, if it's failed, then test will be Broken. + // Mark in allure as Broken + BrokenAssertResponseT(asserts ...AssertResponseT) ExpectHTTPBuilder After ControlTest @@ -288,7 +306,11 @@ type ResultsHTTPBuilder interface { // GetName is a function, which returns name of Test GetName() string // IsFailed is a function, which returns flag about status of test + // Deprecated, use GetResultState() IsFailed() bool + // GetResultState is a function, which returns state of test + // State could be ResultStateSuccess, ResultStateBroken, ResultStateFail + GetResultState() ResultState } // BeforeExecute ... diff --git a/json_marshaler.go b/json_marshaler.go new file mode 100644 index 0000000..035ad1e --- /dev/null +++ b/json_marshaler.go @@ -0,0 +1,20 @@ +package cute + +import "encoding/json" + +// JSONMarshaler is marshaler which use for marshal/unmarshal JSON to/from struct +type JSONMarshaler interface { + Marshal(v any) ([]byte, error) + Unmarshal(data []byte, v any) error +} + +type jsonMarshaler struct { +} + +func (j jsonMarshaler) Marshal(v any) ([]byte, error) { + return json.Marshal(v) +} + +func (j jsonMarshaler) Unmarshal(data []byte, v any) error { + return json.Unmarshal(data, v) +} diff --git a/jsonschema.go b/jsonschema.go index bc9f004..75b7c0a 100644 --- a/jsonschema.go +++ b/jsonschema.go @@ -35,7 +35,7 @@ func checkJSONSchema(expect gojsonschema.JSONLoader, data []byte) []error { validateResult, err := gojsonschema.Validate(expect, gojsonschema.NewBytesLoader(data)) if err != nil { - return []error{err} + return []error{errors.NewAssertErrorWithMessage("could not validate json schema", err.Error())} } if !validateResult.Valid() && len(validateResult.Errors()) > 0 { diff --git a/provider.go b/provider.go index a901290..e2bc3f8 100644 --- a/provider.go +++ b/provider.go @@ -17,6 +17,8 @@ type T interface { type allureProvider interface { internalT Parallel() + Broken() + BrokenNow() Run(testName string, testBody func(provider.T), tags ...string) (res *allure.Result) infoAllureProvider diff --git a/result.go b/result.go new file mode 100644 index 0000000..c0ad4c6 --- /dev/null +++ b/result.go @@ -0,0 +1,56 @@ +package cute + +import ( + "net/http" +) + +// ResultState is state of test +type ResultState int + +// ResultState is state of test +const ( + ResultStateSuccess ResultState = iota + ResultStateBroken + ResultStateFail + + // resultStateFailNow is state for require validations (execute failNow) + resultStateFailNow +) + +type testResults struct { + name string + state ResultState + resp *http.Response + errors []error +} + +func newTestResult(name string, resp *http.Response, state ResultState, errs []error) ResultsHTTPBuilder { + return &testResults{ + name: name, + resp: resp, + state: state, + errors: errs, + } +} + +func (r *testResults) GetHTTPResponse() *http.Response { + return r.resp +} + +func (r *testResults) GetErrors() []error { + return r.errors +} + +func (r *testResults) GetName() string { + return r.name +} + +// IsFailed ... +// Deprecated please use GetResultState +func (r *testResults) IsFailed() bool { + return r.state == ResultStateFail || r.state == resultStateFailNow +} + +func (r *testResults) GetResultState() ResultState { + return r.state +} diff --git a/results_test.go b/result_test.go similarity index 79% rename from results_test.go rename to result_test.go index 47ccd6d..e618507 100644 --- a/results_test.go +++ b/result_test.go @@ -19,9 +19,9 @@ func TestResult(t *testing.T) { name = "Name" testResults ResultsHTTPBuilder = &testResults{ - name: name, - resp: resp, - isFailed: true, + name: name, + state: ResultStateBroken, + resp: resp, errors: []error{ firstErr, secondErr, @@ -30,7 +30,8 @@ func TestResult(t *testing.T) { ) require.Equal(t, name, testResults.GetName()) - require.Equal(t, true, testResults.IsFailed()) + require.Equal(t, false, testResults.IsFailed()) + require.Equal(t, false, testResults.IsFailed()) require.Equal(t, resp, testResults.GetHTTPResponse()) require.Equal(t, []error{firstErr, secondErr}, testResults.GetErrors()) } diff --git a/results.go b/results.go deleted file mode 100644 index 58f57c0..0000000 --- a/results.go +++ /dev/null @@ -1,37 +0,0 @@ -package cute - -import ( - "net/http" -) - -type testResults struct { - isFailed bool - name string - resp *http.Response - errors []error -} - -func newTestResult(name string, resp *http.Response, isFailed bool, errs []error) ResultsHTTPBuilder { - return &testResults{ - name: name, - resp: resp, - isFailed: isFailed, - errors: errs, - } -} - -func (r *testResults) GetHTTPResponse() *http.Response { - return r.resp -} - -func (r *testResults) GetErrors() []error { - return r.errors -} - -func (r *testResults) GetName() string { - return r.name -} - -func (r *testResults) IsFailed() bool { - return r.isFailed -} diff --git a/roundtripper.go b/roundtripper.go index 490fd0e..b6aa363 100644 --- a/roundtripper.go +++ b/roundtripper.go @@ -105,7 +105,6 @@ func (it *Test) validateResponseCode(resp *http.Response) error { return nil } -// PrepareStep returns step based on http request. func addInformationRequest(t T, req *http.Request) error { var ( saveBody io.ReadCloser @@ -123,6 +122,8 @@ func addInformationRequest(t T, req *http.Request) error { t.Log("[Request] Do request") } + // Do not change to JSONMarshaler + // In this case we can keep default for keep JSON, independence from JSONMarshaler headers, err := utils.ToJSON(req.Header) if err != nil { return err diff --git a/step.go b/step.go index 5a459ee..263c208 100644 --- a/step.go +++ b/step.go @@ -39,6 +39,12 @@ func processStepErrors(stepCtx provider.StepCtx, errs []error) { } } + if tErr, ok := err.(errors.BrokenError); ok { + if tErr.IsBroken() { + currentStatus = allure.Broken + } + } + if tErr, ok := err.(errors.WithNameError); ok { currentStep = allure.NewSimpleStep(tErr.GetName()) currentStep.Status = currentStatus diff --git a/test.go b/test.go index 99574a8..9b7fe2e 100644 --- a/test.go +++ b/test.go @@ -3,7 +3,6 @@ package cute import ( "bytes" "context" - "encoding/json" "errors" "fmt" "io" @@ -32,7 +31,8 @@ var ( // Test is a main struct of test. // You may field Request and Expect for create simple test type Test struct { - httpClient *http.Client + httpClient *http.Client + jsonMarshaler JSONMarshaler Name string @@ -170,9 +170,9 @@ func (it *Test) initEmptyFields() { func (it *Test) executeInsideStep(ctx context.Context, t internalT) ResultsHTTPBuilder { resp, errs := it.startTest(ctx, t) - isFailedTest := it.processTestErrors(t, errs) + resultState := it.processTestErrors(t, errs) - return newTestResult(t.Name(), resp, isFailedTest, errs) + return newTestResult(t.Name(), resp, resultState, errs) } func (it *Test) executeInsideAllure(ctx context.Context, allureProvider allureProvider) ResultsHTTPBuilder { @@ -197,24 +197,24 @@ func (it *Test) executeInsideAllure(ctx context.Context, allureProvider allurePr resp, errs = it.startTest(ctx, allureProvider) } - isFailedTest := it.processTestErrors(allureProvider, errs) + resultState := it.processTestErrors(allureProvider, errs) - return newTestResult(name, resp, isFailedTest, errs) + return newTestResult(name, resp, resultState, errs) } // processTestErrors returns flag, which mean finish test or not. // true - need finish test // false - continue -func (it *Test) processTestErrors(t internalT, errs []error) bool { +func (it *Test) processTestErrors(t internalT, errs []error) ResultState { + if len(errs) == 0 { + return ResultStateSuccess + } + var ( countNotOptionalErrors = 0 - failTest = false + state = ResultStateFail ) - if len(errs) == 0 { - return false - } - for _, err := range errs { if tErr, ok := err.(cuteErrors.OptionalError); ok { if tErr.IsOptional() { @@ -224,9 +224,19 @@ func (it *Test) processTestErrors(t internalT, errs []error) bool { } } + if tErr, ok := err.(cuteErrors.BrokenError); ok { + if tErr.IsBroken() { + t.Logf("[BROKEN ERROR] %v", tErr.(error).Error()) + + state = ResultStateBroken + + continue + } + } + if tErr, ok := err.(cuteErrors.RequireError); ok { if tErr.IsRequire() { - failTest = true + state = resultStateFailNow } } @@ -237,10 +247,9 @@ func (it *Test) processTestErrors(t internalT, errs []error) bool { if countNotOptionalErrors != 0 { t.Errorf("Test finished with %v errors", countNotOptionalErrors) - t.Fail() } - return failTest + return state } func (it *Test) startTestWithStep(ctx context.Context, t internalT) (*http.Response, []error) { @@ -422,7 +431,7 @@ func (it *Test) buildRequest(ctx context.Context) (*http.Request, error) { // Set body body := o.body if o.bodyMarshal != nil { - body, err = json.Marshal(o.bodyMarshal) // TODO move marshaler to it struct + body, err = it.jsonMarshaler.Marshal(o.bodyMarshal) if err != nil { return nil, err diff --git a/test_test.go b/test_test.go index f10fd86..9e80304 100644 --- a/test_test.go +++ b/test_test.go @@ -70,6 +70,7 @@ func TestCreateRequestBuilder_MarshalBody(t *testing.T) { ) ht := &Test{ + jsonMarshaler: jsonMarshaler{}, Request: &Request{ Builders: []RequestBuilder{ WithMarshalBody(str),