feat: add conditional verify support (#209)
This commit is contained in:
parent
51bfd94849
commit
80ceae3988
|
@ -133,12 +133,36 @@
|
|||
"type": "string"
|
||||
}
|
||||
},
|
||||
"conditionalVerify": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/ConditionalVerify"
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"title": "Expect"
|
||||
},
|
||||
"ConditionalVerify": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"condition": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"verify":{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Request": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
|
|
2
go.mod
2
go.mod
|
@ -5,7 +5,7 @@ go 1.18
|
|||
require (
|
||||
github.com/Masterminds/sprig/v3 v3.2.3
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883
|
||||
github.com/antonmedv/expr v1.14.0
|
||||
github.com/antonmedv/expr v1.15.0
|
||||
github.com/bufbuild/protocompile v0.6.0
|
||||
github.com/cucumber/godog v0.12.6
|
||||
github.com/flopp/go-findfont v0.1.0
|
||||
|
|
6
go.sum
6
go.sum
|
@ -6,8 +6,8 @@ github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj
|
|||
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/antonmedv/expr v1.14.0 h1:C4BHw+0cVyKy/ndU3uqYo6TV5rCtq/SY2Wdlwanvo/Q=
|
||||
github.com/antonmedv/expr v1.14.0/go.mod h1:FPC8iWArxls7axbVLsW+kpg1mz29A1b2M6jt+hZfDkU=
|
||||
github.com/antonmedv/expr v1.15.0 h1:sBHNMx1i+b1lZfkBFGhicvSLW6RLnca3R0B7jWrk8iM=
|
||||
github.com/antonmedv/expr v1.15.0/go.mod h1:0E/6TxnOlRNp81GMzX9QfDPAmHo2Phg00y4JUv1ihsE=
|
||||
github.com/bufbuild/protocompile v0.6.0 h1:Uu7WiSQ6Yj9DbkdnOe7U4mNKp58y9WDMKDn28/ZlunY=
|
||||
github.com/bufbuild/protocompile v0.6.0/go.mod h1:YNP35qEYoYGme7QMtz5SBCoN4kL4g12jTtjuzRNdjpE=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
|
@ -115,7 +115,6 @@ github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUq
|
|||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
|
@ -123,7 +122,6 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
|
|||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
|
||||
|
|
|
@ -31,24 +31,49 @@ import (
|
|||
|
||||
// Verify if the data satisfies the expression.
|
||||
func Verify(expect testing.Response, data map[string]any) (err error) {
|
||||
for _, verify := range expect.Verify {
|
||||
var program *vm.Program
|
||||
if program, err = expr.Compile(verify, expr.Env(data),
|
||||
expr.AsBool(), kubernetes.PodValidatorFunc(),
|
||||
kubernetes.KubernetesValidatorFunc()); err != nil {
|
||||
return err
|
||||
for _, verifyExpr := range expect.Verify {
|
||||
var ok bool
|
||||
if ok, err = verify(verifyExpr, data); !ok {
|
||||
err = fmt.Errorf("failed to verify: %q, %v", verifyExpr, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for _, verifyCon := range expect.ConditionalVerify {
|
||||
pass := true
|
||||
for _, con := range verifyCon.Condition {
|
||||
if ok, _ := verify(con, data); !ok {
|
||||
pass = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var result interface{}
|
||||
if result, err = expr.Run(program, data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !result.(bool) {
|
||||
err = fmt.Errorf("failed to verify: %s", verify)
|
||||
fmt.Println(err)
|
||||
break
|
||||
if pass {
|
||||
for _, verifyExpr := range verifyCon.Verify {
|
||||
var ok bool
|
||||
if ok, err = verify(verifyExpr, data); !ok {
|
||||
err = fmt.Errorf("failed to verify: %q, %v", verifyExpr, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func verify(verify string, data map[string]any) (ok bool, err error) {
|
||||
var program *vm.Program
|
||||
if program, err = expr.Compile(verify, expr.Env(data),
|
||||
expr.AsBool(), kubernetes.PodValidatorFunc(),
|
||||
kubernetes.KubernetesValidatorFunc()); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var result interface{}
|
||||
if result, err = expr.Run(program, data); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ok = result.(bool)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 API Testing Authors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
package runner_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/linuxsuren/api-testing/pkg/runner"
|
||||
atest "github.com/linuxsuren/api-testing/pkg/testing"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestVerify(t *testing.T) {
|
||||
t.Run("conditionalVerify", func(t *testing.T) {
|
||||
err := runner.Verify(atest.Response{
|
||||
ConditionalVerify: []atest.ConditionalVerify{{
|
||||
Condition: []string{
|
||||
"1 == 1",
|
||||
"2 == 2",
|
||||
},
|
||||
Verify: []string{"1 == 2"},
|
||||
}},
|
||||
}, nil)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = runner.Verify(atest.Response{
|
||||
ConditionalVerify: []atest.ConditionalVerify{{
|
||||
Condition: []string{"1 != 1"},
|
||||
Verify: []string{"1 == 2"},
|
||||
}},
|
||||
}, nil)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Rick
|
||||
Copyright (c) 2023 API Testing Authors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Rick
|
||||
Copyright (c) 2023 API Testing Authors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -529,12 +529,27 @@ func convertToTestingTestCase(in *TestCase) (result testing.TestCase) {
|
|||
result.Expect.Schema = resp.Schema
|
||||
result.Expect.StatusCode = int(resp.StatusCode)
|
||||
result.Expect.Verify = resp.Verify
|
||||
result.Expect.ConditionalVerify = convertConditionalVerify(resp.ConditionalVerify)
|
||||
result.Expect.BodyFieldsExpect = pairToInterMap(resp.BodyFieldsExpect)
|
||||
result.Expect.Header = pairToMap(resp.Header)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func convertConditionalVerify(verify []*ConditionalVerify) (result []testing.ConditionalVerify) {
|
||||
if verify != nil {
|
||||
result = make([]testing.ConditionalVerify, 0)
|
||||
|
||||
for _, item := range verify {
|
||||
result = append(result, testing.ConditionalVerify{
|
||||
Condition: item.Condition,
|
||||
Verify: item.Verify,
|
||||
})
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *server) CreateTestCase(ctx context.Context, in *TestCaseWithSuite) (reply *HelloReply, err error) {
|
||||
reply = &HelloReply{}
|
||||
loader := s.getLoader(ctx)
|
||||
|
|
|
@ -38,6 +38,7 @@ import (
|
|||
_ "embed"
|
||||
|
||||
"github.com/h2non/gock"
|
||||
atest "github.com/linuxsuren/api-testing/pkg/testing"
|
||||
atesting "github.com/linuxsuren/api-testing/pkg/testing"
|
||||
"github.com/linuxsuren/api-testing/sample"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -428,6 +429,16 @@ func TestListTestCase(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.NotNil(t, reply)
|
||||
})
|
||||
|
||||
t.Run("convertConditionalVerify", func(t *testing.T) {
|
||||
assert.Equal(t, []atest.ConditionalVerify{{
|
||||
Condition: []string{"1 == 1"},
|
||||
Verify: []string{"1 == 1"},
|
||||
}}, convertConditionalVerify([]*ConditionalVerify{{
|
||||
Condition: []string{"1 == 1"},
|
||||
Verify: []string{"1 == 1"},
|
||||
}}))
|
||||
})
|
||||
}
|
||||
|
||||
func TestRemoteServerSuite(t *testing.T) {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -146,7 +146,13 @@ message Response {
|
|||
repeated Pair header = 3;
|
||||
repeated Pair bodyFieldsExpect = 4;
|
||||
repeated string verify = 5;
|
||||
string schema = 6;
|
||||
repeated ConditionalVerify ConditionalVerify = 6;
|
||||
string schema = 7;
|
||||
}
|
||||
|
||||
message ConditionalVerify {
|
||||
repeated string condition = 1;
|
||||
repeated string verify = 2;
|
||||
}
|
||||
|
||||
message TestCaseResult {
|
||||
|
|
|
@ -64,10 +64,16 @@ type Request struct {
|
|||
|
||||
// Response is the expected response
|
||||
type Response struct {
|
||||
StatusCode int `yaml:"statusCode,omitempty" json:"statusCode,omitempty"`
|
||||
Body string `yaml:"body,omitempty" json:"body,omitempty"`
|
||||
Header map[string]string `yaml:"header,omitempty" json:"header,omitempty"`
|
||||
BodyFieldsExpect map[string]interface{} `yaml:"bodyFieldsExpect,omitempty" json:"bodyFieldsExpect,omitempty"`
|
||||
Verify []string `yaml:"verify,omitempty" json:"verify,omitempty"`
|
||||
Schema string `yaml:"schema,omitempty" json:"schema,omitempty"`
|
||||
StatusCode int `yaml:"statusCode,omitempty" json:"statusCode,omitempty"`
|
||||
Body string `yaml:"body,omitempty" json:"body,omitempty"`
|
||||
Header map[string]string `yaml:"header,omitempty" json:"header,omitempty"`
|
||||
BodyFieldsExpect map[string]interface{} `yaml:"bodyFieldsExpect,omitempty" json:"bodyFieldsExpect,omitempty"`
|
||||
Verify []string `yaml:"verify,omitempty" json:"verify,omitempty"`
|
||||
ConditionalVerify []ConditionalVerify `yaml:"conditionalVerify,omitempty" json:"conditionalVerify,omitempty"`
|
||||
Schema string `yaml:"schema,omitempty" json:"schema,omitempty"`
|
||||
}
|
||||
|
||||
type ConditionalVerify struct {
|
||||
Condition []string `yaml:"condition,omitempty" json:"condition,omitempty"`
|
||||
Verify []string `yaml:"verify,omitempty" json:"verify,omitempty"`
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue