feat: support convert testSuite to JMeter file (#170)

* feat: support convert testSuite to JMeter file

* chore: report API test in the comment

* add a sub-command to convert to jmeter file

---------

Co-authored-by: rick <linuxsuren@users.noreply.github.com>
This commit is contained in:
Rick 2023-08-18 15:51:53 +08:00 committed by GitHub
parent 200134093d
commit 908829738a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 1165 additions and 119 deletions

View File

@ -2,7 +2,8 @@
# yaml-language-server: $schema=https://linuxsuren.github.io/api-testing/api-testing-schema.json
# https://docs.gitlab.com/ee/api/api_resources.html
name: atest
api: http://localhost:8080/server.Runner
api: |
{{default "http://localhost:8080/server.Runner" (env "SERVER")}}
items:
- name: suites
request:
@ -80,6 +81,7 @@ items:
request:
api: /PopularHeaders
method: POST
- name: list-code-generators
request:
api: /ListCodeGenerator
@ -87,6 +89,42 @@ items:
expect:
verify:
- len(data) == 1
- name: GenerateCode
request:
api: /GenerateCode
method: POST
body: |
{
"TestSuite": "{{index (keys .suites.data) 0}}",
"TestCase": "{{randAlpha 6}}",
"Generator": "golang"
}
expect:
statusCode: 500 # no testcase found
verify:
- indexOf(data.message, "not found") != -1
- name: listConverters
request:
api: /ListConverter
method: POST
expect:
verify:
- len(data) == 1
- name: ConvertTestSuite
request:
api: /ConvertTestSuite
method: POST
body: |
{
"TestSuite": "{{index (keys .suites.data) 0}}",
"Generator": "jmeter"
}
expect:
verify:
- data.message != ""
- indexOf(data.message, "jmeterTestPlan") != -1
- name: list-stores
request:
api: /GetStores

View File

@ -27,15 +27,36 @@ jobs:
bash <(curl -Ls https://coverage.codacy.com/get.sh) report --partial --force-coverage-parser go -r store-git-coverage.out
bash <(curl -Ls https://coverage.codacy.com/get.sh) report --partial --force-coverage-parser go -r operator/cover.out
bash <(curl -Ls https://coverage.codacy.com/get.sh) final
APITest:
runs-on: ubuntu-20.04
steps:
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18.x
- uses: actions/checkout@v3.0.0
- name: API Test
run: |
make build copy
sudo atest service install
sudo atest service restart
sudo atest service status
atest run -p .github/testing/core.yaml --request-ignore-error
atest run -p .github/testing/core.yaml --request-ignore-error --report md --report-file .github/workflows/report.md
sudo atest service status
atest convert -p .github/testing/core.yaml --converter jmeter -t sample.jmx
- name: Report API Test
uses: harupy/comment-on-pr@c0522c44600040927a120b9309b531e3cb6f8d48
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
filename: report.md
- name: Run JMeter Tests
uses: rbhadti94/apache-jmeter-action@v0.5.0
with:
testFilePath: sample.jmx
Build:
runs-on: ubuntu-20.04
steps:

View File

@ -9,8 +9,8 @@ This is a API testing tool.
## Features
* Multiple test report formats: Markdown, HTML, PDF, Stdout
* Response Body fields equation check
* Response Body [eval](https://expr.medv.io/)
* Support converting to [JMeter](https://jmeter.apache.org/) files
* Response Body fields equation check or [eval](https://expr.medv.io/)
* Verify the Kubernetes resources
* Validate the response body with [JSON schema](https://json-schema.org/)
* Pre and post handle with the API request

98
cmd/convert.go Normal file
View File

@ -0,0 +1,98 @@
/*
MIT License
Copyright (c) 2023 API Testing Authors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
package cmd
import (
"fmt"
"os"
"github.com/linuxsuren/api-testing/pkg/generator"
"github.com/linuxsuren/api-testing/pkg/testing"
"github.com/linuxsuren/api-testing/pkg/util"
"github.com/spf13/cobra"
)
func createConvertCommand() (c *cobra.Command) {
opt := &convertOption{}
c = &cobra.Command{
Use: "convert",
Short: "Convert the API testing file to other format",
PreRunE: opt.preRunE,
RunE: opt.runE,
}
converters := generator.GetTestSuiteConverters()
flags := c.Flags()
flags.StringVarP(&opt.pattern, "pattern", "p", "test-suite-*.yaml",
"The file pattern which try to execute the test cases. Brace expansion is supported, such as: test-suite-{1,2}.yaml")
flags.StringVarP(&opt.converter, "converter", "", "",
fmt.Sprintf("The converter format, supported: %s", util.Keys(converters)))
flags.StringVarP(&opt.target, "target", "t", "", "The target file path")
_ = c.MarkFlagRequired("pattern")
_ = c.MarkFlagRequired("converter")
return
}
type convertOption struct {
pattern string
converter string
target string
}
func (o *convertOption) preRunE(c *cobra.Command, args []string) (err error) {
if o.target == "" {
o.target = "sample.jmx"
}
return
}
func (o *convertOption) runE(c *cobra.Command, args []string) (err error) {
loader := testing.NewFileWriter("")
if err = loader.Put(o.pattern); err != nil {
return
}
var output string
var suites []testing.TestSuite
if suites, err = loader.ListTestSuite(); err == nil {
if len(suites) == 0 {
err = fmt.Errorf("no suites found")
} else {
converter := generator.GetTestSuiteConverter(o.converter)
if converter == nil {
err = fmt.Errorf("no converter found")
} else {
output, err = converter.Convert(&suites[0])
}
}
}
if output != "" {
err = os.WriteFile(o.target, []byte(output), 0644)
}
return
}

88
cmd/convert_test.go Normal file
View File

@ -0,0 +1,88 @@
/*
MIT License
Copyright (c) 2023 API Testing Authors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
package cmd_test
import (
"io"
"os"
"path"
"testing"
"time"
"github.com/linuxsuren/api-testing/cmd"
"github.com/linuxsuren/api-testing/pkg/server"
fakeruntime "github.com/linuxsuren/go-fake-runtime"
"github.com/stretchr/testify/assert"
)
func TestConvert(t *testing.T) {
c := cmd.NewRootCmd(fakeruntime.FakeExecer{ExpectOS: "linux"},
cmd.NewFakeGRPCServer(), server.NewFakeHTTPServer())
c.SetOut(io.Discard)
t.Run("normal", func(t *testing.T) {
tmpFile := path.Join(os.TempDir(), time.Now().String())
defer os.RemoveAll(tmpFile)
c.SetArgs([]string{"convert", "-p=testdata/simple-suite.yaml", "--converter=jmeter", "--target", tmpFile})
err := c.Execute()
assert.NoError(t, err)
var data []byte
data, err = os.ReadFile(tmpFile)
if assert.NoError(t, err) {
assert.NotEmpty(t, string(data))
}
})
t.Run("no testSuite", func(t *testing.T) {
c.SetArgs([]string{"convert", "-p=testdata/fake.yaml", "--converter=jmeter"})
err := c.Execute()
assert.Error(t, err)
})
t.Run("no converter found", func(t *testing.T) {
c.SetArgs([]string{"convert", "-p=testdata/simple-suite.yaml", "--converter=fake"})
err := c.Execute()
assert.Error(t, err)
})
t.Run("flag --pattern is required", func(t *testing.T) {
c.SetArgs([]string{"convert", "--converter=fake"})
err := c.Execute()
assert.Error(t, err)
})
t.Run("flag --converter is required", func(t *testing.T) {
c.SetArgs([]string{"convert", "-p=fake"})
err := c.Execute()
assert.Error(t, err)
})
}

View File

@ -21,7 +21,7 @@ func NewRootCmd(execer fakeruntime.Execer, gRPCServer gRPCServer,
c.AddCommand(createInitCommand(execer),
createRunCommand(), createSampleCmd(),
createServerCmd(execer, gRPCServer, httpServer), createJSONSchemaCmd(),
createServiceCommand(execer), createFunctionCmd())
createServiceCommand(execer), createFunctionCmd(), createConvertCommand())
return
}

View File

@ -5,7 +5,6 @@ import (
"fmt"
"io"
"os"
"strings"
"sync"
"time"
@ -239,10 +238,7 @@ func (o *runOption) runSuite(loader testing.Loader, dataContext map[string]inter
continue
}
// reuse the API prefix
if strings.HasPrefix(testCase.Request.API, "/") {
testCase.Request.API = fmt.Sprintf("%s%s", testSuite.API, testCase.Request.API)
}
testCase.Request.RenderAPI(testSuite.API)
var output interface{}
select {

View File

@ -151,6 +151,43 @@ function del() {
})
}
function convert() {
const requestOptions = {
method: 'POST',
headers: {
'X-Store-Name': props.store
},
body: JSON.stringify({
Generator: 'jmeter',
TestSuite: props.name
})
}
fetch('/server.Runner/ConvertTestSuite', requestOptions)
.then((response) => response.json())
.then((e) => {
const blob = new Blob([e.message], { type: `text/xml;charset=utf-8;` });
const link = document.createElement('a');
if (link.download !== undefined) {
const url = URL.createObjectURL(blob);
link.setAttribute('href', url);
link.setAttribute('download', `jmeter.jmx`);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
ElMessage({
message: 'Converted.',
type: 'success'
})
emit('updated')
})
.catch((e) => {
ElMessage.error('Oops, ' + e)
})
}
const suiteCreatingLoading = ref(false)
const apiSpecKinds = [
@ -218,6 +255,8 @@ function paramChange() {
<el-button type="primary" @click="del" test-id="suite-del-but">Delete</el-button>
<el-button type="primary" @click="openNewTestCaseDialog" :icon="Edit" test-id="open-new-case-dialog">New TestCase</el-button>
<el-button type="primary" @click="convert" test-id="convert">Convert</el-button>
</div>
<el-dialog v-model="dialogVisible" title="Create Test Case" width="40%" draggable>

2
go.mod
View File

@ -5,7 +5,7 @@ go 1.18
require (
github.com/Masterminds/sprig/v3 v3.2.3
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883
github.com/antonmedv/expr v1.12.1
github.com/antonmedv/expr v1.14.0
github.com/bufbuild/protocompile v0.6.0
github.com/cucumber/godog v0.12.6
github.com/flopp/go-findfont v0.1.0

View File

@ -545,6 +545,8 @@ github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3
github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/antonmedv/expr v1.14.0 h1:C4BHw+0cVyKy/ndU3uqYo6TV5rCtq/SY2Wdlwanvo/Q=
github.com/antonmedv/expr v1.14.0/go.mod h1:FPC8iWArxls7axbVLsW+kpg1mz29A1b2M6jt+hZfDkU=
github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0=
github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI=
github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU=
@ -872,3 +874,4 @@ google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwS
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=

View File

@ -49,3 +49,27 @@ func GetCodeGenerators() (result map[string]CodeGenerator) {
}
return
}
// TestSuiteConverter is the interface of test suite converter
type TestSuiteConverter interface {
Convert(*testing.TestSuite) (result string, err error)
}
var converters = map[string]TestSuiteConverter{}
func GetTestSuiteConverter(name string) TestSuiteConverter {
return converters[name]
}
func RegisterTestSuiteConverter(name string, converter TestSuiteConverter) {
converters[name] = converter
}
func GetTestSuiteConverters() (result map[string]TestSuiteConverter) {
// returns an immutable map
result = make(map[string]TestSuiteConverter, len(converters))
for k, v := range converters {
result[k] = v
}
return
}

View File

@ -0,0 +1,214 @@
/**
MIT License
Copyright (c) 2023 API Testing Authors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
package generator
import (
"encoding/xml"
"net/url"
"github.com/linuxsuren/api-testing/pkg/testing"
)
type jmeterConverter struct {
}
func init() {
RegisterTestSuiteConverter("jmeter", &jmeterConverter{})
}
func (c *jmeterConverter) Convert(testSuite *testing.TestSuite) (result string, err error) {
var jmeterTestPlan *JmeterTestPlan
if jmeterTestPlan, err = c.buildJmeterTestPlan(testSuite); err == nil {
var data []byte
if data, err = xml.MarshalIndent(jmeterTestPlan, " ", " "); err == nil {
result = string(data)
}
}
return
}
func (c *jmeterConverter) buildJmeterTestPlan(testSuite *testing.TestSuite) (result *JmeterTestPlan, err error) {
if err = testSuite.Render(make(map[string]interface{})); err != nil {
return
}
requestItems := []interface{}{}
for _, item := range testSuite.Items {
item.Request.RenderAPI(testSuite.API)
api, err := url.Parse(item.Request.API)
if err != nil {
continue
}
requestItems = append(requestItems, &HTTPSamplerProxy{
GUIClass: "HttpTestSampleGui",
TestClass: "HTTPSamplerProxy",
Enabled: true,
Name: item.Name,
StringProp: []StringProp{{
Name: "HTTPSampler.domain",
Value: api.Host,
}, {
Name: "HTTPSampler.port",
Value: api.Port(),
}, {
Name: "HTTPSampler.path",
Value: api.Path,
}, {
Name: "HTTPSampler.method",
Value: item.Request.Method,
}},
})
requestItems = append(requestItems, HashTree{})
}
requestItems = append(requestItems, &ResultCollector{
Enabled: true,
GUIClass: "SummaryReport",
TestClass: "ResultCollector",
Name: "Summary Report",
})
result = &JmeterTestPlan{
Version: "1.2",
Properties: "5.0",
JMeter: "5.0",
HashTree: HashTree{
Items: []interface{}{
&TestPlan{
StringProp: []StringProp{{
Name: "TestPlan.comments",
Value: "comment",
}},
Name: testSuite.Name,
GUIClass: "TestPlanGui",
TestClass: "TestPlan",
Enabled: true,
},
HashTree{
Items: []interface{}{
&ThreadGroup{
StringProp: []StringProp{{
Name: "ThreadGroup.num_threads",
Value: "1",
}},
GUIClass: "ThreadGroupGui",
TestClass: "ThreadGroup",
Enabled: true,
Name: "Thread Group",
ElementProp: ElementProp{
Name: "ThreadGroup.main_controller",
Type: "LoopController",
GUIClass: "LoopControlPanel",
TestClass: "LoopController",
BoolProp: []BoolProp{{
Name: "LoopController.continue_forever",
Value: "false",
}},
StringProp: []StringProp{{
Name: "LoopController.loops",
Value: "1",
}},
},
},
HashTree{
Items: requestItems,
},
},
},
},
},
}
return
}
type JmeterTestPlan struct {
XMLName xml.Name `xml:"jmeterTestPlan"`
Version string `xml:"version,attr"`
Properties string `xml:"properties,attr"`
JMeter string `xml:"jmeter,attr"`
HashTree HashTree `xml:"hashTree"`
}
type HashTree struct {
XMLName xml.Name `xml:"hashTree"`
Items []interface{} `xml:"items"`
}
type TestPlan struct {
XMLName xml.Name `xml:"TestPlan"`
Name string `xml:"testname,attr"`
GUIClass string `xml:"guiclass,attr"`
TestClass string `xml:"testclass,attr"`
Enabled bool `xml:"enabled,attr"`
StringProp []StringProp `xml:"stringProp"`
}
type ThreadGroup struct {
XMLName xml.Name `xml:"ThreadGroup"`
GUIClass string `xml:"guiclass,attr"`
TestClass string `xml:"testclass,attr"`
Enabled bool `xml:"enabled,attr"`
Name string `xml:"testname,attr"`
StringProp []StringProp `xml:"stringProp"`
ElementProp ElementProp `xml:"elementProp"`
}
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"`
}
type ResultCollector struct {
XMLName xml.Name `xml:"ResultCollector"`
Enabled bool `xml:"enabled,attr"`
GUIClass string `xml:"guiclass,attr"`
TestClass string `xml:"testclass,attr"`
Name string `xml:"testname,attr"`
}
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"`
}
type StringProp struct {
Name string `xml:"name,attr"`
Value string `xml:",chardata"`
}
type BoolProp struct {
Name string `xml:"name,attr"`
Value string `xml:",chardata"`
}

View File

@ -0,0 +1,65 @@
/**
MIT License
Copyright (c) 2023 API Testing Authors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
package generator
import (
"testing"
_ "embed"
atest "github.com/linuxsuren/api-testing/pkg/testing"
"github.com/stretchr/testify/assert"
)
func TestJmeterConvert(t *testing.T) {
t.Run("common", func(t *testing.T) {
jmeterConvert := GetTestSuiteConverter("jmeter")
assert.NotNil(t, jmeterConvert)
converters := GetTestSuiteConverters()
assert.Equal(t, 1, len(converters))
})
testSuite := &atest.TestSuite{
Name: "API Testing",
API: "http://localhost:8080",
Items: []atest.TestCase{{
Name: "hello-jmeter",
Request: atest.Request{
Method: "POST",
API: "/GetSuites",
},
}},
}
converter := &jmeterConverter{}
output, err := converter.Convert(testSuite)
assert.NoError(t, err)
assert.Equal(t, expectedJmeter, output, output)
}
//go:embed testdata/expected_jmeter.jmx
var expectedJmeter string

View File

@ -0,0 +1,26 @@
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.0">
<hashTree>
<TestPlan testname="API Testing" guiclass="TestPlanGui" testclass="TestPlan" enabled="true">
<stringProp name="TestPlan.comments">comment</stringProp>
</TestPlan>
<hashTree>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" enabled="true" testname="Thread Group">
<stringProp name="ThreadGroup.num_threads">1</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" enabled="false">
<stringProp name="LoopController.loops">1</stringProp>
<boolProp name="LoopController.continue_forever">false</boolProp>
</elementProp>
</ThreadGroup>
<hashTree>
<HTTPSamplerProxy testname="hello-jmeter" guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" enabled="true">
<stringProp name="HTTPSampler.domain">localhost:8080</stringProp>
<stringProp name="HTTPSampler.port">8080</stringProp>
<stringProp name="HTTPSampler.path">/GetSuites</stringProp>
<stringProp name="HTTPSampler.method">POST</stringProp>
</HTTPSamplerProxy>
<hashTree></hashTree>
<ResultCollector enabled="true" guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report"></ResultCollector>
</hashTree>
</hashTree>
</hashTree>
</jmeterTestPlan>

View File

@ -3,6 +3,9 @@ package render
import (
"bytes"
"context"
"crypto/md5"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"html/template"
@ -91,6 +94,27 @@ var advancedFuncs = []AdvancedFunc{{
}
return err.Error()
},
}, {
FuncName: "md5",
Func: func(text string) string {
hash := md5.Sum([]byte(text))
return hex.EncodeToString(hash[:])
},
}, {
FuncName: "base64",
Func: func(text string) string {
return base64.StdEncoding.EncodeToString([]byte(text))
},
}, {
FuncName: "base64Decode",
Func: func(text string) string {
result, err := base64.StdEncoding.DecodeString(text)
if err == nil {
return string(result)
} else {
return err.Error()
}
},
}}
// GetAdvancedFuncs returns all the advanced functions

View File

@ -31,6 +31,22 @@ func TestRender(t *testing.T) {
verify: func(t *testing.T, s string) {
assert.Equal(t, 8, len(s))
},
}, {
name: "md5",
text: `{{md5 "linuxsuren"}}`,
expect: "b559b80ae1ba1c292d9b3265f265e76a",
}, {
name: "base64",
text: `{{base64 "linuxsuren"}}`,
expect: "bGludXhzdXJlbg==",
}, {
name: "base64Decode",
text: `{{base64Decode "bGludXhzdXJlbg=="}}`,
expect: "linuxsuren",
}, {
name: "base64Decode with error",
text: `{{base64Decode "error"}}`,
expect: "illegal base64 data at input byte 4",
}, {
name: "complex",
text: `{{(index .items 0).name}}?a=a&key={{randomKubernetesName}}`,

View File

@ -204,9 +204,7 @@ func (s *server) Run(ctx context.Context, task *TestTask) (reply *TestResult, er
suiteRunner.WithWriteLevel(task.Level)
// reuse the API prefix
if strings.HasPrefix(testCase.Request.API, "/") {
testCase.Request.API = fmt.Sprintf("%s%s", suite.API, testCase.Request.API)
}
testCase.Request.RenderAPI(suite.API)
output, testErr := suiteRunner.RunTestCase(&testCase, dataContext, ctx)
if getter, ok := suiteRunner.(runner.HTTPResponseRecord); ok {
@ -523,13 +521,39 @@ func (s *server) GenerateCode(ctx context.Context, in *CodeGenerateRequest) (rep
loader := s.getLoader(ctx)
if result, err = loader.GetTestCase(in.TestSuite, in.TestCase); err == nil {
output, genErr := instance.Generate(&result)
if genErr != nil {
reply.Success = false
reply.Message = genErr.Error()
} else {
reply.Success = true
reply.Message = output
}
reply.Success = genErr == nil
reply.Message = util.OrErrorMessage(genErr, output)
}
}
return
}
// converter
func (s *server) ListConverter(ctx context.Context, in *Empty) (reply *SimpleList, err error) {
reply = &SimpleList{}
converters := generator.GetTestSuiteConverters()
for name := range converters {
reply.Data = append(reply.Data, &Pair{
Key: name,
})
}
return
}
func (s *server) ConvertTestSuite(ctx context.Context, in *CodeGenerateRequest) (reply *CommonResult, err error) {
reply = &CommonResult{}
instance := generator.GetTestSuiteConverter(in.Generator)
if instance == nil {
reply.Success = false
reply.Message = fmt.Sprintf("converter '%s' not found", in.Generator)
} else {
var result testing.TestSuite
loader := s.getLoader(ctx)
if result, err = loader.GetTestSuite(in.TestSuite, true); err == nil {
output, genErr := instance.Convert(&result)
reply.Success = genErr == nil
reply.Message = util.OrErrorMessage(genErr, output)
}
}
return

View File

@ -604,6 +604,28 @@ func TestCodeGenerator(t *testing.T) {
assert.True(t, result.Success)
assert.NotEmpty(t, result.Message)
})
t.Run("ListConverter", func(t *testing.T) {
list, err := server.ListConverter(ctx, &Empty{})
assert.NoError(t, err)
assert.Equal(t, 1, len(list.Data))
})
t.Run("ConvertTestSuite no converter given", func(t *testing.T) {
reply, err := server.ConvertTestSuite(ctx, &CodeGenerateRequest{})
assert.NoError(t, err)
if assert.NotNil(t, reply) {
assert.False(t, reply.Success)
}
})
t.Run("ConvertTestSuite no suite found", func(t *testing.T) {
reply, err := server.ConvertTestSuite(ctx, &CodeGenerateRequest{Generator: "jmeter"})
assert.NoError(t, err)
if assert.NotNil(t, reply) {
assert.True(t, reply.Success)
}
})
}
func TestFunctionsQueryStream(t *testing.T) {

View File

@ -1979,7 +1979,7 @@ var file_pkg_server_server_proto_rawDesc = []byte{
0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75,
0x65, 0x12, 0x20, 0x0a, 0x0b, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
0x69, 0x6f, 0x6e, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x32, 0xc3, 0x0d, 0x0a,
0x69, 0x6f, 0x6e, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x32, 0xc2, 0x0e, 0x0a,
0x06, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x2d, 0x0a, 0x03, 0x52, 0x75, 0x6e, 0x12, 0x10,
0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x54, 0x61, 0x73, 0x6b,
0x1a, 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65,
@ -2039,59 +2039,67 @@ var file_pkg_server_server_proto_rawDesc = []byte{
0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12,
0x30, 0x0a, 0x0e, 0x50, 0x6f, 0x70, 0x75, 0x6c, 0x61, 0x72, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72,
0x73, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79,
0x1a, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x69, 0x72, 0x73, 0x22,
0x00, 0x12, 0x36, 0x0a, 0x0e, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x51, 0x75,
0x65, 0x72, 0x79, 0x12, 0x13, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x69, 0x6d,
0x70, 0x6c, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x2e, 0x50, 0x61, 0x69, 0x72, 0x73, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x14, 0x46, 0x75, 0x6e,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x65, 0x61,
0x6d, 0x12, 0x13, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c,
0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e,
0x50, 0x61, 0x69, 0x72, 0x73, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, 0x31, 0x0a, 0x0a, 0x47,
0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x2d,
0x0a, 0x06, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x34, 0x0a,
0x0d, 0x47, 0x65, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x4b, 0x69, 0x6e, 0x64, 0x73, 0x12, 0x0d,
0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e,
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x4b, 0x69, 0x6e, 0x64,
0x73, 0x22, 0x00, 0x12, 0x2c, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x73,
0x34, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x72,
0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a,
0x0e, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x73, 0x22,
0x00, 0x12, 0x2d, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65,
0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x1a,
0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x00,
0x12, 0x2d, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12,
0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4c,
0x69, 0x73, 0x74, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74,
0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, 0x12, 0x1b, 0x2e, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e,
0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x30,
0x0a, 0x0e, 0x50, 0x6f, 0x70, 0x75, 0x6c, 0x61, 0x72, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73,
0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a,
0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x69, 0x72, 0x73, 0x22, 0x00,
0x12, 0x36, 0x0a, 0x0e, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x51, 0x75, 0x65,
0x72, 0x79, 0x12, 0x13, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x69, 0x6d, 0x70,
0x6c, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x2e, 0x50, 0x61, 0x69, 0x72, 0x73, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x14, 0x46, 0x75, 0x6e, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d,
0x12, 0x13, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65,
0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x50,
0x61, 0x69, 0x72, 0x73, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, 0x31, 0x0a, 0x0a, 0x47, 0x65,
0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x2d, 0x0a,
0x06, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e,
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x34, 0x0a, 0x0d,
0x47, 0x65, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x4b, 0x69, 0x6e, 0x64, 0x73, 0x12, 0x0d, 0x2e,
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x4b, 0x69, 0x6e, 0x64, 0x73,
0x22, 0x00, 0x12, 0x2c, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x73, 0x12,
0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0e,
0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x73, 0x22, 0x00,
0x12, 0x2d, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12,
0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x1a, 0x0d,
0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x00, 0x12,
0x2d, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x0d,
0x2d, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x0d,
0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x1a, 0x0d, 0x2e,
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x00, 0x12, 0x3a,
0x0a, 0x0b, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x13, 0x2e,
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x51, 0x75, 0x65,
0x72, 0x79, 0x1a, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x2e, 0x0a, 0x0a, 0x47, 0x65,
0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x22, 0x00, 0x12, 0x36, 0x0a, 0x0c, 0x43, 0x72,
0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x0e, 0x2e, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x1a, 0x14, 0x2e, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74,
0x22, 0x00, 0x12, 0x36, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x63, 0x72,
0x65, 0x74, 0x12, 0x0e, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x63, 0x72,
0x65, 0x74, 0x1a, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x36, 0x0a, 0x0c, 0x55, 0x70,
0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x0e, 0x2e, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x1a, 0x14, 0x2e, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74,
0x22, 0x00, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x73, 0x75, 0x72, 0x65, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2d,
0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x00, 0x12, 0x2d,
0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x0d, 0x2e,
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x1a, 0x0d, 0x2e, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x00, 0x12, 0x3a, 0x0a,
0x0b, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x13, 0x2e, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x51, 0x75, 0x65, 0x72,
0x79, 0x1a, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x2e, 0x0a, 0x0a, 0x47, 0x65, 0x74,
0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e,
0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x22, 0x00, 0x12, 0x36, 0x0a, 0x0c, 0x43, 0x72, 0x65,
0x61, 0x74, 0x65, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x0e, 0x2e, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x1a, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22,
0x00, 0x12, 0x36, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x63, 0x72, 0x65,
0x74, 0x12, 0x0e, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65,
0x74, 0x1a, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x36, 0x0a, 0x0c, 0x55, 0x70, 0x64,
0x61, 0x74, 0x65, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x0e, 0x2e, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x1a, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22,
0x00, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x6c, 0x69, 0x6e, 0x75, 0x78, 0x73, 0x75, 0x72, 0x65, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2d, 0x74,
0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@ -2181,53 +2189,57 @@ var file_pkg_server_server_proto_depIdxs = []int32{
2, // 36: server.Runner.DeleteTestCase:input_type -> server.TestCaseIdentity
29, // 37: server.Runner.ListCodeGenerator:input_type -> server.Empty
26, // 38: server.Runner.GenerateCode:input_type -> server.CodeGenerateRequest
29, // 39: server.Runner.PopularHeaders:input_type -> server.Empty
18, // 40: server.Runner.FunctionsQuery:input_type -> server.SimpleQuery
18, // 41: server.Runner.FunctionsQueryStream:input_type -> server.SimpleQuery
29, // 42: server.Runner.GetVersion:input_type -> server.Empty
29, // 43: server.Runner.Sample:input_type -> server.Empty
29, // 44: server.Runner.GetStoreKinds:input_type -> server.Empty
29, // 45: server.Runner.GetStores:input_type -> server.Empty
20, // 46: server.Runner.CreateStore:input_type -> server.Store
20, // 47: server.Runner.UpdateStore:input_type -> server.Store
20, // 48: server.Runner.DeleteStore:input_type -> server.Store
18, // 49: server.Runner.VerifyStore:input_type -> server.SimpleQuery
29, // 50: server.Runner.GetSecrets:input_type -> server.Empty
28, // 51: server.Runner.CreateSecret:input_type -> server.Secret
28, // 52: server.Runner.DeleteSecret:input_type -> server.Secret
28, // 53: server.Runner.UpdateSecret:input_type -> server.Secret
7, // 54: server.Runner.Run:output_type -> server.TestResult
0, // 55: server.Runner.GetSuites:output_type -> server.Suites
8, // 56: server.Runner.CreateTestSuite:output_type -> server.HelloReply
3, // 57: server.Runner.GetTestSuite:output_type -> server.TestSuite
8, // 58: server.Runner.UpdateTestSuite:output_type -> server.HelloReply
8, // 59: server.Runner.DeleteTestSuite:output_type -> server.HelloReply
9, // 60: server.Runner.ListTestCase:output_type -> server.Suite
11, // 61: server.Runner.GetSuggestedAPIs:output_type -> server.TestCases
15, // 62: server.Runner.RunTestCase:output_type -> server.TestCaseResult
12, // 63: server.Runner.GetTestCase:output_type -> server.TestCase
8, // 64: server.Runner.CreateTestCase:output_type -> server.HelloReply
8, // 65: server.Runner.UpdateTestCase:output_type -> server.HelloReply
8, // 66: server.Runner.DeleteTestCase:output_type -> server.HelloReply
24, // 67: server.Runner.ListCodeGenerator:output_type -> server.SimpleList
23, // 68: server.Runner.GenerateCode:output_type -> server.CommonResult
17, // 69: server.Runner.PopularHeaders:output_type -> server.Pairs
17, // 70: server.Runner.FunctionsQuery:output_type -> server.Pairs
17, // 71: server.Runner.FunctionsQueryStream:output_type -> server.Pairs
8, // 72: server.Runner.GetVersion:output_type -> server.HelloReply
8, // 73: server.Runner.Sample:output_type -> server.HelloReply
21, // 74: server.Runner.GetStoreKinds:output_type -> server.StoreKinds
19, // 75: server.Runner.GetStores:output_type -> server.Stores
20, // 76: server.Runner.CreateStore:output_type -> server.Store
20, // 77: server.Runner.UpdateStore:output_type -> server.Store
20, // 78: server.Runner.DeleteStore:output_type -> server.Store
23, // 79: server.Runner.VerifyStore:output_type -> server.CommonResult
27, // 80: server.Runner.GetSecrets:output_type -> server.Secrets
23, // 81: server.Runner.CreateSecret:output_type -> server.CommonResult
23, // 82: server.Runner.DeleteSecret:output_type -> server.CommonResult
23, // 83: server.Runner.UpdateSecret:output_type -> server.CommonResult
54, // [54:84] is the sub-list for method output_type
24, // [24:54] is the sub-list for method input_type
29, // 39: server.Runner.ListConverter:input_type -> server.Empty
26, // 40: server.Runner.ConvertTestSuite:input_type -> server.CodeGenerateRequest
29, // 41: server.Runner.PopularHeaders:input_type -> server.Empty
18, // 42: server.Runner.FunctionsQuery:input_type -> server.SimpleQuery
18, // 43: server.Runner.FunctionsQueryStream:input_type -> server.SimpleQuery
29, // 44: server.Runner.GetVersion:input_type -> server.Empty
29, // 45: server.Runner.Sample:input_type -> server.Empty
29, // 46: server.Runner.GetStoreKinds:input_type -> server.Empty
29, // 47: server.Runner.GetStores:input_type -> server.Empty
20, // 48: server.Runner.CreateStore:input_type -> server.Store
20, // 49: server.Runner.UpdateStore:input_type -> server.Store
20, // 50: server.Runner.DeleteStore:input_type -> server.Store
18, // 51: server.Runner.VerifyStore:input_type -> server.SimpleQuery
29, // 52: server.Runner.GetSecrets:input_type -> server.Empty
28, // 53: server.Runner.CreateSecret:input_type -> server.Secret
28, // 54: server.Runner.DeleteSecret:input_type -> server.Secret
28, // 55: server.Runner.UpdateSecret:input_type -> server.Secret
7, // 56: server.Runner.Run:output_type -> server.TestResult
0, // 57: server.Runner.GetSuites:output_type -> server.Suites
8, // 58: server.Runner.CreateTestSuite:output_type -> server.HelloReply
3, // 59: server.Runner.GetTestSuite:output_type -> server.TestSuite
8, // 60: server.Runner.UpdateTestSuite:output_type -> server.HelloReply
8, // 61: server.Runner.DeleteTestSuite:output_type -> server.HelloReply
9, // 62: server.Runner.ListTestCase:output_type -> server.Suite
11, // 63: server.Runner.GetSuggestedAPIs:output_type -> server.TestCases
15, // 64: server.Runner.RunTestCase:output_type -> server.TestCaseResult
12, // 65: server.Runner.GetTestCase:output_type -> server.TestCase
8, // 66: server.Runner.CreateTestCase:output_type -> server.HelloReply
8, // 67: server.Runner.UpdateTestCase:output_type -> server.HelloReply
8, // 68: server.Runner.DeleteTestCase:output_type -> server.HelloReply
24, // 69: server.Runner.ListCodeGenerator:output_type -> server.SimpleList
23, // 70: server.Runner.GenerateCode:output_type -> server.CommonResult
24, // 71: server.Runner.ListConverter:output_type -> server.SimpleList
23, // 72: server.Runner.ConvertTestSuite:output_type -> server.CommonResult
17, // 73: server.Runner.PopularHeaders:output_type -> server.Pairs
17, // 74: server.Runner.FunctionsQuery:output_type -> server.Pairs
17, // 75: server.Runner.FunctionsQueryStream:output_type -> server.Pairs
8, // 76: server.Runner.GetVersion:output_type -> server.HelloReply
8, // 77: server.Runner.Sample:output_type -> server.HelloReply
21, // 78: server.Runner.GetStoreKinds:output_type -> server.StoreKinds
19, // 79: server.Runner.GetStores:output_type -> server.Stores
20, // 80: server.Runner.CreateStore:output_type -> server.Store
20, // 81: server.Runner.UpdateStore:output_type -> server.Store
20, // 82: server.Runner.DeleteStore:output_type -> server.Store
23, // 83: server.Runner.VerifyStore:output_type -> server.CommonResult
27, // 84: server.Runner.GetSecrets:output_type -> server.Secrets
23, // 85: server.Runner.CreateSecret:output_type -> server.CommonResult
23, // 86: server.Runner.DeleteSecret:output_type -> server.CommonResult
23, // 87: server.Runner.UpdateSecret:output_type -> server.CommonResult
56, // [56:88] is the sub-list for method output_type
24, // [24:56] is the sub-list for method input_type
24, // [24:24] is the sub-list for extension type_name
24, // [24:24] is the sub-list for extension extendee
0, // [0:24] is the sub-list for field type_name

View File

@ -541,6 +541,74 @@ func local_request_Runner_GenerateCode_0(ctx context.Context, marshaler runtime.
}
func request_Runner_ListConverter_0(ctx context.Context, marshaler runtime.Marshaler, client RunnerClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq Empty
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ListConverter(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Runner_ListConverter_0(ctx context.Context, marshaler runtime.Marshaler, server RunnerServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq Empty
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ListConverter(ctx, &protoReq)
return msg, metadata, err
}
func request_Runner_ConvertTestSuite_0(ctx context.Context, marshaler runtime.Marshaler, client RunnerClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq CodeGenerateRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ConvertTestSuite(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Runner_ConvertTestSuite_0(ctx context.Context, marshaler runtime.Marshaler, server RunnerServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq CodeGenerateRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ConvertTestSuite(ctx, &protoReq)
return msg, metadata, err
}
func request_Runner_PopularHeaders_0(ctx context.Context, marshaler runtime.Marshaler, client RunnerClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq Empty
var metadata runtime.ServerMetadata
@ -1441,6 +1509,56 @@ func RegisterRunnerHandlerServer(ctx context.Context, mux *runtime.ServeMux, ser
})
mux.Handle("POST", pattern_Runner_ListConverter_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/server.Runner/ListConverter", runtime.WithHTTPPathPattern("/server.Runner/ListConverter"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Runner_ListConverter_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Runner_ListConverter_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Runner_ConvertTestSuite_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/server.Runner/ConvertTestSuite", runtime.WithHTTPPathPattern("/server.Runner/ConvertTestSuite"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Runner_ConvertTestSuite_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Runner_ConvertTestSuite_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Runner_PopularHeaders_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@ -2169,6 +2287,50 @@ func RegisterRunnerHandlerClient(ctx context.Context, mux *runtime.ServeMux, cli
})
mux.Handle("POST", pattern_Runner_ListConverter_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/server.Runner/ListConverter", runtime.WithHTTPPathPattern("/server.Runner/ListConverter"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Runner_ListConverter_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Runner_ListConverter_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Runner_ConvertTestSuite_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/server.Runner/ConvertTestSuite", runtime.WithHTTPPathPattern("/server.Runner/ConvertTestSuite"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Runner_ConvertTestSuite_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Runner_ConvertTestSuite_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Runner_PopularHeaders_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@ -2533,6 +2695,10 @@ var (
pattern_Runner_GenerateCode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"server.Runner", "GenerateCode"}, ""))
pattern_Runner_ListConverter_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"server.Runner", "ListConverter"}, ""))
pattern_Runner_ConvertTestSuite_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"server.Runner", "ConvertTestSuite"}, ""))
pattern_Runner_PopularHeaders_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"server.Runner", "PopularHeaders"}, ""))
pattern_Runner_FunctionsQuery_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"server.Runner", "FunctionsQuery"}, ""))
@ -2595,6 +2761,10 @@ var (
forward_Runner_GenerateCode_0 = runtime.ForwardResponseMessage
forward_Runner_ListConverter_0 = runtime.ForwardResponseMessage
forward_Runner_ConvertTestSuite_0 = runtime.ForwardResponseMessage
forward_Runner_PopularHeaders_0 = runtime.ForwardResponseMessage
forward_Runner_FunctionsQuery_0 = runtime.ForwardResponseMessage

View File

@ -27,6 +27,10 @@ service Runner {
rpc ListCodeGenerator(Empty) returns (SimpleList) {}
rpc GenerateCode(CodeGenerateRequest) returns (CommonResult) {}
// converter
rpc ListConverter(Empty) returns (SimpleList) {}
rpc ConvertTestSuite(CodeGenerateRequest) returns (CommonResult) {}
// common services
rpc PopularHeaders(Empty) returns (Pairs) {}
rpc FunctionsQuery(SimpleQuery) returns (Pairs) {}

View File

@ -40,6 +40,9 @@ type RunnerClient interface {
// code generator
ListCodeGenerator(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*SimpleList, error)
GenerateCode(ctx context.Context, in *CodeGenerateRequest, opts ...grpc.CallOption) (*CommonResult, error)
// converter
ListConverter(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*SimpleList, error)
ConvertTestSuite(ctx context.Context, in *CodeGenerateRequest, opts ...grpc.CallOption) (*CommonResult, error)
// common services
PopularHeaders(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Pairs, error)
FunctionsQuery(ctx context.Context, in *SimpleQuery, opts ...grpc.CallOption) (*Pairs, error)
@ -203,6 +206,24 @@ func (c *runnerClient) GenerateCode(ctx context.Context, in *CodeGenerateRequest
return out, nil
}
func (c *runnerClient) ListConverter(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*SimpleList, error) {
out := new(SimpleList)
err := c.cc.Invoke(ctx, "/server.Runner/ListConverter", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *runnerClient) ConvertTestSuite(ctx context.Context, in *CodeGenerateRequest, opts ...grpc.CallOption) (*CommonResult, error) {
out := new(CommonResult)
err := c.cc.Invoke(ctx, "/server.Runner/ConvertTestSuite", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *runnerClient) PopularHeaders(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Pairs, error) {
out := new(Pairs)
err := c.cc.Invoke(ctx, "/server.Runner/PopularHeaders", in, out, opts...)
@ -382,6 +403,9 @@ type RunnerServer interface {
// code generator
ListCodeGenerator(context.Context, *Empty) (*SimpleList, error)
GenerateCode(context.Context, *CodeGenerateRequest) (*CommonResult, error)
// converter
ListConverter(context.Context, *Empty) (*SimpleList, error)
ConvertTestSuite(context.Context, *CodeGenerateRequest) (*CommonResult, error)
// common services
PopularHeaders(context.Context, *Empty) (*Pairs, error)
FunctionsQuery(context.Context, *SimpleQuery) (*Pairs, error)
@ -452,6 +476,12 @@ func (UnimplementedRunnerServer) ListCodeGenerator(context.Context, *Empty) (*Si
func (UnimplementedRunnerServer) GenerateCode(context.Context, *CodeGenerateRequest) (*CommonResult, error) {
return nil, status.Errorf(codes.Unimplemented, "method GenerateCode not implemented")
}
func (UnimplementedRunnerServer) ListConverter(context.Context, *Empty) (*SimpleList, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListConverter not implemented")
}
func (UnimplementedRunnerServer) ConvertTestSuite(context.Context, *CodeGenerateRequest) (*CommonResult, error) {
return nil, status.Errorf(codes.Unimplemented, "method ConvertTestSuite not implemented")
}
func (UnimplementedRunnerServer) PopularHeaders(context.Context, *Empty) (*Pairs, error) {
return nil, status.Errorf(codes.Unimplemented, "method PopularHeaders not implemented")
}
@ -780,6 +810,42 @@ func _Runner_GenerateCode_Handler(srv interface{}, ctx context.Context, dec func
return interceptor(ctx, in, info, handler)
}
func _Runner_ListConverter_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Empty)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RunnerServer).ListConverter(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/server.Runner/ListConverter",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RunnerServer).ListConverter(ctx, req.(*Empty))
}
return interceptor(ctx, in, info, handler)
}
func _Runner_ConvertTestSuite_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CodeGenerateRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RunnerServer).ConvertTestSuite(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/server.Runner/ConvertTestSuite",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RunnerServer).ConvertTestSuite(ctx, req.(*CodeGenerateRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Runner_PopularHeaders_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Empty)
if err := dec(in); err != nil {
@ -1125,6 +1191,14 @@ var Runner_ServiceDesc = grpc.ServiceDesc{
MethodName: "GenerateCode",
Handler: _Runner_GenerateCode_Handler,
},
{
MethodName: "ListConverter",
Handler: _Runner_ListConverter_Handler,
},
{
MethodName: "ConvertTestSuite",
Handler: _Runner_ConvertTestSuite_Handler,
},
{
MethodName: "PopularHeaders",
Handler: _Runner_PopularHeaders_Handler,

View File

@ -160,6 +160,14 @@ func (r *Request) Render(ctx interface{}, dataDir string) (err error) {
return
}
// RenderAPI will combine with the base API
func (r *Request) RenderAPI(base string) {
// reuse the API prefix
if strings.HasPrefix(r.API, "/") {
r.API = fmt.Sprintf("%s%s", base, r.API)
}
}
// GetBody returns the request body
func (r *Request) GetBody() (reader io.Reader, err error) {
if len(r.Form) > 0 {

View File

@ -26,8 +26,13 @@ package util
// OKOrErrorMessage returns OK or error message
func OKOrErrorMessage(err error) string {
return OrErrorMessage(err, "OK")
}
// OrErrorMessage returns error message or message
func OrErrorMessage(err error, message string) string {
if err != nil {
return err.Error()
}
return "OK"
return message
}

36
pkg/util/map.go Normal file
View File

@ -0,0 +1,36 @@
/**
MIT License
Copyright (c) 2023 API Testing Authors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
package util
// Keys returns a list of keys
func Keys[T interface{}](data map[string]T) (keys []string) {
keys = make([]string, len(data))
index := 0
for k := range data {
keys[index] = k
index++
}
return
}

39
pkg/util/map_test.go Normal file
View File

@ -0,0 +1,39 @@
/**
MIT License
Copyright (c) 2023 API Testing Authors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
package util_test
import (
"testing"
"github.com/linuxsuren/api-testing/pkg/util"
"github.com/stretchr/testify/assert"
)
func TestKeys(t *testing.T) {
t.Run("normal", func(t *testing.T) {
assert.Equal(t, []string{"foo", "bar"},
util.Keys(map[string]interface{}{"foo": "xx", "bar": "xx"}))
})
}