feat: support write the report to a HTTP server (#367)
This commit is contained in:
parent
ab38bef403
commit
ea911ae8c2
10
cmd/run.go
10
cmd/run.go
|
@ -22,6 +22,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
@ -58,6 +59,8 @@ type runOption struct {
|
|||
reportWriter runner.ReportResultWriter
|
||||
report string
|
||||
reportIgnore bool
|
||||
reportTemplate string
|
||||
reportDest string
|
||||
swaggerURL string
|
||||
level string
|
||||
caseItems []string
|
||||
|
@ -106,9 +109,11 @@ See also https://github.com/LinuxSuRen/api-testing/tree/master/sample`,
|
|||
flags.DurationVarP(&opt.duration, "duration", "", 0, "Running duration")
|
||||
flags.DurationVarP(&opt.requestTimeout, "request-timeout", "", time.Minute, "Timeout for per request")
|
||||
flags.BoolVarP(&opt.requestIgnoreError, "request-ignore-error", "", false, "Indicate if ignore the request error")
|
||||
flags.StringVarP(&opt.report, "report", "", "", "The type of target report. Supported: markdown, md, html, json, discard, std, prometheus")
|
||||
flags.StringVarP(&opt.report, "report", "", "", "The type of target report. Supported: markdown, md, html, json, discard, std, prometheus, http")
|
||||
flags.StringVarP(&opt.reportFile, "report-file", "", "", "The file path of the report")
|
||||
flags.BoolVarP(&opt.reportIgnore, "report-ignore", "", false, "Indicate if ignore the report output")
|
||||
flags.StringVarP(&opt.reportTemplate, "report-template", "", "", "The template used to render the report")
|
||||
flags.StringVarP(&opt.reportDest, "report-dest", "", "", "The server url where you want to send the report")
|
||||
flags.StringVarP(&opt.swaggerURL, "swagger-url", "", "", "The URL of swagger")
|
||||
flags.Int64VarP(&opt.thread, "thread", "", 1, "Threads of the execution")
|
||||
flags.Int32VarP(&opt.qps, "qps", "", 5, "QPS")
|
||||
|
@ -153,6 +158,9 @@ func (o *runOption) preRunE(cmd *cobra.Command, args []string) (err error) {
|
|||
case "github":
|
||||
o.githubReportOption.ReportFile = o.reportFile
|
||||
o.reportWriter, err = runner.NewGithubPRCommentWriter(o.githubReportOption)
|
||||
case "http":
|
||||
templateOption := runner.NewTemplateOption(o.reportTemplate, "json")
|
||||
o.reportWriter = runner.NewHTTPResultWriter(http.MethodPost, o.reportDest, nil, templateOption)
|
||||
default:
|
||||
err = fmt.Errorf("not supported report type: '%s'", o.report)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
Copyright 2024 API Testing Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package runner
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/linuxsuren/api-testing/pkg/apispec"
|
||||
)
|
||||
|
||||
type httpResultWriter struct {
|
||||
requestMethod string
|
||||
targetUrl string
|
||||
parameters map[string]string
|
||||
templateFile *TemplateOption
|
||||
}
|
||||
|
||||
type TemplateOption struct {
|
||||
filename string
|
||||
fileType string
|
||||
}
|
||||
|
||||
// NewHTTPResultWriter creates a new httpResultWriter
|
||||
func NewHTTPResultWriter(requestType string, url string, parameters map[string]string, templateFile *TemplateOption) ReportResultWriter {
|
||||
return &httpResultWriter{
|
||||
requestMethod: requestType,
|
||||
targetUrl: url,
|
||||
parameters: parameters,
|
||||
templateFile: templateFile,
|
||||
}
|
||||
}
|
||||
|
||||
func NewTemplateOption(filename string, fileType string) *TemplateOption {
|
||||
return &TemplateOption{
|
||||
filename: filename,
|
||||
fileType: fileType,
|
||||
}
|
||||
}
|
||||
|
||||
// Output writes the JSON base report to target writer
|
||||
func (w *httpResultWriter) Output(result []ReportResult) (err error) {
|
||||
url := w.targetUrl
|
||||
for key, value := range w.parameters {
|
||||
if url == w.targetUrl {
|
||||
url = fmt.Sprintf("%s?%s=%s", url, key, value)
|
||||
} else {
|
||||
url = fmt.Sprintf("%s&%s=%s", url, key, value)
|
||||
}
|
||||
}
|
||||
log.Println("will send report to:" + url)
|
||||
|
||||
var tmpl *template.Template
|
||||
if w.templateFile == nil {
|
||||
// use the default template file to serialize the data to JSON format
|
||||
tmpl, err = template.New("HTTP report template").Parse(defaultTemplate)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to parse template: %v", err)
|
||||
}
|
||||
} else {
|
||||
content, err := os.ReadFile(w.templateFile.filename)
|
||||
if err != nil {
|
||||
log.Println("Error reading file:", err)
|
||||
return err
|
||||
}
|
||||
|
||||
tmpl, err = template.New("HTTP report template").Parse(string(content))
|
||||
if err != nil {
|
||||
log.Println("Error parsing template:", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
err = tmpl.Execute(buf, result)
|
||||
if err != nil {
|
||||
log.Printf("Failed to render template: %v", err)
|
||||
return
|
||||
}
|
||||
req, err := http.NewRequest(w.requestMethod, url, buf)
|
||||
if err != nil {
|
||||
log.Println("Error creating request:", err)
|
||||
return
|
||||
}
|
||||
|
||||
var contentType string
|
||||
if w.templateFile != nil {
|
||||
switch w.templateFile.fileType {
|
||||
case "html":
|
||||
contentType = "text/html"
|
||||
case "yaml":
|
||||
contentType = "application/yaml"
|
||||
case "xml":
|
||||
contentType = "application/xml"
|
||||
default:
|
||||
contentType = "application/json"
|
||||
}
|
||||
} else {
|
||||
contentType = "application/json"
|
||||
}
|
||||
req.Header.Set("Content-Type", contentType)
|
||||
|
||||
var resp *http.Response
|
||||
if resp, err = http.DefaultClient.Do(req); err != nil {
|
||||
log.Println("error when client do", err)
|
||||
return
|
||||
}
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
var data []byte
|
||||
if data, err = io.ReadAll(resp.Body); err != nil {
|
||||
log.Println("error when ReadAll", err)
|
||||
return
|
||||
}
|
||||
log.Println("getting response back", data)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//go:embed writer_templates/example.tpl
|
||||
var defaultTemplate string
|
||||
|
||||
// WithAPIConverage sets the api coverage
|
||||
func (w *httpResultWriter) WithAPIConverage(apiConverage apispec.APIConverage) ReportResultWriter {
|
||||
return w
|
||||
}
|
||||
|
||||
func (w *httpResultWriter) WithResourceUsage([]ResourceUsage) ReportResultWriter {
|
||||
return w
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
Copyright 2024 API Testing Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package runner
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/h2non/gock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestHTTPResultWriter(t *testing.T) {
|
||||
t.Run("test get request", func(t *testing.T) {
|
||||
defer gock.Off()
|
||||
gock.New("https://test.com").Get("/result/get").Reply(http.StatusOK).JSON([]comment{})
|
||||
|
||||
writer := NewHTTPResultWriter("GET", "https://test.com/result/get", nil, nil)
|
||||
|
||||
err := writer.Output([]ReportResult{{
|
||||
API: "/api",
|
||||
}})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("test post request", func(t *testing.T) {
|
||||
defer gock.Off()
|
||||
gock.New("https://test.com").Post("/result/post").Reply(http.StatusOK).JSON([]comment{})
|
||||
|
||||
writer := NewHTTPResultWriter("POST", "https://test.com/result/post", nil, nil)
|
||||
|
||||
err := writer.Output([]ReportResult{{
|
||||
API: "/api",
|
||||
}})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("test parameters", func(t *testing.T) {
|
||||
defer gock.Off()
|
||||
gock.New("https://test.com/result/post?username=1&pwd=2").Post("").Reply(http.StatusOK).JSON([]comment{})
|
||||
|
||||
parameters := map[string]string{
|
||||
"username": "1",
|
||||
"pwd": "2",
|
||||
}
|
||||
|
||||
writer := NewHTTPResultWriter("POST", "https://test.com/result/post", parameters, nil)
|
||||
|
||||
err := writer.Output([]ReportResult{{
|
||||
API: "/api",
|
||||
}})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("test user does not send template file", func(t *testing.T) {
|
||||
defer gock.Off()
|
||||
gock.New("https://test.com/result/post?username=1&pwd=2").Post("").Reply(http.StatusOK).JSON([]comment{})
|
||||
|
||||
parameters := map[string]string{
|
||||
"username": "1",
|
||||
"pwd": "2",
|
||||
}
|
||||
|
||||
writer := NewHTTPResultWriter("POST", "https://test.com/result/post", parameters, nil)
|
||||
|
||||
err := writer.Output([]ReportResult{{
|
||||
Name: "test",
|
||||
API: "/api",
|
||||
Count: 1,
|
||||
}})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("test user send template file", func(t *testing.T) {
|
||||
defer gock.Off()
|
||||
gock.New("https://test.com/result/post?username=1&pwd=2").Post("").Reply(http.StatusOK).JSON([]comment{})
|
||||
|
||||
parameters := map[string]string{
|
||||
"username": "1",
|
||||
"pwd": "2",
|
||||
}
|
||||
templateOption := NewTemplateOption("./writer_templates/example.tpl", "json")
|
||||
writer := NewHTTPResultWriter("POST", "https://test.com/result/post", parameters, templateOption)
|
||||
|
||||
err := writer.Output([]ReportResult{{
|
||||
Name: "test",
|
||||
API: "/api",
|
||||
Count: 1,
|
||||
}})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
[
|
||||
{{range $index, $result := .}}
|
||||
{
|
||||
"Name": "{{$result.Name}}",
|
||||
"API": "{{$result.API}}",
|
||||
"Count": {{$result.Count}},
|
||||
"Average": "{{$result.Average}}",
|
||||
"Max": "{{$result.Max}}",
|
||||
"Min": "{{$result.Min}}",
|
||||
"QPS": {{$result.QPS}},
|
||||
"Error": {{$result.Error}},
|
||||
"LastErrorMessage": "{{$result.LastErrorMessage}}"
|
||||
}
|
||||
{{end}}
|
||||
]
|
Loading…
Reference in New Issue