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 # yaml-language-server: $schema=https://linuxsuren.github.io/api-testing/api-testing-schema.json
# https://docs.gitlab.com/ee/api/api_resources.html # https://docs.gitlab.com/ee/api/api_resources.html
name: atest name: atest
api: http://localhost:8080/server.Runner api: |
{{default "http://localhost:8080/server.Runner" (env "SERVER")}}
items: items:
- name: suites - name: suites
request: request:
@ -80,6 +81,7 @@ items:
request: request:
api: /PopularHeaders api: /PopularHeaders
method: POST method: POST
- name: list-code-generators - name: list-code-generators
request: request:
api: /ListCodeGenerator api: /ListCodeGenerator
@ -87,6 +89,42 @@ items:
expect: expect:
verify: verify:
- len(data) == 1 - 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 - name: list-stores
request: request:
api: /GetStores 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 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) report --partial --force-coverage-parser go -r operator/cover.out
bash <(curl -Ls https://coverage.codacy.com/get.sh) final 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 - name: API Test
run: | run: |
make build copy make build copy
sudo atest service install sudo atest service install
sudo atest service restart sudo atest service restart
sudo atest service status 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 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: Build:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
steps: steps:

View File

@ -9,8 +9,8 @@ This is a API testing tool.
## Features ## Features
* Multiple test report formats: Markdown, HTML, PDF, Stdout * Multiple test report formats: Markdown, HTML, PDF, Stdout
* Response Body fields equation check * Support converting to [JMeter](https://jmeter.apache.org/) files
* Response Body [eval](https://expr.medv.io/) * Response Body fields equation check or [eval](https://expr.medv.io/)
* Verify the Kubernetes resources * Verify the Kubernetes resources
* Validate the response body with [JSON schema](https://json-schema.org/) * Validate the response body with [JSON schema](https://json-schema.org/)
* Pre and post handle with the API request * 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), c.AddCommand(createInitCommand(execer),
createRunCommand(), createSampleCmd(), createRunCommand(), createSampleCmd(),
createServerCmd(execer, gRPCServer, httpServer), createJSONSchemaCmd(), createServerCmd(execer, gRPCServer, httpServer), createJSONSchemaCmd(),
createServiceCommand(execer), createFunctionCmd()) createServiceCommand(execer), createFunctionCmd(), createConvertCommand())
return return
} }

View File

@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"strings"
"sync" "sync"
"time" "time"
@ -239,10 +238,7 @@ func (o *runOption) runSuite(loader testing.Loader, dataContext map[string]inter
continue continue
} }
// reuse the API prefix testCase.Request.RenderAPI(testSuite.API)
if strings.HasPrefix(testCase.Request.API, "/") {
testCase.Request.API = fmt.Sprintf("%s%s", testSuite.API, testCase.Request.API)
}
var output interface{} var output interface{}
select { 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 suiteCreatingLoading = ref(false)
const apiSpecKinds = [ 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="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="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> </div>
<el-dialog v-model="dialogVisible" title="Create Test Case" width="40%" draggable> <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 ( require (
github.com/Masterminds/sprig/v3 v3.2.3 github.com/Masterminds/sprig/v3 v3.2.3
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 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/bufbuild/protocompile v0.6.0
github.com/cucumber/godog v0.12.6 github.com/cucumber/godog v0.12.6
github.com/flopp/go-findfont v0.1.0 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/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/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/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/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/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI=
github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= 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/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.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.29.1/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 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 ( import (
"bytes" "bytes"
"context" "context"
"crypto/md5"
"encoding/base64"
"encoding/hex"
"encoding/json" "encoding/json"
"fmt" "fmt"
"html/template" "html/template"
@ -91,6 +94,27 @@ var advancedFuncs = []AdvancedFunc{{
} }
return err.Error() 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 // GetAdvancedFuncs returns all the advanced functions

View File

@ -31,6 +31,22 @@ func TestRender(t *testing.T) {
verify: func(t *testing.T, s string) { verify: func(t *testing.T, s string) {
assert.Equal(t, 8, len(s)) 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", name: "complex",
text: `{{(index .items 0).name}}?a=a&key={{randomKubernetesName}}`, 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) suiteRunner.WithWriteLevel(task.Level)
// reuse the API prefix // reuse the API prefix
if strings.HasPrefix(testCase.Request.API, "/") { testCase.Request.RenderAPI(suite.API)
testCase.Request.API = fmt.Sprintf("%s%s", suite.API, testCase.Request.API)
}
output, testErr := suiteRunner.RunTestCase(&testCase, dataContext, ctx) output, testErr := suiteRunner.RunTestCase(&testCase, dataContext, ctx)
if getter, ok := suiteRunner.(runner.HTTPResponseRecord); ok { if getter, ok := suiteRunner.(runner.HTTPResponseRecord); ok {
@ -523,14 +521,40 @@ func (s *server) GenerateCode(ctx context.Context, in *CodeGenerateRequest) (rep
loader := s.getLoader(ctx) loader := s.getLoader(ctx)
if result, err = loader.GetTestCase(in.TestSuite, in.TestCase); err == nil { if result, err = loader.GetTestCase(in.TestSuite, in.TestCase); err == nil {
output, genErr := instance.Generate(&result) output, genErr := instance.Generate(&result)
if genErr != nil { reply.Success = genErr == nil
reply.Success = false reply.Message = util.OrErrorMessage(genErr, output)
reply.Message = genErr.Error()
} else {
reply.Success = true
reply.Message = 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 return
} }

View File

@ -604,6 +604,28 @@ func TestCodeGenerator(t *testing.T) {
assert.True(t, result.Success) assert.True(t, result.Success)
assert.NotEmpty(t, result.Message) 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) { 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 0x34, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 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, 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, 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4c,
0x00, 0x12, 0x2d, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x69, 0x73, 0x74, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74,
0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x1a, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, 0x12, 0x1b, 0x2e, 0x73, 0x65, 0x72, 0x76,
0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x00, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52,
0x12, 0x2d, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 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, 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, 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, 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, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x00, 0x12, 0x2d,
0x0a, 0x0b, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x13, 0x2e, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x0d, 0x2e,
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x51, 0x75, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x1a, 0x0d, 0x2e, 0x73,
0x72, 0x79, 0x1a, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x00, 0x12, 0x3a, 0x0a,
0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x2e, 0x0a, 0x0a, 0x47, 0x65, 0x0b, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x13, 0x2e, 0x73,
0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x51, 0x75, 0x65, 0x72,
0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x79, 0x1a, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f,
0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x22, 0x00, 0x12, 0x36, 0x0a, 0x0c, 0x43, 0x72, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x2e, 0x0a, 0x0a, 0x47, 0x65, 0x74,
0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x0e, 0x2e, 0x73, 0x65, 0x72, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x1a, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e,
0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x22, 0x00, 0x12, 0x36, 0x0a, 0x0c, 0x43, 0x72, 0x65,
0x22, 0x00, 0x12, 0x36, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x63, 0x72, 0x61, 0x74, 0x65, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x0e, 0x2e, 0x73, 0x65, 0x72, 0x76,
0x65, 0x74, 0x12, 0x0e, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x1a, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x76,
0x65, 0x74, 0x1a, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22,
0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x36, 0x0a, 0x0c, 0x55, 0x70, 0x00, 0x12, 0x36, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x63, 0x72, 0x65,
0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x0e, 0x2e, 0x73, 0x65, 0x72, 0x74, 0x12, 0x0e, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65,
0x76, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x1a, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x74, 0x1a, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f,
0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x36, 0x0a, 0x0c, 0x55, 0x70, 0x64,
0x22, 0x00, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x61, 0x74, 0x65, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x0e, 0x2e, 0x73, 0x65, 0x72, 0x76,
0x2f, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x73, 0x75, 0x72, 0x65, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2d, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x1a, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x76,
0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22,
0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 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 ( var (
@ -2181,53 +2189,57 @@ var file_pkg_server_server_proto_depIdxs = []int32{
2, // 36: server.Runner.DeleteTestCase:input_type -> server.TestCaseIdentity 2, // 36: server.Runner.DeleteTestCase:input_type -> server.TestCaseIdentity
29, // 37: server.Runner.ListCodeGenerator:input_type -> server.Empty 29, // 37: server.Runner.ListCodeGenerator:input_type -> server.Empty
26, // 38: server.Runner.GenerateCode:input_type -> server.CodeGenerateRequest 26, // 38: server.Runner.GenerateCode:input_type -> server.CodeGenerateRequest
29, // 39: server.Runner.PopularHeaders:input_type -> server.Empty 29, // 39: server.Runner.ListConverter:input_type -> server.Empty
18, // 40: server.Runner.FunctionsQuery:input_type -> server.SimpleQuery 26, // 40: server.Runner.ConvertTestSuite:input_type -> server.CodeGenerateRequest
18, // 41: server.Runner.FunctionsQueryStream:input_type -> server.SimpleQuery 29, // 41: server.Runner.PopularHeaders:input_type -> server.Empty
29, // 42: server.Runner.GetVersion:input_type -> server.Empty 18, // 42: server.Runner.FunctionsQuery:input_type -> server.SimpleQuery
29, // 43: server.Runner.Sample:input_type -> server.Empty 18, // 43: server.Runner.FunctionsQueryStream:input_type -> server.SimpleQuery
29, // 44: server.Runner.GetStoreKinds:input_type -> server.Empty 29, // 44: server.Runner.GetVersion:input_type -> server.Empty
29, // 45: server.Runner.GetStores:input_type -> server.Empty 29, // 45: server.Runner.Sample:input_type -> server.Empty
20, // 46: server.Runner.CreateStore:input_type -> server.Store 29, // 46: server.Runner.GetStoreKinds:input_type -> server.Empty
20, // 47: server.Runner.UpdateStore:input_type -> server.Store 29, // 47: server.Runner.GetStores:input_type -> server.Empty
20, // 48: server.Runner.DeleteStore:input_type -> server.Store 20, // 48: server.Runner.CreateStore:input_type -> server.Store
18, // 49: server.Runner.VerifyStore:input_type -> server.SimpleQuery 20, // 49: server.Runner.UpdateStore:input_type -> server.Store
29, // 50: server.Runner.GetSecrets:input_type -> server.Empty 20, // 50: server.Runner.DeleteStore:input_type -> server.Store
28, // 51: server.Runner.CreateSecret:input_type -> server.Secret 18, // 51: server.Runner.VerifyStore:input_type -> server.SimpleQuery
28, // 52: server.Runner.DeleteSecret:input_type -> server.Secret 29, // 52: server.Runner.GetSecrets:input_type -> server.Empty
28, // 53: server.Runner.UpdateSecret:input_type -> server.Secret 28, // 53: server.Runner.CreateSecret:input_type -> server.Secret
7, // 54: server.Runner.Run:output_type -> server.TestResult 28, // 54: server.Runner.DeleteSecret:input_type -> server.Secret
0, // 55: server.Runner.GetSuites:output_type -> server.Suites 28, // 55: server.Runner.UpdateSecret:input_type -> server.Secret
8, // 56: server.Runner.CreateTestSuite:output_type -> server.HelloReply 7, // 56: server.Runner.Run:output_type -> server.TestResult
3, // 57: server.Runner.GetTestSuite:output_type -> server.TestSuite 0, // 57: server.Runner.GetSuites:output_type -> server.Suites
8, // 58: server.Runner.UpdateTestSuite:output_type -> server.HelloReply 8, // 58: server.Runner.CreateTestSuite:output_type -> server.HelloReply
8, // 59: server.Runner.DeleteTestSuite:output_type -> server.HelloReply 3, // 59: server.Runner.GetTestSuite:output_type -> server.TestSuite
9, // 60: server.Runner.ListTestCase:output_type -> server.Suite 8, // 60: server.Runner.UpdateTestSuite:output_type -> server.HelloReply
11, // 61: server.Runner.GetSuggestedAPIs:output_type -> server.TestCases 8, // 61: server.Runner.DeleteTestSuite:output_type -> server.HelloReply
15, // 62: server.Runner.RunTestCase:output_type -> server.TestCaseResult 9, // 62: server.Runner.ListTestCase:output_type -> server.Suite
12, // 63: server.Runner.GetTestCase:output_type -> server.TestCase 11, // 63: server.Runner.GetSuggestedAPIs:output_type -> server.TestCases
8, // 64: server.Runner.CreateTestCase:output_type -> server.HelloReply 15, // 64: server.Runner.RunTestCase:output_type -> server.TestCaseResult
8, // 65: server.Runner.UpdateTestCase:output_type -> server.HelloReply 12, // 65: server.Runner.GetTestCase:output_type -> server.TestCase
8, // 66: server.Runner.DeleteTestCase:output_type -> server.HelloReply 8, // 66: server.Runner.CreateTestCase:output_type -> server.HelloReply
24, // 67: server.Runner.ListCodeGenerator:output_type -> server.SimpleList 8, // 67: server.Runner.UpdateTestCase:output_type -> server.HelloReply
23, // 68: server.Runner.GenerateCode:output_type -> server.CommonResult 8, // 68: server.Runner.DeleteTestCase:output_type -> server.HelloReply
17, // 69: server.Runner.PopularHeaders:output_type -> server.Pairs 24, // 69: server.Runner.ListCodeGenerator:output_type -> server.SimpleList
17, // 70: server.Runner.FunctionsQuery:output_type -> server.Pairs 23, // 70: server.Runner.GenerateCode:output_type -> server.CommonResult
17, // 71: server.Runner.FunctionsQueryStream:output_type -> server.Pairs 24, // 71: server.Runner.ListConverter:output_type -> server.SimpleList
8, // 72: server.Runner.GetVersion:output_type -> server.HelloReply 23, // 72: server.Runner.ConvertTestSuite:output_type -> server.CommonResult
8, // 73: server.Runner.Sample:output_type -> server.HelloReply 17, // 73: server.Runner.PopularHeaders:output_type -> server.Pairs
21, // 74: server.Runner.GetStoreKinds:output_type -> server.StoreKinds 17, // 74: server.Runner.FunctionsQuery:output_type -> server.Pairs
19, // 75: server.Runner.GetStores:output_type -> server.Stores 17, // 75: server.Runner.FunctionsQueryStream:output_type -> server.Pairs
20, // 76: server.Runner.CreateStore:output_type -> server.Store 8, // 76: server.Runner.GetVersion:output_type -> server.HelloReply
20, // 77: server.Runner.UpdateStore:output_type -> server.Store 8, // 77: server.Runner.Sample:output_type -> server.HelloReply
20, // 78: server.Runner.DeleteStore:output_type -> server.Store 21, // 78: server.Runner.GetStoreKinds:output_type -> server.StoreKinds
23, // 79: server.Runner.VerifyStore:output_type -> server.CommonResult 19, // 79: server.Runner.GetStores:output_type -> server.Stores
27, // 80: server.Runner.GetSecrets:output_type -> server.Secrets 20, // 80: server.Runner.CreateStore:output_type -> server.Store
23, // 81: server.Runner.CreateSecret:output_type -> server.CommonResult 20, // 81: server.Runner.UpdateStore:output_type -> server.Store
23, // 82: server.Runner.DeleteSecret:output_type -> server.CommonResult 20, // 82: server.Runner.DeleteStore:output_type -> server.Store
23, // 83: server.Runner.UpdateSecret:output_type -> server.CommonResult 23, // 83: server.Runner.VerifyStore:output_type -> server.CommonResult
54, // [54:84] is the sub-list for method output_type 27, // 84: server.Runner.GetSecrets:output_type -> server.Secrets
24, // [24:54] is the sub-list for method input_type 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 type_name
24, // [24:24] is the sub-list for extension extendee 24, // [24:24] is the sub-list for extension extendee
0, // [0:24] is the sub-list for field type_name 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) { 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 protoReq Empty
var metadata runtime.ServerMetadata 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) { mux.Handle("POST", pattern_Runner_PopularHeaders_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context()) ctx, cancel := context.WithCancel(req.Context())
defer cancel() 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) { mux.Handle("POST", pattern_Runner_PopularHeaders_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context()) ctx, cancel := context.WithCancel(req.Context())
defer cancel() 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_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_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"}, "")) 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_GenerateCode_0 = runtime.ForwardResponseMessage
forward_Runner_ListConverter_0 = runtime.ForwardResponseMessage
forward_Runner_ConvertTestSuite_0 = runtime.ForwardResponseMessage
forward_Runner_PopularHeaders_0 = runtime.ForwardResponseMessage forward_Runner_PopularHeaders_0 = runtime.ForwardResponseMessage
forward_Runner_FunctionsQuery_0 = runtime.ForwardResponseMessage forward_Runner_FunctionsQuery_0 = runtime.ForwardResponseMessage

View File

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

View File

@ -40,6 +40,9 @@ type RunnerClient interface {
// code generator // code generator
ListCodeGenerator(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*SimpleList, error) ListCodeGenerator(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*SimpleList, error)
GenerateCode(ctx context.Context, in *CodeGenerateRequest, opts ...grpc.CallOption) (*CommonResult, 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 // common services
PopularHeaders(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Pairs, error) PopularHeaders(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Pairs, error)
FunctionsQuery(ctx context.Context, in *SimpleQuery, 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 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) { func (c *runnerClient) PopularHeaders(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Pairs, error) {
out := new(Pairs) out := new(Pairs)
err := c.cc.Invoke(ctx, "/server.Runner/PopularHeaders", in, out, opts...) err := c.cc.Invoke(ctx, "/server.Runner/PopularHeaders", in, out, opts...)
@ -382,6 +403,9 @@ type RunnerServer interface {
// code generator // code generator
ListCodeGenerator(context.Context, *Empty) (*SimpleList, error) ListCodeGenerator(context.Context, *Empty) (*SimpleList, error)
GenerateCode(context.Context, *CodeGenerateRequest) (*CommonResult, error) GenerateCode(context.Context, *CodeGenerateRequest) (*CommonResult, error)
// converter
ListConverter(context.Context, *Empty) (*SimpleList, error)
ConvertTestSuite(context.Context, *CodeGenerateRequest) (*CommonResult, error)
// common services // common services
PopularHeaders(context.Context, *Empty) (*Pairs, error) PopularHeaders(context.Context, *Empty) (*Pairs, error)
FunctionsQuery(context.Context, *SimpleQuery) (*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) { func (UnimplementedRunnerServer) GenerateCode(context.Context, *CodeGenerateRequest) (*CommonResult, error) {
return nil, status.Errorf(codes.Unimplemented, "method GenerateCode not implemented") 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) { func (UnimplementedRunnerServer) PopularHeaders(context.Context, *Empty) (*Pairs, error) {
return nil, status.Errorf(codes.Unimplemented, "method PopularHeaders not implemented") 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) 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) { func _Runner_PopularHeaders_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Empty) in := new(Empty)
if err := dec(in); err != nil { if err := dec(in); err != nil {
@ -1125,6 +1191,14 @@ var Runner_ServiceDesc = grpc.ServiceDesc{
MethodName: "GenerateCode", MethodName: "GenerateCode",
Handler: _Runner_GenerateCode_Handler, Handler: _Runner_GenerateCode_Handler,
}, },
{
MethodName: "ListConverter",
Handler: _Runner_ListConverter_Handler,
},
{
MethodName: "ConvertTestSuite",
Handler: _Runner_ConvertTestSuite_Handler,
},
{ {
MethodName: "PopularHeaders", MethodName: "PopularHeaders",
Handler: _Runner_PopularHeaders_Handler, Handler: _Runner_PopularHeaders_Handler,

View File

@ -160,6 +160,14 @@ func (r *Request) Render(ctx interface{}, dataDir string) (err error) {
return 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 // GetBody returns the request body
func (r *Request) GetBody() (reader io.Reader, err error) { func (r *Request) GetBody() (reader io.Reader, err error) {
if len(r.Form) > 0 { if len(r.Form) > 0 {

View File

@ -26,8 +26,13 @@ package util
// OKOrErrorMessage returns OK or error message // OKOrErrorMessage returns OK or error message
func OKOrErrorMessage(err error) string { 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 { if err != nil {
return err.Error() 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"}))
})
}