mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-12 02:21:29 +08:00
feat: har2case scaffold
This commit is contained in:
231
examples/demo.har
Normal file
231
examples/demo.har
Normal file
@@ -0,0 +1,231 @@
|
||||
{
|
||||
"log": {
|
||||
"version": "1.2",
|
||||
"creator": {
|
||||
"name": "Charles Proxy",
|
||||
"version": "4.6.1"
|
||||
},
|
||||
"entries": [
|
||||
{
|
||||
"startedDateTime": "2021-10-11T20:33:08.070+08:00",
|
||||
"time": 1348,
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"url": "https://postman-echo.com/get?foo1=Kie7p&foo2=34.5",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"cookies": [],
|
||||
"headers": [
|
||||
{
|
||||
"name": "Host",
|
||||
"value": "postman-echo.com"
|
||||
},
|
||||
{
|
||||
"name": "User-Agent",
|
||||
"value": "HttpBoomer"
|
||||
},
|
||||
{
|
||||
"name": "Accept-Encoding",
|
||||
"value": "gzip"
|
||||
}
|
||||
],
|
||||
"queryString": [
|
||||
{
|
||||
"name": "foo1",
|
||||
"value": "Kie7p"
|
||||
},
|
||||
{
|
||||
"name": "foo2",
|
||||
"value": "34.5"
|
||||
}
|
||||
],
|
||||
"headersSize": 113,
|
||||
"bodySize": 0
|
||||
},
|
||||
"response": {
|
||||
"_charlesStatus": "COMPLETE",
|
||||
"status": 200,
|
||||
"statusText": "OK",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"cookies": [
|
||||
{
|
||||
"name": "sails.sid",
|
||||
"value": "s%3AOf5eKs36eD8xIj5lio09zXrhVra1yPHo.PJyQYxoyPvXNUPal4Tj0OaJDLDJ7tZfZ%2BCL37XxD5Qg",
|
||||
"path": "/",
|
||||
"domain": null,
|
||||
"expires": null,
|
||||
"httpOnly": true,
|
||||
"secure": false,
|
||||
"comment": null,
|
||||
"_maxAge": null
|
||||
}
|
||||
],
|
||||
"headers": [
|
||||
{
|
||||
"name": "Date",
|
||||
"value": "Mon, 11 Oct 2021 12:33:09 GMT"
|
||||
},
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json; charset=utf-8"
|
||||
},
|
||||
{
|
||||
"name": "Content-Length",
|
||||
"value": "300"
|
||||
},
|
||||
{
|
||||
"name": "ETag",
|
||||
"value": "W/\"12c-R4rXPU4pP2zRVaUP5eVfknZVx78\""
|
||||
},
|
||||
{
|
||||
"name": "Vary",
|
||||
"value": "Accept-Encoding"
|
||||
},
|
||||
{
|
||||
"name": "set-cookie",
|
||||
"value": "sails.sid=s%3AOf5eKs36eD8xIj5lio09zXrhVra1yPHo.PJyQYxoyPvXNUPal4Tj0OaJDLDJ7tZfZ%2BCL37XxD5Qg; Path=/; HttpOnly"
|
||||
},
|
||||
{
|
||||
"name": "Connection",
|
||||
"value": "keep-alive"
|
||||
}
|
||||
],
|
||||
"content": {
|
||||
"size": 300,
|
||||
"mimeType": "application/json; charset=utf-8",
|
||||
"text": "eyJhcmdzIjp7ImZvbzEiOiJLaWU3cCIsImZvbzIiOiIzNC41In0sImhlYWRlcnMiOnsieC1mb3J3YXJkZWQtcHJvdG8iOiJodHRwcyIsIngtZm9yd2FyZGVkLXBvcnQiOiI0NDMiLCJob3N0IjoicG9zdG1hbi1lY2hvLmNvbSIsIngtYW16bi10cmFjZS1pZCI6IlJvb3Q9MS02MTY0MmYwNS0xOTZjNjZhNDUzYjEyNTk4NTNiYzc1NGMiLCJ1c2VyLWFnZW50IjoiSHR0cEJvb21lciIsImFjY2VwdC1lbmNvZGluZyI6Imd6aXAifSwidXJsIjoiaHR0cHM6Ly9wb3N0bWFuLWVjaG8uY29tL2dldD9mb28xPUtpZTdwJmZvbzI9MzQuNSJ9",
|
||||
"encoding": "base64"
|
||||
},
|
||||
"redirectURL": null,
|
||||
"headersSize": 0,
|
||||
"bodySize": 300
|
||||
},
|
||||
"serverIPAddress": "54.209.48.16",
|
||||
"cache": {},
|
||||
"timings": {
|
||||
"dns": 137,
|
||||
"connect": 938,
|
||||
"ssl": 579,
|
||||
"send": 1,
|
||||
"wait": 271,
|
||||
"receive": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"startedDateTime": "2021-10-11T20:33:09.646+08:00",
|
||||
"time": 273,
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://postman-echo.com/post",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"cookies": [
|
||||
{
|
||||
"name": "sails.sid",
|
||||
"value": "s%3AOf5eKs36eD8xIj5lio09zXrhVra1yPHo.PJyQYxoyPvXNUPal4Tj0OaJDLDJ7tZfZ%2BCL37XxD5Qg"
|
||||
}
|
||||
],
|
||||
"headers": [
|
||||
{
|
||||
"name": "Host",
|
||||
"value": "postman-echo.com"
|
||||
},
|
||||
{
|
||||
"name": "User-Agent",
|
||||
"value": "Go-http-client/1.1"
|
||||
},
|
||||
{
|
||||
"name": "Content-Length",
|
||||
"value": "28"
|
||||
},
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json; charset=UTF-8"
|
||||
},
|
||||
{
|
||||
"name": "Cookie",
|
||||
"value": "sails.sid=s%3AOf5eKs36eD8xIj5lio09zXrhVra1yPHo.PJyQYxoyPvXNUPal4Tj0OaJDLDJ7tZfZ%2BCL37XxD5Qg"
|
||||
},
|
||||
{
|
||||
"name": "Accept-Encoding",
|
||||
"value": "gzip"
|
||||
}
|
||||
],
|
||||
"queryString": [],
|
||||
"postData": {
|
||||
"mimeType": "application/json; charset=UTF-8",
|
||||
"text": "{\"foo1\":\"Kie7p\",\"foo2\":12.3}"
|
||||
},
|
||||
"headersSize": 271,
|
||||
"bodySize": 28
|
||||
},
|
||||
"response": {
|
||||
"_charlesStatus": "COMPLETE",
|
||||
"status": 200,
|
||||
"statusText": "OK",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"cookies": [
|
||||
{
|
||||
"name": "sails.sid",
|
||||
"value": "s%3A3unIFKLK0Hl_B2pdTkPkT7EfMFT-Haj4.IP8%2BW82GuC6rgKB3ftSTzeIuU06XtsL9MfK7MVk3ADE",
|
||||
"path": "/",
|
||||
"domain": null,
|
||||
"expires": null,
|
||||
"httpOnly": true,
|
||||
"secure": false,
|
||||
"comment": null,
|
||||
"_maxAge": null
|
||||
}
|
||||
],
|
||||
"headers": [
|
||||
{
|
||||
"name": "Date",
|
||||
"value": "Mon, 11 Oct 2021 12:33:09 GMT"
|
||||
},
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json; charset=utf-8"
|
||||
},
|
||||
{
|
||||
"name": "Content-Length",
|
||||
"value": "528"
|
||||
},
|
||||
{
|
||||
"name": "ETag",
|
||||
"value": "W/\"210-jFdmdcCipJ2EiYEjcIabSk/psPI\""
|
||||
},
|
||||
{
|
||||
"name": "Vary",
|
||||
"value": "Accept-Encoding"
|
||||
},
|
||||
{
|
||||
"name": "set-cookie",
|
||||
"value": "sails.sid=s%3A3unIFKLK0Hl_B2pdTkPkT7EfMFT-Haj4.IP8%2BW82GuC6rgKB3ftSTzeIuU06XtsL9MfK7MVk3ADE; Path=/; HttpOnly"
|
||||
},
|
||||
{
|
||||
"name": "Connection",
|
||||
"value": "keep-alive"
|
||||
}
|
||||
],
|
||||
"content": {
|
||||
"size": 528,
|
||||
"mimeType": "application/json; charset=utf-8",
|
||||
"text": "eyJhcmdzIjp7fSwiZGF0YSI6eyJmb28xIjoiS2llN3AiLCJmb28yIjoxMi4zfSwiZmlsZXMiOnt9LCJmb3JtIjp7fSwiaGVhZGVycyI6eyJ4LWZvcndhcmRlZC1wcm90byI6Imh0dHBzIiwieC1mb3J3YXJkZWQtcG9ydCI6IjQ0MyIsImhvc3QiOiJwb3N0bWFuLWVjaG8uY29tIiwieC1hbXpuLXRyYWNlLWlkIjoiUm9vdD0xLTYxNjQyZjA1LTExMTZkZmZlN2U0YTQ5ODg0NDBjMDI2NiIsImNvbnRlbnQtbGVuZ3RoIjoiMjgiLCJ1c2VyLWFnZW50IjoiR28taHR0cC1jbGllbnQvMS4xIiwiY29udGVudC10eXBlIjoiYXBwbGljYXRpb24vanNvbjsgY2hhcnNldD1VVEYtOCIsImNvb2tpZSI6InNhaWxzLnNpZD1zJTNBT2Y1ZUtzMzZlRDh4SWo1bGlvMDl6WHJoVnJhMXlQSG8uUEp5UVl4b3lQdlhOVVBhbDRUajBPYUpETERKN3RaZlolMkJDTDM3WHhENVFnIiwiYWNjZXB0LWVuY29kaW5nIjoiZ3ppcCJ9LCJqc29uIjp7ImZvbzEiOiJLaWU3cCIsImZvbzIiOjEyLjN9LCJ1cmwiOiJodHRwczovL3Bvc3RtYW4tZWNoby5jb20vcG9zdCJ9",
|
||||
"encoding": "base64"
|
||||
},
|
||||
"redirectURL": null,
|
||||
"headersSize": 0,
|
||||
"bodySize": 528
|
||||
},
|
||||
"serverIPAddress": "54.209.48.16",
|
||||
"cache": {},
|
||||
"timings": {
|
||||
"dns": -1,
|
||||
"connect": -1,
|
||||
"ssl": -1,
|
||||
"send": 0,
|
||||
"wait": 272,
|
||||
"receive": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
169
har2case/core.go
169
har2case/core.go
@@ -1,7 +1,14 @@
|
||||
package har2case
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/httprunner/httpboomer"
|
||||
)
|
||||
@@ -21,7 +28,10 @@ type HAR struct {
|
||||
func (h *HAR) GenJSON() (jsonPath string, err error) {
|
||||
jsonPath = getFilenameWithoutExtension(h.path) + ".json"
|
||||
|
||||
tCase := h.makeTestCase()
|
||||
tCase, err := h.makeTestCase()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = tCase.Dump2JSON(jsonPath)
|
||||
return
|
||||
}
|
||||
@@ -29,16 +39,46 @@ func (h *HAR) GenJSON() (jsonPath string, err error) {
|
||||
func (h *HAR) GenYAML() (yamlPath string, err error) {
|
||||
yamlPath = getFilenameWithoutExtension(h.path) + ".yaml"
|
||||
|
||||
tCase := h.makeTestCase()
|
||||
tCase, err := h.makeTestCase()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = tCase.Dump2YAML(yamlPath)
|
||||
return
|
||||
}
|
||||
|
||||
func (h *HAR) makeTestCase() *httpboomer.TCase {
|
||||
return &httpboomer.TCase{
|
||||
Config: *h.prepareConfig(),
|
||||
TestSteps: h.prepareTestSteps(),
|
||||
func (h *HAR) makeTestCase() (*httpboomer.TCase, error) {
|
||||
teststeps, err := h.prepareTestSteps()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tCase := &httpboomer.TCase{
|
||||
Config: *h.prepareConfig(),
|
||||
TestSteps: teststeps,
|
||||
}
|
||||
return tCase, nil
|
||||
}
|
||||
|
||||
func (h *HAR) load() (*Har, error) {
|
||||
fp, err := os.Open(h.path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("open: %w", err)
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadAll(fp)
|
||||
fp.Close()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read: %w", err)
|
||||
}
|
||||
|
||||
har := &Har{}
|
||||
err = json.Unmarshal(data, har)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("json.Unmarshal error: %w", err)
|
||||
}
|
||||
|
||||
return har, nil
|
||||
}
|
||||
|
||||
func (h *HAR) prepareConfig() *httpboomer.TConfig {
|
||||
@@ -49,9 +89,122 @@ func (h *HAR) prepareConfig() *httpboomer.TConfig {
|
||||
}
|
||||
}
|
||||
|
||||
func (h *HAR) prepareTestSteps() []*httpboomer.TStep {
|
||||
func (h *HAR) prepareTestSteps() ([]*httpboomer.TStep, error) {
|
||||
har, err := h.load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var steps []*httpboomer.TStep
|
||||
return steps
|
||||
for _, entry := range har.Log.Entries {
|
||||
step, err := h.prepareTestStep(&entry)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
steps = append(steps, step)
|
||||
}
|
||||
|
||||
return steps, nil
|
||||
}
|
||||
|
||||
func (h *HAR) prepareTestStep(entry *Entry) (*httpboomer.TStep, error) {
|
||||
tStep := &TStep{
|
||||
TStep: httpboomer.TStep{
|
||||
Request: &httpboomer.TRequest{},
|
||||
Validators: make([]httpboomer.TValidator, 0),
|
||||
},
|
||||
}
|
||||
if err := tStep.makeRequestMethod(entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := tStep.makeRequestURL(entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := tStep.makeRequestParams(entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := tStep.makeRequestCookies(entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := tStep.makeRequestHeaders(entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := tStep.makeRequestBody(entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := tStep.makeValidate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tStep.TStep, nil
|
||||
}
|
||||
|
||||
type TStep struct {
|
||||
httpboomer.TStep
|
||||
}
|
||||
|
||||
func (s *TStep) makeRequestMethod(entry *Entry) error {
|
||||
s.Request.Method = httpboomer.EnumHTTPMethod(entry.Request.Method)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *TStep) makeRequestURL(entry *Entry) error {
|
||||
|
||||
u, err := url.Parse(entry.Request.URL)
|
||||
if err != nil {
|
||||
log.Printf("makeRequestURL error: %v", err)
|
||||
return err
|
||||
}
|
||||
s.Request.URL = fmt.Sprintf("%s://%s", u.Scheme, u.Hostname()+u.Path)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *TStep) makeRequestParams(entry *Entry) error {
|
||||
s.Request.Params = make(map[string]interface{})
|
||||
for _, param := range entry.Request.QueryString {
|
||||
s.Request.Params[param.Name] = param.Value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *TStep) makeRequestCookies(entry *Entry) error {
|
||||
s.Request.Cookies = make(map[string]string)
|
||||
for _, cookie := range entry.Request.Cookies {
|
||||
s.Request.Cookies[cookie.Name] = cookie.Value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *TStep) makeRequestHeaders(entry *Entry) error {
|
||||
s.Request.Headers = make(map[string]string)
|
||||
for _, header := range entry.Request.Headers {
|
||||
if strings.EqualFold(header.Name, "cookie") {
|
||||
continue
|
||||
}
|
||||
s.Request.Headers[header.Name] = header.Value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *TStep) makeRequestBody(entry *Entry) error {
|
||||
mimeType := entry.Request.PostData.MimeType
|
||||
if strings.HasPrefix(mimeType, "application/json") {
|
||||
// post json
|
||||
var data interface{}
|
||||
err := json.Unmarshal([]byte(entry.Request.PostData.Text), &data)
|
||||
if err != nil {
|
||||
log.Printf("makeRequestBody error: %v", err)
|
||||
return err
|
||||
}
|
||||
s.Request.Data = data
|
||||
} else if strings.HasPrefix(mimeType, "application/x-www-form-urlencoded") {
|
||||
// TODO: post form data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *TStep) makeValidate() error {
|
||||
s.Validators = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func getFilenameWithoutExtension(path string) string {
|
||||
|
||||
@@ -4,12 +4,14 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var harPath string
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
harPath = "demo.har"
|
||||
harPath = "../examples/demo.har"
|
||||
|
||||
// run all tests
|
||||
code := m.Run()
|
||||
@@ -21,4 +23,71 @@ func TestMain(m *testing.M) {
|
||||
func TestGenJSON(t *testing.T) {
|
||||
jsonPath, err := NewHAR(harPath).GenJSON()
|
||||
log.Printf("jsonPath: %v, err: %v", jsonPath, err)
|
||||
if !assert.NoError(t, err) {
|
||||
t.Fail()
|
||||
}
|
||||
if !assert.NotEmpty(t, jsonPath) {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadHAR(t *testing.T) {
|
||||
har := NewHAR(harPath)
|
||||
h, err := har.load()
|
||||
if !assert.NoError(t, err) {
|
||||
t.Fail()
|
||||
}
|
||||
if !assert.Equal(t, "GET", h.Log.Entries[0].Request.Method) {
|
||||
t.Fail()
|
||||
}
|
||||
if !assert.Equal(t, "POST", h.Log.Entries[1].Request.Method) {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestMakeTestCase(t *testing.T) {
|
||||
har := NewHAR(harPath)
|
||||
tCase, err := har.makeTestCase()
|
||||
if !assert.NoError(t, err) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
// make request method
|
||||
if !assert.EqualValues(t, "GET", tCase.TestSteps[0].Request.Method) {
|
||||
t.Fail()
|
||||
}
|
||||
if !assert.EqualValues(t, "POST", tCase.TestSteps[1].Request.Method) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
// make request url
|
||||
if !assert.Equal(t, "https://postman-echo.com/get", tCase.TestSteps[0].Request.URL) {
|
||||
t.Fail()
|
||||
}
|
||||
if !assert.Equal(t, "https://postman-echo.com/post", tCase.TestSteps[1].Request.URL) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
// make request params
|
||||
if !assert.Equal(t, "Kie7p", tCase.TestSteps[0].Request.Params["foo1"]) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
// make request cookies
|
||||
if !assert.NotEmpty(t, tCase.TestSteps[1].Request.Cookies["sails.sid"]) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
// make request headers
|
||||
if !assert.Equal(t, "HttpBoomer", tCase.TestSteps[0].Request.Headers["User-Agent"]) {
|
||||
t.Fail()
|
||||
}
|
||||
if !assert.Equal(t, "postman-echo.com", tCase.TestSteps[0].Request.Headers["Host"]) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
// make request data
|
||||
if !assert.Equal(t, map[string]interface{}{"foo1": "Kie7p", "foo2": 12.3}, tCase.TestSteps[1].Request.Data) {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
340
har2case/har.go
Normal file
340
har2case/har.go
Normal file
@@ -0,0 +1,340 @@
|
||||
package har2case
|
||||
|
||||
import "time"
|
||||
|
||||
/*
|
||||
HTTP Archive (HAR) format
|
||||
https://w3c.github.io/web-performance/specs/HAR/Overview.html
|
||||
this file is copied from https://github.com/mrichman/hargo/blob/master/types.go
|
||||
*/
|
||||
|
||||
// Har is a container type for deserialization
|
||||
type Har struct {
|
||||
Log Log `json:"log"`
|
||||
}
|
||||
|
||||
// Log represents the root of the exported data. This object MUST be present and its name MUST be "log".
|
||||
type Log struct {
|
||||
// The object contains the following name/value pairs:
|
||||
|
||||
// Required. Version number of the format.
|
||||
Version string `json:"version"`
|
||||
// Required. An object of type creator that contains the name and version
|
||||
// information of the log creator application.
|
||||
Creator Creator `json:"creator"`
|
||||
// Optional. An object of type browser that contains the name and version
|
||||
// information of the user agent.
|
||||
Browser Browser `json:"browser"`
|
||||
// Optional. An array of objects of type page, each representing one exported
|
||||
// (tracked) page. Leave out this field if the application does not support
|
||||
// grouping by pages.
|
||||
Pages []Page `json:"pages,omitempty"`
|
||||
// Required. An array of objects of type entry, each representing one
|
||||
// exported (tracked) HTTP request.
|
||||
Entries []Entry `json:"entries"`
|
||||
// Optional. A comment provided by the user or the application. Sorting
|
||||
// entries by startedDateTime (starting from the oldest) is preferred way how
|
||||
// to export data since it can make importing faster. However the reader
|
||||
// application should always make sure the array is sorted (if required for
|
||||
// the import).
|
||||
Comment string `json:"comment"`
|
||||
}
|
||||
|
||||
// Creator contains information about the log creator application
|
||||
type Creator struct {
|
||||
// Required. The name of the application that created the log.
|
||||
Name string `json:"name"`
|
||||
// Required. The version number of the application that created the log.
|
||||
Version string `json:"version"`
|
||||
// Optional. A comment provided by the user or the application.
|
||||
Comment string `json:"comment,omitempty"`
|
||||
}
|
||||
|
||||
// Browser that created the log
|
||||
type Browser struct {
|
||||
// Required. The name of the browser that created the log.
|
||||
Name string `json:"name"`
|
||||
// Required. The version number of the browser that created the log.
|
||||
Version string `json:"version"`
|
||||
// Optional. A comment provided by the user or the browser.
|
||||
Comment string `json:"comment"`
|
||||
}
|
||||
|
||||
// Page object for every exported web page and one <entry> object for every HTTP request.
|
||||
// In case when an HTTP trace tool isn't able to group requests by a page,
|
||||
// the <pages> object is empty and individual requests doesn't have a parent page.
|
||||
type Page struct {
|
||||
/* There is one <page> object for every exported web page and one <entry>
|
||||
object for every HTTP request. In case when an HTTP trace tool isn't able to
|
||||
group requests by a page, the <pages> object is empty and individual
|
||||
requests doesn't have a parent page.
|
||||
*/
|
||||
|
||||
// Date and time stamp for the beginning of the page load
|
||||
// (ISO 8601 YYYY-MM-DDThh:mm:ss.sTZD, e.g. 2009-07-24T19:20:30.45+01:00).
|
||||
StartedDateTime string `json:"startedDateTime"`
|
||||
// Unique identifier of a page within the . Entries use it to refer the parent page.
|
||||
ID string `json:"id"`
|
||||
// Page title.
|
||||
Title string `json:"title"`
|
||||
// Detailed timing info about page load.
|
||||
PageTiming PageTiming `json:"pageTiming"`
|
||||
// (new in 1.2) A comment provided by the user or the application.
|
||||
Comment string `json:"comment,omitempty"`
|
||||
}
|
||||
|
||||
// PageTiming describes timings for various events (states) fired during the page load.
|
||||
// All times are specified in milliseconds. If a time info is not available appropriate field is set to -1.
|
||||
type PageTiming struct {
|
||||
// Content of the page loaded. Number of milliseconds since page load started
|
||||
// (page.startedDateTime). Use -1 if the timing does not apply to the current
|
||||
// request.
|
||||
// Depeding on the browser, onContentLoad property represents DOMContentLoad
|
||||
// event or document.readyState == interactive.
|
||||
OnContentLoad int `json:"onContentLoad"`
|
||||
// Page is loaded (onLoad event fired). Number of milliseconds since page
|
||||
// load started (page.startedDateTime). Use -1 if the timing does not apply
|
||||
// to the current request.
|
||||
OnLoad int `json:"onLoad"`
|
||||
// (new in 1.2) A comment provided by the user or the application.
|
||||
Comment string `json:"comment"`
|
||||
}
|
||||
|
||||
// Entry is a unique, optional Reference to the parent page.
|
||||
// Leave out this field if the application does not support grouping by pages.
|
||||
type Entry struct {
|
||||
Pageref string `json:"pageref,omitempty"`
|
||||
// Date and time stamp of the request start
|
||||
// (ISO 8601 YYYY-MM-DDThh:mm:ss.sTZD).
|
||||
StartedDateTime string `json:"startedDateTime"`
|
||||
// Total elapsed time of the request in milliseconds. This is the sum of all
|
||||
// timings available in the timings object (i.e. not including -1 values) .
|
||||
Time float32 `json:"time"`
|
||||
// Detailed info about the request.
|
||||
Request Request `json:"request"`
|
||||
// Detailed info about the response.
|
||||
Response Response `json:"response"`
|
||||
// Info about cache usage.
|
||||
Cache Cache `json:"cache"`
|
||||
// Detailed timing info about request/response round trip.
|
||||
PageTimings PageTimings `json:"pageTimings"`
|
||||
// optional (new in 1.2) IP address of the server that was connected
|
||||
// (result of DNS resolution).
|
||||
ServerIPAddress string `json:"serverIPAddress,omitempty"`
|
||||
// optional (new in 1.2) Unique ID of the parent TCP/IP connection, can be
|
||||
// the client port number. Note that a port number doesn't have to be unique
|
||||
// identifier in cases where the port is shared for more connections. If the
|
||||
// port isn't available for the application, any other unique connection ID
|
||||
// can be used instead (e.g. connection index). Leave out this field if the
|
||||
// application doesn't support this info.
|
||||
Connection string `json:"connection,omitempty"`
|
||||
// (new in 1.2) A comment provided by the user or the application.
|
||||
Comment string `json:"comment,omitempty"`
|
||||
}
|
||||
|
||||
// Request contains detailed info about performed request.
|
||||
type Request struct {
|
||||
// Request method (GET, POST, ...).
|
||||
Method string `json:"method"`
|
||||
// Absolute URL of the request (fragments are not included).
|
||||
URL string `json:"url"`
|
||||
// Request HTTP Version.
|
||||
HTTPVersion string `json:"httpVersion"`
|
||||
// List of cookie objects.
|
||||
Cookies []Cookie `json:"cookies"`
|
||||
// List of header objects.
|
||||
Headers []NVP `json:"headers"`
|
||||
// List of query parameter objects.
|
||||
QueryString []NVP `json:"queryString"`
|
||||
// Posted data.
|
||||
PostData PostData `json:"postData"`
|
||||
// Total number of bytes from the start of the HTTP request message until
|
||||
// (and including) the double CRLF before the body. Set to -1 if the info
|
||||
// is not available.
|
||||
HeaderSize int `json:"headerSize"`
|
||||
// Size of the request body (POST data payload) in bytes. Set to -1 if the
|
||||
// info is not available.
|
||||
BodySize int `json:"bodySize"`
|
||||
// (new in 1.2) A comment provided by the user or the application.
|
||||
Comment string `json:"comment"`
|
||||
}
|
||||
|
||||
// Response contains detailed info about the response.
|
||||
type Response struct {
|
||||
// Response status.
|
||||
Status int `json:"status"`
|
||||
// Response status description.
|
||||
StatusText string `json:"statusText"`
|
||||
// Response HTTP Version.
|
||||
HTTPVersion string `json:"httpVersion"`
|
||||
// List of cookie objects.
|
||||
Cookies []Cookie `json:"cookies"`
|
||||
// List of header objects.
|
||||
Headers []NVP `json:"headers"`
|
||||
// Details about the response body.
|
||||
Content Content `json:"content"`
|
||||
// Redirection target URL from the Location response header.
|
||||
RedirectURL string `json:"redirectURL"`
|
||||
// Total number of bytes from the start of the HTTP response message until
|
||||
// (and including) the double CRLF before the body. Set to -1 if the info is
|
||||
// not available.
|
||||
// The size of received response-headers is computed only from headers that
|
||||
// are really received from the server. Additional headers appended by the
|
||||
// browser are not included in this number, but they appear in the list of
|
||||
// header objects.
|
||||
HeadersSize int `json:"headersSize"`
|
||||
// Size of the received response body in bytes. Set to zero in case of
|
||||
// responses coming from the cache (304). Set to -1 if the info is not
|
||||
// available.
|
||||
BodySize int `json:"bodySize"`
|
||||
// optional (new in 1.2) A comment provided by the user or the application.
|
||||
Comment string `json:"comment,omitempty"`
|
||||
}
|
||||
|
||||
// Cookie contains list of all cookies (used in <request> and <response> objects).
|
||||
type Cookie struct {
|
||||
// The name of the cookie.
|
||||
Name string `json:"name"`
|
||||
// The cookie value.
|
||||
Value string `json:"value"`
|
||||
// optional The path pertaining to the cookie.
|
||||
Path string `json:"path,omitempty"`
|
||||
// optional The host of the cookie.
|
||||
Domain string `json:"domain,omitempty"`
|
||||
// optional Cookie expiration time.
|
||||
// (ISO 8601 YYYY-MM-DDThh:mm:ss.sTZD, e.g. 2009-07-24T19:20:30.123+02:00).
|
||||
Expires string `json:"expires,omitempty"`
|
||||
// optional Set to true if the cookie is HTTP only, false otherwise.
|
||||
HTTPOnly bool `json:"httpOnly,omitempty"`
|
||||
// optional (new in 1.2) True if the cookie was transmitted over ssl, false
|
||||
// otherwise.
|
||||
Secure bool `json:"secure,omitempty"`
|
||||
// optional (new in 1.2) A comment provided by the user or the application.
|
||||
Comment bool `json:"comment,omitempty"`
|
||||
}
|
||||
|
||||
// NVP is simply a name/value pair with a comment
|
||||
type NVP struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
Comment string `json:"comment,omitempty"`
|
||||
}
|
||||
|
||||
// PostData describes posted data, if any (embedded in <request> object).
|
||||
type PostData struct {
|
||||
// Mime type of posted data.
|
||||
MimeType string `json:"mimeType"`
|
||||
// List of posted parameters (in case of URL encoded parameters).
|
||||
Params []PostParam `json:"params"`
|
||||
// Plain text posted data
|
||||
Text string `json:"text"`
|
||||
// optional (new in 1.2) A comment provided by the user or the
|
||||
// application.
|
||||
Comment string `json:"comment,omitempty"`
|
||||
}
|
||||
|
||||
// PostParam is a list of posted parameters, if any (embedded in <postData> object).
|
||||
type PostParam struct {
|
||||
// name of a posted parameter.
|
||||
Name string `json:"name"`
|
||||
// optional value of a posted parameter or content of a posted file.
|
||||
Value string `json:"value,omitempty"`
|
||||
// optional name of a posted file.
|
||||
FileName string `json:"fileName,omitempty"`
|
||||
// optional content type of a posted file.
|
||||
ContentType string `json:"contentType,omitempty"`
|
||||
// optional (new in 1.2) A comment provided by the user or the application.
|
||||
Comment string `json:"comment,omitempty"`
|
||||
}
|
||||
|
||||
// Content describes details about response content (embedded in <response> object).
|
||||
type Content struct {
|
||||
// Length of the returned content in bytes. Should be equal to
|
||||
// response.bodySize if there is no compression and bigger when the content
|
||||
// has been compressed.
|
||||
Size int `json:"size"`
|
||||
// optional Number of bytes saved. Leave out this field if the information
|
||||
// is not available.
|
||||
Compression int `json:"compression,omitempty"`
|
||||
// MIME type of the response text (value of the Content-Type response
|
||||
// header). The charset attribute of the MIME type is included (if
|
||||
// available).
|
||||
MimeType string `json:"mimeType"`
|
||||
// optional Response body sent from the server or loaded from the browser
|
||||
// cache. This field is populated with textual content only. The text field
|
||||
// is either HTTP decoded text or a encoded (e.g. "base64") representation of
|
||||
// the response body. Leave out this field if the information is not
|
||||
// available.
|
||||
Text string `json:"text,omitempty"`
|
||||
// optional (new in 1.2) Encoding used for response text field e.g
|
||||
// "base64". Leave out this field if the text field is HTTP decoded
|
||||
// (decompressed & unchunked), than trans-coded from its original character
|
||||
// set into UTF-8.
|
||||
Encoding string `json:"encoding,omitempty"`
|
||||
// optional (new in 1.2) A comment provided by the user or the application.
|
||||
Comment string `json:"comment,omitempty"`
|
||||
}
|
||||
|
||||
// Cache contains info about a request coming from browser cache.
|
||||
type Cache struct {
|
||||
// optional State of a cache entry before the request. Leave out this field
|
||||
// if the information is not available.
|
||||
BeforeRequest CacheObject `json:"beforeRequest,omitempty"`
|
||||
// optional State of a cache entry after the request. Leave out this field if
|
||||
// the information is not available.
|
||||
AfterRequest CacheObject `json:"afterRequest,omitempty"`
|
||||
// optional (new in 1.2) A comment provided by the user or the application.
|
||||
Comment string `json:"comment,omitempty"`
|
||||
}
|
||||
|
||||
// CacheObject is used by both beforeRequest and afterRequest
|
||||
type CacheObject struct {
|
||||
// optional - Expiration time of the cache entry.
|
||||
Expires string `json:"expires,omitempty"`
|
||||
// The last time the cache entry was opened.
|
||||
LastAccess string `json:"lastAccess"`
|
||||
// Etag
|
||||
ETag string `json:"eTag"`
|
||||
// The number of times the cache entry has been opened.
|
||||
HitCount int `json:"hitCount"`
|
||||
// optional (new in 1.2) A comment provided by the user or the application.
|
||||
Comment string `json:"comment,omitempty"`
|
||||
}
|
||||
|
||||
// PageTimings describes various phases within request-response round trip.
|
||||
// All times are specified in milliseconds.
|
||||
type PageTimings struct {
|
||||
Blocked int `json:"blocked,omitempty"`
|
||||
// optional - Time spent in a queue waiting for a network connection. Use -1
|
||||
// if the timing does not apply to the current request.
|
||||
DNS int `json:"dns,omitempty"`
|
||||
// optional - DNS resolution time. The time required to resolve a host name.
|
||||
// Use -1 if the timing does not apply to the current request.
|
||||
Connect int `json:"connect,omitempty"`
|
||||
// optional - Time required to create TCP connection. Use -1 if the timing
|
||||
// does not apply to the current request.
|
||||
Send int `json:"send"`
|
||||
// Time required to send HTTP request to the server.
|
||||
Wait int `json:"wait"`
|
||||
// Waiting for a response from the server.
|
||||
Receive int `json:"receive"`
|
||||
// Time required to read entire response from the server (or cache).
|
||||
Ssl int `json:"ssl,omitempty"`
|
||||
// optional (new in 1.2) - Time required for SSL/TLS negotiation. If this
|
||||
// field is defined then the time is also included in the connect field (to
|
||||
// ensure backward compatibility with HAR 1.1). Use -1 if the timing does not
|
||||
// apply to the current request.
|
||||
Comment string `json:"comment,omitempty"`
|
||||
// optional (new in 1.2) - A comment provided by the user or the application.
|
||||
}
|
||||
|
||||
// TestResult contains results for an individual HTTP request
|
||||
type TestResult struct {
|
||||
URL string `json:"url"`
|
||||
Status int `json:"status"` // 200, 500, etc.
|
||||
StartTime time.Time `json:"startTime"`
|
||||
EndTime time.Time `json:"endTime"`
|
||||
Latency int `json:"latency"` // milliseconds
|
||||
Method string `json:"method"`
|
||||
HarFile string `json:"harfile"`
|
||||
}
|
||||
1
httpboomer/README.md
Normal file
1
httpboomer/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# httpboomer cli
|
||||
18
models.go
18
models.go
@@ -1,15 +1,15 @@
|
||||
package httpboomer
|
||||
|
||||
type enumHTTPMethod string
|
||||
type EnumHTTPMethod string
|
||||
|
||||
const (
|
||||
GET enumHTTPMethod = "GET"
|
||||
HEAD enumHTTPMethod = "HEAD"
|
||||
POST enumHTTPMethod = "POST"
|
||||
PUT enumHTTPMethod = "PUT"
|
||||
DELETE enumHTTPMethod = "DELETE"
|
||||
OPTIONS enumHTTPMethod = "OPTIONS"
|
||||
PATCH enumHTTPMethod = "PATCH"
|
||||
GET EnumHTTPMethod = "GET"
|
||||
HEAD EnumHTTPMethod = "HEAD"
|
||||
POST EnumHTTPMethod = "POST"
|
||||
PUT EnumHTTPMethod = "PUT"
|
||||
DELETE EnumHTTPMethod = "DELETE"
|
||||
OPTIONS EnumHTTPMethod = "OPTIONS"
|
||||
PATCH EnumHTTPMethod = "PATCH"
|
||||
)
|
||||
|
||||
type TConfig struct {
|
||||
@@ -23,7 +23,7 @@ type TConfig struct {
|
||||
}
|
||||
|
||||
type TRequest struct {
|
||||
Method enumHTTPMethod `json:"method" yaml:"method"`
|
||||
Method EnumHTTPMethod `json:"method" yaml:"method"`
|
||||
URL string `json:"url" yaml:"url"`
|
||||
Params map[string]interface{} `json:"params,omitempty" yaml:"params,omitempty"`
|
||||
Headers map[string]string `json:"headers,omitempty" yaml:"headers,omitempty"`
|
||||
|
||||
Reference in New Issue
Block a user