Skip to content

Commit dd7cd46

Browse files
authored
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 <[email protected]>
1 parent cac73fd commit dd7cd46

34 files changed

+1585
-541
lines changed

.github/testing/grpc.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
name: grpc-sample
55
api: 127.0.0.1:7070
66
spec:
7-
grpc:
7+
rpc:
88
import:
99
- ./pkg/server
1010
protofile: server.proto

.github/testing/grpc_descriptor_set.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
name: grpc-sample
55
api: 127.0.0.1:7070
66
spec:
7-
grpc:
7+
rpc:
88
protoset: .github/testing/server.pb
99
items:
1010
- name: GetVersion

.github/testing/grpc_ref.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
name: grpc-sample
55
api: 127.0.0.1:7070
66
spec:
7-
grpc:
7+
rpc:
88
serverReflection: true
99
items:
1010
- name: GetVersion

.github/testing/trpc.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!api-testing
2+
# yaml-language-server: $schema=https://linuxsuren.github.io/api-testing/api-testing-schema.json
3+
# see also https://github.com/LinuxSuRen/api-testing
4+
name: trpc-sample
5+
api: ip://127.0.0.1:8000
6+
spec:
7+
kind: trpc
8+
rpc:
9+
import:
10+
- ./bin
11+
protofile: ./bin/helloworld.proto
12+
items:
13+
- name: Hello
14+
request:
15+
api: Hello
16+
body: |
17+
{
18+
"msg": "atest"
19+
}
20+
expect:
21+
verify:
22+
- data.msg == "Hello atest!"

.github/workflows/build.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,13 @@ jobs:
5757
5858
atest convert -p .github/testing/core.yaml --converter jmeter -t sample.jmx
5959
- name: Report API Test
60-
uses: thollander/actions-comment-pull-request@v2
60+
if: github.event.pull_request.user.login == 'linuxsuren'
61+
uses: thollander/[email protected]
6162
env:
6263
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
6364
with:
6465
filePath: .github/workflows/report.md
66+
comment_tag: execution
6567
- name: Run JMeter Tests
6668
uses: rbhadti94/[email protected]
6769
with:

CONTRIBUTION.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ docker run -p 8080:8080 -e SW_OAP_ADDRESS=http://localhost:12800 -e SW_ZIPKIN_AD
3434
make build
3535

3636
export SW_AGENT_NAME=atest
37-
export SW_AGENT_REPORTER_GRPC_BACKEND_SERVICE=172.11.0.6:32591
37+
export SW_AGENT_REPORTER_GRPC_BACKEND_SERVICE=172.11.0.6:30689
3838
export SW_AGENT_PLUGIN_CONFIG_HTTP_SERVER_COLLECT_PARAMETERS=true
3939
export SW_AGENT_METER_COLLECT_INTERVAL=3
4040
export SW_AGENT_LOG_TYPE=std

README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,17 @@ This is a API testing tool.
88

99
## Features
1010

11+
* Supportted protocols: HTTP, gRPC, tRPC
1112
* Multiple test report formats: Markdown, HTML, PDF, Stdout
1213
* Support converting to [JMeter](https://jmeter.apache.org/) files
1314
* Response Body fields equation check or [eval](https://expr.medv.io/)
14-
* Verify the Kubernetes resources
1515
* Validate the response body with [JSON schema](https://json-schema.org/)
1616
* Pre and post handle with the API request
17-
* Output reference between TestCase
1817
* Run in server mode, and provide the [gRPC](pkg/server/server.proto) and HTTP endpoint
1918
* [VS Code extension](https://github.com/LinuxSuRen/vscode-api-testing) support
2019
* Multiple storage backends supported(Local, ORM Database, S3, Git, etc)
2120
* [HTTP API record](extensions/collector)
22-
* Install in mutiple use cases(CLI, Container, Native-Service, Operator, etc)
21+
* Install in mutiple use cases(CLI, Container, Native-Service, Operator, Helm, etc)
2322
* Monitoring integration with Prometheus, Skywalking
2423

2524
## Get started

console/atest-ui/src/App.vue

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import setTheme from './theme'
1919
2020
const { t } = useI18n()
2121
22-
2322
function switchAppMode()
2423
{
2524
setTheme(appMode.value)
@@ -31,17 +30,20 @@ interface Tree {
3130
parent: string
3231
parentID: string
3332
store: string
33+
kind: string
3434
children?: Tree[]
3535
}
3636
3737
const testCaseName = ref('')
3838
const testSuite = ref('')
3939
const store = ref('')
40+
const testSuiteKind = ref('')
4041
const handleNodeClick = (data: Tree) => {
4142
if (data.children) {
4243
viewName.value = 'testsuite'
4344
testSuite.value = data.label
4445
store.value = data.store
46+
testSuiteKind.value = data.kind
4547
4648
const requestOptions = {
4749
method: 'POST',
@@ -61,6 +63,7 @@ const handleNodeClick = (data: Tree) => {
6163
data.children?.push({
6264
id: data.label + item.name,
6365
label: item.name,
66+
kind: data.kind,
6467
store: data.store,
6568
parent: data.label,
6669
parentID: data.id
@@ -73,6 +76,7 @@ const handleNodeClick = (data: Tree) => {
7376
testCaseName.value = data.label
7477
testSuite.value = data.parent
7578
store.value = data.store
79+
testSuiteKind.value = data.kind
7680
viewName.value = 'testcase'
7781
}
7882
}
@@ -99,6 +103,7 @@ function loadTestSuites(storeName: string) {
99103
let suite = {
100104
id: k,
101105
label: k,
106+
kind: d.data[k].kind,
102107
store: storeName,
103108
children: [] as Tree[]
104109
} as Tree
@@ -108,6 +113,7 @@ function loadTestSuites(storeName: string) {
108113
id: k + item,
109114
label: item,
110115
store: storeName,
116+
kind: suite.kind,
111117
parent: k,
112118
parentID: suite.id
113119
} as Tree)
@@ -176,6 +182,7 @@ function loadStores() {
176182
treeRef.value!.setCheckedKeys([targetChild.id], false)
177183
testSuite.value = targetSuite.label
178184
store.value = targetSuite.store
185+
testSuiteKind.value = targetChild.kind
179186
} else {
180187
viewName.value = ""
181188
}
@@ -190,7 +197,8 @@ const suiteFormRef = ref<FormInstance>()
190197
const testSuiteForm = reactive({
191198
name: '',
192199
api: '',
193-
store: ''
200+
store: '',
201+
kind: ''
194202
})
195203
const importSuiteFormRef = ref<FormInstance>()
196204
const importSuiteForm = reactive({
@@ -223,7 +231,8 @@ const submitForm = async (formEl: FormInstance | undefined) => {
223231
},
224232
body: JSON.stringify({
225233
name: testSuiteForm.name,
226-
api: testSuiteForm.api
234+
api: testSuiteForm.api,
235+
kind: testSuiteForm.kind
227236
})
228237
}
229238
@@ -299,6 +308,14 @@ watch(viewName, (val) => {
299308
useFmp: true
300309
});
301310
})
311+
312+
const suiteKinds = [{
313+
"name": "HTTP",
314+
}, {
315+
"name": "gRPC",
316+
}, {
317+
"name": "tRPC",
318+
}]
302319
</script>
303320

304321
<template>
@@ -348,6 +365,7 @@ watch(viewName, (val) => {
348365
v-else-if="viewName === 'testcase'"
349366
:store="store"
350367
:suite="testSuite"
368+
:kindName="testSuiteKind"
351369
:name="testCaseName"
352370
@updated="loadStores"
353371
data-intro="This is the test case editor. You can edit the test case here."
@@ -393,6 +411,19 @@ watch(viewName, (val) => {
393411
/>
394412
</el-select>
395413
</el-form-item>
414+
<el-form-item :label="t('field.suiteKind')" prop="kind">
415+
<el-select v-model="testSuiteForm.kind" class="m-2"
416+
filterable=true
417+
default-first-option=true
418+
size="middle">
419+
<el-option
420+
v-for="item in suiteKinds"
421+
:key="item.name"
422+
:label="item.name"
423+
:value="item.name"
424+
/>
425+
</el-select>
426+
</el-form-item>
396427
<el-form-item :label="t('field.name')" prop="name">
397428
<el-input v-model="testSuiteForm.name" test-id="suite-form-name" />
398429
</el-form-item>

console/atest-ui/src/locales/en.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
"createTestCase": "Create Test Case",
2121
"createStore": "Create Store",
2222
"createSecret": "Create Secret",
23-
"secretManager": "Secret Manager"
23+
"secretManager": "Secret Manager",
24+
"protoContent": "Proto Content",
25+
"param": "Parameter"
2426
},
2527
"tip": {
2628
"filter": "Filter Keyword"
@@ -35,7 +37,8 @@
3537
"pluginURL": "Plugin URL",
3638
"status": "Status",
3739
"operations": "Operations",
38-
"storageLocation": "Storage Location"
40+
"storageLocation": "Storage Location",
41+
"suiteKind": "Suite Kind"
3942
},
4043
"//see http spec": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403",
4144
"httpCode": {

console/atest-ui/src/views/TestCase.vue

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ const { t } = useI18n()
1414
const props = defineProps({
1515
name: String,
1616
suite: String,
17-
store: String
17+
store: String,
18+
kindName: String,
1819
})
1920
const emit = defineEmits(['updated'])
2021
@@ -357,7 +358,7 @@ watch(currentCodeGenerator, () => {
357358
})
358359
359360
const options = GetHTTPMethods()
360-
const activeName = ref('second')
361+
const activeName = ref('body')
361362
362363
function bodyFiledExpectChange() {
363364
const data = testCaseWithSuite.value.data.response.bodyFieldsExpect
@@ -411,7 +412,7 @@ function formChange() {
411412
}
412413
}
413414
414-
const bodyType = ref(1)
415+
const bodyType = ref(5)
415416
function bodyTypeChange(e: number) {
416417
let contentType = ""
417418
switch (e) {
@@ -491,6 +492,7 @@ const queryPupularHeaders = (queryString: string, cb: (arg: any) => void) => {
491492
<el-button type="primary" @click="openCodeDialog">{{ t('button.generateCode') }}</el-button>
492493
</div>
493494
<el-select
495+
v-if="props.kindName !== 'tRPC' && props.kindName !== 'gRPC'"
494496
v-model="testCaseWithSuite.data.request.method"
495497
class="m-2"
496498
placeholder="Method"
@@ -528,7 +530,7 @@ const queryPupularHeaders = (queryString: string, cb: (arg: any) => void) => {
528530

529531
<el-main>
530532
<el-tabs v-model="activeName" class="demo-tabs">
531-
<el-tab-pane label="Query" name="query">
533+
<el-tab-pane label="Query" name="query" v-if="props.kindName !== 'tRPC' && props.kindName !== 'gRPC'">
532534
<el-table :data="testCaseWithSuite.data.request.query" style="width: 100%">
533535
<el-table-column label="Key" width="180">
534536
<template #default="scope">
@@ -549,7 +551,7 @@ const queryPupularHeaders = (queryString: string, cb: (arg: any) => void) => {
549551
</el-table>
550552
</el-tab-pane>
551553

552-
<el-tab-pane label="Headers" name="second">
554+
<el-tab-pane label="Headers" name="second" v-if="props.kindName !== 'tRPC' && props.kindName !== 'gRPC'">
553555
<el-table :data="testCaseWithSuite.data.request.header" style="width: 100%">
554556
<el-table-column label="Key" width="180">
555557
<template #default="scope">
@@ -571,7 +573,7 @@ const queryPupularHeaders = (queryString: string, cb: (arg: any) => void) => {
571573
</el-table>
572574
</el-tab-pane>
573575

574-
<el-tab-pane label="Body" name="third">
576+
<el-tab-pane label="Body" name="body">
575577
<el-radio-group v-model="bodyType" @change="bodyTypeChange">
576578
<el-radio :label="1">none</el-radio>
577579
<el-radio :label="2">form-data</el-radio>
@@ -604,7 +606,7 @@ const queryPupularHeaders = (queryString: string, cb: (arg: any) => void) => {
604606
</el-table>
605607
</el-tab-pane>
606608

607-
<el-tab-pane label="Expected" name="expected">
609+
<el-tab-pane label="Expected" name="expected" v-if="props.kindName !== 'tRPC' && props.kindName !== 'gRPC'">
608610
<el-row :gutter="20">
609611
<span
610612
class="ml-3 w-50 text-gray-600 inline-flex items-center"
@@ -626,7 +628,7 @@ const queryPupularHeaders = (queryString: string, cb: (arg: any) => void) => {
626628
/>
627629
</el-tab-pane>
628630

629-
<el-tab-pane label="Expected Headers" name="expected-headers">
631+
<el-tab-pane label="Expected Headers" name="expected-headers" v-if="props.kindName !== 'tRPC' && props.kindName !== 'gRPC'">
630632
<el-table :data="testCaseWithSuite.data.response.header" style="width: 100%">
631633
<el-table-column label="Key" width="180">
632634
<template #default="scope">
@@ -647,7 +649,7 @@ const queryPupularHeaders = (queryString: string, cb: (arg: any) => void) => {
647649
</el-table>
648650
</el-tab-pane>
649651

650-
<el-tab-pane label="BodyFiledExpect" name="fourth">
652+
<el-tab-pane label="BodyFiledExpect" name="fourth" v-if="props.kindName !== 'tRPC' && props.kindName !== 'gRPC'">
651653
<el-table :data="testCaseWithSuite.data.response.bodyFieldsExpect" style="width: 100%">
652654
<el-table-column label="Key" width="180">
653655
<template #default="scope">
@@ -670,13 +672,13 @@ const queryPupularHeaders = (queryString: string, cb: (arg: any) => void) => {
670672
</el-table>
671673
</el-tab-pane>
672674

673-
<el-tab-pane label="Verify" name="fifth">
675+
<el-tab-pane label="Verify" name="fifth" v-if="props.kindName !== 'tRPC' && props.kindName !== 'gRPC'">
674676
<div v-for="verify in testCaseWithSuite.data.response.verify" :key="verify">
675677
<el-input :value="verify" />
676678
</div>
677679
</el-tab-pane>
678680

679-
<el-tab-pane label="Schema" name="schema">
681+
<el-tab-pane label="Schema" name="schema" v-if="props.kindName !== 'tRPC' && props.kindName !== 'gRPC'">
680682
<el-input
681683
v-model="testCaseWithSuite.data.response.schema"
682684
:autosize="{ minRows: 4, maxRows: 20 }"

0 commit comments

Comments
 (0)