Skip to content

Commit

Permalink
feat: support to generate robot-framework script (#563)
Browse files Browse the repository at this point in the history
Co-authored-by: rick <[email protected]>
  • Loading branch information
LinuxSuRen and LinuxSuRen authored Nov 18, 2024
1 parent 33703da commit 0f02984
Show file tree
Hide file tree
Showing 18 changed files with 298 additions and 45 deletions.
20 changes: 16 additions & 4 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ type runOption struct {
duration time.Duration
requestTimeout time.Duration
requestIgnoreError bool
caseFilter string
caseFilter []string
thread int64
context context.Context
qps int32
Expand Down Expand Up @@ -117,7 +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.StringArrayVarP(&opt.caseFilter, "case-filter", "", nil, "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 Down Expand Up @@ -359,8 +359,20 @@ func (o *runOption) runSuite(loader testing.Loader, dataContext map[string]inter
}
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 caseFilterObj != nil {
if filter, ok := caseFilterObj.([]string); ok && len(filter) > 0{
match := false
for _, ff := range filter {
if strings.Contains(testCase.Name, ff) {
match = true
break
}
}

if !match {
continue
}
}
}
if !testCase.InScope(o.caseItems) {
continue
Expand Down
14 changes: 14 additions & 0 deletions docs/site/content/zh/latest/tasks/code-generator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
+++
title = "代码生成"
+++

`atest` 支持把测试用例生成多种开发语言的代码:

* curl
* Java
* Golang
* Python
* JavaScript
* [Robot Framework](https://robotframework.org/)

> 该功能需要在 Web UI 上使用。
9 changes: 9 additions & 0 deletions e2e/code-generator/compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ services:
command:
- /workspace/entrypoint.sh
- python
robot-framework:
build:
context: .
dockerfile: Dockerfile
args:
- LAN_ENV=docker.io/library/python:3.8
command:
- /workspace/entrypoint.sh
- robot-framework
javascript:
build:
context: .
Expand Down
14 changes: 14 additions & 0 deletions e2e/code-generator/robot-framework.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash
set -e

export sourcefile=$1
# exit if no source file is specified
if [ -z "$sourcefile" ]
then
echo "no source file is specified"
exit 1
fi

mv ${sourcefile} test.robot
pip install robotframework robotframework-requests
robot test.robot
2 changes: 1 addition & 1 deletion e2e/code-generator/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ set -e

docker compose version

targets=(golang java python javascript curl)
targets=(golang java python javascript curl robot-framework)
for target in "${targets[@]}"
do
docker compose down
Expand Down
41 changes: 40 additions & 1 deletion pkg/generator/code_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,14 @@ limitations under the License.
*/
package generator

import "github.com/linuxsuren/api-testing/pkg/testing"
import (
"bytes"
"fmt"
"net/http"
"text/template"

"github.com/linuxsuren/api-testing/pkg/testing"
)

// CodeGenerator is the interface of code generator
type CodeGenerator interface {
Expand Down Expand Up @@ -64,3 +71,35 @@ func GetTestSuiteConverters() (result map[string]TestSuiteConverter) {
}
return
}

func generate(testsuite *testing.TestSuite, testcase *testing.TestCase, templateName, templateText string) (result string, err error) {
if testcase != nil && testcase.Request.Method == "" {
testcase.Request.Method = http.MethodGet
}
if testsuite != nil && testsuite.Items != nil {
for i, _ := range testsuite.Items {
if testsuite.Items[i].Request.Method == "" {
testsuite.Items[i].Request.Method = http.MethodGet
}
}
}
var tpl *template.Template
if tpl, err = template.New(templateName).
Funcs(template.FuncMap{"safeString": safeString}).
Parse(templateText); err == nil {
buf := new(bytes.Buffer)
var ctx interface{}
if testcase == nil {
ctx = testsuite
} else {
ctx = testcase
}

if err = tpl.Execute(buf, ctx); err == nil {
result = buf.String()
}
} else {
fmt.Println(err)
}
return
}
11 changes: 11 additions & 0 deletions pkg/generator/data/robot-suite.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
*** Settings ***
Library RequestsLibrary

*** Test Cases ***
{{- range $item := .Items}}
{{$item.Name}}
{{- if $item.Request.Header}}
${headers}= Create Dictionary {{- range $key, $val := $item.Request.Header}} {{$key}} {{$val}}{{- end}}
{{- end}}
${response}= {{$item.Request.Method}} {{$item.Request.API}}{{- if .Request.Header}} headers=${headers}{{end}}
{{- end}}
9 changes: 9 additions & 0 deletions pkg/generator/data/robot.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
*** Settings ***
Library RequestsLibrary

*** Test Cases ***
{{.Name}}
{{- if .Request.Header}}
${headers}= Create Dictionary {{- range $key, $val := .Request.Header}} {{$key}} {{$val}}{{- end}}
{{- end}}
${response}= {{.Request.Method}} {{.Request.API}}{{- if .Request.Header}} headers=${headers}{{end}}
18 changes: 2 additions & 16 deletions pkg/generator/javascript_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ limitations under the License.
package generator

import (
"bytes"
"net/http"
"text/template"

_ "embed"

"github.com/linuxsuren/api-testing/pkg/testing"
Expand All @@ -32,18 +28,8 @@ func NewJavaScriptGenerator() CodeGenerator {
return &javascriptGenerator{}
}

func (g *javascriptGenerator) Generate(testSuite *testing.TestSuite, testcase *testing.TestCase) (result string, err error) {
if testcase.Request.Method == "" {
testcase.Request.Method = http.MethodGet
}
var tpl *template.Template
if tpl, err = template.New("javascript template").Funcs(template.FuncMap{"safeString": safeString}).Parse(javascriptTemplate); err == nil {
buf := new(bytes.Buffer)
if err = tpl.Execute(buf, testcase); err == nil {
result = buf.String()
}
}
return
func (g *javascriptGenerator) Generate(testSuite *testing.TestSuite, testcase *testing.TestCase) (string, error) {
return generate(testSuite, testcase, "javascript template", javascriptTemplate)
}

func init() {
Expand Down
16 changes: 1 addition & 15 deletions pkg/generator/python_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ limitations under the License.
package generator

import (
"bytes"
"net/http"
"text/template"

_ "embed"

"github.com/linuxsuren/api-testing/pkg/testing"
Expand All @@ -33,17 +29,7 @@ func NewPythonGenerator() CodeGenerator {
}

func (g *pythonGenerator) Generate(testSuite *testing.TestSuite, testcase *testing.TestCase) (result string, err error) {
if testcase.Request.Method == "" {
testcase.Request.Method = http.MethodGet
}
var tpl *template.Template
if tpl, err = template.New("python template").Parse(pythonTemplate); err == nil {
buf := new(bytes.Buffer)
if err = tpl.Execute(buf, testcase); err == nil {
result = buf.String()
}
}
return
return generate(testSuite, testcase, "python template", pythonTemplate)
}

func init() {
Expand Down
47 changes: 47 additions & 0 deletions pkg/generator/robot_generator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
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 generator

import (
_ "embed"

"github.com/linuxsuren/api-testing/pkg/testing"
)

type robotGenerator struct {
}

func NewRobotGenerator() CodeGenerator {
return &robotGenerator{}
}

func (g *robotGenerator) Generate(testSuite *testing.TestSuite, testcase *testing.TestCase) (string, error) {
tpl := robotTemplate
if testcase == nil {
tpl = robotSuiteTemplate
}
return generate(testSuite, testcase, "robot-framework", tpl)
}

func init() {
RegisterCodeGenerator("robot-framework", NewRobotGenerator())
}

//go:embed data/robot.tpl
var robotTemplate string

//go:embed data/robot-suite.tpl
var robotSuiteTemplate string
92 changes: 92 additions & 0 deletions pkg/generator/robot_generator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
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 generator

import (
_ "embed"
"testing"

atest "github.com/linuxsuren/api-testing/pkg/testing"
)

func TestRobotGenerator(t *testing.T) {
tests := []struct {
name string
testCase *atest.TestCase
testSuite *atest.TestSuite
expect string
}{{
name: "simple",
testCase: &atest.TestCase{
Name: "simple",
Request: atest.Request{
API: fooForTest,
},
},
expect: simpleRobot,
}, {
name: "with header",
testCase: &atest.TestCase{
Name: "simple",
Request: atest.Request{
API: fooForTest,
Header: map[string]string{
"key": "value",
},
},
},
expect: headerRobot,
}, {
name: "test suite",
testSuite: &atest.TestSuite{
Items: []atest.TestCase{{
Name: "one",
Request: atest.Request{
API: fooForTest,
Header: map[string]string{
"key1": "value1",
},
},
}, {
Name: "two",
Request: atest.Request{
API: fooForTest,
Header: map[string]string{
"key2": "value2",
},
},
}},
},
expect: suiteRobot,
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
g := NewRobotGenerator()
if got, err := g.Generate(tt.testSuite, tt.testCase); err != nil || got != tt.expect {
t.Errorf("got %q, want %q, error: %v", got, tt.expect, err)
}
})
}
}

//go:embed testdata/simple.robot
var simpleRobot string

//go:embed testdata/with-headers.robot
var headerRobot string

//go:embed testdata/suite.robot
var suiteRobot string
6 changes: 6 additions & 0 deletions pkg/generator/testdata/simple.robot
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*** Settings ***
Library RequestsLibrary

*** Test Cases ***
simple
${response}= GET http://foo
10 changes: 10 additions & 0 deletions pkg/generator/testdata/suite.robot
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
*** Settings ***
Library RequestsLibrary

*** Test Cases ***
one
${headers}= Create Dictionary key1 value1
${response}= GET http://foo headers=${headers}
two
${headers}= Create Dictionary key2 value2
${response}= GET http://foo headers=${headers}
7 changes: 7 additions & 0 deletions pkg/generator/testdata/with-headers.robot
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
*** Settings ***
Library RequestsLibrary

*** Test Cases ***
simple
${headers}= Create Dictionary key value
${response}= GET http://foo headers=${headers}
Loading

0 comments on commit 0f02984

Please sign in to comment.