diff --git a/Dockerfile b/Dockerfile index 65b974cc..1fad9d5e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.17 as builder +FROM golang:1.18 as builder WORKDIR /workspace COPY . . diff --git a/cmd/run.go b/cmd/run.go index bfe195ba..809a15b2 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -33,6 +33,7 @@ type runOption struct { reportWriter runner.ReportResultWriter report string reportIgnore bool + level string } func newDefaultRunOption() *runOption { @@ -66,6 +67,7 @@ See also https://github.com/LinuxSuRen/api-testing/tree/master/sample`, flags := cmd.Flags() flags.StringVarP(&opt.pattern, "pattern", "p", "test-suite-*.yaml", "The file pattern which try to execute the test cases") + flags.StringVarP(&opt.level, "level", "l", "info", "Set the output log level") flags.DurationVarP(&opt.duration, "duration", "", 0, "Running duration") flags.DurationVarP(&opt.requestTimeout, "request-timeout", "", time.Minute, "Timeout for per request") flags.BoolVarP(&opt.requestIgnoreError, "request-ignore-error", "", false, "Indicate if ignore the request error") diff --git a/go.mod b/go.mod index ef0c8e1f..4d012b3b 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/linuxsuren/api-testing -go 1.17 +go 1.18 require ( github.com/Masterminds/sprig/v3 v3.2.3 diff --git a/pkg/runner/simple.go b/pkg/runner/simple.go index ba090154..f447db5d 100644 --- a/pkg/runner/simple.go +++ b/pkg/runner/simple.go @@ -22,9 +22,60 @@ import ( unstructured "github.com/linuxsuren/unstructured/pkg" ) +// 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...) +} + +// TestCaseRunner represents a test case runner type TestCaseRunner interface { RunTestCase(testcase *testing.TestCase, dataContext interface{}, ctx context.Context) (output interface{}, err error) WithOutputWriter(io.Writer) TestCaseRunner + WithWriteLevel(level string) TestCaseRunner WithTestReporter(TestReporter) TestCaseRunner } @@ -32,6 +83,7 @@ type TestCaseRunner interface { type ReportRecord struct { Method string API string + Body string BeginTime time.Time EndTime time.Time Error error @@ -103,17 +155,20 @@ type TestReporter interface { type simpleTestCaseRunner struct { testReporter TestReporter writer io.Writer + log LevelWriter } // NewSimpleTestCaseRunner creates the instance of the simple test case runner func NewSimpleTestCaseRunner() TestCaseRunner { runner := &simpleTestCaseRunner{} - return runner.WithOutputWriter(io.Discard).WithTestReporter(NewDiscardTestReporter()) + return runner.WithOutputWriter(io.Discard). + WithWriteLevel("info"). + WithTestReporter(NewDiscardTestReporter()) } // RunTestCase is the main entry point of a test case func (r *simpleTestCaseRunner) RunTestCase(testcase *testing.TestCase, dataContext interface{}, ctx context.Context) (output interface{}, err error) { - fmt.Fprintf(r.writer, "start to run: '%s'\n", testcase.Name) + r.log.Info("start to run: '%s'\n", testcase.Name) record := NewReportRecord() defer func(rr *ReportRecord) { rr.EndTime = time.Now() @@ -182,7 +237,7 @@ func (r *simpleTestCaseRunner) RunTestCase(testcase *testing.TestCase, dataConte request.Header.Add(key, val) } - fmt.Fprintf(r.writer, "start to send request to %s\n", testcase.Request.API) + r.log.Info("start to send request to %s\n", testcase.Request.API) // send the HTTP request var resp *http.Response @@ -194,6 +249,8 @@ func (r *simpleTestCaseRunner) RunTestCase(testcase *testing.TestCase, dataConte if responseBodyData, err = io.ReadAll(resp.Body); err != nil { return } + record.Body = string(responseBodyData) + r.log.Debug("response body: %s\n", record.Body) if err = testcase.Expect.Render(nil); err != nil { return @@ -218,6 +275,7 @@ func (r *simpleTestCaseRunner) RunTestCase(testcase *testing.TestCase, dataConte } } + var bodyMap map[string]interface{} mapOutput := map[string]interface{}{} if err = json.Unmarshal(responseBodyData, &mapOutput); err != nil { switch b := err.(type) { @@ -231,17 +289,22 @@ func (r *simpleTestCaseRunner) RunTestCase(testcase *testing.TestCase, dataConte return } output = arrayOutput + mapOutput["data"] = arrayOutput default: return } } else { + bodyMap = mapOutput output = mapOutput + mapOutput = map[string]interface{}{ + "data": bodyMap, + } } for key, expectVal := range testcase.Expect.BodyFieldsExpect { var val interface{} var ok bool - if val, ok, err = unstructured.NestedField(mapOutput, strings.Split(key, "/")...); err != nil { + if val, ok, err = unstructured.NestedField(bodyMap, strings.Split(key, "/")...); err != nil { err = fmt.Errorf("failed to get field: %s, %v", key, err) return } else if !ok { @@ -260,12 +323,12 @@ func (r *simpleTestCaseRunner) RunTestCase(testcase *testing.TestCase, dataConte for _, verify := range testcase.Expect.Verify { var program *vm.Program - if program, err = expr.Compile(verify, expr.Env(output), expr.AsBool()); err != nil { + if program, err = expr.Compile(verify, expr.Env(mapOutput), expr.AsBool()); err != nil { return } var result interface{} - if result, err = expr.Run(program, output); err != nil { + if result, err = expr.Run(program, mapOutput); err != nil { return } @@ -283,6 +346,14 @@ func (r *simpleTestCaseRunner) WithOutputWriter(writer io.Writer) TestCaseRunner return r } +// WithWriteLevel sets the level writer +func (r *simpleTestCaseRunner) WithWriteLevel(level string) TestCaseRunner { + if level != "" { + r.log = NewDefaultLevelWriter(level, r.writer) + } + return r +} + // WithTestReporter sets the TestReporter func (r *simpleTestCaseRunner) WithTestReporter(reporter TestReporter) TestCaseRunner { r.testReporter = reporter diff --git a/pkg/runner/simple_test.go b/pkg/runner/simple_test.go index 1846f8c4..8adbcb26 100644 --- a/pkg/runner/simple_test.go +++ b/pkg/runner/simple_test.go @@ -1,6 +1,7 @@ package runner import ( + "bytes" "context" "errors" "net/http" @@ -40,7 +41,7 @@ func TestTestCase(t *testing.T) { "type": "generic", }, Verify: []string{ - `name == "linuxsuren"`, + `data.name == "linuxsuren"`, }, }, }, @@ -242,7 +243,7 @@ func TestTestCase(t *testing.T) { }, Expect: atest.Response{ Verify: []string{ - "len(items) > 0", + "len(data.items) > 0", }, }, }, @@ -372,5 +373,33 @@ func TestTestCase(t *testing.T) { } } +func TestLevelWriter(t *testing.T) { + tests := []struct { + name string + buf *bytes.Buffer + level string + expect string + }{{ + name: "debug", + buf: new(bytes.Buffer), + level: "debug", + expect: "debuginfo", + }, { + name: "info", + buf: new(bytes.Buffer), + level: "info", + expect: "info", + }} + for _, tt := range tests { + writer := NewDefaultLevelWriter(tt.level, tt.buf) + if assert.NotNil(t, writer) { + writer.Debug("debug") + writer.Info("info") + + assert.Equal(t, tt.expect, tt.buf.String()) + } + } +} + //go:embed testdata/generic_response.json var genericBody string diff --git a/pkg/server/fake_server.go b/pkg/server/fake_server.go new file mode 100644 index 00000000..ca01e7d1 --- /dev/null +++ b/pkg/server/fake_server.go @@ -0,0 +1,73 @@ +package server + +import ( + context "context" + "log" + "net" + + grpc "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/test/bufconn" +) + +type fakeServer struct { + UnimplementedRunnerServer + version string + err error +} + +// NewServer creates a fake server +func NewServer(version string, err error) RunnerServer { + t := &fakeServer{ + version: version, + err: err, + } + return t +} + +// Run runs the task +func (s *fakeServer) Run(ctx context.Context, in *TestTask) (*HelloReply, error) { + return &HelloReply{}, s.err +} + +// GetVersion returns the version +func (s *fakeServer) GetVersion(ctx context.Context, in *Empty) (reply *HelloReply, err error) { + reply = &HelloReply{ + Message: s.version, + } + err = s.err + return +} + +// NewFakeClient creates a fake client +func NewFakeClient(ctx context.Context, version string, err error) (RunnerClient, func()) { + buffer := 101024 * 1024 + lis := bufconn.Listen(buffer) + + baseServer := grpc.NewServer() + RegisterRunnerServer(baseServer, NewServer(version, err)) + go func() { + if err := baseServer.Serve(lis); err != nil { + log.Printf("error serving server: %v", err) + } + }() + + conn, err := grpc.DialContext(ctx, "", + grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) { + return lis.Dial() + }), grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + log.Printf("error connecting to server: %v", err) + } + + closer := func() { + err := lis.Close() + if err != nil { + log.Printf("error closing listener: %v", err) + } + baseServer.Stop() + } + + client := NewRunnerClient(conn) + return client, closer +} diff --git a/pkg/server/remote_server.go b/pkg/server/remote_server.go index 1ba3b74c..1aef7b35 100644 --- a/pkg/server/remote_server.go +++ b/pkg/server/remote_server.go @@ -26,6 +26,10 @@ func NewRemoteServer() RunnerServer { // Run start to run the test task func (s *server) Run(ctx context.Context, task *TestTask) (reply *HelloReply, err error) { + if task.Level == "" { + task.Level = "info" + } + var suite *testing.TestSuite if task.Env == nil { task.Env = map[string]string{} @@ -88,7 +92,8 @@ func (s *server) Run(ctx context.Context, task *TestTask) (reply *HelloReply, er return } - fmt.Println("prepare to run:", suite.Name) + fmt.Printf("prepare to run: %s, with level: %s\n", suite.Name, task.Level) + fmt.Printf("task kind: %s, %d to run\n", task.Kind, len(suite.Items)) dataContext := map[string]interface{}{} var result string @@ -104,6 +109,7 @@ func (s *server) Run(ctx context.Context, task *TestTask) (reply *HelloReply, er for _, testCase := range suite.Items { simpleRunner := runner.NewSimpleTestCaseRunner() simpleRunner.WithOutputWriter(buf) + simpleRunner.WithWriteLevel(task.Level) // reuse the API prefix if strings.HasPrefix(testCase.Request.API, "/") { @@ -128,20 +134,26 @@ func (s *server) GetVersion(ctx context.Context, in *Empty) (reply *HelloReply, } func findParentTestCases(testcase *testing.TestCase, suite *testing.TestSuite) (testcases []testing.TestCase) { - reg, matchErr := regexp.Compile(`.*\{\{\.\w*\..*}\}.*`) - targetReg, targetErr := regexp.Compile(`\{\{\.\w*\.`) + reg, matchErr := regexp.Compile(`.*\{\{.*\.\w*.*}\}.*`) + targetReg, targetErr := regexp.Compile(`\.\w*`) if matchErr == nil && targetErr == nil { expectName := "" for _, val := range testcase.Request.Header { if matched := reg.MatchString(val); matched { expectName = targetReg.FindString(val) - expectName = strings.TrimPrefix(expectName, "{{.") - expectName = strings.TrimSuffix(expectName, ".") + expectName = strings.TrimPrefix(expectName, ".") break } } + if expectName == "" { + if mached := reg.MatchString(testcase.Request.API); mached { + expectName = targetReg.FindString(testcase.Request.API) + expectName = strings.TrimPrefix(expectName, ".") + } + } + for _, item := range suite.Items { if item.Name == expectName { testcases = append(testcases, item) diff --git a/pkg/server/remote_server_test.go b/pkg/server/remote_server_test.go index fb597bf0..dba0b089 100644 --- a/pkg/server/remote_server_test.go +++ b/pkg/server/remote_server_test.go @@ -86,6 +86,27 @@ func TestFindParentTestCases(t *testing.T) { name: "empty cases", testcase: &atesting.TestCase{}, suite: &atesting.TestSuite{}, + }, { + name: "complex", + testcase: &atesting.TestCase{ + Name: "user", + Request: atesting.Request{ + API: "/users/{{(index .login 0).name}}", + }, + }, + suite: &atesting.TestSuite{ + Items: []atesting.TestCase{{ + Name: "login", + }, { + Name: "user", + Request: atesting.Request{ + API: "/users/{{(index .login 0).name}}", + }, + }}, + }, + expect: []atesting.TestCase{{ + Name: "login", + }}, }} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/server/server.pb.go b/pkg/server/server.pb.go index dd728648..83930a77 100644 --- a/pkg/server/server.pb.go +++ b/pkg/server/server.pb.go @@ -24,7 +24,8 @@ type TestTask struct { Data string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` Kind string `protobuf:"bytes,2,opt,name=kind,proto3" json:"kind,omitempty"` CaseName string `protobuf:"bytes,3,opt,name=caseName,proto3" json:"caseName,omitempty"` - Env map[string]string `protobuf:"bytes,4,rep,name=env,proto3" json:"env,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Level string `protobuf:"bytes,4,opt,name=level,proto3" json:"level,omitempty"` + Env map[string]string `protobuf:"bytes,5,rep,name=env,proto3" json:"env,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -76,6 +77,13 @@ func (m *TestTask) GetCaseName() string { return "" } +func (m *TestTask) GetLevel() string { + if m != nil { + return m.Level + } + return "" +} + func (m *TestTask) GetEnv() map[string]string { if m != nil { return m.Env @@ -165,24 +173,24 @@ func init() { } var fileDescriptor_36fb7b77b8f76c98 = []byte{ - // 291 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0x4d, 0x4b, 0xf3, 0x40, - 0x14, 0x85, 0xdf, 0x34, 0x6d, 0x9a, 0xf7, 0x8a, 0x50, 0x2e, 0x82, 0x31, 0xab, 0x92, 0x85, 0x14, - 0xb4, 0x09, 0x56, 0x10, 0x71, 0x29, 0x04, 0x5d, 0xb9, 0x08, 0xc5, 0x85, 0xbb, 0x69, 0x7b, 0x89, - 0x63, 0x92, 0x49, 0x98, 0x8f, 0x60, 0x7e, 0x97, 0x7f, 0x50, 0xf2, 0x65, 0x41, 0x5c, 0xcd, 0x39, - 0x0f, 0xf7, 0xde, 0x33, 0x70, 0xe0, 0xbc, 0xca, 0xd2, 0x48, 0x91, 0xac, 0x49, 0x0e, 0x4f, 0x58, - 0xc9, 0x52, 0x97, 0xe8, 0xf4, 0x2e, 0xf8, 0xb2, 0xc0, 0xdd, 0x92, 0xd2, 0x5b, 0xa6, 0x32, 0x44, - 0x98, 0x1e, 0x98, 0x66, 0x9e, 0xb5, 0xb4, 0x56, 0xff, 0x93, 0x4e, 0xb7, 0x2c, 0xe3, 0xe2, 0xe0, - 0x4d, 0x7a, 0xd6, 0x6a, 0xf4, 0xc1, 0xdd, 0x33, 0x45, 0x2f, 0xac, 0x20, 0xcf, 0xee, 0xf8, 0x8f, - 0xc7, 0x2b, 0xb0, 0x49, 0xd4, 0xde, 0x74, 0x69, 0xaf, 0x4e, 0x36, 0x17, 0xe1, 0x10, 0x3a, 0x46, - 0x84, 0xb1, 0xa8, 0x63, 0xa1, 0x65, 0x93, 0xb4, 0x53, 0xfe, 0x1d, 0xb8, 0x23, 0xc0, 0x05, 0xd8, - 0x19, 0x35, 0x43, 0x76, 0x2b, 0xf1, 0x0c, 0x66, 0x35, 0xcb, 0x0d, 0x0d, 0xd9, 0xbd, 0x79, 0x98, - 0xdc, 0x5b, 0xc1, 0x25, 0xc0, 0x33, 0xe5, 0x79, 0x99, 0x50, 0x95, 0x37, 0xe8, 0xc1, 0xbc, 0x20, - 0xa5, 0x58, 0x4a, 0xc3, 0xf6, 0x68, 0x83, 0x39, 0xcc, 0xe2, 0xa2, 0xd2, 0xcd, 0xe6, 0x03, 0x9c, - 0xc4, 0x08, 0x41, 0x12, 0xd7, 0x60, 0x27, 0x46, 0xe0, 0xe2, 0xf7, 0xcf, 0x7c, 0x1c, 0xc9, 0xf1, - 0x72, 0xf0, 0x0f, 0x6f, 0x00, 0x9e, 0x48, 0xbf, 0x92, 0x54, 0xbc, 0x14, 0x78, 0x3a, 0xce, 0x74, - 0x57, 0xff, 0x5e, 0x79, 0x0c, 0xdf, 0xae, 0x53, 0xae, 0xdf, 0xcd, 0x2e, 0xdc, 0x97, 0x45, 0x94, - 0x73, 0x61, 0x3e, 0x95, 0x91, 0x24, 0x22, 0x56, 0xf1, 0xb5, 0x26, 0xa5, 0xb9, 0x48, 0xa3, 0x63, - 0x2f, 0x3b, 0xa7, 0x6b, 0xe4, 0xf6, 0x3b, 0x00, 0x00, 0xff, 0xff, 0xf9, 0x82, 0x4d, 0xe3, 0xac, - 0x01, 0x00, 0x00, + // 301 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0x4b, 0x4b, 0xfb, 0x40, + 0x14, 0xc5, 0xff, 0x69, 0xfa, 0xfa, 0x5f, 0x11, 0xca, 0x45, 0x70, 0xec, 0xaa, 0x64, 0x21, 0x05, + 0x6d, 0x82, 0x15, 0x44, 0x5c, 0x0a, 0x45, 0x57, 0x2e, 0x42, 0x71, 0xe1, 0x6e, 0xda, 0x5e, 0xe2, + 0x98, 0xc9, 0x24, 0xcc, 0x23, 0x98, 0x8f, 0xe8, 0xb7, 0x92, 0xbc, 0x2c, 0x88, 0xab, 0x39, 0xe7, + 0x37, 0xf7, 0x71, 0xe0, 0xc2, 0x79, 0x91, 0x26, 0x91, 0x21, 0x5d, 0x92, 0xee, 0x9e, 0xb0, 0xd0, + 0xb9, 0xcd, 0x71, 0xdc, 0xba, 0xe0, 0xcb, 0x83, 0xe9, 0x96, 0x8c, 0xdd, 0x72, 0x93, 0x22, 0xc2, + 0xf0, 0xc0, 0x2d, 0x67, 0xde, 0xc2, 0x5b, 0xfe, 0x8f, 0x1b, 0x5d, 0xb3, 0x54, 0xa8, 0x03, 0x1b, + 0xb4, 0xac, 0xd6, 0x38, 0x87, 0xe9, 0x9e, 0x1b, 0x7a, 0xe1, 0x19, 0x31, 0xbf, 0xe1, 0x3f, 0x1e, + 0xcf, 0x60, 0x24, 0xa9, 0x24, 0xc9, 0x86, 0xcd, 0x47, 0x6b, 0xf0, 0x0a, 0x7c, 0x52, 0x25, 0x1b, + 0x2d, 0xfc, 0xe5, 0xc9, 0xfa, 0x22, 0xec, 0xa2, 0xf4, 0x8b, 0xc3, 0x8d, 0x2a, 0x37, 0xca, 0xea, + 0x2a, 0xae, 0xab, 0xe6, 0x77, 0x30, 0xed, 0x01, 0xce, 0xc0, 0x4f, 0xa9, 0xea, 0x12, 0xd5, 0xb2, + 0x5e, 0x50, 0x72, 0xe9, 0xa8, 0x4b, 0xd4, 0x9a, 0x87, 0xc1, 0xbd, 0x17, 0x5c, 0x02, 0x3c, 0x93, + 0x94, 0x79, 0x4c, 0x85, 0xac, 0x90, 0xc1, 0x24, 0x23, 0x63, 0x78, 0x42, 0x5d, 0x77, 0x6f, 0x83, + 0x09, 0x8c, 0x36, 0x59, 0x61, 0xab, 0xf5, 0x07, 0x8c, 0x63, 0xa7, 0x14, 0x69, 0x5c, 0x81, 0x1f, + 0x3b, 0x85, 0xb3, 0xdf, 0xc9, 0xe6, 0xd8, 0x93, 0xe3, 0xe4, 0xe0, 0x1f, 0xde, 0x00, 0x3c, 0x91, + 0x7d, 0x25, 0x6d, 0x44, 0xae, 0xf0, 0xb4, 0xaf, 0x69, 0xa6, 0xfe, 0xdd, 0xf2, 0x18, 0xbe, 0x5d, + 0x27, 0xc2, 0xbe, 0xbb, 0x5d, 0xb8, 0xcf, 0xb3, 0x48, 0x0a, 0xe5, 0x3e, 0x8d, 0xd3, 0xa4, 0x22, + 0x5e, 0x88, 0x95, 0x25, 0x63, 0x85, 0x4a, 0xa2, 0xe3, 0xb5, 0x76, 0xe3, 0xe6, 0x4e, 0xb7, 0xdf, + 0x01, 0x00, 0x00, 0xff, 0xff, 0xa2, 0x3b, 0xc8, 0x00, 0xc2, 0x01, 0x00, 0x00, } diff --git a/pkg/server/server.proto b/pkg/server/server.proto index a4b66bea..5528bfc1 100644 --- a/pkg/server/server.proto +++ b/pkg/server/server.proto @@ -13,7 +13,8 @@ message TestTask { string data = 1; string kind = 2; string caseName = 3; - map env = 4; + string level = 4; + map env = 5; } message HelloReply { diff --git a/pkg/server/server_grpc_test.go b/pkg/server/server_grpc_test.go index 718bc477..f750a2ff 100644 --- a/pkg/server/server_grpc_test.go +++ b/pkg/server/server_grpc_test.go @@ -2,14 +2,63 @@ package server_test import ( "context" + "errors" "testing" "github.com/linuxsuren/api-testing/pkg/server" "github.com/stretchr/testify/assert" ) -func TestXxx(t *testing.T) { +func TestUnimplement(t *testing.T) { unimplemented := &server.UnimplementedRunnerServer{} _, err := unimplemented.Run(context.TODO(), nil) assert.NotNil(t, err) + + _, err = unimplemented.GetVersion(context.Background(), nil) + assert.NotNil(t, err) + + var reply *server.HelloReply + assert.Empty(t, reply.GetMessage()) + assert.Empty(t, &server.Empty{}) + + var task *server.TestTask + assert.Empty(t, task.GetData()) + assert.Empty(t, task.GetKind()) + assert.Empty(t, task.GetCaseName()) + assert.Empty(t, task.GetLevel()) + assert.Nil(t, task.GetEnv()) + + task = &server.TestTask{ + Data: "data", + Kind: "kind", + CaseName: "casename", + Level: "level", + Env: map[string]string{}, + } + assert.Equal(t, "data", task.GetData()) + assert.Equal(t, "kind", task.GetKind()) + assert.Equal(t, "casename", task.GetCaseName()) + assert.Equal(t, "level", task.GetLevel()) + assert.Equal(t, map[string]string{}, task.GetEnv()) +} + +func TestServer(t *testing.T) { + client, _ := server.NewFakeClient(context.Background(), "version", nil) + reply, err := client.GetVersion(context.Background(), &server.Empty{}) + assert.NotNil(t, reply) + assert.Equal(t, "version", reply.GetMessage()) + assert.Nil(t, err) + + reply, err = client.Run(context.Background(), &server.TestTask{}) + assert.NotNil(t, reply) + assert.Nil(t, err) + + clientWithErr, _ := server.NewFakeClient(context.Background(), "version", errors.New("fake")) + reply, err = clientWithErr.GetVersion(context.Background(), &server.Empty{}) + assert.NotNil(t, err) + assert.Nil(t, reply) + + reply, err = clientWithErr.Run(context.Background(), &server.TestTask{}) + assert.NotNil(t, err) + assert.Nil(t, reply) } diff --git a/sample/testsuite-gitee.yaml b/sample/testsuite-gitee.yaml new file mode 100644 index 00000000..0f4b2835 --- /dev/null +++ b/sample/testsuite-gitee.yaml @@ -0,0 +1,22 @@ +#!api-testing +name: Gitee +api: https://gitee.com/api/v5 +items: +- name: stargazers + request: + api: /repos/linuxsuren/api-testing/stargazers + expect: + verify: + - len(["data"]) > 0 +- name: branches + request: + api: /repos/linuxsuren/api-testing/branches + expect: + verify: + - len(filter(data, .name == "master")) == 1 +- name: branche + request: + api: /repos/linuxsuren/api-testing/branches/{{(index .branches 0).name}} + expect: + verify: + - len(data.name) > 0 \ No newline at end of file diff --git a/sample/testsuite-gitlab.yaml b/sample/testsuite-gitlab.yaml index 84179a5e..6e76805b 100644 --- a/sample/testsuite-gitlab.yaml +++ b/sample/testsuite-gitlab.yaml @@ -1,3 +1,4 @@ +#!api-testing # yaml-language-server: $schema=api-testing-schema.json # https://docs.gitlab.com/ee/api/api_resources.html name: Gitlab