From 82f2fdf849fbab80145b19ce161be8d29f507ad3 Mon Sep 17 00:00:00 2001 From: Rick <1450685+LinuxSuRen@users.noreply.github.com> Date: Wed, 5 Apr 2023 18:59:08 +0800 Subject: [PATCH] feat: support to run a specific test case via grpc (#28) Co-authored-by: Rick --- .goreleaser.yaml | 2 +- README.md | 2 + cmd/root.go | 10 +- go.mod | 4 +- pkg/server/remote_server.go | 29 +++ pkg/server/remote_server_test.go | 22 ++ pkg/server/server.pb.go | 345 ++++++++++++++++++++++--------- pkg/server/server.proto | 5 + pkg/server/server_grpc.pb.go | 36 ++++ pkg/server/testdata/simple.yaml | 6 +- pkg/version/constants.go | 10 + pkg/version/constants_test.go | 13 ++ sample/api-testing-schema.json | 126 +++++++++++ sample/testsuite-gitlab.yaml | 1 + 14 files changed, 507 insertions(+), 104 deletions(-) create mode 100644 pkg/version/constants.go create mode 100644 pkg/version/constants_test.go create mode 100644 sample/api-testing-schema.json diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 284c265..36c33c5 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -15,7 +15,7 @@ builds: ldflags: - -w - -s - - -X github.com/linuxsuren/api-testing/cmd.version={{.Version}} + - -X github.com/linuxsuren/api-testing/pkg/version.version={{.Version}} archives: - name_template: "{{ .Binary }}-{{ .Os }}-{{ .Arch }}" format_overrides: diff --git a/README.md b/README.md index 7b9c754..abe5800 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ This is a API testing tool. * Response Body fields equation check * Response Body [eval](https://expr.medv.io/) * Output reference between TestCase +* Run in server mode, and provide the gRPC endpoint +* [VS Code extension](https://github.com/LinuxSuRen/vscode-api-testing) support ## Template The following fields are templated with [sprig](http://masterminds.github.io/sprig/): diff --git a/cmd/root.go b/cmd/root.go index 421297a..45d9750 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,9 +1,9 @@ package cmd -import "github.com/spf13/cobra" - -// should be injected during the build process -var version string +import ( + "github.com/linuxsuren/api-testing/pkg/version" + "github.com/spf13/cobra" +) // NewRootCmd creates the root command func NewRootCmd() (c *cobra.Command) { @@ -11,7 +11,7 @@ func NewRootCmd() (c *cobra.Command) { Use: "atest", Short: "API testing tool", } - c.Version = version + c.Version = version.GetVersion() c.AddCommand(createInitCommand(), createRunCommand(), createSampleCmd(), createServerCmd()) diff --git a/go.mod b/go.mod index 27b6dc9..82fc3ae 100644 --- a/go.mod +++ b/go.mod @@ -6,13 +6,13 @@ require ( github.com/Masterminds/sprig/v3 v3.2.3 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 github.com/antonmedv/expr v1.12.1 - github.com/golang/protobuf v1.5.2 github.com/h2non/gock v1.2.0 github.com/linuxsuren/unstructured v0.0.1 github.com/spf13/cobra v1.6.1 github.com/stretchr/testify v1.8.2 golang.org/x/sync v0.1.0 google.golang.org/grpc v1.54.0 + google.golang.org/protobuf v1.30.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -20,6 +20,7 @@ require ( github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/golang/protobuf v1.5.2 // indirect github.com/google/uuid v1.3.0 // indirect github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect github.com/huandu/xstrings v1.3.3 // indirect @@ -37,6 +38,5 @@ require ( golang.org/x/sys v0.6.0 // indirect golang.org/x/text v0.8.0 // indirect google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/server/remote_server.go b/pkg/server/remote_server.go index 4b8c2aa..c759e87 100644 --- a/pkg/server/remote_server.go +++ b/pkg/server/remote_server.go @@ -10,6 +10,7 @@ import ( "github.com/linuxsuren/api-testing/pkg/render" "github.com/linuxsuren/api-testing/pkg/runner" "github.com/linuxsuren/api-testing/pkg/testing" + "github.com/linuxsuren/api-testing/pkg/version" ) type server struct { @@ -41,6 +42,28 @@ func (s *server) Run(ctx context.Context, task *TestTask) (reply *HelloReply, er suite = &testing.TestSuite{ Items: []testing.TestCase{*testCase}, } + case "testcaseInSuite": + if suite, err = testing.ParseFromData([]byte(task.Data)); err != nil { + return + } else if suite == nil || suite.Items == nil { + err = fmt.Errorf("no test suite found") + return + } + + var targetTestcase *testing.TestCase + for _, item := range suite.Items { + if item.Name == task.CaseName { + targetTestcase = &item + break + } + } + + if targetTestcase != nil { + suite.Items = []testing.TestCase{*targetTestcase} + } else { + err = fmt.Errorf("cannot found testcase %s", task.CaseName) + return + } default: err = fmt.Errorf("not support '%s'", task.Kind) return @@ -77,3 +100,9 @@ func (s *server) Run(ctx context.Context, task *TestTask) (reply *HelloReply, er reply = &HelloReply{Message: buf.String()} return } + +// GetVersion returns the version +func (s *server) GetVersion(ctx context.Context, in *Empty) (reply *HelloReply, err error) { + reply = &HelloReply{Message: version.GetVersion()} + return +} diff --git a/pkg/server/remote_server_test.go b/pkg/server/remote_server_test.go index 0ca73bb..5b1f3ac 100644 --- a/pkg/server/remote_server_test.go +++ b/pkg/server/remote_server_test.go @@ -18,6 +18,7 @@ func TestRemoteServer(t *testing.T) { }) assert.NotNil(t, err) + gock.New("http://foo").Get("/").Reply(http.StatusOK).JSON(&server) gock.New("http://foo").Get("/").Reply(http.StatusOK).JSON(&server) _, err = server.Run(context.TODO(), &TestTask{ Kind: "suite", @@ -31,6 +32,27 @@ func TestRemoteServer(t *testing.T) { Data: simpleTestCase, }) assert.Nil(t, err) + + gock.New("http://foo").Get("/").Reply(http.StatusOK).JSON(&server) + _, err = server.Run(context.TODO(), &TestTask{ + Kind: "testcaseInSuite", + Data: simpleSuite, + CaseName: "get", + }) + assert.Nil(t, err) + + gock.New("http://foo").Get("/").Reply(http.StatusOK).JSON(&server) + _, err = server.Run(context.TODO(), &TestTask{ + Kind: "testcaseInSuite", + Data: simpleSuite, + CaseName: "fake", + }) + assert.NotNil(t, err) + + var ver *HelloReply + ver, err = server.GetVersion(context.TODO(), &Empty{}) + assert.Empty(t, ver.Message) + assert.Nil(t, err) } //go:embed testdata/simple.yaml diff --git a/pkg/server/server.pb.go b/pkg/server/server.pb.go index e52ec92..2cb0b9d 100644 --- a/pkg/server/server.pb.go +++ b/pkg/server/server.pb.go @@ -1,133 +1,288 @@ // Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v4.22.2 // source: pkg/server/server.proto package server import ( - fmt "fmt" - proto "github.com/golang/protobuf/proto" - math "math" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) 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"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + 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"` } -func (m *TestTask) Reset() { *m = TestTask{} } -func (m *TestTask) String() string { return proto.CompactTextString(m) } -func (*TestTask) ProtoMessage() {} +func (x *TestTask) Reset() { + *x = TestTask{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_server_server_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TestTask) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TestTask) ProtoMessage() {} + +func (x *TestTask) ProtoReflect() protoreflect.Message { + mi := &file_pkg_server_server_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TestTask.ProtoReflect.Descriptor instead. func (*TestTask) Descriptor() ([]byte, []int) { - return fileDescriptor_36fb7b77b8f76c98, []int{0} + return file_pkg_server_server_proto_rawDescGZIP(), []int{0} } -func (m *TestTask) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_TestTask.Unmarshal(m, b) -} -func (m *TestTask) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_TestTask.Marshal(b, m, deterministic) -} -func (m *TestTask) XXX_Merge(src proto.Message) { - xxx_messageInfo_TestTask.Merge(m, src) -} -func (m *TestTask) XXX_Size() int { - return xxx_messageInfo_TestTask.Size(m) -} -func (m *TestTask) XXX_DiscardUnknown() { - xxx_messageInfo_TestTask.DiscardUnknown(m) -} - -var xxx_messageInfo_TestTask proto.InternalMessageInfo - -func (m *TestTask) GetData() string { - if m != nil { - return m.Data +func (x *TestTask) GetData() string { + if x != nil { + return x.Data } return "" } -func (m *TestTask) GetKind() string { - if m != nil { - return m.Kind +func (x *TestTask) GetKind() string { + if x != nil { + return x.Kind + } + return "" +} + +func (x *TestTask) GetCaseName() string { + if x != nil { + return x.CaseName } return "" } type HelloReply struct { - Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` } -func (m *HelloReply) Reset() { *m = HelloReply{} } -func (m *HelloReply) String() string { return proto.CompactTextString(m) } -func (*HelloReply) ProtoMessage() {} +func (x *HelloReply) Reset() { + *x = HelloReply{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_server_server_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HelloReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HelloReply) ProtoMessage() {} + +func (x *HelloReply) ProtoReflect() protoreflect.Message { + mi := &file_pkg_server_server_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HelloReply.ProtoReflect.Descriptor instead. func (*HelloReply) Descriptor() ([]byte, []int) { - return fileDescriptor_36fb7b77b8f76c98, []int{1} + return file_pkg_server_server_proto_rawDescGZIP(), []int{1} } -func (m *HelloReply) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_HelloReply.Unmarshal(m, b) -} -func (m *HelloReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_HelloReply.Marshal(b, m, deterministic) -} -func (m *HelloReply) XXX_Merge(src proto.Message) { - xxx_messageInfo_HelloReply.Merge(m, src) -} -func (m *HelloReply) XXX_Size() int { - return xxx_messageInfo_HelloReply.Size(m) -} -func (m *HelloReply) XXX_DiscardUnknown() { - xxx_messageInfo_HelloReply.DiscardUnknown(m) -} - -var xxx_messageInfo_HelloReply proto.InternalMessageInfo - -func (m *HelloReply) GetMessage() string { - if m != nil { - return m.Message +func (x *HelloReply) GetMessage() string { + if x != nil { + return x.Message } return "" } -func init() { - proto.RegisterType((*TestTask)(nil), "server.TestTask") - proto.RegisterType((*HelloReply)(nil), "server.HelloReply") +type Empty struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields } -func init() { - proto.RegisterFile("pkg/server/server.proto", fileDescriptor_36fb7b77b8f76c98) +func (x *Empty) Reset() { + *x = Empty{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_server_server_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -var fileDescriptor_36fb7b77b8f76c98 = []byte{ - // 194 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x44, 0x8f, 0xbd, 0x6b, 0xc3, 0x30, - 0x10, 0xc5, 0xeb, 0xb6, 0xb8, 0xed, 0x4d, 0x45, 0x4b, 0x4d, 0xa7, 0xe2, 0xa1, 0x74, 0xa8, 0x25, - 0x70, 0x86, 0xec, 0x99, 0x32, 0x0b, 0x4f, 0xd9, 0xe4, 0xf8, 0x50, 0x84, 0x65, 0x49, 0xe8, 0x23, - 0x24, 0xff, 0x7d, 0xf0, 0x17, 0x9e, 0xee, 0xbd, 0x1f, 0xdc, 0xdd, 0x7b, 0xf0, 0xe5, 0x7a, 0xc9, - 0x02, 0xfa, 0x2b, 0xfa, 0x65, 0x50, 0xe7, 0x6d, 0xb4, 0x24, 0x9f, 0x5d, 0x59, 0xc3, 0x7b, 0x83, - 0x21, 0x36, 0x22, 0xf4, 0x84, 0xc0, 0x6b, 0x27, 0xa2, 0x28, 0xb2, 0x9f, 0xec, 0xef, 0x83, 0x4f, - 0x7a, 0x64, 0xbd, 0x32, 0x5d, 0xf1, 0x3c, 0xb3, 0x51, 0x97, 0xbf, 0x00, 0x47, 0xd4, 0xda, 0x72, - 0x74, 0xfa, 0x4e, 0x0a, 0x78, 0x1b, 0x30, 0x04, 0x21, 0x71, 0x59, 0x5c, 0x6d, 0xbd, 0x87, 0x9c, - 0x27, 0x63, 0xd0, 0x93, 0x0a, 0x5e, 0x78, 0x32, 0xe4, 0x93, 0x2e, 0x19, 0xd6, 0x97, 0xdf, 0x64, - 0x25, 0xdb, 0xc1, 0xf2, 0xe9, 0x40, 0x4f, 0xff, 0x52, 0xc5, 0x4b, 0x6a, 0xe9, 0xd9, 0x0e, 0x4c, - 0x2b, 0x93, 0x6e, 0x21, 0x79, 0x34, 0x4c, 0x38, 0x55, 0x45, 0x0c, 0x51, 0x19, 0xc9, 0xb6, 0x66, - 0x6d, 0x3e, 0x75, 0xda, 0x3d, 0x02, 0x00, 0x00, 0xff, 0xff, 0x89, 0x35, 0xcb, 0xb0, 0xee, 0x00, - 0x00, 0x00, +func (x *Empty) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Empty) ProtoMessage() {} + +func (x *Empty) ProtoReflect() protoreflect.Message { + mi := &file_pkg_server_server_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Empty.ProtoReflect.Descriptor instead. +func (*Empty) Descriptor() ([]byte, []int) { + return file_pkg_server_server_proto_rawDescGZIP(), []int{2} +} + +var File_pkg_server_server_proto protoreflect.FileDescriptor + +var file_pkg_server_server_proto_rawDesc = []byte{ + 0x0a, 0x17, 0x70, 0x6b, 0x67, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x22, 0x4e, 0x0a, 0x08, 0x54, 0x65, 0x73, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x12, 0x0a, + 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, + 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, + 0x65, 0x22, 0x26, 0x0a, 0x0a, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, + 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x32, 0x6a, 0x0a, 0x06, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x2d, 0x0a, 0x03, + 0x52, 0x75, 0x6e, 0x12, 0x10, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, + 0x74, 0x54, 0x61, 0x73, 0x6b, 0x1a, 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, + 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x0a, 0x47, + 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x2e, + 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x6e, + 0x75, 0x78, 0x73, 0x75, 0x72, 0x65, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2d, 0x74, 0x65, 0x73, 0x74, + 0x69, 0x6e, 0x67, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_pkg_server_server_proto_rawDescOnce sync.Once + file_pkg_server_server_proto_rawDescData = file_pkg_server_server_proto_rawDesc +) + +func file_pkg_server_server_proto_rawDescGZIP() []byte { + file_pkg_server_server_proto_rawDescOnce.Do(func() { + file_pkg_server_server_proto_rawDescData = protoimpl.X.CompressGZIP(file_pkg_server_server_proto_rawDescData) + }) + return file_pkg_server_server_proto_rawDescData +} + +var file_pkg_server_server_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_pkg_server_server_proto_goTypes = []interface{}{ + (*TestTask)(nil), // 0: server.TestTask + (*HelloReply)(nil), // 1: server.HelloReply + (*Empty)(nil), // 2: server.Empty +} +var file_pkg_server_server_proto_depIdxs = []int32{ + 0, // 0: server.Runner.Run:input_type -> server.TestTask + 2, // 1: server.Runner.GetVersion:input_type -> server.Empty + 1, // 2: server.Runner.Run:output_type -> server.HelloReply + 1, // 3: server.Runner.GetVersion:output_type -> server.HelloReply + 2, // [2:4] is the sub-list for method output_type + 0, // [0:2] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_pkg_server_server_proto_init() } +func file_pkg_server_server_proto_init() { + if File_pkg_server_server_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_pkg_server_server_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TestTask); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pkg_server_server_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HelloReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pkg_server_server_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Empty); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_pkg_server_server_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_pkg_server_server_proto_goTypes, + DependencyIndexes: file_pkg_server_server_proto_depIdxs, + MessageInfos: file_pkg_server_server_proto_msgTypes, + }.Build() + File_pkg_server_server_proto = out.File + file_pkg_server_server_proto_rawDesc = nil + file_pkg_server_server_proto_goTypes = nil + file_pkg_server_server_proto_depIdxs = nil } diff --git a/pkg/server/server.proto b/pkg/server/server.proto index 1c3b74e..e3a99ee 100644 --- a/pkg/server/server.proto +++ b/pkg/server/server.proto @@ -6,13 +6,18 @@ package server; service Runner { rpc Run (TestTask) returns (HelloReply) {} + rpc GetVersion(Empty) returns (HelloReply) {} } message TestTask { string data = 1; string kind = 2; + string caseName = 3; } message HelloReply { string message = 1; +} + +message Empty { } \ No newline at end of file diff --git a/pkg/server/server_grpc.pb.go b/pkg/server/server_grpc.pb.go index 79661d9..9989fbb 100644 --- a/pkg/server/server_grpc.pb.go +++ b/pkg/server/server_grpc.pb.go @@ -23,6 +23,7 @@ const _ = grpc.SupportPackageIsVersion7 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type RunnerClient interface { Run(ctx context.Context, in *TestTask, opts ...grpc.CallOption) (*HelloReply, error) + GetVersion(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*HelloReply, error) } type runnerClient struct { @@ -42,11 +43,21 @@ func (c *runnerClient) Run(ctx context.Context, in *TestTask, opts ...grpc.CallO return out, nil } +func (c *runnerClient) GetVersion(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*HelloReply, error) { + out := new(HelloReply) + err := c.cc.Invoke(ctx, "/server.Runner/GetVersion", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // RunnerServer is the server API for Runner service. // All implementations must embed UnimplementedRunnerServer // for forward compatibility type RunnerServer interface { Run(context.Context, *TestTask) (*HelloReply, error) + GetVersion(context.Context, *Empty) (*HelloReply, error) mustEmbedUnimplementedRunnerServer() } @@ -57,6 +68,9 @@ type UnimplementedRunnerServer struct { func (UnimplementedRunnerServer) Run(context.Context, *TestTask) (*HelloReply, error) { return nil, status.Errorf(codes.Unimplemented, "method Run not implemented") } +func (UnimplementedRunnerServer) GetVersion(context.Context, *Empty) (*HelloReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetVersion not implemented") +} func (UnimplementedRunnerServer) mustEmbedUnimplementedRunnerServer() {} // UnsafeRunnerServer may be embedded to opt out of forward compatibility for this service. @@ -88,6 +102,24 @@ func _Runner_Run_Handler(srv interface{}, ctx context.Context, dec func(interfac return interceptor(ctx, in, info, handler) } +func _Runner_GetVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RunnerServer).GetVersion(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/server.Runner/GetVersion", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RunnerServer).GetVersion(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + // Runner_ServiceDesc is the grpc.ServiceDesc for Runner service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -99,6 +131,10 @@ var Runner_ServiceDesc = grpc.ServiceDesc{ MethodName: "Run", Handler: _Runner_Run_Handler, }, + { + MethodName: "GetVersion", + Handler: _Runner_GetVersion_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "pkg/server/server.proto", diff --git a/pkg/server/testdata/simple.yaml b/pkg/server/testdata/simple.yaml index 6360b01..09a912e 100644 --- a/pkg/server/testdata/simple.yaml +++ b/pkg/server/testdata/simple.yaml @@ -1,5 +1,9 @@ name: simple +api: http://foo items: - name: get request: - api: http://foo \ No newline at end of file + api: http://foo + - name: query + request: + api: / \ No newline at end of file diff --git a/pkg/version/constants.go b/pkg/version/constants.go new file mode 100644 index 0000000..f76ab61 --- /dev/null +++ b/pkg/version/constants.go @@ -0,0 +1,10 @@ +// Package version provides the version access of this app +package version + +// should be injected during the build process +var version string + +// GetVersion returns the version +func GetVersion() string { + return version +} diff --git a/pkg/version/constants_test.go b/pkg/version/constants_test.go new file mode 100644 index 0000000..c791a70 --- /dev/null +++ b/pkg/version/constants_test.go @@ -0,0 +1,13 @@ +package version_test + +import ( + "testing" + + "github.com/linuxsuren/api-testing/pkg/version" + "github.com/stretchr/testify/assert" +) + +func TestVersion(t *testing.T) { + ver := version.GetVersion() + assert.Empty(t, ver) +} diff --git a/sample/api-testing-schema.json b/sample/api-testing-schema.json new file mode 100644 index 0000000..0da2e80 --- /dev/null +++ b/sample/api-testing-schema.json @@ -0,0 +1,126 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/APITesting", + "definitions": { + "APITesting": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" + }, + "api": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/Item" + } + } + }, + "required": [ + "items", + "name" + ], + "title": "APITesting" + }, + "Item": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" + }, + "request": { + "$ref": "#/definitions/Request" + }, + "expect": { + "$ref": "#/definitions/Expect" + } + }, + "required": [ + "name", + "request" + ], + "title": "Item" + }, + "Expect": { + "type": "object", + "additionalProperties": false, + "properties": { + "statusCode": { + "type": "integer" + }, + "body": { + "type": "string" + }, + "header": { + "description": "HTTP response header", + "type": "object", + "title": "Header", + "additionalProperties": true + }, + "bodyFieldsExpect": { + "description": "Body fields expect", + "type": "object", + "additionalProperties": true + }, + "verify": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "statusCode" + ], + "title": "Expect" + }, + "Request": { + "type": "object", + "additionalProperties": false, + "properties": { + "api": { + "type": "string", + "qt-uri-protocols": [ + "https" + ] + }, + "method": { + "type": "string", + "enum": ["GET", "POST", "PUT", "PATCH", "DELETE"] + }, + "query": { + "description": "HTTP request query", + "type": "object", + "title": "Query", + "additionalProperties": true + }, + "header": { + "description": "HTTP request header", + "type": "object", + "title": "Header", + "additionalProperties": true + }, + "form": { + "description": "HTTP request form", + "type": "object", + "title": "Form", + "additionalProperties": true + }, + "body": { + "type": "string" + }, + "bodyFromFile": { + "type": "string" + } + }, + "required": [ + "api" + ], + "title": "Request" + } + } +} diff --git a/sample/testsuite-gitlab.yaml b/sample/testsuite-gitlab.yaml index e60a1cc..84179a5 100644 --- a/sample/testsuite-gitlab.yaml +++ b/sample/testsuite-gitlab.yaml @@ -1,3 +1,4 @@ +# yaml-language-server: $schema=api-testing-schema.json # https://docs.gitlab.com/ee/api/api_resources.html name: Gitlab items: