Skip to content

Commit 316a427

Browse files
committed
Complete the basic test feature
1 parent 3d55ec1 commit 316a427

File tree

13 files changed

+482
-0
lines changed

13 files changed

+482
-0
lines changed

.github/release-drafter.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Configuration for Release Drafter: https://github.com/toolmantim/release-drafter
2+
name-template: 'v$NEXT_PATCH_VERSION 🌈'
3+
tag-template: 'v$NEXT_PATCH_VERSION'
4+
version-template: $MAJOR.$MINOR.$PATCH
5+
# Emoji reference: https://gitmoji.carloscuesta.me/
6+
categories:
7+
- title: '🚀 Features'
8+
labels:
9+
- 'feature'
10+
- 'enhancement'
11+
- 'kind/feature'
12+
- title: '🐛 Bug Fixes'
13+
labels:
14+
- 'fix'
15+
- 'bugfix'
16+
- 'bug'
17+
- 'regression'
18+
- 'kind/bug'
19+
- title: 📝 Documentation updates
20+
labels:
21+
- documentation
22+
- 'kind/doc'
23+
- title: 👻 Maintenance
24+
labels:
25+
- chore
26+
- dependencies
27+
- 'kind/chore'
28+
- 'kind/dep'
29+
- title: 🚦 Tests
30+
labels:
31+
- test
32+
- tests
33+
exclude-labels:
34+
- reverted
35+
- no-changelog
36+
- skip-changelog
37+
- invalid
38+
change-template: '* $TITLE (#$NUMBER) @$AUTHOR'
39+
template: |
40+
## What’s Changed
41+
42+
$CHANGES
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: Release Drafter
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
8+
jobs:
9+
UpdateReleaseDraft:
10+
runs-on: ubuntu-20.04
11+
steps:
12+
- uses: release-drafter/release-drafter@v5
13+
env:
14+
GITHUB_TOKEN: ${{ secrets.GH_PUBLISH_SECRETS }}

Dockerfile

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
FROM golang:1.17 as builder
2+
3+
WORKDIR /workspace
4+
COPY . .
5+
RUN go mod download
6+
RUN CGO_ENABLE=0 go build -ldflags "-w -s" -o atest cmd/*.go
7+
8+
FROM ghcr.io/linuxsuren/hd:v0.0.67 as hd
9+
10+
FROM alpine:3.10
11+
12+
LABEL "com.github.actions.name"="API testing"
13+
LABEL "com.github.actions.description"="API testing"
14+
LABEL "com.github.actions.icon"="home"
15+
LABEL "com.github.actions.color"="red"
16+
17+
LABEL "repository"="https://github.com/linuxsuren/api-testing"
18+
LABEL "homepage"="https://github.com/linuxsuren/api-testing"
19+
LABEL "maintainer"="Rick <[email protected]>"
20+
21+
LABEL "Name"="API testing"
22+
23+
ENV LC_ALL C.UTF-8
24+
ENV LANG en_US.UTF-8
25+
ENV LANGUAGE en_US.UTF-8
26+
27+
RUN apk add --no-cache \
28+
git \
29+
openssh-client \
30+
libc6-compat \
31+
libstdc++
32+
33+
COPY entrypoint.sh /entrypoint.sh
34+
COPY --from=builder /workspace/atest /usr/bin/atest
35+
COPY --from=hd /usr/local/bin/hd /usr/local/bin/hd
36+
37+
ENTRYPOINT ["/entrypoint.sh"]

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This is a API testing tool.

action.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name: 'API testing'
2+
description: 'API testing'
3+
inputs:
4+
pattern:
5+
description: 'The pattern of the items'
6+
required: true
7+
default: 'testcase-*.yaml'
8+
runs:
9+
using: 'docker'
10+
image: 'Dockerfile'
11+
args:
12+
- ${{ inputs.pattern }}

cmd/root.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package main
2+
3+
import (
4+
"github.com/linuxsuren/api-testing/pkg/runner"
5+
"github.com/linuxsuren/api-testing/pkg/testing"
6+
"github.com/spf13/cobra"
7+
"os"
8+
"path/filepath"
9+
)
10+
11+
type option struct {
12+
pattern string
13+
}
14+
15+
func main() {
16+
opt := &option{}
17+
18+
cmd := &cobra.Command{
19+
Use: "atest",
20+
RunE: opt.runE,
21+
}
22+
23+
// set flags
24+
flags := cmd.Flags()
25+
flags.StringVarP(&opt.pattern, "pattern", "p", "testcase-*.yaml",
26+
"The file pattern which try to execute the test cases")
27+
28+
// run command
29+
if err := cmd.Execute(); err != nil {
30+
os.Exit(1)
31+
}
32+
}
33+
34+
func (o *option) runE(cmd *cobra.Command, args []string) (err error) {
35+
var files []string
36+
if files, err = filepath.Glob(o.pattern); err == nil {
37+
for i := range files {
38+
item := files[i]
39+
40+
var testcase *testing.TestCase
41+
if testcase, err = testing.Parse(item); err != nil {
42+
return
43+
}
44+
45+
if err = runner.RunTestCase(testcase); err != nil {
46+
return
47+
}
48+
}
49+
}
50+
return
51+
}

entrypoint.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/sh
2+
3+
atest -p "$1"

go.mod

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module github.com/linuxsuren/api-testing
2+
3+
go 1.17
4+
5+
require (
6+
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883
7+
github.com/spf13/cobra v1.4.0
8+
gopkg.in/yaml.v2 v2.4.0
9+
)
10+
11+
require (
12+
github.com/inconshreveable/mousetrap v1.0.0 // indirect
13+
github.com/sergi/go-diff v1.2.0 // indirect
14+
github.com/spf13/pflag v1.0.5 // indirect
15+
)

go.sum

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
2+
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
3+
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
4+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
6+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
7+
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
8+
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
9+
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
10+
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
11+
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
12+
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
13+
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
14+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
15+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
16+
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
17+
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
18+
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
19+
github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
20+
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
21+
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
22+
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
23+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
24+
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
25+
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
26+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
27+
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
28+
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
29+
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
30+
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
31+
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
32+
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

pkg/exec/command.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package exec
2+
3+
import (
4+
"bytes"
5+
"io"
6+
"os"
7+
"os/exec"
8+
"sync"
9+
)
10+
11+
// LookPath is the wrapper of os/exec.LookPath
12+
func LookPath(file string) (string, error) {
13+
return exec.LookPath(file)
14+
}
15+
16+
// RunCommandAndReturn runs a command, then returns the output
17+
func RunCommandAndReturn(name, dir string, args ...string) (result string, err error) {
18+
stdout := &bytes.Buffer{}
19+
if err = RunCommandWithBuffer(name, dir, stdout, nil, args...); err == nil {
20+
result = stdout.String()
21+
}
22+
return
23+
}
24+
25+
// RunCommandWithBuffer runs a command with buffer
26+
// stdout and stderr could be nil
27+
func RunCommandWithBuffer(name, dir string, stdout, stderr *bytes.Buffer, args ...string) error {
28+
if stdout == nil {
29+
stdout = &bytes.Buffer{}
30+
}
31+
if stderr != nil {
32+
stderr = &bytes.Buffer{}
33+
}
34+
return RunCommandWithIO(name, dir, stdout, stderr, args...)
35+
}
36+
37+
// RunCommandWithIO runs a command with given IO
38+
func RunCommandWithIO(name, dir string, stdout, stderr io.Writer, args ...string) (err error) {
39+
command := exec.Command(name, args...)
40+
if dir != "" {
41+
command.Dir = dir
42+
}
43+
44+
//var stdout []byte
45+
//var errStdout error
46+
stdoutIn, _ := command.StdoutPipe()
47+
stderrIn, _ := command.StderrPipe()
48+
err = command.Start()
49+
if err != nil {
50+
return
51+
}
52+
53+
// cmd.Wait() should be called only after we finish reading
54+
// from stdoutIn and stderrIn.
55+
// wg ensures that we finish
56+
var wg sync.WaitGroup
57+
wg.Add(1)
58+
go func() {
59+
_, _ = copyAndCapture(stdout, stdoutIn)
60+
wg.Done()
61+
}()
62+
63+
_, _ = copyAndCapture(stderr, stderrIn)
64+
65+
wg.Wait()
66+
67+
err = command.Wait()
68+
return
69+
}
70+
71+
// RunCommandInDir runs a command
72+
func RunCommandInDir(name, dir string, args ...string) error {
73+
return RunCommandWithIO(name, dir, os.Stdout, os.Stderr, args...)
74+
}
75+
76+
// RunCommand runs a command
77+
func RunCommand(name string, arg ...string) (err error) {
78+
return RunCommandInDir(name, "", arg...)
79+
}
80+
81+
// RunCommandWithSudo runs a command with sudo
82+
func RunCommandWithSudo(name string, args ...string) (err error) {
83+
newArgs := make([]string, 0)
84+
newArgs = append(newArgs, name)
85+
newArgs = append(newArgs, args...)
86+
return RunCommand("sudo", newArgs...)
87+
}
88+
89+
func copyAndCapture(w io.Writer, r io.Reader) ([]byte, error) {
90+
var out []byte
91+
buf := make([]byte, 1024, 1024)
92+
for {
93+
n, err := r.Read(buf[:])
94+
if n > 0 {
95+
d := buf[:n]
96+
out = append(out, d...)
97+
_, err := w.Write(d)
98+
if err != nil {
99+
return out, err
100+
}
101+
}
102+
if err != nil {
103+
// Read returns io.EOF at the end of file, which is not an error for us
104+
if err == io.EOF {
105+
err = nil
106+
}
107+
return out, err
108+
}
109+
}
110+
}

0 commit comments

Comments
 (0)