feat: add writeFile function to expr (#277)

This commit is contained in:
Rick 2023-11-17 14:13:04 +08:00 committed by GitHub
parent 7124dc4e29
commit 649b0d8e85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 686 additions and 97 deletions

View File

@ -17,7 +17,7 @@ fmt:
build: build:
mkdir -p bin mkdir -p bin
rm -rf bin/atest rm -rf bin/atest
go build ${TOOLEXEC} -a ${BUILD_FLAG} -o bin/${BINARY} main.go CGO_ENABLED=0 go build ${TOOLEXEC} -a ${BUILD_FLAG} -o bin/${BINARY} main.go
build-ext: build-ext-git build-ext-orm build-ext-s3 build-ext-etcd build-ext: build-ext-git build-ext-orm build-ext-s3 build-ext-etcd
build-ext-git: build-ext-git:
CGO_ENABLED=0 go build -ldflags "-w -s" -o bin/atest-store-git extensions/store-git/main.go CGO_ENABLED=0 go build -ldflags "-w -s" -o bin/atest-store-git extensions/store-git/main.go

View File

@ -261,6 +261,8 @@ func (o *runOption) runSuite(loader testing.Loader, dataContext map[string]inter
runner := runner.GetTestSuiteRunner(testSuite) runner := runner.GetTestSuiteRunner(testSuite)
runner.WithTestReporter(o.reporter) runner.WithTestReporter(o.reporter)
runner.WithSecure(testSuite.Spec.Secure) runner.WithSecure(testSuite.Spec.Secure)
runner.WithOutputWriter(os.Stdout)
runner.WithWriteLevel(o.level)
if output, err = runner.RunTestCase(&testCase, dataContext, ctxWithTimeout); err != nil && !o.requestIgnoreError { if output, err = runner.RunTestCase(&testCase, dataContext, ctxWithTimeout); err != nil && !o.requestIgnoreError {
err = fmt.Errorf("failed to run '%s', %v", testCase.Name, err) err = fmt.Errorf("failed to run '%s', %v", testCase.Name, err)
return return

View File

@ -26,32 +26,21 @@ SOFTWARE.
package runner package runner
import ( import (
"encoding/json"
"fmt" "fmt"
"io"
"log"
"net/http" "net/http"
"os"
"os/exec" "os/exec"
"time" "time"
"github.com/antonmedv/expr"
"github.com/antonmedv/expr/ast" "github.com/antonmedv/expr/ast"
"github.com/antonmedv/expr/builtin"
"github.com/antonmedv/expr/vm"
) )
var extensionFuncs = []*ast.Function{
{
Name: "sleep",
Func: ExprFuncSleep,
},
{
Name: "httpReady",
Func: ExprFuncHTTPReady,
},
{
Name: "exec",
Func: func(params ...interface{}) (res any, err error) {
exec.Command("sh", "-c", params[0].(string)).Run()
return
},
},
}
// ExprFuncSleep is an expr function for sleeping // ExprFuncSleep is an expr function for sleeping
func ExprFuncSleep(params ...interface{}) (res interface{}, err error) { func ExprFuncSleep(params ...interface{}) (res interface{}, err error) {
if len(params) < 1 { if len(params) < 1 {
@ -90,14 +79,88 @@ func ExprFuncHTTPReady(params ...interface{}) (res interface{}, err error) {
return return
} }
var resp *http.Response
for i := 0; i < retry; i++ { for i := 0; i < retry; i++ {
var resp *http.Response resp, err = http.Get(api)
if resp, err = http.Get(api); err == nil && resp != nil && resp.StatusCode == http.StatusOK { alive := err == nil && resp != nil && resp.StatusCode == http.StatusOK
if alive && len(params) >= 3 {
log.Println("checking the response")
exprText := params[2].(string)
// check the response
var data []byte
if data, err = io.ReadAll(resp.Body); err == nil {
unstruct := make(map[string]interface{})
if err = json.Unmarshal(data, &unstruct); err != nil {
log.Printf("failed to unmarshal the response data: %v\n", err)
return
}
unstruct["data"] = unstruct
var program *vm.Program
if program, err = expr.Compile(exprText, expr.Env(unstruct)); err != nil {
log.Printf("failed to compile: %s, %v\n", exprText, err)
return
}
var result interface{}
if result, err = expr.Run(program, unstruct); err != nil {
log.Printf("failed to Run: %s, %v\n", exprText, err)
return
}
if val, ok := result.(bool); ok {
if val {
return
}
} else {
err = fmt.Errorf("the result of %s should be a bool", exprText)
return
}
}
} else if alive {
return return
} }
fmt.Println("waiting for", api)
log.Println("waiting for", api)
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
} }
err = fmt.Errorf("failed to wait for the API ready in %d times", retry) err = fmt.Errorf("failed to wait for the API ready in %d times", retry)
return return
} }
func init() {
builtin.Builtins = append(builtin.Builtins, []*ast.Function{
{
Name: "sleep",
Func: ExprFuncSleep,
},
{
Name: "httpReady",
Func: ExprFuncHTTPReady,
},
{
Name: "command",
Func: func(params ...interface{}) (res any, err error) {
var output []byte
output, err = exec.Command("sh", "-c", params[0].(string)).CombinedOutput()
if output != nil {
res = string(output)
}
return
},
},
{
Name: "writeFile",
Func: func(params ...interface{}) (res any, err error) {
filename := params[0]
content := params[1]
err = os.WriteFile(filename.(string), []byte(content.(string)), 0644)
return
},
},
}...)
}

View File

@ -25,9 +25,14 @@ SOFTWARE.
package runner_test package runner_test
import ( import (
"fmt"
"io"
"net/http" "net/http"
"os"
"testing" "testing"
"github.com/antonmedv/expr"
"github.com/antonmedv/expr/vm"
"github.com/h2non/gock" "github.com/h2non/gock"
"github.com/linuxsuren/api-testing/pkg/runner" "github.com/linuxsuren/api-testing/pkg/runner"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -60,7 +65,7 @@ func TestExprFuncSleep(t *testing.T) {
func TestExprFuncHTTPReady(t *testing.T) { func TestExprFuncHTTPReady(t *testing.T) {
t.Run("normal", func(t *testing.T) { t.Run("normal", func(t *testing.T) {
defer gock.Clean() defer gock.Off()
gock.New(urlFoo).Reply(http.StatusOK) gock.New(urlFoo).Reply(http.StatusOK)
_, err := runner.ExprFuncHTTPReady(urlFoo, 1) _, err := runner.ExprFuncHTTPReady(urlFoo, 1)
@ -68,7 +73,7 @@ func TestExprFuncHTTPReady(t *testing.T) {
}) })
t.Run("failed", func(t *testing.T) { t.Run("failed", func(t *testing.T) {
defer gock.Clean() defer gock.Off()
gock.New(urlFoo).Reply(http.StatusNotFound) gock.New(urlFoo).Reply(http.StatusNotFound)
_, err := runner.ExprFuncHTTPReady(urlFoo, 1) _, err := runner.ExprFuncHTTPReady(urlFoo, 1)
@ -89,4 +94,95 @@ func TestExprFuncHTTPReady(t *testing.T) {
_, err := runner.ExprFuncHTTPReady(urlFoo, "two") _, err := runner.ExprFuncHTTPReady(urlFoo, "two")
assert.Error(t, err) assert.Error(t, err)
}) })
t.Run("check the response", func(t *testing.T) {
defer gock.Off()
gock.New(urlFoo).Reply(http.StatusOK).BodyString(`{"name": "test"}`)
_, err := runner.ExprFuncHTTPReady(urlFoo, 1, `data.name == "test"`)
assert.NoError(t, err)
})
t.Run("response is not JSON", func(t *testing.T) {
defer gock.Off()
gock.New(urlFoo).Reply(http.StatusOK).BodyString(`name: test`)
_, err := runner.ExprFuncHTTPReady(urlFoo, 1, `data.name == "test"`)
assert.Error(t, err)
})
t.Run("response checking result is failed", func(t *testing.T) {
defer gock.Off()
gock.New(urlFoo).Reply(http.StatusOK).BodyString(`{"name": "test"}`)
_, err := runner.ExprFuncHTTPReady(urlFoo, 1, `data.name == "test"`)
assert.NoError(t, err)
})
t.Run("not a bool expr", func(t *testing.T) {
defer gock.Off()
gock.New(urlFoo).Reply(http.StatusOK).BodyString(`{"name": "test"}`)
_, err := runner.ExprFuncHTTPReady(urlFoo, 1, `name + "test"`)
assert.Error(t, err)
})
t.Run("failed to compile", func(t *testing.T) {
defer gock.Off()
gock.New(urlFoo).Reply(http.StatusOK).BodyString(`{"name": "test"}`)
_, err := runner.ExprFuncHTTPReady(urlFoo, 1, `1~!@`)
assert.Error(t, err)
})
}
func TestFunctions(t *testing.T) {
tmpFile, err := os.CreateTemp(os.TempDir(), "test")
if err != nil {
t.Fatal("failed to create temp file")
}
defer os.Remove(tmpFile.Name())
tests := []struct {
name string
expr string
syntaxErr bool
verify func(t *testing.T, result any, resultErr error)
}{{
name: "invalid syntax",
expr: "sleep 1",
syntaxErr: true,
}, {
name: "command",
expr: `command("echo 1")`,
verify: func(t *testing.T, result any, resultErr error) {
assert.NoError(t, resultErr)
assert.Equal(t, "1\n", result)
},
}, {
name: "writeFile",
expr: fmt.Sprintf(`writeFile("%s", "hello")`, tmpFile.Name()),
verify: func(t *testing.T, result any, resultErr error) {
assert.NoError(t, resultErr)
data, err := io.ReadAll(tmpFile)
assert.NoError(t, err)
assert.Equal(t, "hello", string(data))
},
}}
for i, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var program *vm.Program
program, err = expr.Compile(tt.expr, expr.Env(tt))
if tt.syntaxErr {
assert.Error(t, err, "%q %d", tt.name, i)
return
}
if !assert.NotNil(t, program, "%q %d", tt.name, i) {
return
}
var result any
result, err = expr.Run(program, tt)
if tt.verify != nil {
tt.verify(t, result, err)
}
})
}
} }

View File

@ -93,7 +93,7 @@ func (r *gRPCTestCaseRunner) RunTestCase(testcase *testing.TestCase, dataContext
defer func() { defer func() {
if err == nil { if err == nil {
err = runJob(testcase.After, dataContext) err = runJob(testcase.After, dataContext, output)
} }
}() }()
@ -102,7 +102,7 @@ func (r *gRPCTestCaseRunner) RunTestCase(testcase *testing.TestCase, dataContext
return return
} }
if err = runJob(testcase.Before, dataContext); err != nil { if err = runJob(testcase.Before, dataContext, nil); err != nil {
return return
} }

View File

@ -1,3 +1,27 @@
/*
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 package runner
import ( import (
@ -22,55 +46,6 @@ import (
"github.com/xeipuuv/gojsonschema" "github.com/xeipuuv/gojsonschema"
) )
// LevelWriter represents a writer with level
type LevelWriter interface {
Info(format string, a ...any)
Debug(format string, a ...any)
}
// FormatPrinter represents a formart printer with level
type FormatPrinter interface {
Fprintf(w io.Writer, level, format string, a ...any) (n int, err error)
}
type defaultLevelWriter struct {
level int
io.Writer
FormatPrinter
}
// NewDefaultLevelWriter creates a default LevelWriter instance
func NewDefaultLevelWriter(level string, writer io.Writer) LevelWriter {
result := &defaultLevelWriter{
Writer: writer,
}
switch level {
case "debug":
result.level = 7
case "info":
result.level = 3
}
return result
}
// Fprintf implements interface FormatPrinter
func (w *defaultLevelWriter) Fprintf(writer io.Writer, level int, format string, a ...any) (n int, err error) {
if level <= w.level {
return fmt.Fprintf(writer, format, a...)
}
return
}
// Info writes the info level message
func (w *defaultLevelWriter) Info(format string, a ...any) {
w.Fprintf(w.Writer, 3, format, a...)
}
// Debug writes the debug level message
func (w *defaultLevelWriter) Debug(format string, a ...any) {
w.Fprintf(w.Writer, 7, format, a...)
}
// ReportResult represents the report result of a set of the same API requests // ReportResult represents the report result of a set of the same API requests
type ReportResult struct { type ReportResult struct {
API string API string
@ -154,7 +129,7 @@ func (r *simpleTestCaseRunner) RunTestCase(testcase *testing.TestCase, dataConte
defer func() { defer func() {
if err == nil { if err == nil {
err = runJob(testcase.After, dataContext) err = runJob(testcase.After, dataContext, output)
} }
}() }()
@ -184,7 +159,7 @@ func (r *simpleTestCaseRunner) RunTestCase(testcase *testing.TestCase, dataConte
request.Header.Add(key, val) request.Header.Add(key, val)
} }
if err = runJob(testcase.Before, dataContext); err != nil { if err = runJob(testcase.Before, dataContext, nil); err != nil {
return return
} }
@ -201,12 +176,14 @@ func (r *simpleTestCaseRunner) RunTestCase(testcase *testing.TestCase, dataConte
return return
} }
r.log.Debug("status code: %d\n", resp.StatusCode)
var responseBodyData []byte var responseBodyData []byte
if responseBodyData, err = r.withResponseRecord(resp); err != nil { if responseBodyData, err = r.withResponseRecord(resp); err != nil {
return return
} }
record.Body = string(responseBodyData) record.Body = string(responseBodyData)
r.log.Debug("response body: %s\n", record.Body) r.log.Trace("response body: %s\n", record.Body)
if err = testcase.Expect.Render(nil); err != nil { if err = testcase.Expect.Render(nil); err != nil {
return return
@ -384,12 +361,15 @@ func valueCompare(expect interface{}, acutalResult gjson.Result, key string) (er
return return
} }
func runJob(job *testing.Job, ctx interface{}) (err error) { func runJob(job *testing.Job, ctx interface{}, current interface{}) (err error) {
if job == nil { if job == nil {
return return
} }
var program *vm.Program var program *vm.Program
env := struct{}{} env := map[string]interface{}{
"ctx": ctx,
"current": current,
}
for _, item := range job.Items { for _, item := range job.Items {
var exprText string var exprText string
@ -398,7 +378,7 @@ func runJob(job *testing.Job, ctx interface{}) (err error) {
break break
} }
if program, err = expr.Compile(exprText, getCustomExprFuncs(env)...); err != nil { if program, err = expr.Compile(exprText, expr.Env(env)); err != nil {
fmt.Printf("failed to compile: %s, %v\n", item, err) fmt.Printf("failed to compile: %s, %v\n", item, err)
return return
} }
@ -410,11 +390,3 @@ func runJob(job *testing.Job, ctx interface{}) (err error) {
} }
return return
} }
func getCustomExprFuncs(env any) (opts []expr.Option) {
opts = append(opts, expr.Env(env))
for _, item := range extensionFuncs {
opts = append(opts, expr.Function(item.Name, item.Func))
}
return
}

View File

@ -460,7 +460,7 @@ func TestRunJob(t *testing.T) {
}} }}
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
err := runJob(&tt.job, nil) err := runJob(&tt.job, nil, nil)
assert.Equal(t, tt.hasErr, err != nil, err) assert.Equal(t, tt.hasErr, err != nil, err)
}) })
} }

94
pkg/runner/logger.go Normal file
View File

@ -0,0 +1,94 @@
/*
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
import (
"fmt"
"io"
)
// LevelWriter represents a writer with level
type LevelWriter interface {
Info(format string, a ...any)
Debug(format string, a ...any)
Trace(format string, a ...any)
}
// FormatPrinter represents a formart printer with level
type FormatPrinter interface {
Fprintf(w io.Writer, level, format string, a ...any) (n int, err error)
}
type defaultLevelWriter struct {
level LogLevel
io.Writer
FormatPrinter
}
// NewDefaultLevelWriter creates a default LevelWriter instance
func NewDefaultLevelWriter(level string, writer io.Writer) LevelWriter {
result := &defaultLevelWriter{
Writer: writer,
}
switch level {
case "trace":
result.level = LogLevelTrace
case "debug":
result.level = LogLevelDebug
case "info":
result.level = LogLevelInfo
}
return result
}
type LogLevel int
const (
LogLevelInfo LogLevel = 3
LogLevelDebug LogLevel = 5
LogLevelTrace LogLevel = 7
)
// Fprintf implements interface FormatPrinter
func (w *defaultLevelWriter) Fprintf(writer io.Writer, level LogLevel, format string, a ...any) (n int, err error) {
if level <= w.level {
return fmt.Fprintf(writer, format, a...)
}
return
}
// Info writes the info level message
func (w *defaultLevelWriter) Info(format string, a ...any) {
w.Fprintf(w.Writer, LogLevelInfo, format, a...)
}
// Debug writes the debug level message
func (w *defaultLevelWriter) Debug(format string, a ...any) {
w.Fprintf(w.Writer, LogLevelDebug, format, a...)
}
func (w *defaultLevelWriter) Trace(format string, a ...any) {
w.Fprintf(w.Writer, LogLevelTrace, format, a...)
}

View File

@ -1,3 +1,27 @@
/*
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 package runner
import "time" import "time"

View File

@ -1,3 +1,27 @@
/*
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 package runner
type discardTestReporter struct { type discardTestReporter struct {

View File

@ -1,3 +1,27 @@
/*
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 package runner_test
import ( import (

View File

@ -1,3 +1,27 @@
/*
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 package runner
import ( import (

View File

@ -1,3 +1,27 @@
/*
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 package runner_test
import ( import (

View File

@ -1,3 +1,27 @@
/*
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 package runner
import ( import (

View File

@ -69,7 +69,7 @@ func (r *tRPCTestCaseRunner) RunTestCase(testcase *testing.TestCase, dataContext
defer func() { defer func() {
if err == nil { if err == nil {
err = runJob(testcase.After, dataContext) err = runJob(testcase.After, dataContext, output)
} }
}() }()
@ -78,7 +78,7 @@ func (r *tRPCTestCaseRunner) RunTestCase(testcase *testing.TestCase, dataContext
return return
} }
if err = runJob(testcase.Before, dataContext); err != nil { if err = runJob(testcase.Before, dataContext, nil); err != nil {
return return
} }

View File

@ -1,3 +1,27 @@
/*
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 package runner
import "github.com/linuxsuren/api-testing/pkg/apispec" import "github.com/linuxsuren/api-testing/pkg/apispec"

View File

@ -1,3 +1,27 @@
/*
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 package runner
import ( import (

View File

@ -1,3 +1,27 @@
/*
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 package runner_test
import ( import (

View File

@ -1,11 +1,36 @@
/*
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 package runner
import ( import (
_ "embed" _ "embed"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/linuxsuren/api-testing/pkg/apispec"
"io" "io"
"github.com/linuxsuren/api-testing/pkg/apispec"
) )
type jsonResultWriter struct { type jsonResultWriter struct {

View File

@ -1,3 +1,27 @@
/*
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 package runner_test
import ( import (

View File

@ -1,3 +1,27 @@
/*
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 package runner
import ( import (

View File

@ -1,3 +1,27 @@
/*
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 package runner_test
import ( import (

View File

@ -1,15 +1,40 @@
/*
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 package runner
import ( import (
_ "embed" _ "embed"
"fmt" "fmt"
"github.com/flopp/go-findfont"
"github.com/linuxsuren/api-testing/pkg/apispec"
"github.com/signintech/gopdf"
"io" "io"
"log" "log"
"strconv" "strconv"
"github.com/flopp/go-findfont"
"github.com/linuxsuren/api-testing/pkg/apispec"
"github.com/signintech/gopdf"
) )
type pdfResultWriter struct { type pdfResultWriter struct {

View File

@ -1,3 +1,27 @@
/*
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 package runner
import ( import (

View File

@ -152,7 +152,7 @@ func TestRunTestCase(t *testing.T) {
Testcase: "get", Testcase: "get",
}) })
assert.NoError(t, err) assert.NoError(t, err)
assert.Contains(t, result.Output, "start to run: 'get'\nstart to send request to http://foo\nresponse body:") assert.Contains(t, "start to run: 'get'\nstart to send request to http://foo\nstatus code: 200\n", result.Output)
} }
func TestFindParentTestCases(t *testing.T) { func TestFindParentTestCases(t *testing.T) {