feat: auto locate to the last testcase (#197)
This commit is contained in:
parent
9efccb1430
commit
2bbb634688
|
@ -45,6 +45,7 @@ Mirror Images: docker.m.daocloud.io/linuxsuren/api-testing`,
|
||||||
flags.StringVarP(&opt.version, "version", "", version.GetVersion(), "The version of the service image")
|
flags.StringVarP(&opt.version, "version", "", version.GetVersion(), "The version of the service image")
|
||||||
flags.StringVarP(&opt.localStorage, "local-storage", "", "/var/data/atest",
|
flags.StringVarP(&opt.localStorage, "local-storage", "", "/var/data/atest",
|
||||||
"The local storage path which will be mounted into the container")
|
"The local storage path which will be mounted into the container")
|
||||||
|
flags.StringVarP(&opt.secretServer, "secret-server", "", "", "The secret server URL")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,6 +59,7 @@ type serviceOption struct {
|
||||||
mode string
|
mode string
|
||||||
localStorage string
|
localStorage string
|
||||||
pull string
|
pull string
|
||||||
|
secretServer string
|
||||||
|
|
||||||
stdOut io.Writer
|
stdOut io.Writer
|
||||||
}
|
}
|
||||||
|
@ -213,7 +215,7 @@ func (o *serviceOption) getContainerService() (service Service, err error) {
|
||||||
clientPath = client
|
clientPath = client
|
||||||
}
|
}
|
||||||
service = newContainerService(o.Execer, clientPath,
|
service = newContainerService(o.Execer, clientPath,
|
||||||
o.image, o.version, o.pull, o.localStorage, o.stdOut)
|
o.image, o.version, o.pull, o.localStorage, o.secretServer, o.stdOut)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -319,13 +321,14 @@ type containerService struct {
|
||||||
tag string
|
tag string
|
||||||
pull string
|
pull string
|
||||||
localStorage string
|
localStorage string
|
||||||
|
secretServer string
|
||||||
stdOut io.Writer
|
stdOut io.Writer
|
||||||
errOut io.Writer
|
errOut io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultImage = "ghcr.io/linuxsuren/api-testing"
|
const defaultImage = "ghcr.io/linuxsuren/api-testing"
|
||||||
|
|
||||||
func newContainerService(execer fakeruntime.Execer, client, image, tag, pull, localStorage string, writer io.Writer) (svc Service) {
|
func newContainerService(execer fakeruntime.Execer, client, image, tag, pull, localStorage string, secretServer string, writer io.Writer) (svc Service) {
|
||||||
if tag == "" {
|
if tag == "" {
|
||||||
tag = "latest"
|
tag = "latest"
|
||||||
}
|
}
|
||||||
|
@ -341,6 +344,7 @@ func newContainerService(execer fakeruntime.Execer, client, image, tag, pull, lo
|
||||||
tag: tag,
|
tag: tag,
|
||||||
pull: pull,
|
pull: pull,
|
||||||
localStorage: localStorage,
|
localStorage: localStorage,
|
||||||
|
secretServer: secretServer,
|
||||||
stdOut: writer,
|
stdOut: writer,
|
||||||
errOut: writer,
|
errOut: writer,
|
||||||
}
|
}
|
||||||
|
@ -398,14 +402,20 @@ func (s *containerService) exist() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *containerService) getStartArgs() []string {
|
func (s *containerService) getStartArgs() []string {
|
||||||
return []string{"run", "--name=" + s.name,
|
args := []string{"run", "--name=" + s.name,
|
||||||
"--restart=always",
|
"--restart=always",
|
||||||
"-d",
|
"-d",
|
||||||
fmt.Sprintf("--pull=%s", s.pull),
|
fmt.Sprintf("--pull=%s", s.pull),
|
||||||
"--network=host",
|
"--network=host",
|
||||||
"-v", s.localStorage + ":/var/www/data",
|
"-v", s.localStorage + ":/var/www/data",
|
||||||
"-v", "/root/.config/atest:/root/.config/atest",
|
"-v", "/root/.config/atest:/root/.config/atest",
|
||||||
s.image + ":" + s.tag}
|
s.image + ":" + s.tag,
|
||||||
|
"atest", "server"}
|
||||||
|
if s.secretServer != "" {
|
||||||
|
args = append(args, "--secret-server="+s.secretServer)
|
||||||
|
}
|
||||||
|
args = append(args, "--console-path=/var/www/html")
|
||||||
|
return args
|
||||||
}
|
}
|
||||||
|
|
||||||
type podmanService struct {
|
type podmanService struct {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { ElTree } from 'element-plus'
|
||||||
import type { FormInstance, FormRules } from 'element-plus'
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
import { Edit, Share } from '@element-plus/icons-vue'
|
import { Edit, Share } from '@element-plus/icons-vue'
|
||||||
import type { Suite } from './types'
|
import type { Suite } from './types'
|
||||||
|
import { GetLastTestCaseLocation, SetLastTestCaseLocation } from './views/cache'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
@ -18,6 +19,7 @@ interface Tree {
|
||||||
id: string
|
id: string
|
||||||
label: string
|
label: string
|
||||||
parent: string
|
parent: string
|
||||||
|
parentID: string
|
||||||
store: string
|
store: string
|
||||||
children?: Tree[]
|
children?: Tree[]
|
||||||
}
|
}
|
||||||
|
@ -50,12 +52,14 @@ const handleNodeClick = (data: Tree) => {
|
||||||
id: data.label + item.name,
|
id: data.label + item.name,
|
||||||
label: item.name,
|
label: item.name,
|
||||||
store: data.store,
|
store: data.store,
|
||||||
parent: data.label
|
parent: data.label,
|
||||||
|
parentID: data.id
|
||||||
} as Tree)
|
} as Tree)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
SetLastTestCaseLocation(data.parentID, data.id)
|
||||||
testCaseName.value = data.label
|
testCaseName.value = data.label
|
||||||
testSuite.value = data.parent
|
testSuite.value = data.parent
|
||||||
store.value = data.store
|
store.value = data.store
|
||||||
|
@ -74,46 +78,34 @@ function loadTestSuites(storeName: string) {
|
||||||
'X-Store-Name': storeName
|
'X-Store-Name': storeName
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
fetch('/server.Runner/GetSuites', requestOptions)
|
return async () => {
|
||||||
.then((response) => response.json())
|
await fetch('/server.Runner/GetSuites', requestOptions)
|
||||||
.then((d) => {
|
.then((response) => response.json())
|
||||||
if (!d.data) {
|
.then((d) => {
|
||||||
return
|
if (!d.data) {
|
||||||
}
|
return
|
||||||
Object.keys(d.data).map((k) => {
|
|
||||||
let suite = {
|
|
||||||
id: k,
|
|
||||||
label: k,
|
|
||||||
store: storeName,
|
|
||||||
children: [] as Tree[]
|
|
||||||
} as Tree
|
|
||||||
|
|
||||||
d.data[k].data.forEach((item: any) => {
|
|
||||||
suite.children?.push({
|
|
||||||
id: k + item,
|
|
||||||
label: item,
|
|
||||||
store: storeName,
|
|
||||||
parent: k
|
|
||||||
} as Tree)
|
|
||||||
})
|
|
||||||
data.value.push(suite)
|
|
||||||
})
|
|
||||||
|
|
||||||
if (data.value.length > 0) {
|
|
||||||
const firstItem = data.value[0]
|
|
||||||
if (firstItem.children && firstItem.children.length > 0) {
|
|
||||||
const child = firstItem.children[0].id
|
|
||||||
|
|
||||||
currentNodekey.value = child
|
|
||||||
treeRef.value!.setCurrentKey(child)
|
|
||||||
treeRef.value!.setCheckedKeys([child], false)
|
|
||||||
}
|
}
|
||||||
|
Object.keys(d.data).map((k) => {
|
||||||
|
let suite = {
|
||||||
|
id: k,
|
||||||
|
label: k,
|
||||||
|
store: storeName,
|
||||||
|
children: [] as Tree[]
|
||||||
|
} as Tree
|
||||||
|
|
||||||
viewName.value = 'testsuite'
|
d.data[k].data.forEach((item: any) => {
|
||||||
testSuite.value = firstItem.label
|
suite.children?.push({
|
||||||
store.value = firstItem.store
|
id: k + item,
|
||||||
}
|
label: item,
|
||||||
})
|
store: storeName,
|
||||||
|
parent: k,
|
||||||
|
parentID: suite.id
|
||||||
|
} as Tree)
|
||||||
|
})
|
||||||
|
data.value.push(suite)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Store {
|
interface Store {
|
||||||
|
@ -128,17 +120,52 @@ function loadStores() {
|
||||||
}
|
}
|
||||||
fetch('/server.Runner/GetStores', requestOptions)
|
fetch('/server.Runner/GetStores', requestOptions)
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((d) => {
|
.then(async (d) => {
|
||||||
stores.value = d.data
|
stores.value = d.data
|
||||||
data.value = [] as Tree[]
|
data.value = [] as Tree[]
|
||||||
|
|
||||||
d.data.forEach((item: any) => {
|
for (const item of d.data) {
|
||||||
if (item.ready) {
|
if (item.ready) {
|
||||||
loadTestSuites(item.name)
|
await loadTestSuites(item.name)()
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
if (data.value.length === 0) {
|
if (data.value.length > 0) {
|
||||||
|
const key = GetLastTestCaseLocation()
|
||||||
|
|
||||||
|
let targetSuite = {} as Tree
|
||||||
|
let targetChild = {} as Tree
|
||||||
|
if (key.suite !== '' && key.testcase !== '') {
|
||||||
|
for (var i = 0; i < data.value.length; i++) {
|
||||||
|
const item = data.value[i]
|
||||||
|
if (item.id === key.suite && item.children) {
|
||||||
|
for (var j = 0; j < item.children.length; j++) {
|
||||||
|
const child = item.children[j]
|
||||||
|
if (child.id === key.testcase) {
|
||||||
|
targetSuite = item
|
||||||
|
targetChild = child
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!targetChild.id || targetChild.id === '') {
|
||||||
|
targetSuite = data.value[0]
|
||||||
|
if (targetSuite.children && targetSuite.children.length > 0) {
|
||||||
|
targetChild = targetSuite.children[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewName.value = 'testsuite'
|
||||||
|
currentNodekey.value = targetChild.id
|
||||||
|
treeRef.value!.setCurrentKey(targetChild.id)
|
||||||
|
treeRef.value!.setCheckedKeys([targetChild.id], false)
|
||||||
|
testSuite.value = targetSuite.label
|
||||||
|
store.value = targetSuite.store
|
||||||
|
} else {
|
||||||
viewName.value = ""
|
viewName.value = ""
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -278,6 +305,8 @@ const viewName = ref('')
|
||||||
@node-click="handleNodeClick"
|
@node-click="handleNodeClick"
|
||||||
data-intro="This is the test suite tree. You can click the test suite to edit it."
|
data-intro="This is the test suite tree. You can click the test suite to edit it."
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<TemplateFunctions/>
|
||||||
</el-aside>
|
</el-aside>
|
||||||
|
|
||||||
<el-main>
|
<el-main>
|
||||||
|
@ -391,8 +420,6 @@ const viewName = ref('')
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<TemplateFunctions/>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
@ -25,7 +25,13 @@ function loadStores() {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
}
|
}
|
||||||
fetch('/server.Runner/GetSecrets', requestOptions)
|
fetch('/server.Runner/GetSecrets', requestOptions)
|
||||||
.then((response) => response.json())
|
.then((response) => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(response.statusText)
|
||||||
|
} else {
|
||||||
|
response.json()
|
||||||
|
}
|
||||||
|
})
|
||||||
.then((e) => {
|
.then((e) => {
|
||||||
secrets.value = e.data
|
secrets.value = e.data
|
||||||
})
|
})
|
||||||
|
@ -125,6 +131,10 @@ const submitForm = async (formEl: FormInstance | undefined) => {
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
|
<div style="margin-top: 20px; margin-bottom: 20px; position: absolute; bottom: 0px;">
|
||||||
|
Follow <el-link href="https://linuxsuren.github.io/api-testing/#secret-server" target="_blank">the instructions</el-link> to configure the secret server.
|
||||||
|
</div>
|
||||||
|
|
||||||
<el-dialog v-model="dialogVisible" :title="t('title.createSecret')" width="30%" draggable>
|
<el-dialog v-model="dialogVisible" :title="t('title.createSecret')" width="30%" draggable>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
|
|
|
@ -185,6 +185,10 @@ function updateKeys() {
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
|
<div style="margin-top: 20px; margin-bottom: 20px; position: absolute; bottom: 0px;">
|
||||||
|
Follow <el-link href="https://linuxsuren.github.io/api-testing/#storage" target="_blank">the instructions</el-link> to configure the storage plugins.
|
||||||
|
</div>
|
||||||
|
|
||||||
<el-dialog v-model="dialogVisible" :title="t('title.createStore')" width="30%" draggable>
|
<el-dialog v-model="dialogVisible" :title="t('title.createStore')" width="30%" draggable>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
|
|
|
@ -4,7 +4,7 @@ export interface TestCaseResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GetTestCaseResponseCache(id: string) {
|
export function GetTestCaseResponseCache(id: string) {
|
||||||
const val = sessionStorage.getItem(id)
|
const val = sessionStorage.getItem(id)
|
||||||
if (val && val !== '') {
|
if (val && val !== '') {
|
||||||
return JSON.parse(val)
|
return JSON.parse(val)
|
||||||
} else {
|
} else {
|
||||||
|
@ -15,3 +15,21 @@ export function GetTestCaseResponseCache(id: string) {
|
||||||
export function SetTestCaseResponseCache(id: string, resp: TestCaseResponse) {
|
export function SetTestCaseResponseCache(id: string, resp: TestCaseResponse) {
|
||||||
sessionStorage.setItem(id, JSON.stringify(resp))
|
sessionStorage.setItem(id, JSON.stringify(resp))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const lastTestCaseLocationKey = "api-testing-case-location"
|
||||||
|
export function GetLastTestCaseLocation() {
|
||||||
|
const val = sessionStorage.getItem(lastTestCaseLocationKey)
|
||||||
|
if (val && val !== '') {
|
||||||
|
return JSON.parse(val)
|
||||||
|
} else {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SetLastTestCaseLocation(suite: string, testcase: string) {
|
||||||
|
sessionStorage.setItem(lastTestCaseLocationKey, JSON.stringify({
|
||||||
|
suite: suite,
|
||||||
|
testcase: testcase
|
||||||
|
}))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue