Skip to content

Commit

Permalink
support to run test case with filter (#560)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
LinuxSuRen and LinuxSuRen authored Nov 11, 2024
1 parent 19871a5 commit 9e4259f
Show file tree
Hide file tree
Showing 23 changed files with 326 additions and 8 deletions.
4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ FROM docker.io/golang:1.22.4 AS builder
ARG VERSION
ARG GOPROXY
WORKDIR /workspace
RUN mkdir -p console/atest-ui

COPY cmd/ cmd/
COPY pkg/ pkg/
COPY operator/ operator/
Expand All @@ -21,6 +23,8 @@ COPY go.sum go.sum
COPY go.work go.work
COPY go.work.sum go.work.sum
COPY main.go main.go
COPY console/atest-ui/ui.go console/atest-ui/ui.go
COPY console/atest-ui/package.json console/atest-ui/package.json
COPY README.md README.md
COPY LICENSE LICENSE

Expand Down
19 changes: 17 additions & 2 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type runOption struct {
duration time.Duration
requestTimeout time.Duration
requestIgnoreError bool
caseFilter string
thread int64
context context.Context
qps int32
Expand Down Expand Up @@ -116,6 +117,7 @@ See also https://github.com/LinuxSuRen/api-testing/tree/master/sample`,
flags.DurationVarP(&opt.duration, "duration", "", 0, "Running duration")
flags.DurationVarP(&opt.requestTimeout, "request-timeout", "", time.Minute, "Timeout for per request")
flags.BoolVarP(&opt.requestIgnoreError, "request-ignore-error", "", false, "Indicate if ignore the request error")
flags.StringVarP(&opt.caseFilter, "case-filter", "", "", "The filter of the test case")
flags.StringVarP(&opt.report, "report", "", "", "The type of target report. Supported: markdown, md, html, json, discard, std, prometheus, http, grpc")
flags.StringVarP(&opt.reportFile, "report-file", "", "", "The file path of the report")
flags.BoolVarP(&opt.reportIgnore, "report-ignore", "", false, "Indicate if ignore the report output")
Expand All @@ -130,8 +132,14 @@ See also https://github.com/LinuxSuRen/api-testing/tree/master/sample`,
return
}

const caseFilter = "case-filter"

func (o *runOption) preRunE(cmd *cobra.Command, args []string) (err error) {
o.context = cmd.Context()
ctx := cmd.Context()
if ctx == nil {
ctx = context.Background()
}
o.context = context.WithValue(ctx, caseFilter, o.caseFilter)
writer := cmd.OutOrStdout()

if o.reportFile != "" && !strings.HasPrefix(o.reportFile, "http://") && !strings.HasPrefix(o.reportFile, "https://") {
Expand Down Expand Up @@ -345,8 +353,15 @@ func (o *runOption) runSuite(loader testing.Loader, dataContext map[string]inter
suiteRunner.WithOutputWriter(os.Stdout)
suiteRunner.WithWriteLevel(o.level)
suiteRunner.WithSuite(testSuite)
runLogger.Info("run test suite", "name", testSuite.Name)
var caseFilterObj interface{}
if o.context != nil {
caseFilterObj = o.context.Value(caseFilter)
}
runLogger.Info("run test suite", "name", testSuite.Name, "filter", caseFilter)
for _, testCase := range testSuite.Items {
if caseFilterObj != nil && !strings.Contains(testCase.Name, caseFilterObj.(string)) {
continue
}
if !testCase.InScope(o.caseItems) {
continue
}
Expand Down
1 change: 1 addition & 0 deletions cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ func (o *serverOption) runE(cmd *cobra.Command, args []string) (err error) {
mux.HandlePath(http.MethodGet, "/swagger.json", frontEndHandlerWithLocation(o.consolePath))
mux.HandlePath(http.MethodGet, "/get", o.getAtestBinary)
mux.HandlePath(http.MethodPost, "/runner/{suite}/{case}", service.WebRunnerHandler)
mux.HandlePath(http.MethodGet, "/api/v1/sbom", service.SBomHandler)

postRequestProxyFunc := postRequestProxy(o.skyWalking)
mux.HandlePath(http.MethodPost, "/browser/{app}", postRequestProxyFunc)
Expand Down
3 changes: 3 additions & 0 deletions console/atest-ui/src/views/TemplateFunctions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,8 @@ Magic.Keys(() => {
</el-table-column>
</el-table>
</span>
<div>
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>.
</div>
</el-dialog>
</template>
44 changes: 44 additions & 0 deletions console/atest-ui/src/views/WelcomePage.vue
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
<script setup lang="ts">
import { ref } from 'vue'
import { API } from '../views/net'
interface SBOM {
go: {}
js: {
dependencies: {}
devDependencies: {}
}
}
const sbomItems = ref({} as SBOM)
API.SBOM((d) => {
sbomItems.value = d
})
</script>

<template>
<div>Welcome to use atest to improve your code quality!</div>
<div>Please read the following guide if this is your first time to use atest.</div>
Expand All @@ -8,4 +25,31 @@
<div>
Please get more details from the <a href="https://linuxsuren.github.io/api-testing/" target="_blank" rel="noopener">official document</a>.
</div>

<el-divider/>

<div>
Golang dependencies:
<div>
<el-scrollbar height="200px" always>
<li v-for="k, v in sbomItems.go">
{{ v }}@{{ k }}
</li>
</el-scrollbar>
</div>
</div>

<div>
JavaScript dependencies:
<div>
<el-scrollbar height="200px" always>
<li v-for="k, v in sbomItems.js.dependencies">
{{ v }}@{{ k }}
</li>
<li v-for="k, v in sbomItems.js.devDependencies">
{{ v }}@{{ k }}
</li>
</el-scrollbar>
</div>
</div>
</template>
7 changes: 6 additions & 1 deletion console/atest-ui/src/views/net.ts
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,11 @@ function DownloadResponseFile(testcase,
.then(callback).catch(errHandle)
}

var SBOM = (callback: (d: any) => void) => {
fetch(`/api/sbom`, {})
.then(DefaultResponseProcess)
.then(callback)
}

export const API = {
DefaultResponseProcess,
Expand All @@ -780,6 +785,6 @@ export const API = {
FunctionsQuery,
GetSecrets, DeleteSecret, CreateOrUpdateSecret,
GetSuggestedAPIs,
ReloadMockServer, GetMockConfig,
ReloadMockServer, GetMockConfig, SBOM,
getToken
}
20 changes: 20 additions & 0 deletions console/atest-ui/ui.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package ui

import (
_ "embed"
"encoding/json"
)

//go:embed package.json
var packageJSON []byte

type JSON struct {
Dependencies map[string]string `json:"dependencies"`
DevDependencies map[string]string `json:"devDependencies"`
}

func GetPackageJSON() (data JSON) {
data = JSON{}
_ = json.Unmarshal(packageJSON, &data)
return
}
8 changes: 7 additions & 1 deletion docs/site/content/zh/latest/tasks/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,10 @@ description: 只需几个简单的步骤即可开始使用 API Testing。

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

// TBD
## 执行部分测试用例

下面的命令会执行名称中包含 `sbom` 的所有测试用例:

```shell
atest run -p test-suite.yaml --case-filter sbom
```
27 changes: 27 additions & 0 deletions docs/site/content/zh/latest/tasks/verify.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,30 @@ title = "测试用例验证"
verify:
- len(data.data) == 6
```
## 数组值检查
```yaml
- name: popularHeaders
request:
api: /popularHeaders
expect:
verify:
- any(data.data, {.key == "Content-Type"})
```
[更多用法](https://expr-lang.org/docs/language-definition#any).
## 字符串判断
```yaml
- name: metrics
request:
api: |
{{.param.server}}/metrics
expect:
verify:
- indexOf(data, "atest_execution_count") != -1
```
[更多用法](https://expr-lang.org/docs/language-definition#indexOf).
9 changes: 9 additions & 0 deletions e2e/test-suite-common.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -376,3 +376,12 @@ items:
- indexOf(data, "atest_execution_success") != -1
- indexOf(data, "atest_runners_count") != -1
- indexOf(data, "http_requests_total") != -1

- name: sbom
request:
api: /sbom
expect:
verify:
- len(data.go) > 0
- len(data.js.dependencies) > 0
- len(data.js.devDependencies) > 0
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ require (
gopkg.in/yaml.v3 v3.0.1
)

require golang.org/x/mod v0.22.0 // indirect

require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
Expand Down
1 change: 1 addition & 0 deletions go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2154,6 +2154,7 @@ google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9
google.golang.org/api v0.155.0 h1:vBmGhCYs0djJttDNynWo44zosHlPvHmA0XiN2zP2DtA=
google.golang.org/api v0.155.0/go.mod h1:GI5qK5f40kCpHfPn6+YzGAByIKWv8ujFnmoWm7Igduk=
google.golang.org/api v0.162.0/go.mod h1:6SulDkfoBIg4NFmCuZ39XeeAgSHCPecfSUuDyYlAHs0=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk=
google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
Expand Down
7 changes: 6 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
package main

import (
_ "embed"
"github.com/linuxsuren/api-testing/pkg/version"
"os"

// _ "github.com/apache/skywalking-go"
"github.com/linuxsuren/api-testing/cmd"
"github.com/linuxsuren/api-testing/pkg/server"
exec "github.com/linuxsuren/go-fake-runtime"
)

func main() {
version.SetMod(goMod)
c := cmd.NewRootCmd(exec.NewDefaultExecer(), server.NewDefaultHTTPServer())
if err := c.Execute(); err != nil {
os.Exit(1)
}
}

//go:embed go.mod
var goMod string
6 changes: 6 additions & 0 deletions pkg/render/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
"github.com/linuxsuren/api-testing/pkg/version"
"io"
mathrand "math/rand"
"strings"
Expand Down Expand Up @@ -193,6 +194,11 @@ func GetAdvancedFuncs() []AdvancedFunc {
return advancedFuncs
}

func GetEngineVersion() (ver string) {
ver, _ = version.GetModVersion("github.com/Masterminds/sprig", "")
return
}

func generateJSONString(fields []string) (result string) {
data := make(map[string]string)
for _, item := range fields {
Expand Down
5 changes: 5 additions & 0 deletions pkg/render/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,3 +289,8 @@ func TestFuncUsages(t *testing.T) {
assert.NotEmpty(t, usage)
}
}

func TestGetEngineVersion(t *testing.T) {
ver := GetEngineVersion()
assert.Empty(t, ver)
}
3 changes: 1 addition & 2 deletions pkg/runner/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,8 @@ func (r *simpleTestCaseRunner) RunTestCase(testcase *testing.TestCase, dataConte
Value: v,
})
}
r.log.Info("request method: %s\n", request.Method)
r.log.Info("start to send request to %v with method %s\n", request.URL, request.Method)
r.log.Info("request header %v\n", request.Header)
r.log.Info("start to send request to %v\n", request.URL)

// TODO only do this for unit testing, should remove it once we have a better way
if strings.HasPrefix(testcase.Request.API, "http://") {
Expand Down
2 changes: 1 addition & 1 deletion pkg/server/remote_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ func TestRunTestCase(t *testing.T) {
})
assert.NoError(t, err)
assert.Equal(t, sampleBody, result.Body)
assert.Contains(t, result.Output, "request method: GET")
assert.Contains(t, result.Output, "with method GET")
assert.Contains(t, result.Output, "request header")
assert.Contains(t, result.Output, "start to send request to http://foo")
assert.Contains(t, result.Output, "test case \"get\", status code: 200")
Expand Down
40 changes: 40 additions & 0 deletions pkg/service/sbom.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
Copyright 2024 API Testing Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package service

import (
"net/http"

ui "github.com/linuxsuren/api-testing/console/atest-ui"
"github.com/linuxsuren/api-testing/pkg/util"
"github.com/linuxsuren/api-testing/pkg/version"
)

func SBomHandler(w http.ResponseWriter, r *http.Request,
params map[string]string) {
modMap, err := version.GetModVersions("")
packageJSON := ui.GetPackageJSON()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
} else {
data := make(map[string]interface{})
data["js"] = packageJSON
data["go"] = modMap
util.WriteAsJSON(data, w)
}
}
10 changes: 10 additions & 0 deletions pkg/util/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package util
import (
"bytes"
"crypto/tls"
"encoding/json"
"io"
"net/http"
)
Expand Down Expand Up @@ -68,3 +69,12 @@ func (c *cachedClient) RoundTrip(req *http.Request) (*http.Response, error) {

return resp, err
}

func WriteAsJSON(obj interface{}, w http.ResponseWriter) (n int, err error) {
w.Header().Set(ContentType, JSON)
var data []byte
if data, err = json.Marshal(obj); err == nil {
n, err = w.Write(data)
}
return
}
Loading

0 comments on commit 9e4259f

Please sign in to comment.