Skip to content

Commit

Permalink
chore: add release note v0.0.13 (#175)
Browse files Browse the repository at this point in the history
  • Loading branch information
LinuxSuRen authored Aug 22, 2023
1 parent bd78fa4 commit 1ad11f3
Show file tree
Hide file tree
Showing 14 changed files with 244 additions and 83 deletions.
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
IMG_TOOL?=podman
BINARY?=atest

build:
mkdir -p bin
Expand All @@ -9,10 +10,12 @@ build-embed-ui:
cp console/atest-ui/dist/index.html cmd/data/index.html
cp console/atest-ui/dist/assets/*.js cmd/data/index.js
cp console/atest-ui/dist/assets/*.css cmd/data/index.css
go build -ldflags "-w -s -X github.com/linuxsuren/api-testing/pkg/version.version=$(shell git rev-parse --short HEAD)" -o bin/atest main.go
GOOS=${OS} go build -ldflags "-w -s -X github.com/linuxsuren/api-testing/pkg/version.version=$(shell git rev-parse --short HEAD)" -o bin/${BINARY} main.go
echo -n '' > cmd/data/index.html
echo -n '' > cmd/data/index.js
echo -n '' > cmd/data/index.css
build-win-embed-ui:
BINARY=atest.exe OS=windows make build-embed-ui
goreleaser:
goreleaser build --rm-dist --snapshot
build-image:
Expand Down
4 changes: 1 addition & 3 deletions cmd/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,7 @@ type convertOption struct {
}

func (o *convertOption) preRunE(c *cobra.Command, args []string) (err error) {
if o.target == "" {
o.target = "sample.jmx"
}
o.target = util.EmptyThenDefault(o.target, "sample.jmx")
return
}

Expand Down
8 changes: 8 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ Please see the following example usage:
sudo atest service install -m podman --version master
```

or run in Docker:
```shell
docker run -v /var/www/sample:/var/www/sample \
--network host \
linuxsuren/api-testing:master
```

the default web server port is `8080`. So you can visit it via: http://localhost:8080

## Run in k3s
Expand Down Expand Up @@ -203,6 +210,7 @@ You could find the official images from both [Docker Hub](https://hub.docker.com
The tag `latest` represents the latest release version. The tag `master` represents the image of the latest master branch. We highly recommend you using a fixed version instead of those in a production environment.

## Release Notes
* [v0.0.13](release-note-v0.0.13.md)
* [v0.0.12](release-note-v0.0.12.md)

## Articles
Expand Down
68 changes: 68 additions & 0 deletions docs/release-note-v0.0.13.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
`atest` 版本发布 `v0.0.13`

`atest` 是一款用 Golang 编写的、开源的接口测试工具。

你可以在容器中启动:

```shell
docker run -v /var/www/sample:/var/www/sample \
--network host \
linuxsuren/api-testing:master
```

或者,直接[下载二进制文件](https://github.com/LinuxSuRen/api-testing/releases/tag/v0.0.12)后启动:

```shell
atest server --local-storage /var/www/sample
```

对于持续集成(CI)场景,可以通过在流水线中执行命令的方式:

```shell
# 执行本地文件
atest run -p your-test-suite.yaml
# 执行远程文件
atest run -p https://gitee.com/linuxsuren/api-testing/raw/master/sample/testsuite-gitee.yaml
# 容器中执行
docker run linuxsuren/api-testing:master atest run -p https://gitee.com/linuxsuren/api-testing/raw/master/sample/testsuite-gitee.yaml
```

你也可以把测试用例转为 JMeter 文件并执行:

```shell
# 格式转换
atest convert --converter jmeter -p https://gitee.com/linuxsuren/api-testing/raw/master/sample/testsuite-gitee.yaml --target gitee.jmx
# 执行
jmeter -n -t gitee.jmx
```

## 主要的新功能

* 增加了插件扩展机制,支持以 Git、S3、关系型数据为后端存储,支持从 [Vault](https://github.com/hashicorp/vault) 获取密码等敏感信息
* 新增对 gRPC 接口的用例支持 @Ink-33
* 支持导出 [JMeter](https://github.com/apache/jmeter) 文件
* 支持通过 [Operator](https://operatorhub.io/operator/api-testing-operator) 的方式安装,并上架 OperatorHub.io
* 提供了基本的 Web UI
* 支持导出 PDF 格式的测试报告 @wjsvec

本次版本发布,包含了以下 5 位 contributor 的努力:

* [@Ink-33](https://github.com/Ink-33)
* [@LinuxSuRen](https://github.com/LinuxSuRen)
* [@chan158](https://github.com/chan158)
* [@setcy](https://github.com/setcy)
* [@wjsvec](https://github.com/wjsvec)

## 相关数据

下面是 `atest` 截止到 `v0.0.13` 的部分数据:

* watch 7
* fork 18
* star 69
* contributor 8
* 二进制文件下载量 872
* 代码行数 45k
* 单元测试覆盖率 84%

想了解完整信息的话,请访问 https://github.com/LinuxSuRen/api-testing/releases/tag/v0.0.13
76 changes: 59 additions & 17 deletions pkg/generator/converter_jmeter.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ package generator

import (
"encoding/xml"
"fmt"
"net/url"

"github.com/linuxsuren/api-testing/pkg/testing"
Expand All @@ -50,27 +51,31 @@ func (c *jmeterConverter) Convert(testSuite *testing.TestSuite) (result string,
}

func (c *jmeterConverter) buildJmeterTestPlan(testSuite *testing.TestSuite) (result *JmeterTestPlan, err error) {
if err = testSuite.Render(make(map[string]interface{})); err != nil {
emptyCtx := make(map[string]interface{})
if err = testSuite.Render(emptyCtx); err != nil {
return
}

requestItems := []interface{}{}
for _, item := range testSuite.Items {
item.Request.RenderAPI(testSuite.API)
if reqRenderErr := item.Request.Render(emptyCtx, ""); reqRenderErr != nil {
fmt.Println("Error rendering request: ", reqRenderErr)
}

api, err := url.Parse(item.Request.API)
if err != nil {
continue
}

requestItems = append(requestItems, &HTTPSamplerProxy{
requestItem := &HTTPSamplerProxy{
GUIClass: "HttpTestSampleGui",
TestClass: "HTTPSamplerProxy",
Enabled: true,
Name: item.Name,
StringProp: []StringProp{{
Name: "HTTPSampler.domain",
Value: api.Host,
Value: api.Hostname(),
}, {
Name: "HTTPSampler.port",
Value: api.Port(),
Expand All @@ -81,7 +86,36 @@ func (c *jmeterConverter) buildJmeterTestPlan(testSuite *testing.TestSuite) (res
Name: "HTTPSampler.method",
Value: item.Request.Method,
}},
})
}
if item.Request.Body != "" {
requestItem.BoolProp = append(requestItem.BoolProp, BoolProp{
Name: "HTTPSampler.postBodyRaw",
Value: "true",
})
requestItem.ElementProp = append(requestItem.ElementProp, ElementProp{
Name: "HTTPsampler.Arguments",
Type: "Arguments",
CollectionProp: []CollectionProp{{
Name: "Arguments.arguments",
ElementProp: []ElementProp{{
Name: "",
Type: "HTTPArgument",
BoolProp: []BoolProp{{
Name: "HTTPArgument.always_encode",
Value: "false",
}},
StringProp: []StringProp{{
Name: "Argument.value",
Value: item.Request.Body,
}, {
Name: "Argument.metadata",
Value: "=",
}},
}},
}},
})
}
requestItems = append(requestItems, requestItem)
requestItems = append(requestItems, HashTree{})
}
requestItems = append(requestItems, &ResultCollector{
Expand Down Expand Up @@ -177,12 +211,14 @@ type ThreadGroup struct {
}

type HTTPSamplerProxy struct {
XMLName xml.Name `xml:"HTTPSamplerProxy"`
StringProp []StringProp `xml:"stringProp"`
Name string `xml:"testname,attr"`
GUIClass string `xml:"guiclass,attr"`
TestClass string `xml:"testclass,attr"`
Enabled bool `xml:"enabled,attr"`
XMLName xml.Name `xml:"HTTPSamplerProxy"`
Name string `xml:"testname,attr"`
GUIClass string `xml:"guiclass,attr"`
TestClass string `xml:"testclass,attr"`
Enabled bool `xml:"enabled,attr"`
StringProp []StringProp `xml:"stringProp"`
BoolProp []BoolProp `xml:"boolProp"`
ElementProp []ElementProp `xml:"elementProp"`
}

type ResultCollector struct {
Expand All @@ -194,13 +230,19 @@ type ResultCollector struct {
}

type ElementProp struct {
Name string `xml:"name,attr"`
Type string `xml:"elementType,attr"`
GUIClass string `xml:"guiclass,attr"`
TestClass string `xml:"testclass,attr"`
Enabled bool `xml:"enabled,attr"`
StringProp []StringProp `xml:"stringProp"`
BoolProp []BoolProp `xml:"boolProp"`
Name string `xml:"name,attr"`
Type string `xml:"elementType,attr"`
GUIClass string `xml:"guiclass,attr"`
TestClass string `xml:"testclass,attr"`
Enabled bool `xml:"enabled,attr"`
StringProp []StringProp `xml:"stringProp"`
BoolProp []BoolProp `xml:"boolProp"`
CollectionProp []CollectionProp `xml:"collectionProp"`
}

type CollectionProp struct {
Name string `xml:"name,attr"`
ElementProp []ElementProp `xml:"elementProp"`
}

type StringProp struct {
Expand Down
3 changes: 2 additions & 1 deletion pkg/generator/converter_jmeter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,13 @@ func TestJmeterConvert(t *testing.T) {
func createTestSuiteForTest() *atest.TestSuite {
return &atest.TestSuite{
Name: "API Testing",
API: "http://localhost:8080",
API: `{{default "http://localhost:8080/server.Runner" (env "SERVER")}}`,
Items: []atest.TestCase{{
Name: "hello-jmeter",
Request: atest.Request{
Method: "POST",
API: "/GetSuites",
Body: `sample`,
},
}},
}
Expand Down
14 changes: 12 additions & 2 deletions pkg/generator/testdata/expected_jmeter.jmx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,20 @@
</ThreadGroup>
<hashTree>
<HTTPSamplerProxy testname="hello-jmeter" guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" enabled="true">
<stringProp name="HTTPSampler.domain">localhost:8080</stringProp>
<stringProp name="HTTPSampler.domain">localhost</stringProp>
<stringProp name="HTTPSampler.port">8080</stringProp>
<stringProp name="HTTPSampler.path">/GetSuites</stringProp>
<stringProp name="HTTPSampler.path">/server.Runner/GetSuites</stringProp>
<stringProp name="HTTPSampler.method">POST</stringProp>
<boolProp name="HTTPSampler.postBodyRaw">true</boolProp>
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="" testclass="" enabled="false">
<collectionProp name="Arguments.arguments">
<elementProp name="" elementType="HTTPArgument" guiclass="" testclass="" enabled="false">
<stringProp name="Argument.value">sample</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
<boolProp name="HTTPArgument.always_encode">false</boolProp>
</elementProp>
</collectionProp>
</elementProp>
</HTTPSamplerProxy>
<hashTree></hashTree>
<ResultCollector enabled="true" guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report"></ResultCollector>
Expand Down
3 changes: 2 additions & 1 deletion pkg/generator/testdata/expected_testsuite.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
name: API Testing
api: http://localhost:8080
api: http://localhost:8080/server.Runner
items:
- name: hello-jmeter
request:
api: /GetSuites
method: POST
body: sample
16 changes: 10 additions & 6 deletions pkg/testing/loader_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,17 @@ func NewFileWriter(parent string) Writer {
// HasMore returns if there are more test cases
func (l *fileLoader) HasMore() bool {
l.index++
return l.index < len(l.paths)
return l.index < len(l.paths) && l.index >= 0
}

// Load returns the test case content
func (l *fileLoader) Load() (data []byte, err error) {
targetFile := l.paths[l.index]
data, err = loadData(targetFile)
return
}

func loadData(targetFile string) (data []byte, err error) {
if strings.HasPrefix(targetFile, "http://") || strings.HasPrefix(targetFile, "https://") {
var ok bool
data, ok, err = gRPCCompitableRequest(targetFile)
Expand Down Expand Up @@ -132,14 +137,13 @@ func (l *fileLoader) Reset() {
}

func (l *fileLoader) ListTestSuite() (suites []TestSuite, err error) {
defer func() {
l.Reset()
}()
l.lock.RLocker().Lock()
defer l.lock.RUnlock()

for l.HasMore() {
for _, target := range l.paths {
var data []byte
var loadErr error
if data, loadErr = l.Load(); err != nil {
if data, loadErr = loadData(target); err != nil {
fmt.Println("failed to load data", loadErr)
continue
}
Expand Down
20 changes: 2 additions & 18 deletions pkg/testing/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func (r *Request) Render(ctx interface{}, dataDir string) (err error) {
}

// setting default values
r.Method = EmptyThenDefault(r.Method, http.MethodGet)
r.Method = util.EmptyThenDefault(r.Method, http.MethodGet)
return
}

Expand Down Expand Up @@ -201,7 +201,7 @@ func (r *Request) GetBody() (reader io.Reader, err error) {

// Render renders the response
func (r *Response) Render(ctx interface{}) (err error) {
r.StatusCode = ZeroThenDefault(r.StatusCode, http.StatusOK)
r.StatusCode = util.ZeroThenDefault(r.StatusCode, http.StatusOK)
return
}

Expand All @@ -217,19 +217,3 @@ func renderMap(ctx interface{}, data map[string]string, title string) (result ma
result = data
return
}

// ZeroThenDefault return the default value if the val is zero
func ZeroThenDefault(val, defVal int) int {
if val == 0 {
val = defVal
}
return val
}

// EmptyThenDefault return the default value if the val is empty
func EmptyThenDefault(val, defVal string) string {
if strings.TrimSpace(val) == "" {
val = defVal
}
return val
}
Loading

0 comments on commit 1ad11f3

Please sign in to comment.