Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add trpc protocol support #254

Merged
merged 5 commits into from
Oct 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/testing/grpc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
name: grpc-sample
api: 127.0.0.1:7070
spec:
grpc:
rpc:
import:
- ./pkg/server
protofile: server.proto
Expand Down
2 changes: 1 addition & 1 deletion .github/testing/grpc_descriptor_set.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
name: grpc-sample
api: 127.0.0.1:7070
spec:
grpc:
rpc:
protoset: .github/testing/server.pb
items:
- name: GetVersion
Expand Down
2 changes: 1 addition & 1 deletion .github/testing/grpc_ref.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
name: grpc-sample
api: 127.0.0.1:7070
spec:
grpc:
rpc:
serverReflection: true
items:
- name: GetVersion
Expand Down
22 changes: 22 additions & 0 deletions .github/testing/trpc.yaml
Original file line number Diff line number Diff line change
@@ -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!"
4 changes: 3 additions & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
37 changes: 34 additions & 3 deletions console/atest-ui/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import setTheme from './theme'

const { t } = useI18n()


function switchAppMode()
{
setTheme(appMode.value)
Expand All @@ -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',
Expand All @@ -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
Expand All @@ -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'
}
}
Expand All @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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 = ""
}
Expand All @@ -190,7 +197,8 @@ const suiteFormRef = ref<FormInstance>()
const testSuiteForm = reactive({
name: '',
api: '',
store: ''
store: '',
kind: ''
})
const importSuiteFormRef = ref<FormInstance>()
const importSuiteForm = reactive({
Expand Down Expand Up @@ -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
})
}

Expand Down Expand Up @@ -299,6 +308,14 @@ watch(viewName, (val) => {
useFmp: true
});
})

const suiteKinds = [{
"name": "HTTP",
}, {
"name": "gRPC",
}, {
"name": "tRPC",
}]
</script>

<template>
Expand Down Expand Up @@ -348,6 +365,7 @@ watch(viewName, (val) => {
v-else-if="viewName === 'testcase'"
:store="store"
:suite="testSuite"
:kindName="testSuiteKind"
:name="testCaseName"
@updated="loadStores"
data-intro="This is the test case editor. You can edit the test case here."
Expand Down Expand Up @@ -393,6 +411,19 @@ watch(viewName, (val) => {
/>
</el-select>
</el-form-item>
<el-form-item :label="t('field.suiteKind')" prop="kind">
<el-select v-model="testSuiteForm.kind" class="m-2"
filterable=true
default-first-option=true
size="middle">
<el-option
v-for="item in suiteKinds"
:key="item.name"
:label="item.name"
:value="item.name"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('field.name')" prop="name">
<el-input v-model="testSuiteForm.name" test-id="suite-form-name" />
</el-form-item>
Expand Down
7 changes: 5 additions & 2 deletions console/atest-ui/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
"createTestCase": "Create Test Case",
"createStore": "Create Store",
"createSecret": "Create Secret",
"secretManager": "Secret Manager"
"secretManager": "Secret Manager",
"protoContent": "Proto Content",
"param": "Parameter"
},
"tip": {
"filter": "Filter Keyword"
Expand All @@ -35,7 +37,8 @@
"pluginURL": "Plugin URL",
"status": "Status",
"operations": "Operations",
"storageLocation": "Storage Location"
"storageLocation": "Storage Location",
"suiteKind": "Suite Kind"
},
"//see http spec": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403",
"httpCode": {
Expand Down
24 changes: 13 additions & 11 deletions console/atest-ui/src/views/TestCase.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ const { t } = useI18n()
const props = defineProps({
name: String,
suite: String,
store: String
store: String,
kindName: String,
})
const emit = defineEmits(['updated'])

Expand Down Expand Up @@ -357,7 +358,7 @@ watch(currentCodeGenerator, () => {
})

const options = GetHTTPMethods()
const activeName = ref('second')
const activeName = ref('body')

function bodyFiledExpectChange() {
const data = testCaseWithSuite.value.data.response.bodyFieldsExpect
Expand Down Expand Up @@ -411,7 +412,7 @@ function formChange() {
}
}

const bodyType = ref(1)
const bodyType = ref(5)
function bodyTypeChange(e: number) {
let contentType = ""
switch (e) {
Expand Down Expand Up @@ -491,6 +492,7 @@ const queryPupularHeaders = (queryString: string, cb: (arg: any) => void) => {
<el-button type="primary" @click="openCodeDialog">{{ t('button.generateCode') }}</el-button>
</div>
<el-select
v-if="props.kindName !== 'tRPC' && props.kindName !== 'gRPC'"
v-model="testCaseWithSuite.data.request.method"
class="m-2"
placeholder="Method"
Expand Down Expand Up @@ -528,7 +530,7 @@ const queryPupularHeaders = (queryString: string, cb: (arg: any) => void) => {

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

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

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

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

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

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

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

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