Skip to content

Commit 9e4259f

Browse files
authoredNov 11, 2024··
support to run test case with filter (#560)
* feat: support to get go mod version * support to run test case with filter * fix unit tests * fix dockerfile * add missing console/atest-ui/package.json * fix the e2e --------- Co-authored-by: rick <LinuxSuRen@users.noreply.github.com>
1 parent 19871a5 commit 9e4259f

File tree

23 files changed

+326
-8
lines changed

23 files changed

+326
-8
lines changed
 

‎Dockerfile

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ FROM docker.io/golang:1.22.4 AS builder
1010
ARG VERSION
1111
ARG GOPROXY
1212
WORKDIR /workspace
13+
RUN mkdir -p console/atest-ui
14+
1315
COPY cmd/ cmd/
1416
COPY pkg/ pkg/
1517
COPY operator/ operator/
@@ -21,6 +23,8 @@ COPY go.sum go.sum
2123
COPY go.work go.work
2224
COPY go.work.sum go.work.sum
2325
COPY main.go main.go
26+
COPY console/atest-ui/ui.go console/atest-ui/ui.go
27+
COPY console/atest-ui/package.json console/atest-ui/package.json
2428
COPY README.md README.md
2529
COPY LICENSE LICENSE
2630

‎cmd/run.go

+17-2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ type runOption struct {
5151
duration time.Duration
5252
requestTimeout time.Duration
5353
requestIgnoreError bool
54+
caseFilter string
5455
thread int64
5556
context context.Context
5657
qps int32
@@ -116,6 +117,7 @@ See also https://github.com/LinuxSuRen/api-testing/tree/master/sample`,
116117
flags.DurationVarP(&opt.duration, "duration", "", 0, "Running duration")
117118
flags.DurationVarP(&opt.requestTimeout, "request-timeout", "", time.Minute, "Timeout for per request")
118119
flags.BoolVarP(&opt.requestIgnoreError, "request-ignore-error", "", false, "Indicate if ignore the request error")
120+
flags.StringVarP(&opt.caseFilter, "case-filter", "", "", "The filter of the test case")
119121
flags.StringVarP(&opt.report, "report", "", "", "The type of target report. Supported: markdown, md, html, json, discard, std, prometheus, http, grpc")
120122
flags.StringVarP(&opt.reportFile, "report-file", "", "", "The file path of the report")
121123
flags.BoolVarP(&opt.reportIgnore, "report-ignore", "", false, "Indicate if ignore the report output")
@@ -130,8 +132,14 @@ See also https://github.com/LinuxSuRen/api-testing/tree/master/sample`,
130132
return
131133
}
132134

135+
const caseFilter = "case-filter"
136+
133137
func (o *runOption) preRunE(cmd *cobra.Command, args []string) (err error) {
134-
o.context = cmd.Context()
138+
ctx := cmd.Context()
139+
if ctx == nil {
140+
ctx = context.Background()
141+
}
142+
o.context = context.WithValue(ctx, caseFilter, o.caseFilter)
135143
writer := cmd.OutOrStdout()
136144

137145
if o.reportFile != "" && !strings.HasPrefix(o.reportFile, "http://") && !strings.HasPrefix(o.reportFile, "https://") {
@@ -345,8 +353,15 @@ func (o *runOption) runSuite(loader testing.Loader, dataContext map[string]inter
345353
suiteRunner.WithOutputWriter(os.Stdout)
346354
suiteRunner.WithWriteLevel(o.level)
347355
suiteRunner.WithSuite(testSuite)
348-
runLogger.Info("run test suite", "name", testSuite.Name)
356+
var caseFilterObj interface{}
357+
if o.context != nil {
358+
caseFilterObj = o.context.Value(caseFilter)
359+
}
360+
runLogger.Info("run test suite", "name", testSuite.Name, "filter", caseFilter)
349361
for _, testCase := range testSuite.Items {
362+
if caseFilterObj != nil && !strings.Contains(testCase.Name, caseFilterObj.(string)) {
363+
continue
364+
}
350365
if !testCase.InScope(o.caseItems) {
351366
continue
352367
}

‎cmd/server.go

+1
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ func (o *serverOption) runE(cmd *cobra.Command, args []string) (err error) {
337337
mux.HandlePath(http.MethodGet, "/swagger.json", frontEndHandlerWithLocation(o.consolePath))
338338
mux.HandlePath(http.MethodGet, "/get", o.getAtestBinary)
339339
mux.HandlePath(http.MethodPost, "/runner/{suite}/{case}", service.WebRunnerHandler)
340+
mux.HandlePath(http.MethodGet, "/api/v1/sbom", service.SBomHandler)
340341

341342
postRequestProxyFunc := postRequestProxy(o.skyWalking)
342343
mux.HandlePath(http.MethodPost, "/browser/{app}", postRequestProxyFunc)

‎console/atest-ui/src/views/TemplateFunctions.vue

+3
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,8 @@ Magic.Keys(() => {
5656
</el-table-column>
5757
</el-table>
5858
</span>
59+
<div>
60+
Powered by <a href="https://masterminds.github.io/sprig/" target="_blank">Sprig</a> and <a href="https://pkg.go.dev/text/template" target="_blank">built-in templates</a>.
61+
</div>
5962
</el-dialog>
6063
</template>

‎console/atest-ui/src/views/WelcomePage.vue

+44
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
<script setup lang="ts">
2+
import { ref } from 'vue'
3+
import { API } from '../views/net'
4+
5+
interface SBOM {
6+
go: {}
7+
js: {
8+
dependencies: {}
9+
devDependencies: {}
10+
}
11+
}
12+
const sbomItems = ref({} as SBOM)
13+
API.SBOM((d) => {
14+
sbomItems.value = d
15+
})
16+
</script>
17+
118
<template>
219
<div>Welcome to use atest to improve your code quality!</div>
320
<div>Please read the following guide if this is your first time to use atest.</div>
@@ -8,4 +25,31 @@
825
<div>
926
Please get more details from the <a href="https://linuxsuren.github.io/api-testing/" target="_blank" rel="noopener">official document</a>.
1027
</div>
28+
29+
<el-divider/>
30+
31+
<div>
32+
Golang dependencies:
33+
<div>
34+
<el-scrollbar height="200px" always>
35+
<li v-for="k, v in sbomItems.go">
36+
{{ v }}@{{ k }}
37+
</li>
38+
</el-scrollbar>
39+
</div>
40+
</div>
41+
42+
<div>
43+
JavaScript dependencies:
44+
<div>
45+
<el-scrollbar height="200px" always>
46+
<li v-for="k, v in sbomItems.js.dependencies">
47+
{{ v }}@{{ k }}
48+
</li>
49+
<li v-for="k, v in sbomItems.js.devDependencies">
50+
{{ v }}@{{ k }}
51+
</li>
52+
</el-scrollbar>
53+
</div>
54+
</div>
1155
</template>

‎console/atest-ui/src/views/net.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,11 @@ function DownloadResponseFile(testcase,
767767
.then(callback).catch(errHandle)
768768
}
769769

770+
var SBOM = (callback: (d: any) => void) => {
771+
fetch(`/api/sbom`, {})
772+
.then(DefaultResponseProcess)
773+
.then(callback)
774+
}
770775

771776
export const API = {
772777
DefaultResponseProcess,
@@ -780,6 +785,6 @@ export const API = {
780785
FunctionsQuery,
781786
GetSecrets, DeleteSecret, CreateOrUpdateSecret,
782787
GetSuggestedAPIs,
783-
ReloadMockServer, GetMockConfig,
788+
ReloadMockServer, GetMockConfig, SBOM,
784789
getToken
785790
}

‎console/atest-ui/ui.go

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package ui
2+
3+
import (
4+
_ "embed"
5+
"encoding/json"
6+
)
7+
8+
//go:embed package.json
9+
var packageJSON []byte
10+
11+
type JSON struct {
12+
Dependencies map[string]string `json:"dependencies"`
13+
DevDependencies map[string]string `json:"devDependencies"`
14+
}
15+
16+
func GetPackageJSON() (data JSON) {
17+
data = JSON{}
18+
_ = json.Unmarshal(packageJSON, &data)
19+
return
20+
}

‎docs/site/content/zh/latest/tasks/quickstart.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,10 @@ description: 只需几个简单的步骤即可开始使用 API Testing。
66

77
本指南将帮助您通过几个简单的步骤开始使用 API Testing。
88

9-
// TBD
9+
## 执行部分测试用例
10+
11+
下面的命令会执行名称中包含 `sbom` 的所有测试用例:
12+
13+
```shell
14+
atest run -p test-suite.yaml --case-filter sbom
15+
```

‎docs/site/content/zh/latest/tasks/verify.md

+27
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,30 @@ title = "测试用例验证"
1616
verify:
1717
- len(data.data) == 6
1818
```
19+
20+
## 数组值检查
21+
22+
```yaml
23+
- name: popularHeaders
24+
request:
25+
api: /popularHeaders
26+
expect:
27+
verify:
28+
- any(data.data, {.key == "Content-Type"})
29+
```
30+
31+
[更多用法](https://expr-lang.org/docs/language-definition#any).
32+
33+
## 字符串判断
34+
35+
```yaml
36+
- name: metrics
37+
request:
38+
api: |
39+
{{.param.server}}/metrics
40+
expect:
41+
verify:
42+
- indexOf(data, "atest_execution_count") != -1
43+
```
44+
45+
[更多用法](https://expr-lang.org/docs/language-definition#indexOf).

‎e2e/test-suite-common.yaml

+9
Original file line numberDiff line numberDiff line change
@@ -376,3 +376,12 @@ items:
376376
- indexOf(data, "atest_execution_success") != -1
377377
- indexOf(data, "atest_runners_count") != -1
378378
- indexOf(data, "http_requests_total") != -1
379+
380+
- name: sbom
381+
request:
382+
api: /sbom
383+
expect:
384+
verify:
385+
- len(data.go) > 0
386+
- len(data.js.dependencies) > 0
387+
- len(data.js.devDependencies) > 0

‎go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ require (
4141
gopkg.in/yaml.v3 v3.0.1
4242
)
4343

44+
require golang.org/x/mod v0.22.0 // indirect
45+
4446
require (
4547
github.com/Masterminds/goutils v1.1.1 // indirect
4648
github.com/Masterminds/semver/v3 v3.2.1 // indirect

‎go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,8 @@ golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4
224224
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
225225
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
226226
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
227+
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
228+
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
227229
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
228230
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
229231
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=

‎go.work.sum

+1
Original file line numberDiff line numberDiff line change
@@ -2154,6 +2154,7 @@ google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9
21542154
google.golang.org/api v0.155.0 h1:vBmGhCYs0djJttDNynWo44zosHlPvHmA0XiN2zP2DtA=
21552155
google.golang.org/api v0.155.0/go.mod h1:GI5qK5f40kCpHfPn6+YzGAByIKWv8ujFnmoWm7Igduk=
21562156
google.golang.org/api v0.162.0/go.mod h1:6SulDkfoBIg4NFmCuZ39XeeAgSHCPecfSUuDyYlAHs0=
2157+
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
21572158
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
21582159
google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk=
21592160
google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=

‎main.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
package main
22

33
import (
4+
_ "embed"
5+
"github.com/linuxsuren/api-testing/pkg/version"
46
"os"
57

6-
// _ "github.com/apache/skywalking-go"
78
"github.com/linuxsuren/api-testing/cmd"
89
"github.com/linuxsuren/api-testing/pkg/server"
910
exec "github.com/linuxsuren/go-fake-runtime"
1011
)
1112

1213
func main() {
14+
version.SetMod(goMod)
1315
c := cmd.NewRootCmd(exec.NewDefaultExecer(), server.NewDefaultHTTPServer())
1416
if err := c.Execute(); err != nil {
1517
os.Exit(1)
1618
}
1719
}
20+
21+
//go:embed go.mod
22+
var goMod string

‎pkg/render/template.go

+6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"encoding/hex"
2727
"encoding/json"
2828
"fmt"
29+
"github.com/linuxsuren/api-testing/pkg/version"
2930
"io"
3031
mathrand "math/rand"
3132
"strings"
@@ -193,6 +194,11 @@ func GetAdvancedFuncs() []AdvancedFunc {
193194
return advancedFuncs
194195
}
195196

197+
func GetEngineVersion() (ver string) {
198+
ver, _ = version.GetModVersion("github.com/Masterminds/sprig", "")
199+
return
200+
}
201+
196202
func generateJSONString(fields []string) (result string) {
197203
data := make(map[string]string)
198204
for _, item := range fields {

‎pkg/render/template_test.go

+5
Original file line numberDiff line numberDiff line change
@@ -289,3 +289,8 @@ func TestFuncUsages(t *testing.T) {
289289
assert.NotEmpty(t, usage)
290290
}
291291
}
292+
293+
func TestGetEngineVersion(t *testing.T) {
294+
ver := GetEngineVersion()
295+
assert.Empty(t, ver)
296+
}

‎pkg/runner/http.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,8 @@ func (r *simpleTestCaseRunner) RunTestCase(testcase *testing.TestCase, dataConte
176176
Value: v,
177177
})
178178
}
179-
r.log.Info("request method: %s\n", request.Method)
179+
r.log.Info("start to send request to %v with method %s\n", request.URL, request.Method)
180180
r.log.Info("request header %v\n", request.Header)
181-
r.log.Info("start to send request to %v\n", request.URL)
182181

183182
// TODO only do this for unit testing, should remove it once we have a better way
184183
if strings.HasPrefix(testcase.Request.API, "http://") {

‎pkg/server/remote_server_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ func TestRunTestCase(t *testing.T) {
148148
})
149149
assert.NoError(t, err)
150150
assert.Equal(t, sampleBody, result.Body)
151-
assert.Contains(t, result.Output, "request method: GET")
151+
assert.Contains(t, result.Output, "with method GET")
152152
assert.Contains(t, result.Output, "request header")
153153
assert.Contains(t, result.Output, "start to send request to http://foo")
154154
assert.Contains(t, result.Output, "test case \"get\", status code: 200")

‎pkg/service/sbom.go

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
Copyright 2024 API Testing Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package service
18+
19+
import (
20+
"net/http"
21+
22+
ui "github.com/linuxsuren/api-testing/console/atest-ui"
23+
"github.com/linuxsuren/api-testing/pkg/util"
24+
"github.com/linuxsuren/api-testing/pkg/version"
25+
)
26+
27+
func SBomHandler(w http.ResponseWriter, r *http.Request,
28+
params map[string]string) {
29+
modMap, err := version.GetModVersions("")
30+
packageJSON := ui.GetPackageJSON()
31+
if err != nil {
32+
w.WriteHeader(http.StatusInternalServerError)
33+
w.Write([]byte(err.Error()))
34+
} else {
35+
data := make(map[string]interface{})
36+
data["js"] = packageJSON
37+
data["go"] = modMap
38+
util.WriteAsJSON(data, w)
39+
}
40+
}

‎pkg/util/http.go

+10
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package util
1818
import (
1919
"bytes"
2020
"crypto/tls"
21+
"encoding/json"
2122
"io"
2223
"net/http"
2324
)
@@ -68,3 +69,12 @@ func (c *cachedClient) RoundTrip(req *http.Request) (*http.Response, error) {
6869

6970
return resp, err
7071
}
72+
73+
func WriteAsJSON(obj interface{}, w http.ResponseWriter) (n int, err error) {
74+
w.Header().Set(ContentType, JSON)
75+
var data []byte
76+
if data, err = json.Marshal(obj); err == nil {
77+
n, err = w.Write(data)
78+
}
79+
return
80+
}

0 commit comments

Comments
 (0)
Please sign in to comment.