feat: add a service commnd (#39)
* feat: add a service commnd The following command will install atest as a Linux service. `atest service --action install`. Set the default service port to be 7070 to avoid confliction * add unit tests * add more unit tests
This commit is contained in:
parent
9ee38ffc17
commit
e08c2046d5
11
cmd/init.go
11
cmd/init.go
|
@ -1,19 +1,20 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/linuxsuren/api-testing/pkg/exec"
|
fakeruntime "github.com/linuxsuren/go-fake-runtime"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
type initOption struct {
|
type initOption struct {
|
||||||
|
execer fakeruntime.Execer
|
||||||
kustomization string
|
kustomization string
|
||||||
waitNamespace string
|
waitNamespace string
|
||||||
waitResource string
|
waitResource string
|
||||||
}
|
}
|
||||||
|
|
||||||
// createInitCommand returns the init command
|
// createInitCommand returns the init command
|
||||||
func createInitCommand() (cmd *cobra.Command) {
|
func createInitCommand(execer fakeruntime.Execer) (cmd *cobra.Command) {
|
||||||
opt := &initOption{}
|
opt := &initOption{execer: execer}
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "init",
|
Use: "init",
|
||||||
Long: "Support to init Kubernetes cluster with kustomization, and wait it with command: kubectl wait",
|
Long: "Support to init Kubernetes cluster with kustomization, and wait it with command: kubectl wait",
|
||||||
|
@ -30,13 +31,13 @@ func createInitCommand() (cmd *cobra.Command) {
|
||||||
|
|
||||||
func (o *initOption) runE(cmd *cobra.Command, args []string) (err error) {
|
func (o *initOption) runE(cmd *cobra.Command, args []string) (err error) {
|
||||||
if o.kustomization != "" {
|
if o.kustomization != "" {
|
||||||
if err = exec.RunCommand("kubectl", "apply", "-k", o.kustomization, "--wait=true"); err != nil {
|
if err = o.execer.RunCommand("kubectl", "apply", "-k", o.kustomization, "--wait=true"); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.waitNamespace != "" && o.waitResource != "" {
|
if o.waitNamespace != "" && o.waitResource != "" {
|
||||||
if err = exec.RunCommand("kubectl", "wait", "-n", o.waitNamespace, o.waitResource, "--for", "condition=Available=True", "--timeout=900s"); err != nil {
|
if err = o.execer.RunCommand("kubectl", "wait", "-n", o.waitNamespace, o.waitResource, "--for", "condition=Available=True", "--timeout=900s"); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,12 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/linuxsuren/api-testing/cmd"
|
"github.com/linuxsuren/api-testing/cmd"
|
||||||
|
fakeruntime "github.com/linuxsuren/go-fake-runtime"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestJSONSchemaCmd(t *testing.T) {
|
func TestJSONSchemaCmd(t *testing.T) {
|
||||||
c := cmd.NewRootCmd()
|
c := cmd.NewRootCmd(fakeruntime.FakeExecer{ExpectOS: "linux"})
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
c.SetOut(buf)
|
c.SetOut(buf)
|
||||||
|
|
10
cmd/root.go
10
cmd/root.go
|
@ -4,19 +4,23 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/linuxsuren/api-testing/pkg/version"
|
"github.com/linuxsuren/api-testing/pkg/version"
|
||||||
|
fakeruntime "github.com/linuxsuren/go-fake-runtime"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewRootCmd creates the root command
|
// NewRootCmd creates the root command
|
||||||
func NewRootCmd() (c *cobra.Command) {
|
func NewRootCmd(execer fakeruntime.Execer) (c *cobra.Command) {
|
||||||
c = &cobra.Command{
|
c = &cobra.Command{
|
||||||
Use: "atest",
|
Use: "atest",
|
||||||
Short: "API testing tool",
|
Short: "API testing tool",
|
||||||
}
|
}
|
||||||
c.SetOut(os.Stdout)
|
c.SetOut(os.Stdout)
|
||||||
c.Version = version.GetVersion()
|
c.Version = version.GetVersion()
|
||||||
c.AddCommand(createInitCommand(),
|
gRPCServer := grpc.NewServer()
|
||||||
|
c.AddCommand(createInitCommand(execer),
|
||||||
createRunCommand(), createSampleCmd(),
|
createRunCommand(), createSampleCmd(),
|
||||||
createServerCmd(), createJSONSchemaCmd())
|
createServerCmd(gRPCServer), createJSONSchemaCmd(),
|
||||||
|
createServiceCommand(execer))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
atesting "github.com/linuxsuren/api-testing/pkg/testing"
|
atesting "github.com/linuxsuren/api-testing/pkg/testing"
|
||||||
|
exec "github.com/linuxsuren/go-fake-runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_setRelativeDir(t *testing.T) {
|
func Test_setRelativeDir(t *testing.T) {
|
||||||
|
@ -43,10 +44,15 @@ func TestCreateRunCommand(t *testing.T) {
|
||||||
cmd := createRunCommand()
|
cmd := createRunCommand()
|
||||||
assert.Equal(t, "run", cmd.Use)
|
assert.Equal(t, "run", cmd.Use)
|
||||||
|
|
||||||
init := createInitCommand()
|
init := createInitCommand(exec.FakeExecer{})
|
||||||
assert.Equal(t, "init", init.Use)
|
assert.Equal(t, "init", init.Use)
|
||||||
|
|
||||||
server := createServerCmd()
|
server := createServerCmd(&fakeGRPCServer{})
|
||||||
assert.NotNil(t, server)
|
assert.NotNil(t, server)
|
||||||
assert.Equal(t, "server", server.Use)
|
assert.Equal(t, "server", server.Use)
|
||||||
|
|
||||||
|
root := NewRootCmd(exec.FakeExecer{})
|
||||||
|
root.SetArgs([]string{"init", "-k=demo.yaml", "--wait-namespace", "demo", "--wait-resource", "demo"})
|
||||||
|
err := root.Execute()
|
||||||
|
assert.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
"github.com/h2non/gock"
|
"github.com/h2non/gock"
|
||||||
"github.com/linuxsuren/api-testing/pkg/limit"
|
"github.com/linuxsuren/api-testing/pkg/limit"
|
||||||
|
fakeruntime "github.com/linuxsuren/go-fake-runtime"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
@ -103,7 +104,7 @@ func TestRunCommand(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRootCmd(t *testing.T) {
|
func TestRootCmd(t *testing.T) {
|
||||||
c := NewRootCmd()
|
c := NewRootCmd(fakeruntime.FakeExecer{ExpectOS: "linux"})
|
||||||
assert.NotNil(t, c)
|
assert.NotNil(t, c)
|
||||||
assert.Equal(t, "atest", c.Use)
|
assert.Equal(t, "atest", c.Use)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,12 @@ import (
|
||||||
|
|
||||||
"github.com/linuxsuren/api-testing/cmd"
|
"github.com/linuxsuren/api-testing/cmd"
|
||||||
"github.com/linuxsuren/api-testing/sample"
|
"github.com/linuxsuren/api-testing/sample"
|
||||||
|
fakeruntime "github.com/linuxsuren/go-fake-runtime"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSampleCmd(t *testing.T) {
|
func TestSampleCmd(t *testing.T) {
|
||||||
c := cmd.NewRootCmd()
|
c := cmd.NewRootCmd(fakeruntime.FakeExecer{ExpectOS: "linux"})
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
c.SetOut(buf)
|
c.SetOut(buf)
|
||||||
|
|
|
@ -11,20 +11,21 @@ import (
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func createServerCmd() (c *cobra.Command) {
|
func createServerCmd(gRPCServer gRPCServer) (c *cobra.Command) {
|
||||||
opt := &serverOption{}
|
opt := &serverOption{gRPCServer: gRPCServer}
|
||||||
c = &cobra.Command{
|
c = &cobra.Command{
|
||||||
Use: "server",
|
Use: "server",
|
||||||
Short: "Run as a server mode",
|
Short: "Run as a server mode",
|
||||||
RunE: opt.runE,
|
RunE: opt.runE,
|
||||||
}
|
}
|
||||||
flags := c.Flags()
|
flags := c.Flags()
|
||||||
flags.IntVarP(&opt.port, "port", "p", 9090, "The RPC server port")
|
flags.IntVarP(&opt.port, "port", "p", 7070, "The RPC server port")
|
||||||
flags.BoolVarP(&opt.printProto, "print-proto", "", false, "Print the proto content and exit")
|
flags.BoolVarP(&opt.printProto, "print-proto", "", false, "Print the proto content and exit")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type serverOption struct {
|
type serverOption struct {
|
||||||
|
gRPCServer gRPCServer
|
||||||
port int
|
port int
|
||||||
printProto bool
|
printProto bool
|
||||||
}
|
}
|
||||||
|
@ -43,9 +44,26 @@ func (o *serverOption) runE(cmd *cobra.Command, args []string) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s := grpc.NewServer()
|
s := o.gRPCServer
|
||||||
server.RegisterRunnerServer(s, server.NewRemoteServer())
|
server.RegisterRunnerServer(s, server.NewRemoteServer())
|
||||||
log.Printf("server listening at %v", lis.Addr())
|
log.Printf("server listening at %v", lis.Addr())
|
||||||
s.Serve(lis)
|
s.Serve(lis)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type gRPCServer interface {
|
||||||
|
Serve(lis net.Listener) error
|
||||||
|
grpc.ServiceRegistrar
|
||||||
|
}
|
||||||
|
|
||||||
|
type fakeGRPCServer struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serve is a fake method
|
||||||
|
func (s *fakeGRPCServer) Serve(net.Listener) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterService is a fake method
|
||||||
|
func (s *fakeGRPCServer) RegisterService(desc *grpc.ServiceDesc, impl interface{}) {
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
fakeruntime "github.com/linuxsuren/go-fake-runtime"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -30,11 +31,15 @@ func TestPrintProto(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) {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
root := NewRootCmd()
|
root := NewRootCmd(fakeruntime.FakeExecer{ExpectOS: "linux"})
|
||||||
root.SetOut(buf)
|
root.SetOut(buf)
|
||||||
root.SetArgs(tt.args)
|
root.SetArgs(tt.args)
|
||||||
err := root.Execute()
|
err := root.Execute()
|
||||||
tt.verify(t, buf, err)
|
tt.verify(t, buf, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
server := createServerCmd(&fakeGRPCServer{})
|
||||||
|
err := server.Execute()
|
||||||
|
assert.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
// Package cmd provides a service command
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
fakeruntime "github.com/linuxsuren/go-fake-runtime"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func createServiceCommand(execer fakeruntime.Execer) (c *cobra.Command) {
|
||||||
|
opt := &serviceOption{
|
||||||
|
Execer: execer,
|
||||||
|
}
|
||||||
|
c = &cobra.Command{
|
||||||
|
Use: "service",
|
||||||
|
Aliases: []string{"s"},
|
||||||
|
Short: "Install atest as a Linux service",
|
||||||
|
PreRunE: opt.preRunE,
|
||||||
|
RunE: opt.runE,
|
||||||
|
}
|
||||||
|
flags := c.Flags()
|
||||||
|
flags.StringVarP(&opt.action, "action", "a", "", "The action of service, support actions: install, start, stop, restart, status")
|
||||||
|
flags.StringVarP(&opt.scriptPath, "script-path", "", "/lib/systemd/system/atest.service", "The service script file path")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type serviceOption struct {
|
||||||
|
action string
|
||||||
|
scriptPath string
|
||||||
|
fakeruntime.Execer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *serviceOption) preRunE(c *cobra.Command, args []string) (err error) {
|
||||||
|
if o.Execer.OS() != "linux" {
|
||||||
|
err = fmt.Errorf("only support on Linux")
|
||||||
|
}
|
||||||
|
if o.action == "" && len(args) > 0 {
|
||||||
|
o.action = args[0]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *serviceOption) runE(c *cobra.Command, args []string) (err error) {
|
||||||
|
var output string
|
||||||
|
switch o.action {
|
||||||
|
case "install", "i":
|
||||||
|
err = os.WriteFile(o.scriptPath, []byte(script), os.ModeAppend)
|
||||||
|
case "start":
|
||||||
|
output, err = o.Execer.RunCommandAndReturn("systemctl", "", "start", "atest")
|
||||||
|
case "stop":
|
||||||
|
output, err = o.Execer.RunCommandAndReturn("systemctl", "", "stop", "atest")
|
||||||
|
case "restart":
|
||||||
|
output, err = o.Execer.RunCommandAndReturn("systemctl", "", "restart", "atest")
|
||||||
|
case "status":
|
||||||
|
output, err = o.Execer.RunCommandAndReturn("systemctl", "", "status", "atest")
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("not support action: '%s'", o.action)
|
||||||
|
}
|
||||||
|
|
||||||
|
if output != "" {
|
||||||
|
c.Println(output)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var script = `[Unit]
|
||||||
|
Description=API Testing
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=atest server
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
`
|
|
@ -0,0 +1,69 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
fakeruntime "github.com/linuxsuren/go-fake-runtime"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestService(t *testing.T) {
|
||||||
|
root := NewRootCmd(fakeruntime.FakeExecer{ExpectOS: "linux"})
|
||||||
|
root.SetArgs([]string{"service", "fake"})
|
||||||
|
err := root.Execute()
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
|
notLinux := NewRootCmd(fakeruntime.FakeExecer{ExpectOS: "fake"})
|
||||||
|
notLinux.SetArgs([]string{"service", "--action", "install"})
|
||||||
|
err = notLinux.Execute()
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
|
tmpFile, err := os.CreateTemp(os.TempDir(), "service")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
defer func() {
|
||||||
|
os.RemoveAll(tmpFile.Name())
|
||||||
|
}()
|
||||||
|
|
||||||
|
targetScript := NewRootCmd(fakeruntime.FakeExecer{ExpectOS: "linux"})
|
||||||
|
targetScript.SetArgs([]string{"service", "--action", "install", "--script-path", tmpFile.Name()})
|
||||||
|
err = targetScript.Execute()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
data, err := os.ReadFile(tmpFile.Name())
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, script, string(data))
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
action string
|
||||||
|
expectOutput string
|
||||||
|
}{{
|
||||||
|
name: "action: start",
|
||||||
|
action: "start",
|
||||||
|
expectOutput: "output1",
|
||||||
|
}, {
|
||||||
|
name: "action: stop",
|
||||||
|
action: "stop",
|
||||||
|
expectOutput: "output2",
|
||||||
|
}, {
|
||||||
|
name: "action: restart",
|
||||||
|
action: "restart",
|
||||||
|
expectOutput: "output3",
|
||||||
|
}, {
|
||||||
|
name: "action: status",
|
||||||
|
action: "status",
|
||||||
|
expectOutput: "output4",
|
||||||
|
}}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
normalRoot := NewRootCmd(fakeruntime.FakeExecer{ExpectOS: "linux", ExpectOutput: tt.expectOutput})
|
||||||
|
normalRoot.SetOut(buf)
|
||||||
|
normalRoot.SetArgs([]string{"service", "--action", tt.action})
|
||||||
|
err = normalRoot.Execute()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, tt.expectOutput+"\n", buf.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
1
go.mod
1
go.mod
|
@ -28,6 +28,7 @@ require (
|
||||||
github.com/imdario/mergo v0.3.11 // indirect
|
github.com/imdario/mergo v0.3.11 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||||
github.com/invopop/jsonschema v0.7.0 // indirect
|
github.com/invopop/jsonschema v0.7.0 // indirect
|
||||||
|
github.com/linuxsuren/go-fake-runtime v0.0.0-20230413085645-15e77ab55dbd // indirect
|
||||||
github.com/mitchellh/copystructure v1.0.0 // indirect
|
github.com/mitchellh/copystructure v1.0.0 // indirect
|
||||||
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -563,6 +563,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/linuxsuren/go-fake-runtime v0.0.0-20230413085645-15e77ab55dbd h1:2Avir30WOgcDqG3sA4hlW4bC4c/tgseAUntPhf5JQ6E=
|
||||||
|
github.com/linuxsuren/go-fake-runtime v0.0.0-20230413085645-15e77ab55dbd/go.mod h1:zmh6J78hSnWZo68faMA2eKOdaEp8eFbERHi3ZB9xHCQ=
|
||||||
github.com/linuxsuren/unstructured v0.0.1 h1:ilUA8MUYbR6l9ebo/YPV2bKqlf62bzQursDSE+j00iU=
|
github.com/linuxsuren/unstructured v0.0.1 h1:ilUA8MUYbR6l9ebo/YPV2bKqlf62bzQursDSE+j00iU=
|
||||||
github.com/linuxsuren/unstructured v0.0.1/go.mod h1:KH6aTj+FegzGBzc1vS6mzZx3/duhTUTEVyW5sO7p4as=
|
github.com/linuxsuren/unstructured v0.0.1/go.mod h1:KH6aTj+FegzGBzc1vS6mzZx3/duhTUTEVyW5sO7p4as=
|
||||||
github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
|
github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
|
||||||
|
|
3
main.go
3
main.go
|
@ -4,10 +4,11 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/linuxsuren/api-testing/cmd"
|
"github.com/linuxsuren/api-testing/cmd"
|
||||||
|
exec "github.com/linuxsuren/go-fake-runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
c := cmd.NewRootCmd()
|
c := cmd.NewRootCmd(exec.DefaultExecer{})
|
||||||
if err := c.Execute(); err != nil {
|
if err := c.Execute(); err != nil {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,8 @@ import (
|
||||||
"github.com/andreyvit/diff"
|
"github.com/andreyvit/diff"
|
||||||
"github.com/antonmedv/expr"
|
"github.com/antonmedv/expr"
|
||||||
"github.com/antonmedv/expr/vm"
|
"github.com/antonmedv/expr/vm"
|
||||||
"github.com/linuxsuren/api-testing/pkg/exec"
|
|
||||||
"github.com/linuxsuren/api-testing/pkg/testing"
|
"github.com/linuxsuren/api-testing/pkg/testing"
|
||||||
|
fakeruntime "github.com/linuxsuren/go-fake-runtime"
|
||||||
unstructured "github.com/linuxsuren/unstructured/pkg"
|
unstructured "github.com/linuxsuren/unstructured/pkg"
|
||||||
"github.com/xeipuuv/gojsonschema"
|
"github.com/xeipuuv/gojsonschema"
|
||||||
)
|
)
|
||||||
|
@ -78,6 +78,7 @@ type TestCaseRunner interface {
|
||||||
WithOutputWriter(io.Writer) TestCaseRunner
|
WithOutputWriter(io.Writer) TestCaseRunner
|
||||||
WithWriteLevel(level string) TestCaseRunner
|
WithWriteLevel(level string) TestCaseRunner
|
||||||
WithTestReporter(TestReporter) TestCaseRunner
|
WithTestReporter(TestReporter) TestCaseRunner
|
||||||
|
WithExecer(fakeruntime.Execer) TestCaseRunner
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReportRecord represents the raw data of a HTTP request
|
// ReportRecord represents the raw data of a HTTP request
|
||||||
|
@ -157,6 +158,7 @@ type simpleTestCaseRunner struct {
|
||||||
testReporter TestReporter
|
testReporter TestReporter
|
||||||
writer io.Writer
|
writer io.Writer
|
||||||
log LevelWriter
|
log LevelWriter
|
||||||
|
execer fakeruntime.Execer
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSimpleTestCaseRunner creates the instance of the simple test case runner
|
// NewSimpleTestCaseRunner creates the instance of the simple test case runner
|
||||||
|
@ -164,7 +166,8 @@ func NewSimpleTestCaseRunner() TestCaseRunner {
|
||||||
runner := &simpleTestCaseRunner{}
|
runner := &simpleTestCaseRunner{}
|
||||||
return runner.WithOutputWriter(io.Discard).
|
return runner.WithOutputWriter(io.Discard).
|
||||||
WithWriteLevel("info").
|
WithWriteLevel("info").
|
||||||
WithTestReporter(NewDiscardTestReporter())
|
WithTestReporter(NewDiscardTestReporter()).
|
||||||
|
WithExecer(fakeruntime.DefaultExecer{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunTestCase is the main entry point of a test case
|
// RunTestCase is the main entry point of a test case
|
||||||
|
@ -179,16 +182,14 @@ func (r *simpleTestCaseRunner) RunTestCase(testcase *testing.TestCase, dataConte
|
||||||
r.testReporter.PutRecord(rr)
|
r.testReporter.PutRecord(rr)
|
||||||
}(record)
|
}(record)
|
||||||
|
|
||||||
if err = doPrepare(testcase); err != nil {
|
if err = r.doPrepare(testcase); err != nil {
|
||||||
err = fmt.Errorf("failed to prepare, error: %v", err)
|
err = fmt.Errorf("failed to prepare, error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if testcase.Clean.CleanPrepare {
|
if testcase.Clean.CleanPrepare {
|
||||||
if err = doCleanPrepare(testcase); err != nil {
|
err = r.doCleanPrepare(testcase)
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -363,29 +364,29 @@ func (r *simpleTestCaseRunner) WithTestReporter(reporter TestReporter) TestCaseR
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated
|
// WithExecer sets the execer
|
||||||
// RunTestCase runs the test case.
|
func (r *simpleTestCaseRunner) WithExecer(execer fakeruntime.Execer) TestCaseRunner {
|
||||||
func RunTestCase(testcase *testing.TestCase, dataContext interface{}, ctx context.Context) (output interface{}, err error) {
|
r.execer = execer
|
||||||
return NewSimpleTestCaseRunner().WithOutputWriter(os.Stdout).RunTestCase(testcase, dataContext, ctx)
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func doPrepare(testcase *testing.TestCase) (err error) {
|
func (r *simpleTestCaseRunner) doPrepare(testcase *testing.TestCase) (err error) {
|
||||||
for i := range testcase.Prepare.Kubernetes {
|
for i := range testcase.Prepare.Kubernetes {
|
||||||
item := testcase.Prepare.Kubernetes[i]
|
item := testcase.Prepare.Kubernetes[i]
|
||||||
|
|
||||||
if err = exec.RunCommand("kubectl", "apply", "-f", item); err != nil {
|
if err = r.execer.RunCommand("kubectl", "apply", "-f", item); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func doCleanPrepare(testcase *testing.TestCase) (err error) {
|
func (r *simpleTestCaseRunner) doCleanPrepare(testcase *testing.TestCase) (err error) {
|
||||||
count := len(testcase.Prepare.Kubernetes)
|
count := len(testcase.Prepare.Kubernetes)
|
||||||
for i := count - 1; i >= 0; i-- {
|
for i := count - 1; i >= 0; i-- {
|
||||||
item := testcase.Prepare.Kubernetes[i]
|
item := testcase.Prepare.Kubernetes[i]
|
||||||
|
|
||||||
if err = exec.RunCommand("kubectl", "delete", "-f", item); err != nil {
|
if err = r.execer.RunCommand("kubectl", "delete", "-f", item); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,23 +5,37 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
|
||||||
"github.com/h2non/gock"
|
"github.com/h2non/gock"
|
||||||
atest "github.com/linuxsuren/api-testing/pkg/testing"
|
atest "github.com/linuxsuren/api-testing/pkg/testing"
|
||||||
|
fakeruntime "github.com/linuxsuren/go-fake-runtime"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTestCase(t *testing.T) {
|
func TestTestCase(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
execer fakeruntime.Execer
|
||||||
testCase *atest.TestCase
|
testCase *atest.TestCase
|
||||||
ctx interface{}
|
ctx interface{}
|
||||||
prepare func()
|
prepare func()
|
||||||
verify func(t *testing.T, output interface{}, err error)
|
verify func(t *testing.T, output interface{}, err error)
|
||||||
}{{
|
}{{
|
||||||
|
name: "failed during the prepare stage",
|
||||||
|
testCase: &atest.TestCase{
|
||||||
|
Prepare: atest.Prepare{
|
||||||
|
Kubernetes: []string{"demo.yaml"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
execer: fakeruntime.FakeExecer{ExpectError: errors.New("fake")},
|
||||||
|
verify: func(t *testing.T, output interface{}, err error) {
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
},
|
||||||
|
}, {
|
||||||
name: "normal, response is map",
|
name: "normal, response is map",
|
||||||
testCase: &atest.TestCase{
|
testCase: &atest.TestCase{
|
||||||
Request: atest.Request{
|
Request: atest.Request{
|
||||||
|
@ -44,7 +58,14 @@ func TestTestCase(t *testing.T) {
|
||||||
`data.name == "linuxsuren"`,
|
`data.name == "linuxsuren"`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Prepare: atest.Prepare{
|
||||||
|
Kubernetes: []string{"demo.yaml"},
|
||||||
},
|
},
|
||||||
|
Clean: atest.Clean{
|
||||||
|
CleanPrepare: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
execer: fakeruntime.FakeExecer{},
|
||||||
prepare: func() {
|
prepare: func() {
|
||||||
gock.New("http://localhost").
|
gock.New("http://localhost").
|
||||||
Get("/foo").
|
Get("/foo").
|
||||||
|
@ -370,7 +391,11 @@ func TestTestCase(t *testing.T) {
|
||||||
if tt.prepare != nil {
|
if tt.prepare != nil {
|
||||||
tt.prepare()
|
tt.prepare()
|
||||||
}
|
}
|
||||||
output, err := RunTestCase(tt.testCase, tt.ctx, context.TODO())
|
runner := NewSimpleTestCaseRunner().WithOutputWriter(os.Stdout)
|
||||||
|
if tt.execer != nil {
|
||||||
|
runner.WithExecer(tt.execer)
|
||||||
|
}
|
||||||
|
output, err := runner.RunTestCase(tt.testCase, tt.ctx, context.TODO())
|
||||||
tt.verify(t, output, err)
|
tt.verify(t, output, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,9 +37,9 @@ metadata:
|
||||||
spec:
|
spec:
|
||||||
ports:
|
ports:
|
||||||
- name: server
|
- name: server
|
||||||
port: 9090
|
port: 7070
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
targetPort: 9090
|
targetPort: 7070
|
||||||
selector:
|
selector:
|
||||||
app: api-testing
|
app: api-testing
|
||||||
sessionAffinity: None
|
sessionAffinity: None
|
||||||
|
|
Loading…
Reference in New Issue