feat: support to run a specific test case via grpc (#28)

Co-authored-by: Rick <linuxsuren@users.noreply.github.com>
This commit is contained in:
Rick 2023-04-05 18:59:08 +08:00 committed by GitHub
parent 3720aca07f
commit 82f2fdf849
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 507 additions and 104 deletions

View File

@ -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:

View File

@ -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/):

View File

@ -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())

4
go.mod
View File

@ -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
)

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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 {
}

View File

@ -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",

View File

@ -1,5 +1,9 @@
name: simple
api: http://foo
items:
- name: get
request:
api: http://foo
api: http://foo
- name: query
request:
api: /

10
pkg/version/constants.go Normal file
View File

@ -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
}

View File

@ -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)
}

View File

@ -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"
}
}
}

View File

@ -1,3 +1,4 @@
# yaml-language-server: $schema=api-testing-schema.json
# https://docs.gitlab.com/ee/api/api_resources.html
name: Gitlab
items: