Skip to content
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
76 changes: 38 additions & 38 deletions cmd/mock-compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,49 +17,49 @@ limitations under the License.
package cmd

import (
"github.com/linuxsuren/api-testing/pkg/mock"
"github.com/spf13/cobra"
"os"
"os/signal"
"syscall"
"github.com/linuxsuren/api-testing/pkg/mock"
"github.com/spf13/cobra"
"os"
"os/signal"
"syscall"
)

func createMockComposeCmd() (c *cobra.Command) {
c = &cobra.Command{
Use: "mock-compose",
Short: "Mock multiple servers",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) (err error) {
reader := mock.NewLocalFileReader(args[0])
c = &cobra.Command{
Use: "mock-compose",
Short: "Mock multiple servers",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) (err error) {
reader := mock.NewLocalFileReader(args[0])

var server *mock.Server
if server, err = reader.Parse(); err != nil {
return
}
var server *mock.Server
if server, err = reader.Parse(); err != nil {
return
}

var subServers []mock.DynamicServer
for _, proxy := range server.Proxies {
subProxy := &mock.Server{
Proxies: []mock.Proxy{proxy},
}
var subServers []mock.DynamicServer
for _, proxy := range server.Proxies {
subProxy := &mock.Server{
Proxies: []mock.Proxy{proxy},
}

subReader := mock.NewObjectReader(subProxy)
subServer := mock.NewInMemoryServer(c.Context(), proxy.Port)
go subServer.Start(subReader, proxy.Prefix)
subServers = append(subServers, subServer)
}
subReader := mock.NewObjectReader(subProxy)
subServer := mock.NewInMemoryServer(c.Context(), proxy.Port)
go subServer.Start(subReader, proxy.Prefix)
subServers = append(subServers, subServer)
}

clean := make(chan os.Signal, 1)
signal.Notify(clean, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)
select {
case <-c.Context().Done():
case <-clean:
}
for _, server := range subServers {
server.Stop()
}
return
},
}
return
clean := make(chan os.Signal, 1)
signal.Notify(clean, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)
select {
case <-c.Context().Done():
case <-clean:
}
for _, server := range subServers {
server.Stop()
}
return
},
}
return
}
7 changes: 5 additions & 2 deletions cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
"context"
"errors"
"fmt"
"github.com/linuxsuren/api-testing/pkg/apispec"
"math"
"net"
"net/http"
"os"
Expand All @@ -33,6 +33,8 @@ import (
"syscall"
"time"

"github.com/linuxsuren/api-testing/pkg/apispec"

"github.com/linuxsuren/api-testing/pkg/runner"
"github.com/linuxsuren/api-testing/pkg/util/home"

Expand Down Expand Up @@ -336,7 +338,8 @@ func (o *serverOption) runE(cmd *cobra.Command, args []string) (err error) {
server.RegisterMockHandlerFromEndpoint(ctx, mux, gRPCServerAddr, []grpc.DialOption{grpc.WithTransportCredentials(creds)}),
server.RegisterDataServerHandlerFromEndpoint(ctx, mux, gRPCServerAddr, []grpc.DialOption{grpc.WithTransportCredentials(creds)}))
} else {
dialOption := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
dialOption := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(math.MaxInt))}
err = errors.Join(
server.RegisterRunnerHandlerFromEndpoint(ctx, mux, gRPCServerAddr, dialOption),
server.RegisterMockHandlerFromEndpoint(ctx, mux, gRPCServerAddr, dialOption),
Expand Down
12 changes: 6 additions & 6 deletions console/atest-ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 26 additions & 12 deletions console/atest-ui/src/views/TestCase.vue
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ const parseResponseBody = (body: any) => {
}
}

const currentContentType = ref('')
const currentImageContent = ref('')

/**
* Handles test result data from API response
*
Expand All @@ -124,15 +127,23 @@ const parseResponseBody = (body: any) => {
*/
const handleTestResult = (e: any): void => {
testResult.value = e;
currentContentType.value = e.header.find((h: Pair) => h.key.toLowerCase() === 'content-type')?.value || '';
if (currentContentType.value.startsWith('image/')) {
API.DownloadResponseFile({
body: e.body}, (e) => {
if (e && e.data) {
currentImageContent.value = `data:${currentContentType.value};base64,${e.data}`;
} else {
console.error('No data to display as image.');
}
});
}

if (!isHistoryTestCase.value) {
handleTestResultError(e)
}
const isFilePath = e.body.startsWith("isFilePath-")

if(isFilePath){
isResponseFile.value = true
} else if(e.body !== ''){
isResponseFile.value = e.body.startsWith("isFilePath-")
if(!isResponseFile.value && e.body !== ''){
testResult.value.bodyLength = e.body.length
try {
// Try to parse as JSON, fallback to plain text if parsing fails
Expand All @@ -149,11 +160,11 @@ const handleTestResult = (e: any): void => {
}
}

Cache.SetTestCaseResponseCache(suite + '-' + name, {
body: testResult.value.bodyObject,
output: e.output,
statusCode: testResult.value.statusCode
} as TestCaseResponse)
Cache.SetTestCaseResponseCache(suite + '-' + name, {
body: testResult.value.bodyObject,
output: e.output,
statusCode: testResult.value.statusCode
} as TestCaseResponse)

parameters.value = [];
}
Expand Down Expand Up @@ -436,7 +447,9 @@ function downloadResponseFile(){
} else {
console.error('No data to download.');
}
})
}, (e) => {
UIAPI.ErrorTip(e);
});
}

function setDefaultValues(e) {
Expand Down Expand Up @@ -1373,7 +1386,8 @@ const renameTestCase = (name: string) => {
</div>
<div v-else>
<Codemirror v-if="!isResponseFile" v-model="testResult.bodyText"/>
<div v-if="isResponseFile" style="padding-top: 10px;">
<img v-if="currentContentType.startsWith('image')" :src="currentImageContent" style="max-width: 100%; max-height: 500px;"/>
<div v-else-if="isResponseFile" style="padding-top: 10px;">
<el-row>
<el-col :span="10">
<div>Response body is too large, please download to view.</div>
Expand Down
6 changes: 5 additions & 1 deletion console/atest-ui/src/views/__test__/net.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ beforeEach(() => {

describe('net', () => {
test('GetVersion', () => {
fetchMock.mockResponseOnce(`{"version":"v0.0.2"}`)
fetchMock.mockResponseOnce(`{"version":"v0.0.2"}`, {
headers: {
'Content-Type': 'application/json'
}
})
API.GetVersion((d) => {
expect(d.version).toEqual('v0.0.2')
})
Expand Down
15 changes: 7 additions & 8 deletions console/atest-ui/src/views/net.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ async function DefaultResponseProcess(response: any): Promise<any> {

// For OK responses, handle content based on Content-Type
const contentType = response.headers.get('Content-Type') ?? '';
if (contentType.startsWith('text/plain')) {
if (isTextReadableExpectJSON(contentType)) {
// For text/plain, directly return the text
return await response.text();
}
Expand All @@ -90,6 +90,11 @@ async function DefaultResponseProcess(response: any): Promise<any> {
}
}

const isTextReadableExpectJSON = (contentType: string): boolean => {
// Check if the content type is text-based
return contentType.startsWith('text/') || contentType === 'application/javascript';
}

interface AppVersion {
version: string
commit: string
Expand Down Expand Up @@ -823,16 +828,10 @@ interface ResponseFile {
function DownloadResponseFile(testcase: ResponseFile,
callback: (d: any) => void, errHandle?: (e: any) => void | null) {
const requestOptions = {
method: 'POST',
headers: {
'X-Store-Name': Cache.GetCurrentStore().name,
'X-Auth': getToken()
},
body: JSON.stringify({
response: {
body: testcase.body,
}
})
}
}
fetch(`/api/v1/downloadFile/${testcase.body}`, requestOptions)
.then(DefaultResponseProcess)
Expand Down
4 changes: 2 additions & 2 deletions console/atest-ui/src/views/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export interface Suite {

export interface TestResult {
body: string
bodyObject: {}
bodyObject: {} | null
bodyText: string
bodyLength: number
output: string
Expand All @@ -46,7 +46,7 @@ export interface TestResult {
header: Pair[]

// inner fields
originBodyObject:{}
originBodyObject:{} | null
}

export interface Pair {
Expand Down
64 changes: 32 additions & 32 deletions pkg/generator/curl_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,56 +16,56 @@ limitations under the License.
package generator

import (
"bytes"
_ "embed"
"net/http"
"strings"
"text/template"
"bytes"
_ "embed"
"net/http"
"strings"
"text/template"

"github.com/linuxsuren/api-testing/pkg/testing"
"github.com/linuxsuren/api-testing/pkg/testing"
)

type curlGenerator struct {
}

func NewCurlGenerator() CodeGenerator {
return &curlGenerator{}
return &curlGenerator{}
}

func (g *curlGenerator) Generate(testSuite *testing.TestSuite, testcase *testing.TestCase) (result string, err error) {
if testcase.Request.Method == "" {
testcase.Request.Method = http.MethodGet
}
if testcase.Request.Method == "" {
testcase.Request.Method = http.MethodGet
}

if !strings.HasSuffix(testcase.Request.API, "?") {
testcase.Request.API += "?"
}
if !strings.HasSuffix(testcase.Request.API, "?") {
testcase.Request.API += "?"
}

queryKeys := testcase.Request.Query.Keys()
for _, k := range queryKeys {
testcase.Request.API += k + "=" + testcase.Request.Query.GetValue(k) + "&"
}
queryKeys := testcase.Request.Query.Keys()
for _, k := range queryKeys {
testcase.Request.API += k + "=" + testcase.Request.Query.GetValue(k) + "&"
}

testcase.Request.API = strings.TrimSuffix(testcase.Request.API, "&")
testcase.Request.API = strings.TrimSuffix(testcase.Request.API, "?")
if err = testcase.Request.Render(nil, ""); err != nil {
return
}
testcase.Request.API = strings.TrimSuffix(testcase.Request.API, "&")
testcase.Request.API = strings.TrimSuffix(testcase.Request.API, "?")
if err = testcase.Request.Render(nil, ""); err != nil {
return
}

var tpl *template.Template
if tpl, err = template.New("curl template").Parse(curlTemplate); err == nil {
buf := new(bytes.Buffer)
if err = tpl.Execute(buf, testcase); err == nil {
result = strings.TrimSpace(buf.String())
var tpl *template.Template
if tpl, err = template.New("curl template").Parse(curlTemplate); err == nil {
buf := new(bytes.Buffer)
if err = tpl.Execute(buf, testcase); err == nil {
result = strings.TrimSpace(buf.String())

result = strings.TrimSuffix(result, " \\")
}
}
return
result = strings.TrimSuffix(result, " \\")
}
}
return
}

func init() {
RegisterCodeGenerator("curl", NewCurlGenerator())
RegisterCodeGenerator("curl", NewCurlGenerator())
}

//go:embed data/curl.tpl
Expand Down
Loading
Loading