From dd7cd4634e19623815790a2b63bd4289b18dd586 Mon Sep 17 00:00:00 2001 From: Rick <1450685+LinuxSuRen@users.noreply.github.com> Date: Sun, 29 Oct 2023 19:45:46 +0800 Subject: [PATCH] feat: add trpc protocol support (#254) * feat: add trpc protocol support * test pass the trpc on web ui * add unit tests * fix the trpc service parsing issue --------- Co-authored-by: rick --- .github/testing/grpc.yaml | 2 +- .github/testing/grpc_descriptor_set.yaml | 2 +- .github/testing/grpc_ref.yaml | 2 +- .github/testing/trpc.yaml | 22 + .github/workflows/build.yaml | 4 +- CONTRIBUTION.md | 2 +- README.md | 5 +- console/atest-ui/src/App.vue | 37 +- console/atest-ui/src/locales/en.json | 7 +- console/atest-ui/src/views/TestCase.vue | 24 +- console/atest-ui/src/views/TestSuite.vue | 48 +- docs/api-testing-schema.json | 9 +- docs/grpc-manual-zh.md | 4 +- docs/grpc-manual.md | 4 +- docs/helm.md | 12 +- go.mod | 40 +- go.sum | 427 +++++++++++++- go.work.sum | 38 +- pkg/runner/fakeclient.go | 35 ++ pkg/runner/grpc.go | 23 +- pkg/runner/grpc_test.go | 32 +- pkg/runner/runner_factory.go | 22 +- pkg/runner/runner_test.go | 4 +- pkg/runner/trpc.go | 208 +++++++ pkg/runner/trpc_test.go | 66 +++ pkg/runner/verify.go | 1 + pkg/server/convert.go | 122 +++- pkg/server/convert_test.go | 64 +++ pkg/server/remote_server.go | 125 +--- pkg/server/remote_server_test.go | 2 +- pkg/server/server.pb.go | 697 ++++++++++++----------- pkg/server/server.proto | 7 +- pkg/testing/case.go | 12 +- pkg/testing/remote/converter.go | 19 +- 34 files changed, 1586 insertions(+), 542 deletions(-) create mode 100644 .github/testing/trpc.yaml create mode 100644 pkg/runner/fakeclient.go create mode 100644 pkg/runner/trpc.go create mode 100644 pkg/runner/trpc_test.go diff --git a/.github/testing/grpc.yaml b/.github/testing/grpc.yaml index 227d2d9..15b073e 100644 --- a/.github/testing/grpc.yaml +++ b/.github/testing/grpc.yaml @@ -4,7 +4,7 @@ name: grpc-sample api: 127.0.0.1:7070 spec: - grpc: + rpc: import: - ./pkg/server protofile: server.proto diff --git a/.github/testing/grpc_descriptor_set.yaml b/.github/testing/grpc_descriptor_set.yaml index dee2085..dc91781 100644 --- a/.github/testing/grpc_descriptor_set.yaml +++ b/.github/testing/grpc_descriptor_set.yaml @@ -4,7 +4,7 @@ name: grpc-sample api: 127.0.0.1:7070 spec: - grpc: + rpc: protoset: .github/testing/server.pb items: - name: GetVersion diff --git a/.github/testing/grpc_ref.yaml b/.github/testing/grpc_ref.yaml index e0e8ba0..0639a6e 100644 --- a/.github/testing/grpc_ref.yaml +++ b/.github/testing/grpc_ref.yaml @@ -4,7 +4,7 @@ name: grpc-sample api: 127.0.0.1:7070 spec: - grpc: + rpc: serverReflection: true items: - name: GetVersion diff --git a/.github/testing/trpc.yaml b/.github/testing/trpc.yaml new file mode 100644 index 0000000..a319a8e --- /dev/null +++ b/.github/testing/trpc.yaml @@ -0,0 +1,22 @@ +#!api-testing +# yaml-language-server: $schema=https://linuxsuren.github.io/api-testing/api-testing-schema.json +# see also https://github.com/LinuxSuRen/api-testing +name: trpc-sample +api: ip://127.0.0.1:8000 +spec: + kind: trpc + rpc: + import: + - ./bin + protofile: ./bin/helloworld.proto +items: + - name: Hello + request: + api: Hello + body: | + { + "msg": "atest" + } + expect: + verify: + - data.msg == "Hello atest!" diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 98d4533..c472ea0 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -57,11 +57,13 @@ jobs: atest convert -p .github/testing/core.yaml --converter jmeter -t sample.jmx - name: Report API Test - uses: thollander/actions-comment-pull-request@v2 + if: github.event.pull_request.user.login == 'linuxsuren' + uses: thollander/actions-comment-pull-request@v2.4.3 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: filePath: .github/workflows/report.md + comment_tag: execution - name: Run JMeter Tests uses: rbhadti94/apache-jmeter-action@v0.5.0 with: diff --git a/CONTRIBUTION.md b/CONTRIBUTION.md index 5bb0a13..9187f41 100644 --- a/CONTRIBUTION.md +++ b/CONTRIBUTION.md @@ -34,7 +34,7 @@ docker run -p 8080:8080 -e SW_OAP_ADDRESS=http://localhost:12800 -e SW_ZIPKIN_AD make build export SW_AGENT_NAME=atest -export SW_AGENT_REPORTER_GRPC_BACKEND_SERVICE=172.11.0.6:32591 +export SW_AGENT_REPORTER_GRPC_BACKEND_SERVICE=172.11.0.6:30689 export SW_AGENT_PLUGIN_CONFIG_HTTP_SERVER_COLLECT_PARAMETERS=true export SW_AGENT_METER_COLLECT_INTERVAL=3 export SW_AGENT_LOG_TYPE=std diff --git a/README.md b/README.md index 3af0e52..f944838 100644 --- a/README.md +++ b/README.md @@ -8,18 +8,17 @@ This is a API testing tool. ## Features +* Supportted protocols: HTTP, gRPC, tRPC * Multiple test report formats: Markdown, HTML, PDF, Stdout * 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 -* Output reference between TestCase * Run in server mode, and provide the [gRPC](pkg/server/server.proto) and HTTP endpoint * [VS Code extension](https://github.com/LinuxSuRen/vscode-api-testing) support * Multiple storage backends supported(Local, ORM Database, S3, Git, etc) * [HTTP API record](extensions/collector) -* Install in mutiple use cases(CLI, Container, Native-Service, Operator, etc) +* Install in mutiple use cases(CLI, Container, Native-Service, Operator, Helm, etc) * Monitoring integration with Prometheus, Skywalking ## Get started diff --git a/console/atest-ui/src/App.vue b/console/atest-ui/src/App.vue index 96f1b5b..ef7ce04 100644 --- a/console/atest-ui/src/App.vue +++ b/console/atest-ui/src/App.vue @@ -19,7 +19,6 @@ import setTheme from './theme' const { t } = useI18n() - function switchAppMode() { setTheme(appMode.value) @@ -31,17 +30,20 @@ interface Tree { parent: string parentID: string store: string + kind: string children?: Tree[] } const testCaseName = ref('') const testSuite = ref('') const store = ref('') +const testSuiteKind = ref('') const handleNodeClick = (data: Tree) => { if (data.children) { viewName.value = 'testsuite' testSuite.value = data.label store.value = data.store + testSuiteKind.value = data.kind const requestOptions = { method: 'POST', @@ -61,6 +63,7 @@ const handleNodeClick = (data: Tree) => { data.children?.push({ id: data.label + item.name, label: item.name, + kind: data.kind, store: data.store, parent: data.label, parentID: data.id @@ -73,6 +76,7 @@ const handleNodeClick = (data: Tree) => { testCaseName.value = data.label testSuite.value = data.parent store.value = data.store + testSuiteKind.value = data.kind viewName.value = 'testcase' } } @@ -99,6 +103,7 @@ function loadTestSuites(storeName: string) { let suite = { id: k, label: k, + kind: d.data[k].kind, store: storeName, children: [] as Tree[] } as Tree @@ -108,6 +113,7 @@ function loadTestSuites(storeName: string) { id: k + item, label: item, store: storeName, + kind: suite.kind, parent: k, parentID: suite.id } as Tree) @@ -176,6 +182,7 @@ function loadStores() { treeRef.value!.setCheckedKeys([targetChild.id], false) testSuite.value = targetSuite.label store.value = targetSuite.store + testSuiteKind.value = targetChild.kind } else { viewName.value = "" } @@ -190,7 +197,8 @@ const suiteFormRef = ref() const testSuiteForm = reactive({ name: '', api: '', - store: '' + store: '', + kind: '' }) const importSuiteFormRef = ref() const importSuiteForm = reactive({ @@ -223,7 +231,8 @@ const submitForm = async (formEl: FormInstance | undefined) => { }, body: JSON.stringify({ name: testSuiteForm.name, - api: testSuiteForm.api + api: testSuiteForm.api, + kind: testSuiteForm.kind }) } @@ -299,6 +308,14 @@ watch(viewName, (val) => { useFmp: true }); }) + +const suiteKinds = [{ + "name": "HTTP", +}, { + "name": "gRPC", +}, { + "name": "tRPC", +}]