Merge pull request #653 from LinuxSuRen/feat/iotdb

feat: add iotdb support
This commit is contained in:
Rick 2025-03-27 17:17:37 +08:00 committed by GitHub
commit 34eeb2a253
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 650 additions and 598 deletions

View File

@ -6,13 +6,14 @@ import type { Pair } from './types'
import { ElMessage } from 'element-plus'
import { Codemirror } from 'vue-codemirror'
import HistoryInput from '../components/HistoryInput.vue'
import type { Ref } from 'vue'
const stores = ref([] as Store[])
const stores: Ref<Store[]> = ref([])
const kind = ref('')
const store = ref('')
const sqlQuery = ref('')
const queryResult = ref([] as any[])
const queryResultAsJSON= ref('')
const queryResultAsJSON = ref('')
const columns = ref([] as string[])
const queryTip = ref('')
const loadingStores = ref(true)
@ -20,7 +21,10 @@ const dataFormat = ref('table')
const dataFormatOptions = ['table', 'json']
const queryDataMeta = ref({} as QueryDataMeta)
const tablesTree = ref([])
interface TreeItem {
label: string
}
const tablesTree = ref([] as TreeItem[])
watch(store, (s) => {
kind.value = ''
stores.value.forEach((e: Store) => {
@ -60,6 +64,7 @@ const queryTables = () => {
watch(kind, (k) => {
switch (k) {
case 'atest-store-orm':
case 'atest-store-iotdb':
queryTip.value = 'Enter SQL query'
executeQuery()
break;
@ -144,6 +149,7 @@ const executeQuery = async () => {
const data = await API.DataQueryAsync(store.value, kind.value, queryDataMeta.value.currentDatabase, sqlQuery.value);
switch (kind.value) {
case 'atest-store-orm':
case 'atest-store-iotdb':
ormDataHandler(data)
success = true
break;
@ -174,13 +180,15 @@ const executeQuery = async () => {
<template>
<div>
<el-container style="height: calc(100vh - 50px);">
<el-aside v-if="kind === 'atest-store-orm'">
<el-aside v-if="kind === 'atest-store-orm' || kind === 'atest-store-iotdb'">
<el-scrollbar>
<el-select v-model="queryDataMeta.currentDatabase" placeholder="Select database" @change="queryTables" filterable>
<el-select v-model="queryDataMeta.currentDatabase" placeholder="Select database"
@change="queryTables" filterable>
<el-option v-for="item in queryDataMeta.databases" :key="item" :label="item"
:value="item"></el-option>
</el-select>
<el-tree :data="tablesTree" node-key="label" @node-click="queryDataFromTable" highlight-current draggable/>
<el-tree :data="tablesTree" node-key="label" @node-click="queryDataFromTable" highlight-current
draggable />
</el-scrollbar>
</el-aside>
<el-container>
@ -189,15 +197,17 @@ const executeQuery = async () => {
<el-row :gutter="10">
<el-col :span="4">
<el-form-item>
<el-select v-model="store" placeholder="Select store" filterable :loading="loadingStores">
<el-select v-model="store" placeholder="Select store" filterable
:loading="loadingStores">
<el-option v-for="item in stores" :key="item.name" :label="item.name"
:value="item.name" :disabled="!item.ready" :kind="item.kind.name"></el-option>
:value="item.name" :disabled="!item.ready"
:kind="item.kind.name"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item>
<HistoryInput :placeholder="queryTip" :callback="executeQuery" v-model="sqlQuery"/>
<HistoryInput :placeholder="queryTip" :callback="executeQuery" v-model="sqlQuery" />
</el-form-item>
</el-col>
<el-col :span="2">
@ -207,7 +217,8 @@ const executeQuery = async () => {
</el-col>
<el-col :span="2">
<el-select v-model="dataFormat" placeholder="Select data format">
<el-option v-for="item in dataFormatOptions" :key="item" :label="item" :value="item"></el-option>
<el-option v-for="item in dataFormatOptions" :key="item" :label="item"
:value="item"></el-option>
</el-select>
</el-col>
</el-row>
@ -220,10 +231,9 @@ const executeQuery = async () => {
<el-tag type="primary" v-for="label in queryDataMeta.labels">{{ label.value }}</el-tag>
</div>
<el-table :data="queryResult" stripe v-if="dataFormat === 'table'">
<el-table-column v-for="col in columns" :key="col" :prop="col" :label="col" sortable/>
<el-table-column v-for="col in columns" :key="col" :prop="col" :label="col" sortable />
</el-table>
<Codemirror v-else-if="dataFormat === 'json'"
v-model="queryResultAsJSON"/>
<Codemirror v-else-if="dataFormat === 'json'" v-model="queryResultAsJSON" />
</el-main>
</el-container>
</el-container>

View File

@ -14,12 +14,12 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {SupportedExtension, SupportedExtensions} from "../store";
import { SupportedExtension, SupportedExtensions } from "../store";
describe("SupportedExtensions", () => {
test('length check', () => {
const extensions = SupportedExtensions()
expect(extensions.length).toBe(6)
expect(extensions.length).toBe(7)
})
for (const extension of SupportedExtensions()) {

View File

@ -23,7 +23,7 @@ async function DefaultResponseProcess(response: any) {
throw new Error("Unauthenticated")
}
const message = await response.json().then((data :any) => data.message)
const message = await response.json().then((data: any) => data.message)
throw new Error(message)
} else {
return response.json()
@ -38,7 +38,7 @@ interface AppVersion {
function safeToggleFunc(toggle?: (e: boolean) => void) {
if (!toggle) {
return (e: boolean) => {}
return (e: boolean) => { }
}
return toggle
}
@ -205,7 +205,7 @@ export interface TestCase {
}
interface HistoryTestCase {
historyCaseID : string,
historyCaseID: string,
suiteName: string
caseName: string
}
@ -367,7 +367,7 @@ const BatchRunTestCase = (request: BatchRunTestCaseRequest,
function DuplicateTestCase(sourceSuiteName: string, targetSuiteName: string,
sourceTestCaseName: string, targetTestCaseName: string,
callback: (d: any) => void, errHandle?: ((reason: any) => PromiseLike<never>) | undefined | null ) {
callback: (d: any) => void, errHandle?: ((reason: any) => PromiseLike<never>) | undefined | null) {
const requestOptions = {
method: 'POST',
headers: {
@ -388,7 +388,7 @@ function DuplicateTestCase(sourceSuiteName: string, targetSuiteName: string,
function RenameTestCase(sourceSuiteName: string, targetSuiteName: string,
sourceTestCaseName: string, targetTestCaseName: string,
callback: (d: any) => void, errHandle?: ((reason: any) => PromiseLike<never>) | undefined | null ) {
callback: (d: any) => void, errHandle?: ((reason: any) => PromiseLike<never>) | undefined | null) {
const requestOptions = {
method: 'POST',
headers: {
@ -675,7 +675,7 @@ function emptyOrDefault(fn: any) {
if (fn) {
return fn
}
return () => {}
return () => { }
}
function GetHistoryTestCaseWithResult(req: HistoryTestCase,
@ -713,7 +713,7 @@ function DeleteHistoryTestCase(req: HistoryTestCase,
'X-Auth': getToken()
},
body: JSON.stringify({
ID : req.historyCaseID
ID: req.historyCaseID
})
}
fetch(`/api/v1/historyTestCase/${req.historyCaseID}`, requestOptions)
@ -729,7 +729,7 @@ function DeleteAllHistoryTestCase(suiteName: string, caseName: string,
'X-Auth': getToken()
},
body: JSON.stringify({
suiteName : suiteName,
suiteName: suiteName,
caseName: caseName,
})
}
@ -791,6 +791,10 @@ var DataQueryAsync = (store: string, kind: string, currentDatabase: string, quer
queryObj['sql'] = query;
queryObj['key'] = currentDatabase;
break;
case 'atest-store-iotdb':
queryObj['sql'] = query;
queryObj['key'] = currentDatabase;
break;
case 'atest-store-etcd':
queryObj['key'] = query;
break;
@ -811,7 +815,35 @@ var DataQueryAsync = (store: string, kind: string, currentDatabase: string, quer
}
var DataQuery = (store: string, kind: string, currentDatabase: string, query: string, callback: (d: any) => void, errHandler: (d: any) => void) => {
DataQueryAsync(store, kind, currentDatabase, query).then(callback).catch(errHandler)
const queryObj = {} as QueryObject
switch (kind) {
case 'atest-store-orm':
queryObj['sql'] = query;
queryObj['key'] = currentDatabase;
break;
case 'atest-store-iotdb':
queryObj['sql'] = query;
queryObj['key'] = currentDatabase;
break;
case 'atest-store-etcd':
queryObj['key'] = query;
break;
case 'atest-store-redis':
queryObj['key'] = query;
break;
}
const requestOptions = {
method: 'POST',
headers: {
'X-Store-Name': store,
'X-Database': currentDatabase
},
body: JSON.stringify(queryObj)
}
fetch(`/api/v1/data/query`, requestOptions)
.then(DefaultResponseProcess)
.then(callback)
.catch(errHandler)
}
export const API = {
@ -819,7 +851,7 @@ export const API = {
GetVersion,
CreateTestSuite, UpdateTestSuite, ImportTestSuite, GetTestSuite, DeleteTestSuite, ConvertTestSuite, DuplicateTestSuite, RenameTestSuite, GetTestSuiteYaml,
CreateTestCase, UpdateTestCase, GetTestCase, ListTestCase, DeleteTestCase, DuplicateTestCase, RenameTestCase, RunTestCase, BatchRunTestCase,
GetHistoryTestCaseWithResult, DeleteHistoryTestCase,GetHistoryTestCase, GetTestCaseAllHistory, DeleteAllHistoryTestCase, DownloadResponseFile,
GetHistoryTestCaseWithResult, DeleteHistoryTestCase, GetHistoryTestCase, GetTestCaseAllHistory, DeleteAllHistoryTestCase, DownloadResponseFile,
GenerateCode, ListCodeGenerator, HistoryGenerateCode,
PopularHeaders,
CreateOrUpdateStore, GetStores, DeleteStore, VerifyStore,

View File

@ -83,6 +83,11 @@ const storeExtensions = [
}],
link: 'https://github.com/LinuxSuRen/atest-ext-store-orm'
},
{
name: 'atest-store-iotdb',
params: [],
link: 'https://github.com/LinuxSuRen/atest-ext-store-iotdb'
},
{
name: 'atest-store-etcd',
params: [],

View File

@ -8,6 +8,7 @@ Ports in extensions:
| Store | [git](https://github.com/LinuxSuRen/atest-ext-store-git) | 4074 |
| Store | [mongodb](https://github.com/LinuxSuRen/atest-ext-store-mongodb) | 4075 |
| Store | [redis](https://github.com/LinuxSuRen/atest-ext-store-redis) | |
| Store | [iotdb](https://github.com/LinuxSuRen/atest-ext-store-iotdb) | |
| Monitor | [docker-monitor](https://github.com/LinuxSuRen/atest-ext-monitor-docker) | |
| Agent | [collector](https://github.com/LinuxSuRen/atest-ext-collector) | |
| Secret | [Vault](https://github.com/LinuxSuRen/api-testing-vault-extension) | |
@ -20,6 +21,7 @@ Ports in extensions:
* Finally, add the extension's name into function [SupportedExtensions](../console/atest-ui/src/views/store.ts).
## Naming conventions
Please follow the following conventions if you want to add a new store extension:
`store-xxx`

View File

@ -1157,6 +1157,9 @@ func (s *server) GetStores(ctx context.Context, in *Empty) (reply *Stores, err e
}
for _, item := range stores {
grpcStore := ToGRPCStore(item)
if item.Disabled {
continue
}
storeStatus, sErr := s.VerifyStore(ctx, &SimpleQuery{Name: item.Name})
grpcStore.Ready = sErr == nil && storeStatus.Ready