From 700cdfd815bc70c4e841abfbdb9c21ecb973947c Mon Sep 17 00:00:00 2001 From: debugtalk Date: Mon, 27 Jun 2022 00:25:32 +0800 Subject: [PATCH 1/6] refactor: simplify testcase converter --- docs/CHANGELOG.md | 1 + hrp/internal/convert/converter.go | 276 +++++++----------- hrp/internal/convert/converter_har.go | 109 ++----- hrp/internal/convert/converter_har_test.go | 117 +------- hrp/internal/convert/converter_json.go | 73 +---- hrp/internal/convert/converter_postman.go | 121 ++------ .../convert/converter_postman_test.go | 72 +---- hrp/internal/convert/converter_pytest.go | 39 --- hrp/internal/convert/converter_swagger.go | 26 ++ hrp/internal/convert/converter_yaml.go | 64 +--- 10 files changed, 228 insertions(+), 670 deletions(-) create mode 100644 hrp/internal/convert/converter_swagger.go diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 0bda2b7d..ff38210a 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -12,6 +12,7 @@ - fix: failed to load json/data content in api reference - fix: failed to convert postman collection containing multipart/form-data requests to pytest - fix: only get the first parameter in referenced testcase +- refactor: simplify testcase converter **python version** diff --git a/hrp/internal/convert/converter.go b/hrp/internal/convert/converter.go index 107afa15..7bb11ed9 100644 --- a/hrp/internal/convert/converter.go +++ b/hrp/internal/convert/converter.go @@ -4,9 +4,7 @@ import ( _ "embed" "fmt" "path/filepath" - "reflect" - "github.com/go-openapi/spec" "github.com/pkg/errors" "github.com/rs/zerolog/log" @@ -15,6 +13,7 @@ import ( "github.com/httprunner/httprunner/v4/hrp/internal/sdk" ) +// target testcase format extensions const ( suffixJSON = ".json" suffixYAML = ".yaml" @@ -83,15 +82,11 @@ func (outputType OutputType) String() string { // TCaseConverter holds the common properties of case converter type TCaseConverter struct { - InputPath string - OutputDir string - Profile *Profile - InputType InputType - OutputType OutputType - CaseHAR *CaseHar - CasePostman *CasePostman - CaseSwagger *spec.Swagger - TCase *hrp.TCase + InputPath string + OutputDir string + InputType InputType + OutputType OutputType + TCase *hrp.TCase } // Profile is used to override or update(create if not existed) original headers and cookies @@ -101,102 +96,64 @@ type Profile struct { Cookies map[string]string `json:"cookies" yaml:"cookies"` } -func NewTCaseConverter(path string) (tCaseConverter *TCaseConverter) { - tCaseConverter = &TCaseConverter{ - InputPath: path, - InputType: InputTypeUnknown, - } +// LoadTCase loads source file and convert to TCase type +func LoadTCase(path string) (*hrp.TCase, error) { extName := filepath.Ext(path) if extName == "" { - log.Warn().Msg("extension name should be specified") - return + return nil, errors.New("file extension is not specified") } - var err error switch extName { case ".har": - caseHAR := new(CaseHar) - err = builtin.LoadFile(path, caseHAR) - if err == nil && !reflect.ValueOf(*caseHAR).IsZero() { - tCaseConverter.InputType = InputTypeHAR - tCaseConverter.CaseHAR = caseHAR + tCase, err := LoadHARCase(path) + if err != nil { + return nil, err } + return tCase, nil case ".json": - tCase := new(hrp.TCase) - err = builtin.LoadFile(path, tCase) - if err == nil && !reflect.ValueOf(*tCase).IsZero() { - tCaseConverter.InputType = InputTypeJSON - tCaseConverter.TCase = tCase - break + // priority: hrp JSON case > postman > swagger + // check if hrp JSON case + tCase, err := LoadJSONCase(path) + if err == nil { + return tCase, nil } - casePostman := new(CasePostman) - err = builtin.LoadFile(path, casePostman) - // deal with postman field name conflict with swagger - descriptionBackup := casePostman.Info.Description - casePostman.Info.Description = "" - if err == nil && !reflect.ValueOf(*casePostman).IsZero() { - tCaseConverter.InputType = InputTypePostman - casePostman.Info.Description = descriptionBackup - tCaseConverter.CasePostman = casePostman - break + + // check if postman format + casePostman, err := LoadPostmanCase(path) + if err == nil { + return casePostman, nil } - caseSwagger := new(spec.Swagger) - err = builtin.LoadFile(path, caseSwagger) - if err == nil && !reflect.ValueOf(*caseSwagger).IsZero() { - tCaseConverter.InputType = InputTypeSwagger - tCaseConverter.CaseSwagger = caseSwagger + + // check if swagger format + caseSwagger, err := LoadSwaggerCase(path) + if err == nil { + return caseSwagger, nil } + + return nil, errors.New("unexpected JSON format") case ".yaml", ".yml": - tCase := new(hrp.TCase) - err = builtin.LoadFile(path, tCase) - if err == nil && !reflect.ValueOf(*tCase).IsZero() { - tCaseConverter.InputType = InputTypeYAML - tCaseConverter.TCase = tCase - break + // priority: hrp YAML case > swagger + // check if hrp YAML case + tCase, err := NewYAMLCase(path) + if err == nil { + return tCase, nil } - caseSwagger := new(spec.Swagger) - err = builtin.LoadFile(path, caseSwagger) - if err == nil && !reflect.ValueOf(*caseSwagger).IsZero() { - tCaseConverter.InputType = InputTypeSwagger - tCaseConverter.CaseSwagger = caseSwagger + + // check if swagger format + caseSwagger, err := LoadSwaggerCase(path) + if err == nil { + return caseSwagger, nil } + + return nil, errors.New("unexpected YAML format") case ".go": // TODO - tCaseConverter.InputType = InputTypeGoTest + return nil, errors.New("convert gotest is not implemented") case ".py": // TODO - tCaseConverter.InputType = InputTypePyTest + return nil, errors.New("convert pytest is not implemented") case ".jmx": // TODO - tCaseConverter.InputType = InputTypeJMeter - default: - log.Warn(). - Str("input path", tCaseConverter.InputPath). - Msgf("unsupported file type: %v", extName) + return nil, errors.New("convert JMeter jmx is not implemented") } - if tCaseConverter.InputType != InputTypeUnknown { - log.Info(). - Str("input path", tCaseConverter.InputPath). - Msgf("load case as: %s", tCaseConverter.InputType.String()) - } else { - log.Error().Err(err). - Str("input path", tCaseConverter.InputPath). - Msgf("failed to load case") - } - return -} -func (c *TCaseConverter) SetProfile(path string) { - log.Info().Str("input path", c.InputPath).Str("profile", path).Msg("set profile") - profile := new(Profile) - err := builtin.LoadFile(path, profile) - if err != nil { - log.Warn().Str("path", path). - Msg("failed to load profile, ignore!") - return - } - c.Profile = profile -} - -func (c *TCaseConverter) SetOutputDir(dir string) { - log.Info().Str("input path", c.InputPath).Str("output directory", dir).Msg("set output directory") - c.OutputDir = dir + return nil, fmt.Errorf("unsupported file type: %v", extName) } func (c *TCaseConverter) genOutputPath(suffix string) string { @@ -209,40 +166,39 @@ func (c *TCaseConverter) genOutputPath(suffix string) string { // TODO avoid outFileFullName conflict? } +// convert TCase to pytest case func (c *TCaseConverter) ToPyTest() (string, error) { - script := convertConfig(c.TCase.Config) - println(script) - return script, nil -} - -func convertConfig(config *hrp.TConfig) string { - script := fmt.Sprintf("Config('%s')", config.Name) - - if config.Variables != nil { - script += fmt.Sprintf(".variables(**{%v})", config.Variables) - } - if config.BaseURL != "" { - script += fmt.Sprintf(".base_url('%s')", config.BaseURL) - } - if config.Export != nil { - script += fmt.Sprintf(".export(*%v)", config.Export) - } - script += fmt.Sprintf(".verify(%v)", config.Verify) - - return script + args := append([]string{"make"}, c.InputPath) + err := builtin.ExecPython3Command("httprunner", args...) + if err != nil { + return "", err + } + return c.genOutputPath(suffixPyTest), nil } +// TODO: convert TCase to gotest case func (c *TCaseConverter) ToGoTest() (string, error) { return "", nil } -// ICaseConverter represents all kinds of case converters which could convert case into JSON/YAML/gotest/pytest format -type ICaseConverter interface { - Struct() *TCaseConverter - ToJSON() (string, error) - ToYAML() (string, error) - ToGoTest() (string, error) - ToPyTest() (string, error) +// convert TCase to JSON case +func (c *TCaseConverter) ToJSON() (string, error) { + jsonPath := c.genOutputPath(suffixJSON) + err := builtin.Dump2JSON(c.TCase, jsonPath) + if err != nil { + return "", err + } + return jsonPath, nil +} + +// convert TCase to YAML case +func (c *TCaseConverter) ToYAML() (string, error) { + yamlPath := c.genOutputPath(suffixYAML) + err := builtin.Dump2YAML(c.TCase, yamlPath) + if err != nil { + return "", err + } + return yamlPath, nil } func Run(outputType OutputType, outputDir, profilePath string, args []string) { @@ -252,57 +208,40 @@ func Run(outputType OutputType, outputDir, profilePath string, args []string) { Action: fmt.Sprintf("hrp convert --to-%s", outputType.String()), }) - // identify input and load converters - var iCaseConverters []ICaseConverter - for _, arg := range args { - tCaseConverter := NewTCaseConverter(arg) - tCaseConverter.OutputType = outputType - if outputDir != "" { - tCaseConverter.SetOutputDir(outputDir) - } - if profilePath != "" { - tCaseConverter.SetProfile(profilePath) - } - switch tCaseConverter.InputType { - case InputTypeHAR: - iCaseConverters = append(iCaseConverters, NewConverterHAR(tCaseConverter)) - case InputTypePostman: - iCaseConverters = append(iCaseConverters, NewConverterPostman(tCaseConverter)) - case InputTypeJSON: - iCaseConverters = append(iCaseConverters, NewConverterJSON(tCaseConverter)) - case InputTypeYAML: - iCaseConverters = append(iCaseConverters, NewConverterYAML(tCaseConverter)) - case InputTypeSwagger, InputTypeJMeter, InputTypeGoTest, InputTypePyTest: - log.Warn(). - Str("input path", tCaseConverter.InputPath). - Msg("case type not supported yet, ignore!") - default: - log.Warn(). - Str("input path", tCaseConverter.InputPath). - Msg("unknown case type, ignore!") - } - } - - // start converting var outputFiles []string - var err error - for _, iCaseConverter := range iCaseConverters { - log.Info().Str("input path", iCaseConverter.Struct().InputPath).Msg("start converting") + for _, path := range args { + // loads source file in support types and convert to TCase format + tCase, err := LoadTCase(path) + if err != nil { + log.Warn().Err(err).Str("path", path).Msg("construct case loader failed") + continue + } + + caseConverter := TCaseConverter{ + OutputDir: outputDir, + OutputType: outputType, + TCase: tCase, + } + + // override TCase with profile + caseConverter.overrideWithProfile(profilePath) + + // convert TCase format to target case format var outputFile string - switch iCaseConverter.Struct().OutputType { + switch outputType { case OutputTypeYAML: - outputFile, err = iCaseConverter.ToYAML() + outputFile, err = caseConverter.ToYAML() case OutputTypeGoTest: - outputFile, err = iCaseConverter.ToGoTest() + outputFile, err = caseConverter.ToGoTest() case OutputTypePyTest: - outputFile, err = iCaseConverter.ToPyTest() + outputFile, err = caseConverter.ToPyTest() default: - outputFile, err = iCaseConverter.ToJSON() + outputFile, err = caseConverter.ToJSON() } if err != nil { log.Error().Err(err). - Str("input path", iCaseConverter.Struct().InputPath). - Msg("error occurs during converting") + Str("source path", path). + Msg("convert case failed") continue } outputFiles = append(outputFiles, outputFile) @@ -310,16 +249,17 @@ func Run(outputType OutputType, outputDir, profilePath string, args []string) { log.Info().Strs("output files", outputFiles).Msg("conversion completed") } -func makeTestCaseFromJSONYAML(iCaseConverter ICaseConverter) (*hrp.TCase, error) { - tCase := iCaseConverter.Struct().TCase - if tCase == nil { - return nil, errors.Errorf("empty json/yaml testcase occurs") +func (c *TCaseConverter) overrideWithProfile(path string) error { + log.Info().Str("path", path).Msg("load profile") + profile := new(Profile) + err := builtin.LoadFile(path, profile) + if err != nil { + log.Warn().Str("path", path). + Msg("failed to load profile, ignore!") + return err } - profile := iCaseConverter.Struct().Profile - if profile == nil { - return tCase, nil - } - for _, step := range tCase.TestSteps { + + for _, step := range c.TCase.TestSteps { // override original headers and cookies if profile.Override { step.Request.Headers = make(map[string]string) @@ -339,5 +279,5 @@ func makeTestCaseFromJSONYAML(iCaseConverter ICaseConverter) (*hrp.TCase, error) step.Request.Cookies[k] = v } } - return tCase, nil + return nil } diff --git a/hrp/internal/convert/converter_har.go b/hrp/internal/convert/converter_har.go index 6ee9c156..7d004dbf 100644 --- a/hrp/internal/convert/converter_har.go +++ b/hrp/internal/convert/converter_har.go @@ -4,6 +4,7 @@ import ( "encoding/base64" "fmt" "net/url" + "reflect" "sort" "strings" "time" @@ -357,56 +358,31 @@ type TestResult struct { // ==================== model definition ends here ==================== -func NewConverterHAR(converter *TCaseConverter) *ConverterHAR { - return &ConverterHAR{ - converter: converter, - } -} - -type ConverterHAR struct { - converter *TCaseConverter -} - -func (c *ConverterHAR) Struct() *TCaseConverter { - return c.converter -} - -func (c *ConverterHAR) ToJSON() (string, error) { - tCase, err := c.makeTestCase() +func LoadHARCase(path string) (*hrp.TCase, error) { + // load har file + caseHAR, err := loadCaseHAR(path) if err != nil { - return "", err + return nil, err } - jsonPath := c.converter.genOutputPath(suffixJSON) - err = builtin.Dump2JSON(tCase, jsonPath) + + // convert to TCase format + return caseHAR.ToTCase() +} + +func loadCaseHAR(path string) (*CaseHar, error) { + caseHAR := new(CaseHar) + err := builtin.LoadFile(path, caseHAR) if err != nil { - return "", err + return nil, errors.Wrap(err, "load har file failed") } - return jsonPath, nil -} - -func (c *ConverterHAR) ToYAML() (string, error) { - tCase, err := c.makeTestCase() - if err != nil { - return "", err + if reflect.ValueOf(*caseHAR).IsZero() { + return nil, errors.New("invalid har file") } - yamlPath := c.converter.genOutputPath(suffixYAML) - err = builtin.Dump2YAML(tCase, yamlPath) - if err != nil { - return "", err - } - return yamlPath, nil + return caseHAR, nil } -func (c *ConverterHAR) ToGoTest() (string, error) { - //TODO implement me - return "", errors.New("convert from har to gotest scripts is not supported yet") -} - -func (c *ConverterHAR) ToPyTest() (string, error) { - return convertToPyTest(c) -} - -func (c *ConverterHAR) makeTestCase() (*hrp.TCase, error) { +// convert CaseHar to TCase format +func (c *CaseHar) ToTCase() (*hrp.TCase, error) { teststeps, err := c.prepareTestSteps() if err != nil { return nil, err @@ -423,27 +399,14 @@ func (c *ConverterHAR) makeTestCase() (*hrp.TCase, error) { return tCase, nil } -func (c *ConverterHAR) load() (*CaseHar, error) { - har := c.converter.CaseHAR - if har == nil { - return nil, errors.New("empty har case occurs") - } - return har, nil -} - -func (c *ConverterHAR) prepareConfig() *hrp.TConfig { +func (c *CaseHar) prepareConfig() *hrp.TConfig { return hrp.NewConfig("testcase description"). SetVerifySSL(false) } -func (c *ConverterHAR) prepareTestSteps() ([]*hrp.TStep, error) { - har, err := c.load() - if err != nil { - return nil, err - } - +func (c *CaseHar) prepareTestSteps() ([]*hrp.TStep, error) { var steps []*hrp.TStep - for _, entry := range har.Log.Entries { + for _, entry := range c.Log.Entries { step, err := c.prepareTestStep(&entry) if err != nil { return nil, err @@ -454,7 +417,7 @@ func (c *ConverterHAR) prepareTestSteps() ([]*hrp.TStep, error) { return steps, nil } -func (c *ConverterHAR) prepareTestStep(entry *Entry) (*hrp.TStep, error) { +func (c *CaseHar) prepareTestStep(entry *Entry) (*hrp.TStep, error) { log.Info(). Str("method", entry.Request.Method). Str("url", entry.Request.URL). @@ -465,7 +428,6 @@ func (c *ConverterHAR) prepareTestStep(entry *Entry) (*hrp.TStep, error) { Request: &hrp.Request{}, Validators: make([]interface{}, 0), }, - profile: c.converter.Profile, } if err := step.makeRequestMethod(entry); err != nil { return nil, err @@ -493,7 +455,6 @@ func (c *ConverterHAR) prepareTestStep(entry *Entry) (*hrp.TStep, error) { type stepFromHAR struct { hrp.TStep - profile *Profile } func (s *stepFromHAR) makeRequestMethod(entry *Entry) error { @@ -525,18 +486,6 @@ func (s *stepFromHAR) makeRequestCookies(entry *Entry) error { for _, cookie := range entry.Request.Cookies { s.Request.Cookies[cookie.Name] = cookie.Value } - - if s.profile == nil { - return nil - } - // override all cookies according to the profile - if s.profile.Override { - s.Request.Cookies = make(map[string]string) - } - // create or update the cookies according to the profile - for k, v := range s.profile.Cookies { - s.Request.Cookies[k] = v - } return nil } @@ -549,18 +498,6 @@ func (s *stepFromHAR) makeRequestHeaders(entry *Entry) error { } s.Request.Headers[header.Name] = header.Value } - - if s.profile == nil { - return nil - } - // override all headers according to the profile - if s.profile.Override { - s.Request.Headers = make(map[string]string) - } - // create or update the headers according to the profile - for k, v := range s.profile.Headers { - s.Request.Headers[k] = v - } return nil } diff --git a/hrp/internal/convert/converter_har_test.go b/hrp/internal/convert/converter_har_test.go index af94c98c..711e191e 100644 --- a/hrp/internal/convert/converter_har_test.go +++ b/hrp/internal/convert/converter_har_test.go @@ -14,65 +14,27 @@ var ( harProfileOverridePath = "../../../examples/data/har/profile_override.yml" ) -var converterHAR = NewConverterHAR(NewTCaseConverter(harPath)) -var converterHAR2 = NewConverterHAR(NewTCaseConverter(harPath2)) +var caseHar *CaseHar -func TestHAR2JSON(t *testing.T) { - jsonPath, err := converterHAR.ToJSON() - if !assert.NoError(t, err) { - t.Fatal() - } - if !assert.NotEmpty(t, jsonPath) { - t.Fatal() - } -} - -func TestHAR2YAML(t *testing.T) { - yamlPath, err := converterHAR2.ToYAML() - if !assert.NoError(t, err) { - t.Fatal() - } - if !assert.NotEmpty(t, yamlPath) { - t.Fatal() - } +func init() { + caseHar, _ = loadCaseHAR(harPath) } func TestLoadHAR(t *testing.T) { - h, err := converterHAR.load() + caseHAR, err := loadCaseHAR(harPath) if !assert.NoError(t, err) { t.Fatal() } - if !assert.Equal(t, "GET", h.Log.Entries[0].Request.Method) { + if !assert.Equal(t, "GET", caseHAR.Log.Entries[0].Request.Method) { t.Fatal() } - if !assert.Equal(t, "POST", h.Log.Entries[1].Request.Method) { + if !assert.Equal(t, "POST", caseHAR.Log.Entries[1].Request.Method) { t.Fatal() } } -func TestLoadHARWithProfile(t *testing.T) { - tCaseConverter := NewTCaseConverter(harPath) - tCaseConverter.SetProfile(harProfileOverridePath) - h := NewConverterHAR(tCaseConverter) - _, err := h.load() - if !assert.NoError(t, err) { - t.Fatal() - } - - if !assert.Equal(t, - map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - h.converter.Profile.Headers) { - t.Fatal() - } - if !assert.Equal(t, - map[string]string{"UserName": "debugtalk"}, - h.converter.Profile.Cookies) { - t.Fatal() - } -} - -func TestMakeTestCaseFromHAR(t *testing.T) { - tCase, err := converterHAR.makeTestCase() +func TestLoadTCaseFromHAR(t *testing.T) { + tCase, err := LoadHARCase(harPath) if !assert.NoError(t, err) { t.Fatal() } @@ -143,7 +105,7 @@ func TestMakeRequestURL(t *testing.T) { URL: "http://127.0.0.1:8080/api/login", }, } - step, err := converterHAR.prepareTestStep(entry) + step, err := caseHar.prepareTestStep(entry) if !assert.NoError(t, err) { t.Fatal() } @@ -162,7 +124,7 @@ func TestMakeRequestHeaders(t *testing.T) { }, }, } - step, err := converterHAR.prepareTestStep(entry) + step, err := caseHar.prepareTestStep(entry) if !assert.NoError(t, err) { t.Fatal() } @@ -174,30 +136,6 @@ func TestMakeRequestHeaders(t *testing.T) { } } -func TestMakeRequestHeadersWithProfileOverride(t *testing.T) { - tCaseConverter := NewTCaseConverter(harPath) - tCaseConverter.SetProfile(harProfileOverridePath) - h := NewConverterHAR(tCaseConverter) - entry := &Entry{ - Request: Request{ - Method: "POST", - Headers: []NVP{ - {Name: "Content-Type", Value: "application/json; charset=utf-8"}, - }, - }, - } - step, err := h.prepareTestStep(entry) - if !assert.NoError(t, err) { - t.Fatal() - } - - if !assert.Equal(t, map[string]string{ - "Content-Type": "application/x-www-form-urlencoded", - }, step.Request.Headers) { - t.Fatal() - } -} - func TestMakeRequestCookies(t *testing.T) { entry := &Entry{ Request: Request{ @@ -208,7 +146,7 @@ func TestMakeRequestCookies(t *testing.T) { }, }, } - step, err := converterHAR.prepareTestStep(entry) + step, err := caseHar.prepareTestStep(entry) if !assert.NoError(t, err) { t.Fatal() } @@ -221,31 +159,6 @@ func TestMakeRequestCookies(t *testing.T) { } } -func TestMakeRequestCookiesWithProfileOverride(t *testing.T) { - tCaseConverter := NewTCaseConverter(harPath) - tCaseConverter.SetProfile(harProfileOverridePath) - h := NewConverterHAR(tCaseConverter) - entry := &Entry{ - Request: Request{ - Method: "POST", - Cookies: []Cookie{ - {Name: "abc", Value: "123"}, - {Name: "UserName", Value: "leolee"}, - }, - }, - } - step, err := h.prepareTestStep(entry) - if !assert.NoError(t, err) { - t.Fatal() - } - - if !assert.Equal(t, map[string]string{ - "UserName": "debugtalk", - }, step.Request.Cookies) { - t.Fatal() - } -} - func TestMakeRequestDataParams(t *testing.T) { entry := &Entry{ Request: Request{ @@ -259,7 +172,7 @@ func TestMakeRequestDataParams(t *testing.T) { }, }, } - step, err := converterHAR.prepareTestStep(entry) + step, err := caseHar.prepareTestStep(entry) if !assert.NoError(t, err) { t.Fatal() } @@ -279,7 +192,7 @@ func TestMakeRequestDataJSON(t *testing.T) { }, }, } - step, err := converterHAR.prepareTestStep(entry) + step, err := caseHar.prepareTestStep(entry) if !assert.NoError(t, err) { t.Fatal() } @@ -299,7 +212,7 @@ func TestMakeRequestDataTextEmpty(t *testing.T) { }, }, } - step, err := converterHAR.prepareTestStep(entry) + step, err := caseHar.prepareTestStep(entry) if !assert.NoError(t, err) { t.Fatal() } @@ -325,7 +238,7 @@ func TestMakeValidate(t *testing.T) { }, }, } - step, err := converterHAR.prepareTestStep(entry) + step, err := caseHar.prepareTestStep(entry) if !assert.NoError(t, err) { t.Fatal() } diff --git a/hrp/internal/convert/converter_json.go b/hrp/internal/convert/converter_json.go index f55a7f5c..0eaf1019 100644 --- a/hrp/internal/convert/converter_json.go +++ b/hrp/internal/convert/converter_json.go @@ -1,78 +1,29 @@ package convert import ( + "reflect" + "github.com/pkg/errors" "github.com/httprunner/httprunner/v4/hrp" "github.com/httprunner/httprunner/v4/hrp/internal/builtin" ) -func NewConverterJSON(converter *TCaseConverter) *ConverterJSON { - return &ConverterJSON{ - converter: converter, - } -} - -type ConverterJSON struct { - converter *TCaseConverter -} - -func (c *ConverterJSON) Struct() *TCaseConverter { - return c.converter -} - -func (c *ConverterJSON) ToJSON() (string, error) { - testCase, err := c.makeTestCase() +func LoadJSONCase(path string) (*hrp.TCase, error) { + // load json case file + caseJSON := new(hrp.TCase) + err := builtin.LoadFile(path, caseJSON) if err != nil { - return "", err + return nil, errors.Wrap(err, "load json file failed") } - jsonPath := c.converter.genOutputPath(suffixJSON) - err = builtin.Dump2JSON(testCase, jsonPath) - if err != nil { - return "", err + if reflect.ValueOf(*caseJSON).IsZero() { + return nil, errors.New("invalid json file") } - return jsonPath, nil -} -func (c *ConverterJSON) ToYAML() (string, error) { - testCase, err := c.makeTestCase() - if err != nil { - return "", err - } - yamlPath := c.converter.genOutputPath(suffixYAML) - err = builtin.Dump2YAML(testCase, yamlPath) - if err != nil { - return "", err - } - return yamlPath, nil -} - -func (c *ConverterJSON) ToGoTest() (string, error) { - // TODO implement me - return "", errors.New("convert from json testcase to gotest scripts is not supported yet") -} - -func (c *ConverterJSON) ToPyTest() (string, error) { - return convertToPyTest(c) -} - -func (c *ConverterJSON) MakePyTestScript() (string, error) { - args := append([]string{"make"}, c.converter.InputPath) - err := builtin.ExecPython3Command("httprunner", args...) - if err != nil { - return "", err - } - return c.converter.genOutputPath(suffixPyTest), nil -} - -func (c *ConverterJSON) makeTestCase() (*hrp.TCase, error) { - tCase, err := makeTestCaseFromJSONYAML(c) + // convert json case to TCase + err = caseJSON.MakeCompat() if err != nil { return nil, err } - err = tCase.MakeCompat() - if err != nil { - return nil, err - } - return tCase, nil + return caseJSON, nil } diff --git a/hrp/internal/convert/converter_postman.go b/hrp/internal/convert/converter_postman.go index 742a8721..01d9f3e5 100644 --- a/hrp/internal/convert/converter_postman.go +++ b/hrp/internal/convert/converter_postman.go @@ -112,66 +112,37 @@ var contentTypeMap = map[string]string{ "xml": "application/xml", } -func NewConverterPostman(converter *TCaseConverter) *ConverterPostman { - return &ConverterPostman{ - converter: converter, - } -} - -type ConverterPostman struct { - converter *TCaseConverter -} - -func (c *ConverterPostman) Struct() *TCaseConverter { - return c.converter -} - -func (c *ConverterPostman) ToJSON() (string, error) { - testCase, err := c.makeTestCase() - if err != nil { - return "", err - } - jsonPath := c.converter.genOutputPath(suffixJSON) - err = builtin.Dump2JSON(testCase, jsonPath) - if err != nil { - return "", err - } - return jsonPath, nil -} - -func (c *ConverterPostman) ToYAML() (string, error) { - testCase, err := c.makeTestCase() - if err != nil { - return "", err - } - yamlPath := c.converter.genOutputPath(suffixYAML) - err = builtin.Dump2YAML(testCase, yamlPath) - if err != nil { - return "", err - } - return yamlPath, nil -} - -func (c *ConverterPostman) ToGoTest() (string, error) { - // TODO implement me - return "", errors.New("convert from postman to gotest scripts is not supported yet") -} - -func (c *ConverterPostman) ToPyTest() (string, error) { - return convertToPyTest(c) -} - -func (c *ConverterPostman) makeTestCase() (*hrp.TCase, error) { - casePostman, err := c.load() +func LoadPostmanCase(path string) (*hrp.TCase, error) { + // load postman file + casePostman, err := loadCasePostman(path) if err != nil { return nil, err } - teststeps, err := c.prepareTestSteps(casePostman) + + // convert to TCase format + return casePostman.ToTCase() +} + +func loadCasePostman(path string) (*CasePostman, error) { + casePostman := new(CasePostman) + err := builtin.LoadFile(path, casePostman) + if err != nil { + return nil, errors.Wrap(err, "load postman file failed") + } + if reflect.ValueOf(*casePostman).IsZero() { + return nil, errors.New("invalid postman file") + } + + return casePostman, nil +} + +func (c *CasePostman) ToTCase() (*hrp.TCase, error) { + teststeps, err := c.prepareTestSteps() if err != nil { return nil, err } tCase := &hrp.TCase{ - Config: c.prepareConfig(casePostman), + Config: c.prepareConfig(), TestSteps: teststeps, } err = tCase.MakeCompat() @@ -181,23 +152,15 @@ func (c *ConverterPostman) makeTestCase() (*hrp.TCase, error) { return tCase, nil } -func (c *ConverterPostman) load() (*CasePostman, error) { - casePostman := c.converter.CasePostman - if casePostman == nil { - return nil, errors.New("empty postman case occurs") - } - return casePostman, nil -} - -func (c *ConverterPostman) prepareConfig(casePostman *CasePostman) *hrp.TConfig { - return hrp.NewConfig(casePostman.Info.Name). +func (c *CasePostman) prepareConfig() *hrp.TConfig { + return hrp.NewConfig(c.Info.Name). SetVerifySSL(false) } -func (c *ConverterPostman) prepareTestSteps(casePostman *CasePostman) ([]*hrp.TStep, error) { +func (c *CasePostman) prepareTestSteps() ([]*hrp.TStep, error) { // recursively convert collection items into a list var itemList []TItem - for _, item := range casePostman.Items { + for _, item := range c.Items { extractItemList(item, &itemList) } @@ -229,7 +192,7 @@ func extractItemList(item TItem, itemList *[]TItem) { } } -func (c *ConverterPostman) prepareTestStep(item *TItem) (*hrp.TStep, error) { +func (c *CasePostman) prepareTestStep(item *TItem) (*hrp.TStep, error) { log.Info(). Str("method", item.Request.Method). Str("url", item.Request.URL.Raw). @@ -240,7 +203,6 @@ func (c *ConverterPostman) prepareTestStep(item *TItem) (*hrp.TStep, error) { Request: &hrp.Request{}, Validators: make([]interface{}, 0), }, - profile: c.converter.Profile, } if err := step.makeRequestName(item); err != nil { return nil, err @@ -268,7 +230,6 @@ func (c *ConverterPostman) prepareTestStep(item *TItem) (*hrp.TStep, error) { type stepFromPostman struct { hrp.TStep - profile *Profile } // makeRequestName indicates the step name the same as item name @@ -317,18 +278,6 @@ func (s *stepFromPostman) makeRequestHeaders(item *TItem) error { } s.Request.Headers[field.Key] = field.Value } - - if s.profile == nil { - return nil - } - // override all headers according to the profile - if s.profile.Override { - s.Request.Headers = make(map[string]string) - } - // create or update the headers according to the profile - for k, v := range s.profile.Headers { - s.Request.Headers[k] = v - } return nil } @@ -341,18 +290,6 @@ func (s *stepFromPostman) makeRequestCookies(item *TItem) error { } s.parseRequestCookiesMap(field.Value) } - - if s.profile == nil { - return nil - } - // override all cookies according to the profile - if s.profile.Override { - s.Request.Cookies = make(map[string]string) - } - // create or update the cookies according to the profile - for k, v := range s.profile.Cookies { - s.Request.Cookies[k] = v - } return nil } diff --git a/hrp/internal/convert/converter_postman_test.go b/hrp/internal/convert/converter_postman_test.go index 57085bf2..2315a5bd 100644 --- a/hrp/internal/convert/converter_postman_test.go +++ b/hrp/internal/convert/converter_postman_test.go @@ -12,30 +12,8 @@ var ( collectionProfilePath = "../../../examples/data/postman/profile.yml" ) -var converterPostman = NewConverterPostman(NewTCaseConverter(collectionPath)) - -func TestPostman2JSON(t *testing.T) { - jsonPath, err := converterPostman.ToJSON() - if !assert.NoError(t, err) { - t.Fatal() - } - if !assert.NotEmpty(t, jsonPath) { - t.Fatal() - } -} - -func TestPostman2YAML(t *testing.T) { - yamlPath, err := converterPostman.ToYAML() - if !assert.NoError(t, err) { - t.Fatal() - } - if !assert.NotEmpty(t, yamlPath) { - t.Fatal() - } -} - func TestLoadCollection(t *testing.T) { - casePostman, err := converterPostman.load() + casePostman, err := loadCasePostman(collectionPath) if !assert.NoError(t, err) { t.Fatal(err) } @@ -45,7 +23,7 @@ func TestLoadCollection(t *testing.T) { } func TestMakeTestCaseFromCollection(t *testing.T) { - tCase, err := converterPostman.makeTestCase() + tCase, err := LoadPostmanCase(collectionPath) if !assert.NoError(t, err) { t.Fatal() } @@ -102,49 +80,3 @@ func TestMakeTestCaseFromCollection(t *testing.T) { t.Fatal() } } - -func TestMakeTestCaseWithProfileOverride(t *testing.T) { - tCaseConverter := NewTCaseConverter(collectionPath) - tCaseConverter.SetProfile(collectionProfileOverridePath) - c := NewConverterPostman(tCaseConverter) - tCase, err := c.makeTestCase() - if !assert.NoError(t, err) { - t.Fatal() - } - for _, step := range tCase.TestSteps { - if step.Request.Method == "GET" && !assert.Len(t, step.Request.Headers, 1) { - t.Fatal() - } - if !assert.Equal(t, "all original headers will be overridden", step.Request.Headers["Header1"]) { - t.Fatal() - } - if !assert.Len(t, step.Request.Cookies, 1) { - t.Fatal() - } - if !assert.Equal(t, "all original cookies will be overridden", step.Request.Cookies["Cookie1"]) { - t.Fatal() - } - } -} - -func TestMakeTestCaseWithProfile(t *testing.T) { - tCaseConverter := NewTCaseConverter(collectionPath) - tCaseConverter.SetProfile(collectionProfilePath) - c := NewConverterPostman(tCaseConverter) - tCase, err := c.makeTestCase() - if !assert.NoError(t, err) { - t.Fatal() - } - // create cookies Cookie1 indicated in profile - if !assert.Equal(t, "this cookie will be created or updated", tCase.TestSteps[0].Request.Cookies["Cookie1"]) { - t.Fatal() - } - // update header User-Agent indicated in profile - if !assert.Equal(t, "this header will be created or updated", tCase.TestSteps[5].Request.Headers["User-Agent"]) { - t.Fatal() - } - // pass header Connection which is not indicated in profile - if !assert.Equal(t, "close", tCase.TestSteps[5].Request.Headers["Connection"]) { - t.Fatal() - } -} diff --git a/hrp/internal/convert/converter_pytest.go b/hrp/internal/convert/converter_pytest.go index c2edca2c..233bcded 100644 --- a/hrp/internal/convert/converter_pytest.go +++ b/hrp/internal/convert/converter_pytest.go @@ -1,40 +1 @@ package convert - -import ( - "os" - - "github.com/pkg/errors" - "github.com/rs/zerolog/log" -) - -func convertToPyTest(iCaseConverter ICaseConverter) (string, error) { - // convert to temporary json testcase - jsonPath, err := iCaseConverter.ToJSON() - inputType := iCaseConverter.Struct().InputType - if err != nil { - return "", errors.Wrapf(err, "(%s -> pytest step 1) failed to convert to temporary json testcase", inputType.String()) - } - defer func() { - if jsonPath != "" { - if err = os.Remove(jsonPath); err != nil { - log.Error().Err(err).Msgf("(%s -> pytest step defer) failed to clean temporary json testcase", inputType.String()) - } - } - }() - - // convert from temporary json testcase to pytest - converterJSON := NewConverterJSON(NewTCaseConverter(jsonPath)) - pyTestPath, err := converterJSON.MakePyTestScript() - if err != nil { - return "", errors.Wrap(err, "(json -> pytest step 2) failed to convert from temporary json testcase to pytest ") - } - - // rename resultant pytest - renamedPyTestPath := iCaseConverter.Struct().genOutputPath(suffixPyTest) - err = os.Rename(pyTestPath, renamedPyTestPath) - if err != nil { - log.Error().Err(err).Msg("(json -> pytest step 3) failed to rename the resultant pytest file") - return pyTestPath, nil - } - return renamedPyTestPath, nil -} diff --git a/hrp/internal/convert/converter_swagger.go b/hrp/internal/convert/converter_swagger.go new file mode 100644 index 00000000..ce3c7557 --- /dev/null +++ b/hrp/internal/convert/converter_swagger.go @@ -0,0 +1,26 @@ +package convert + +import ( + "reflect" + + "github.com/go-openapi/spec" + "github.com/pkg/errors" + + "github.com/httprunner/httprunner/v4/hrp" + "github.com/httprunner/httprunner/v4/hrp/internal/builtin" +) + +func LoadSwaggerCase(path string) (*hrp.TCase, error) { + // load swagger file + caseSwagger := new(spec.Swagger) + err := builtin.LoadFile(path, caseSwagger) + if err != nil { + return nil, errors.Wrap(err, "load swagger file failed") + } + if reflect.ValueOf(*caseSwagger).IsZero() { + return nil, errors.New("invalid swagger file") + } + + // convert swagger to TCase + return nil, nil +} diff --git a/hrp/internal/convert/converter_yaml.go b/hrp/internal/convert/converter_yaml.go index 2ad783b1..93abc0f0 100644 --- a/hrp/internal/convert/converter_yaml.go +++ b/hrp/internal/convert/converter_yaml.go @@ -1,69 +1,29 @@ package convert import ( + "reflect" + "github.com/pkg/errors" "github.com/httprunner/httprunner/v4/hrp" "github.com/httprunner/httprunner/v4/hrp/internal/builtin" ) -func NewConverterYAML(converter *TCaseConverter) *ConverterYAML { - return &ConverterYAML{ - converter: converter, - } -} - -type ConverterYAML struct { - converter *TCaseConverter -} - -func (c *ConverterYAML) Struct() *TCaseConverter { - return c.converter -} - -func (c *ConverterYAML) ToJSON() (string, error) { - testCase, err := c.makeTestCase() +func NewYAMLCase(path string) (*hrp.TCase, error) { + // load yaml case file + caseJSON := new(hrp.TCase) + err := builtin.LoadFile(path, caseJSON) if err != nil { - return "", err + return nil, errors.Wrap(err, "load yaml file failed") } - jsonPath := c.converter.genOutputPath(suffixJSON) - err = builtin.Dump2JSON(testCase, jsonPath) - if err != nil { - return "", err + if reflect.ValueOf(*caseJSON).IsZero() { + return nil, errors.New("invalid yaml file") } - return jsonPath, nil -} -func (c *ConverterYAML) ToYAML() (string, error) { - testCase, err := c.makeTestCase() - if err != nil { - return "", err - } - yamlPath := c.converter.genOutputPath(suffixYAML) - err = builtin.Dump2YAML(testCase, yamlPath) - if err != nil { - return "", err - } - return yamlPath, nil -} - -func (c *ConverterYAML) ToGoTest() (string, error) { - //TODO implement me - return "", errors.New("convert from yaml testcase to gotest scripts is not supported yet") -} - -func (c *ConverterYAML) ToPyTest() (string, error) { - return convertToPyTest(c) -} - -func (c *ConverterYAML) makeTestCase() (*hrp.TCase, error) { - tCase, err := makeTestCaseFromJSONYAML(c) + // convert json case to TCase + err = caseJSON.MakeCompat() if err != nil { return nil, err } - err = tCase.MakeCompat() - if err != nil { - return nil, err - } - return tCase, nil + return caseJSON, nil } From ccdd60dba1592f360f4f19c128283264aaef3f20 Mon Sep 17 00:00:00 2001 From: debugtalk Date: Mon, 27 Jun 2022 16:33:49 +0800 Subject: [PATCH 2/6] change: add unittest for override --- examples/data/har/postman-echo.har | 4694 ----------------- examples/data/postman/postman_collection.json | 498 -- examples/data/postman/profile.yml | 4 - examples/data/postman/profile_override.yml | 5 - examples/data/profile.yml | 4 + examples/data/{har => }/profile_override.yml | 0 hrp/internal/convert/README.md | 4 + hrp/internal/convert/converter.go | 160 +- hrp/internal/convert/converter_har_test.go | 6 +- .../convert/converter_postman_test.go | 6 +- hrp/internal/convert/converter_test.go | 140 + 11 files changed, 213 insertions(+), 5308 deletions(-) delete mode 100644 examples/data/har/postman-echo.har delete mode 100644 examples/data/postman/postman_collection.json delete mode 100644 examples/data/postman/profile.yml delete mode 100644 examples/data/postman/profile_override.yml create mode 100644 examples/data/profile.yml rename examples/data/{har => }/profile_override.yml (100%) create mode 100644 hrp/internal/convert/converter_test.go diff --git a/examples/data/har/postman-echo.har b/examples/data/har/postman-echo.har deleted file mode 100644 index 362055a2..00000000 --- a/examples/data/har/postman-echo.har +++ /dev/null @@ -1,4694 +0,0 @@ -{ - "log": { - "version": "1.2", - "creator": { - "name": "Charles Proxy", - "version": "4.6.1" - }, - "entries": [ - { - "startedDateTime": "2021-10-16T15:04:52.736+08:00", - "time": 1763, - "request": { - "method": "GET", - "url": "https://postman-echo.com/get?foo1=bar1&foo2=bar2", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3ASAXM8INphoz4_-5nCeQNBtrlsWuHs5Mt.83PsbOXUZUoPolzR2vpghXLUghDPLyA3NSrVKI8A8ws" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "ea19464c-ddd4-4724-abe9-5e2b254c2723" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3ASAXM8INphoz4_-5nCeQNBtrlsWuHs5Mt.83PsbOXUZUoPolzR2vpghXLUghDPLyA3NSrVKI8A8ws" - } - ], - "queryString": [ - { - "name": "foo1", - "value": "bar1" - }, - { - "name": "foo2", - "value": "bar2" - } - ], - "headersSize": 351, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3Ack89N2nb1AxU-T-nxvJrvOS1KvUXbiU2.3nAhh%2FjA%2F%2FNvHtWI8NApXa1QWV3hDD6LBsfUwpIdYQc", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:04:54 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "521" - }, - { - "name": "ETag", - "value": "W/\"209-bxFKtsTdtFVMiL0IMqJLfvcJtAI\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3Ack89N2nb1AxU-T-nxvJrvOS1KvUXbiU2.3nAhh%2FjA%2F%2FNvHtWI8NApXa1QWV3hDD6LBsfUwpIdYQc; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 521, - "mimeType": "application/json; charset=utf-8", - "text": "eyJhcmdzIjp7ImZvbzEiOiJiYXIxIiwiZm9vMiI6ImJhcjIifSwiaGVhZGVycyI6eyJ4LWZvcndhcmRlZC1wcm90byI6Imh0dHBzIiwieC1mb3J3YXJkZWQtcG9ydCI6IjQ0MyIsImhvc3QiOiJwb3N0bWFuLWVjaG8uY29tIiwieC1hbXpuLXRyYWNlLWlkIjoiUm9vdD0xLTYxNmE3OTk2LTZhZjVmMWMzMjc2YmI5ZjI0NjczOGFmZSIsInVzZXItYWdlbnQiOiJQb3N0bWFuUnVudGltZS83LjI4LjQiLCJhY2NlcHQiOiIqLyoiLCJjYWNoZS1jb250cm9sIjoibm8tY2FjaGUiLCJwb3N0bWFuLXRva2VuIjoiZWExOTQ2NGMtZGRkNC00NzI0LWFiZTktNWUyYjI1NGMyNzIzIiwiYWNjZXB0LWVuY29kaW5nIjoiZ3ppcCwgZGVmbGF0ZSwgYnIiLCJjb29raWUiOiJzYWlscy5zaWQ9cyUzQVNBWE04SU5waG96NF8tNW5DZVFOQnRybHNXdUhzNU10LjgzUHNiT1hVWlVvUG9selIydnBnaFhMVWdoRFBMeUEzTlNyVktJOEE4d3MifSwidXJsIjoiaHR0cHM6Ly9wb3N0bWFuLWVjaG8uY29tL2dldD9mb28xPWJhcjEmZm9vMj1iYXIyIn0=", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 521 - }, - "serverIPAddress": "52.7.241.1", - "cache": {}, - "timings": { - "dns": 489, - "connect": 950, - "ssl": 587, - "send": 0, - "wait": 324, - "receive": 0 - } - }, - { - "startedDateTime": "2021-10-16T15:04:54.568+08:00", - "time": 1131, - "request": { - "method": "POST", - "url": "https://postman-echo.com/post", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3Ack89N2nb1AxU-T-nxvJrvOS1KvUXbiU2.3nAhh%2FjA%2F%2FNvHtWI8NApXa1QWV3hDD6LBsfUwpIdYQc" - } - ], - "headers": [ - { - "name": "Content-Type", - "value": "text/plain" - }, - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "40756814-a974-4fcc-98d2-1f2aec73c295" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Content-Length", - "value": "58" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3Ack89N2nb1AxU-T-nxvJrvOS1KvUXbiU2.3nAhh%2FjA%2F%2FNvHtWI8NApXa1QWV3hDD6LBsfUwpIdYQc" - } - ], - "queryString": [], - "postData": { - "mimeType": "text/plain", - "text": "This is expected to be sent back as part of response body." - }, - "headersSize": 385, - "bodySize": 58 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3A4bF7QNsgYKOBRnxJEclo-wiPIm6YxzFY.zmgnSBoVtZ3C40cBCJPsFS6KXTPoQBlKdS2FIdoxFaA", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:04:55 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "632" - }, - { - "name": "ETag", - "value": "W/\"278-Xov3AabKgpWo3NrcmrTPiUSe5vU\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3A4bF7QNsgYKOBRnxJEclo-wiPIm6YxzFY.zmgnSBoVtZ3C40cBCJPsFS6KXTPoQBlKdS2FIdoxFaA; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 632, - "mimeType": "application/json; charset=utf-8", - "text": "eyJhcmdzIjp7fSwiZGF0YSI6IlRoaXMgaXMgZXhwZWN0ZWQgdG8gYmUgc2VudCBiYWNrIGFzIHBhcnQgb2YgcmVzcG9uc2UgYm9keS4iLCJmaWxlcyI6e30sImZvcm0iOnt9LCJoZWFkZXJzIjp7IngtZm9yd2FyZGVkLXByb3RvIjoiaHR0cHMiLCJ4LWZvcndhcmRlZC1wb3J0IjoiNDQzIiwiaG9zdCI6InBvc3RtYW4tZWNoby5jb20iLCJ4LWFtem4tdHJhY2UtaWQiOiJSb290PTEtNjE2YTc5OTctNmE1YTAwMTQ0ZjIyMmQ0MDNjYmUyZTcyIiwiY29udGVudC1sZW5ndGgiOiI1OCIsImNvbnRlbnQtdHlwZSI6InRleHQvcGxhaW4iLCJ1c2VyLWFnZW50IjoiUG9zdG1hblJ1bnRpbWUvNy4yOC40IiwiYWNjZXB0IjoiKi8qIiwiY2FjaGUtY29udHJvbCI6Im5vLWNhY2hlIiwicG9zdG1hbi10b2tlbiI6IjQwNzU2ODE0LWE5NzQtNGZjYy05OGQyLTFmMmFlYzczYzI5NSIsImFjY2VwdC1lbmNvZGluZyI6Imd6aXAsIGRlZmxhdGUsIGJyIiwiY29va2llIjoic2FpbHMuc2lkPXMlM0Fjazg5TjJuYjFBeFUtVC1ueHZKcnZPUzFLdlVYYmlVMi4zbkFoaCUyRmpBJTJGJTJGTnZIdFdJOE5BcFhhMVFXVjNoREQ2TEJzZlV3cElkWVFjIn0sImpzb24iOm51bGwsInVybCI6Imh0dHBzOi8vcG9zdG1hbi1lY2hvLmNvbS9wb3N0In0=", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 632 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 5, - "connect": 844, - "ssl": 566, - "send": 0, - "wait": 281, - "receive": 1 - } - }, - { - "startedDateTime": "2021-10-16T15:04:55.733+08:00", - "time": 1171, - "request": { - "method": "POST", - "url": "https://postman-echo.com/post", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3A4bF7QNsgYKOBRnxJEclo-wiPIm6YxzFY.zmgnSBoVtZ3C40cBCJPsFS6KXTPoQBlKdS2FIdoxFaA" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "93843e50-2fe8-422d-b900-91095f9f0cdb" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Content-Type", - "value": "application/x-www-form-urlencoded" - }, - { - "name": "Content-Length", - "value": "19" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3A4bF7QNsgYKOBRnxJEclo-wiPIm6YxzFY.zmgnSBoVtZ3C40cBCJPsFS6KXTPoQBlKdS2FIdoxFaA" - } - ], - "queryString": [], - "postData": { - "mimeType": "application/x-www-form-urlencoded", - "params": [ - { - "name": "foo1", - "value": "bar1" - }, - { - "name": "foo2", - "value": "bar2" - } - ] - }, - "headersSize": 402, - "bodySize": 19 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3A7Kp8q3TlXZgZpLiLQNE4OGvpaqJwWmWX.SkW6gD2iyLO%2FFZYMAbg0bTsfuHwnEBezprz6nbykPWg", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:04:57 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "643" - }, - { - "name": "ETag", - "value": "W/\"283-0tKS85K793Mxd9D1GST4xg1ZBfI\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3A7Kp8q3TlXZgZpLiLQNE4OGvpaqJwWmWX.SkW6gD2iyLO%2FFZYMAbg0bTsfuHwnEBezprz6nbykPWg; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 643, - "mimeType": "application/json; charset=utf-8", - "text": "eyJhcmdzIjp7fSwiZGF0YSI6IiIsImZpbGVzIjp7fSwiZm9ybSI6eyJmb28xIjoiYmFyMSIsImZvbzIiOiJiYXIyIn0sImhlYWRlcnMiOnsieC1mb3J3YXJkZWQtcHJvdG8iOiJodHRwcyIsIngtZm9yd2FyZGVkLXBvcnQiOiI0NDMiLCJob3N0IjoicG9zdG1hbi1lY2hvLmNvbSIsIngtYW16bi10cmFjZS1pZCI6IlJvb3Q9MS02MTZhNzk5OS00NzcxNWU0ZjFhMjlmOGM1MmFmYTQyNDEiLCJjb250ZW50LWxlbmd0aCI6IjE5IiwidXNlci1hZ2VudCI6IlBvc3RtYW5SdW50aW1lLzcuMjguNCIsImFjY2VwdCI6IiovKiIsImNhY2hlLWNvbnRyb2wiOiJuby1jYWNoZSIsInBvc3RtYW4tdG9rZW4iOiI5Mzg0M2U1MC0yZmU4LTQyMmQtYjkwMC05MTA5NWY5ZjBjZGIiLCJhY2NlcHQtZW5jb2RpbmciOiJnemlwLCBkZWZsYXRlLCBiciIsImNvbnRlbnQtdHlwZSI6ImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIsImNvb2tpZSI6InNhaWxzLnNpZD1zJTNBNGJGN1FOc2dZS09CUm54SkVjbG8td2lQSW02WXh6Rlkuem1nblNCb1Z0WjNDNDBjQkNKUHNGUzZLWFRQb1FCbEtkUzJGSWRveEZhQSJ9LCJqc29uIjp7ImZvbzEiOiJiYXIxIiwiZm9vMiI6ImJhcjIifSwidXJsIjoiaHR0cHM6Ly9wb3N0bWFuLWVjaG8uY29tL3Bvc3QifQ==", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 643 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 883, - "ssl": 571, - "send": 0, - "wait": 286, - "receive": 1 - } - }, - { - "startedDateTime": "2021-10-16T15:04:56.938+08:00", - "time": 1458, - "request": { - "method": "PUT", - "url": "https://postman-echo.com/put", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3A7Kp8q3TlXZgZpLiLQNE4OGvpaqJwWmWX.SkW6gD2iyLO%2FFZYMAbg0bTsfuHwnEBezprz6nbykPWg" - } - ], - "headers": [ - { - "name": "Content-Type", - "value": "text/plain" - }, - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "5d357b2b-0f10-4ded-bc9a-299ebef7a2d5" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Content-Length", - "value": "58" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3A7Kp8q3TlXZgZpLiLQNE4OGvpaqJwWmWX.SkW6gD2iyLO%2FFZYMAbg0bTsfuHwnEBezprz6nbykPWg" - } - ], - "queryString": [], - "postData": { - "mimeType": "text/plain", - "text": "This is expected to be sent back as part of response body." - }, - "headersSize": 379, - "bodySize": 58 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3ArMIVJXM1u78IGSzps0LYNjimloLEMdqk.6bzxgShLW4DTNlqRdZREK7OUV1kqu2kMHtEVxR9Xlyg", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:04:58 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "627" - }, - { - "name": "ETag", - "value": "W/\"273-pgr4Cuw5RxQ81uMoLc1tfZ0rHvc\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3ArMIVJXM1u78IGSzps0LYNjimloLEMdqk.6bzxgShLW4DTNlqRdZREK7OUV1kqu2kMHtEVxR9Xlyg; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 627, - "mimeType": "application/json; charset=utf-8", - "text": "eyJhcmdzIjp7fSwiZGF0YSI6IlRoaXMgaXMgZXhwZWN0ZWQgdG8gYmUgc2VudCBiYWNrIGFzIHBhcnQgb2YgcmVzcG9uc2UgYm9keS4iLCJmaWxlcyI6e30sImZvcm0iOnt9LCJoZWFkZXJzIjp7IngtZm9yd2FyZGVkLXByb3RvIjoiaHR0cHMiLCJ4LWZvcndhcmRlZC1wb3J0IjoiNDQzIiwiaG9zdCI6InBvc3RtYW4tZWNoby5jb20iLCJ4LWFtem4tdHJhY2UtaWQiOiJSb290PTEtNjE2YTc5OWEtMjNiYzAyNGYwNWY5YTc5OTYwZTY4OWI3IiwiY29udGVudC1sZW5ndGgiOiI1OCIsImNvbnRlbnQtdHlwZSI6InRleHQvcGxhaW4iLCJ1c2VyLWFnZW50IjoiUG9zdG1hblJ1bnRpbWUvNy4yOC40IiwiYWNjZXB0IjoiKi8qIiwiY2FjaGUtY29udHJvbCI6Im5vLWNhY2hlIiwicG9zdG1hbi10b2tlbiI6IjVkMzU3YjJiLTBmMTAtNGRlZC1iYzlhLTI5OWViZWY3YTJkNSIsImFjY2VwdC1lbmNvZGluZyI6Imd6aXAsIGRlZmxhdGUsIGJyIiwiY29va2llIjoic2FpbHMuc2lkPXMlM0E3S3A4cTNUbFhaZ1pwTGlMUU5FNE9HdnBhcUp3V21XWC5Ta1c2Z0QyaXlMTyUyRkZaWU1BYmcwYlRzZnVId25FQmV6cHJ6Nm5ieWtQV2cifSwianNvbiI6bnVsbCwidXJsIjoiaHR0cHM6Ly9wb3N0bWFuLWVjaG8uY29tL3B1dCJ9", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 627 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 1056, - "ssl": 717, - "send": 0, - "wait": 400, - "receive": 1 - } - }, - { - "startedDateTime": "2021-10-16T15:04:58.430+08:00", - "time": 1130, - "request": { - "method": "PATCH", - "url": "https://postman-echo.com/patch", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3ArMIVJXM1u78IGSzps0LYNjimloLEMdqk.6bzxgShLW4DTNlqRdZREK7OUV1kqu2kMHtEVxR9Xlyg" - } - ], - "headers": [ - { - "name": "Content-Type", - "value": "text/plain" - }, - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "27a30a79-5d88-43c0-8c83-fce5bb585729" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Content-Length", - "value": "58" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3ArMIVJXM1u78IGSzps0LYNjimloLEMdqk.6bzxgShLW4DTNlqRdZREK7OUV1kqu2kMHtEVxR9Xlyg" - } - ], - "queryString": [], - "postData": { - "mimeType": "text/plain", - "text": "This is expected to be sent back as part of response body." - }, - "headersSize": 381, - "bodySize": 58 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AlTv3pBzULeMHqjWpJWW-rwLZYYdqzSyW.J5YSZCf1unKehq5zNyuee%2B2xYkqoK%2BcTPTr3RzHYtYM", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:04:59 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "627" - }, - { - "name": "ETag", - "value": "W/\"273-AGMTrKyVT6uBRPjNxv5QoHk04dc\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3AlTv3pBzULeMHqjWpJWW-rwLZYYdqzSyW.J5YSZCf1unKehq5zNyuee%2B2xYkqoK%2BcTPTr3RzHYtYM; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 627, - "mimeType": "application/json; charset=utf-8", - "text": "eyJhcmdzIjp7fSwiZGF0YSI6IlRoaXMgaXMgZXhwZWN0ZWQgdG8gYmUgc2VudCBiYWNrIGFzIHBhcnQgb2YgcmVzcG9uc2UgYm9keS4iLCJmaWxlcyI6e30sImZvcm0iOnt9LCJoZWFkZXJzIjp7IngtZm9yd2FyZGVkLXByb3RvIjoiaHR0cHMiLCJ4LWZvcndhcmRlZC1wb3J0IjoiNDQzIiwiaG9zdCI6InBvc3RtYW4tZWNoby5jb20iLCJ4LWFtem4tdHJhY2UtaWQiOiJSb290PTEtNjE2YTc5OWItNjhhOTBmMWM0ZDU5NGUwMzUxZDhlNjIwIiwiY29udGVudC1sZW5ndGgiOiI1OCIsImNvbnRlbnQtdHlwZSI6InRleHQvcGxhaW4iLCJ1c2VyLWFnZW50IjoiUG9zdG1hblJ1bnRpbWUvNy4yOC40IiwiYWNjZXB0IjoiKi8qIiwiY2FjaGUtY29udHJvbCI6Im5vLWNhY2hlIiwicG9zdG1hbi10b2tlbiI6IjI3YTMwYTc5LTVkODgtNDNjMC04YzgzLWZjZTViYjU4NTcyOSIsImFjY2VwdC1lbmNvZGluZyI6Imd6aXAsIGRlZmxhdGUsIGJyIiwiY29va2llIjoic2FpbHMuc2lkPXMlM0FyTUlWSlhNMXU3OElHU3pwczBMWU5qaW1sb0xFTWRxay42Ynp4Z1NoTFc0RFRObHFSZFpSRUs3T1VWMWtxdTJrTUh0RVZ4UjlYbHlnIn0sImpzb24iOm51bGwsInVybCI6Imh0dHBzOi8vcG9zdG1hbi1lY2hvLmNvbS9wYXRjaCJ9", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 627 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 846, - "ssl": 567, - "send": 0, - "wait": 282, - "receive": 1 - } - }, - { - "startedDateTime": "2021-10-16T15:04:59.597+08:00", - "time": 1261, - "request": { - "method": "DELETE", - "url": "https://postman-echo.com/delete", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AlTv3pBzULeMHqjWpJWW-rwLZYYdqzSyW.J5YSZCf1unKehq5zNyuee%2B2xYkqoK%2BcTPTr3RzHYtYM" - } - ], - "headers": [ - { - "name": "Content-Type", - "value": "text/plain" - }, - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "b11f7819-4c39-41b3-9d06-696b38c3e515" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Content-Length", - "value": "58" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AlTv3pBzULeMHqjWpJWW-rwLZYYdqzSyW.J5YSZCf1unKehq5zNyuee%2B2xYkqoK%2BcTPTr3RzHYtYM" - } - ], - "queryString": [], - "postData": { - "mimeType": "text/plain", - "text": "This is expected to be sent back as part of response body." - }, - "headersSize": 387, - "bodySize": 58 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3A6Sj7Mduyb72fC-X0OQbDmFqp77bVEgt8.b5X8H%2BtACzKfkUlH%2FBtSYH%2FdSQ5fHynzHjK8gE3s%2FpI", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:00 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "632" - }, - { - "name": "ETag", - "value": "W/\"278-oXQWd2iRqZbkTY58xndHHEJ9sVo\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3A6Sj7Mduyb72fC-X0OQbDmFqp77bVEgt8.b5X8H%2BtACzKfkUlH%2FBtSYH%2FdSQ5fHynzHjK8gE3s%2FpI; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 632, - "mimeType": "application/json; charset=utf-8", - "text": "eyJhcmdzIjp7fSwiZGF0YSI6IlRoaXMgaXMgZXhwZWN0ZWQgdG8gYmUgc2VudCBiYWNrIGFzIHBhcnQgb2YgcmVzcG9uc2UgYm9keS4iLCJmaWxlcyI6e30sImZvcm0iOnt9LCJoZWFkZXJzIjp7IngtZm9yd2FyZGVkLXByb3RvIjoiaHR0cHMiLCJ4LWZvcndhcmRlZC1wb3J0IjoiNDQzIiwiaG9zdCI6InBvc3RtYW4tZWNoby5jb20iLCJ4LWFtem4tdHJhY2UtaWQiOiJSb290PTEtNjE2YTc5OWMtNzdhNjA3NzI2ODIxZjc4ODcxNjU2MmZkIiwiY29udGVudC1sZW5ndGgiOiI1OCIsImNvbnRlbnQtdHlwZSI6InRleHQvcGxhaW4iLCJ1c2VyLWFnZW50IjoiUG9zdG1hblJ1bnRpbWUvNy4yOC40IiwiYWNjZXB0IjoiKi8qIiwiY2FjaGUtY29udHJvbCI6Im5vLWNhY2hlIiwicG9zdG1hbi10b2tlbiI6ImIxMWY3ODE5LTRjMzktNDFiMy05ZDA2LTY5NmIzOGMzZTUxNSIsImFjY2VwdC1lbmNvZGluZyI6Imd6aXAsIGRlZmxhdGUsIGJyIiwiY29va2llIjoic2FpbHMuc2lkPXMlM0FsVHYzcEJ6VUxlTUhxaldwSldXLXJ3TFpZWWRxelN5Vy5KNVlTWkNmMXVuS2VocTV6Tnl1ZWUlMkIyeFlrcW9LJTJCY1RQVHIzUnpIWXRZTSJ9LCJqc29uIjpudWxsLCJ1cmwiOiJodHRwczovL3Bvc3RtYW4tZWNoby5jb20vZGVsZXRlIn0=", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 632 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 930, - "ssl": 649, - "send": 0, - "wait": 330, - "receive": 0 - } - }, - { - "startedDateTime": "2021-10-16T15:05:00.891+08:00", - "time": 1236, - "request": { - "method": "GET", - "url": "https://postman-echo.com/headers", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3A6Sj7Mduyb72fC-X0OQbDmFqp77bVEgt8.b5X8H%2BtACzKfkUlH%2FBtSYH%2FdSQ5fHynzHjK8gE3s%2FpI" - } - ], - "headers": [ - { - "name": "my-sample-header", - "value": "Lorem ipsum dolor sit amet" - }, - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "1a4e2039-d29b-4ed7-89e9-584b354246be" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3A6Sj7Mduyb72fC-X0OQbDmFqp77bVEgt8.b5X8H%2BtACzKfkUlH%2FBtSYH%2FdSQ5fHynzHjK8gE3s%2FpI" - } - ], - "queryString": [], - "headersSize": 389, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AvvP5l4Bk7WCLBU9LNXalNk4w4x3Q_2Zi.JiGgykR8RlAGIdRWv%2FdCmCL0Tbmwyni9KkXXgnzn59s", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:02 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "483" - }, - { - "name": "ETag", - "value": "W/\"1e3-vZgcezgrti0mSOuFJY4fsdEQ6aE\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3AvvP5l4Bk7WCLBU9LNXalNk4w4x3Q_2Zi.JiGgykR8RlAGIdRWv%2FdCmCL0Tbmwyni9KkXXgnzn59s; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 483, - "mimeType": "application/json; charset=utf-8", - "text": "eyJoZWFkZXJzIjp7IngtZm9yd2FyZGVkLXByb3RvIjoiaHR0cHMiLCJ4LWZvcndhcmRlZC1wb3J0IjoiNDQzIiwiaG9zdCI6InBvc3RtYW4tZWNoby5jb20iLCJ4LWFtem4tdHJhY2UtaWQiOiJSb290PTEtNjE2YTc5OWUtNjY1MjlmNGExNjkxM2U0YTY2YThiZmM3IiwibXktc2FtcGxlLWhlYWRlciI6IkxvcmVtIGlwc3VtIGRvbG9yIHNpdCBhbWV0IiwidXNlci1hZ2VudCI6IlBvc3RtYW5SdW50aW1lLzcuMjguNCIsImFjY2VwdCI6IiovKiIsImNhY2hlLWNvbnRyb2wiOiJuby1jYWNoZSIsInBvc3RtYW4tdG9rZW4iOiIxYTRlMjAzOS1kMjliLTRlZDctODllOS01ODRiMzU0MjQ2YmUiLCJhY2NlcHQtZW5jb2RpbmciOiJnemlwLCBkZWZsYXRlLCBiciIsImNvb2tpZSI6InNhaWxzLnNpZD1zJTNBNlNqN01kdXliNzJmQy1YME9RYkRtRnFwNzdiVkVndDguYjVYOEglMkJ0QUN6S2ZrVWxIJTJGQnRTWUglMkZkU1E1Zkh5bnpIaks4Z0UzcyUyRnBJIn19", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 483 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 949, - "ssl": 571, - "send": 0, - "wait": 286, - "receive": 0 - } - }, - { - "startedDateTime": "2021-10-16T15:05:02.177+08:00", - "time": 1543, - "request": { - "method": "GET", - "url": "https://postman-echo.com/response-headers?foo1=bar1&foo2=bar2", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AvvP5l4Bk7WCLBU9LNXalNk4w4x3Q_2Zi.JiGgykR8RlAGIdRWv%2FdCmCL0Tbmwyni9KkXXgnzn59s" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "b00d3c25-a84b-4152-bcf8-4c573c06024b" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AvvP5l4Bk7WCLBU9LNXalNk4w4x3Q_2Zi.JiGgykR8RlAGIdRWv%2FdCmCL0Tbmwyni9KkXXgnzn59s" - } - ], - "queryString": [ - { - "name": "foo1", - "value": "bar1" - }, - { - "name": "foo2", - "value": "bar2" - } - ], - "headersSize": 366, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3APA71Iib2-7KqjRMajldmUsDqOqmRDB6-.zpTeobSmlq81Z7R%2FyL7q3o8%2FAP0tfOOZSPQdBlirJ6g", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:03 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "29" - }, - { - "name": "foo1", - "value": "bar1" - }, - { - "name": "foo2", - "value": "bar2" - }, - { - "name": "ETag", - "value": "W/\"1d-PgOLWVqd2mMvcpNzTF0Cfy4hftg\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3APA71Iib2-7KqjRMajldmUsDqOqmRDB6-.zpTeobSmlq81Z7R%2FyL7q3o8%2FAP0tfOOZSPQdBlirJ6g; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 29, - "mimeType": "application/json; charset=utf-8", - "text": "eyJmb28xIjoiYmFyMSIsImZvbzIiOiJiYXIyIn0=", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 29 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 1140, - "ssl": 811, - "send": 0, - "wait": 402, - "receive": 0 - } - }, - { - "startedDateTime": "2021-10-16T15:05:03.761+08:00", - "time": 1174, - "request": { - "method": "GET", - "url": "https://postman-echo.com/basic-auth", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3APA71Iib2-7KqjRMajldmUsDqOqmRDB6-.zpTeobSmlq81Z7R%2FyL7q3o8%2FAP0tfOOZSPQdBlirJ6g" - } - ], - "headers": [ - { - "name": "Authorization", - "value": "Basic cG9zdG1hbjpwYXNzd29yZA==" - }, - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "d9f810a2-292d-41c4-95e1-ec9f9ae778d6" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3APA71Iib2-7KqjRMajldmUsDqOqmRDB6-.zpTeobSmlq81Z7R%2FyL7q3o8%2FAP0tfOOZSPQdBlirJ6g" - } - ], - "queryString": [], - "headersSize": 389, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AT2IbNG9nLojvklvDr1mo2cCftGUgcAgU.f1XqnM5ebKiLtIs3CKYYvBo7j5iHwiP9EuG9i91RR%2FU", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:05 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "22" - }, - { - "name": "ETag", - "value": "W/\"16-sJz8uwjdDv0wvm7//BYdNw8vMbU\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3AT2IbNG9nLojvklvDr1mo2cCftGUgcAgU.f1XqnM5ebKiLtIs3CKYYvBo7j5iHwiP9EuG9i91RR%2FU; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 22, - "mimeType": "application/json; charset=utf-8", - "text": "eyJhdXRoZW50aWNhdGVkIjp0cnVlfQ==", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 22 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 2, - "connect": 886, - "ssl": 607, - "send": 0, - "wait": 286, - "receive": 0 - } - }, - { - "startedDateTime": "2021-10-16T15:05:04.977+08:00", - "time": 1201, - "request": { - "method": "GET", - "url": "https://postman-echo.com/digest-auth", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AT2IbNG9nLojvklvDr1mo2cCftGUgcAgU.f1XqnM5ebKiLtIs3CKYYvBo7j5iHwiP9EuG9i91RR%2FU" - } - ], - "headers": [ - { - "name": "Authorization", - "value": "Digest username=\"postman\", realm=\"Users\", nonce=\"W7kT5VowsR0pcTfL9fTwZKv2tRdEiG6c\", uri=\"/digest-auth\", algorithm=\"MD5\", response=\"bab1b1e6534f84b43e9deb17bca9371b\"" - }, - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "42e8340a-852b-4c7a-ab7d-d0b027f044ca" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AT2IbNG9nLojvklvDr1mo2cCftGUgcAgU.f1XqnM5ebKiLtIs3CKYYvBo7j5iHwiP9EuG9i91RR%2FU" - } - ], - "queryString": [], - "headersSize": 522, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AWyHRwAoLc64u8sF_LqU0BUYAieEguHiH.gb%2BNYX72g6n5lHjLdl5K1hsKmLHYJUwoOwKkDWVl7qY", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:06 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "22" - }, - { - "name": "ETag", - "value": "W/\"16-sJz8uwjdDv0wvm7//BYdNw8vMbU\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3AWyHRwAoLc64u8sF_LqU0BUYAieEguHiH.gb%2BNYX72g6n5lHjLdl5K1hsKmLHYJUwoOwKkDWVl7qY; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 22, - "mimeType": "application/json; charset=utf-8", - "text": "eyJhdXRoZW50aWNhdGVkIjp0cnVlfQ==", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 22 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 857, - "ssl": 571, - "send": 0, - "wait": 342, - "receive": 1 - } - }, - { - "startedDateTime": "2021-10-16T15:05:06.216+08:00", - "time": 1601, - "request": { - "method": "GET", - "url": "https://postman-echo.com/auth/hawk", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AWyHRwAoLc64u8sF_LqU0BUYAieEguHiH.gb%2BNYX72g6n5lHjLdl5K1hsKmLHYJUwoOwKkDWVl7qY" - } - ], - "headers": [ - { - "name": "Authorization", - "value": "Hawk id=\"dh37fgj492je\", ts=\"1634367906\", nonce=\"RZKGNz\", mac=\"EASK1an/9fmDhFJcqH8XE4pTuUaSJisuQVM+NCOjNlM=\"" - }, - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "46645864-583c-446b-9d36-9610fb114d99" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AWyHRwAoLc64u8sF_LqU0BUYAieEguHiH.gb%2BNYX72g6n5lHjLdl5K1hsKmLHYJUwoOwKkDWVl7qY" - } - ], - "queryString": [], - "headersSize": 463, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AZQRuQaIb28umtrzP-HOj4fSqeag88Pvj.KVLylhlYJ3JKMHUS0UVeLCT6qRcBgQl%2BM14UxI7EgQs", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:07 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "44" - }, - { - "name": "ETag", - "value": "W/\"2c-UZ5QLCWp1r9bxkKdVTupq1/XxUI\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3AZQRuQaIb28umtrzP-HOj4fSqeag88Pvj.KVLylhlYJ3JKMHUS0UVeLCT6qRcBgQl%2BM14UxI7EgQs; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 44, - "mimeType": "application/json; charset=utf-8", - "text": "eyJtZXNzYWdlIjoiSGF3ayBBdXRoZW50aWNhdGlvbiBTdWNjZXNzZnVsIn0=", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 44 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 1196, - "ssl": 915, - "send": 0, - "wait": 403, - "receive": 1 - } - }, - { - "startedDateTime": "2021-10-16T15:05:07.866+08:00", - "time": 1196, - "request": { - "method": "GET", - "url": "https://postman-echo.com/oauth1", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AZQRuQaIb28umtrzP-HOj4fSqeag88Pvj.KVLylhlYJ3JKMHUS0UVeLCT6qRcBgQl%2BM14UxI7EgQs" - } - ], - "headers": [ - { - "name": "Authorization", - "value": "OAuth oauth_consumer_key=\"RKCGzna7bv9YD57c\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1634367907\",oauth_nonce=\"pAoTV0k5VZa\",oauth_signature=\"ZTkfsaUA1B2s7kyl3HaFm1zFow4%3D\"" - }, - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "3d9db9bb-5bcf-425e-b0e4-a958c07d7969" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AZQRuQaIb28umtrzP-HOj4fSqeag88Pvj.KVLylhlYJ3JKMHUS0UVeLCT6qRcBgQl%2BM14UxI7EgQs" - } - ], - "queryString": [], - "headersSize": 535, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AsdmvN2_ZNE0YlwQY5GxY04ptWTOYR5NU.kkH0dnWlEMsblzPMurLX8nsQRRbRqLqteIhA0621onY", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:09 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "78" - }, - { - "name": "ETag", - "value": "W/\"4e-dXPS7nEYaa6r6PVjN9RjHjrHaLU\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3AsdmvN2_ZNE0YlwQY5GxY04ptWTOYR5NU.kkH0dnWlEMsblzPMurLX8nsQRRbRqLqteIhA0621onY; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 78, - "mimeType": "application/json; charset=utf-8", - "text": "eyJzdGF0dXMiOiJwYXNzIiwibWVzc2FnZSI6Ik9BdXRoLTEuMGEgc2lnbmF0dXJlIHZlcmlmaWNhdGlvbiB3YXMgc3VjY2Vzc2Z1bCJ9", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 78 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 2, - "connect": 855, - "ssl": 573, - "send": 0, - "wait": 339, - "receive": 0 - } - }, - { - "startedDateTime": "2021-10-16T15:05:09.099+08:00", - "time": 1290, - "request": { - "method": "GET", - "url": "https://postman-echo.com/cookies/set?foo1=bar1&foo2=bar2", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AsdmvN2_ZNE0YlwQY5GxY04ptWTOYR5NU.kkH0dnWlEMsblzPMurLX8nsQRRbRqLqteIhA0621onY" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "ff927796-58d3-4f43-8701-8411747c4313" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AsdmvN2_ZNE0YlwQY5GxY04ptWTOYR5NU.kkH0dnWlEMsblzPMurLX8nsQRRbRqLqteIhA0621onY" - } - ], - "queryString": [ - { - "name": "foo1", - "value": "bar1" - }, - { - "name": "foo2", - "value": "bar2" - } - ], - "headersSize": 359, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 302, - "statusText": "Found", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "foo1", - "value": "bar1", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": false, - "secure": false, - "comment": null, - "_maxAge": null - }, - { - "name": "foo2", - "value": "bar2", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": false, - "secure": false, - "comment": null, - "_maxAge": null - }, - { - "name": "sails.sid", - "value": "s%3AlVpTnkb0ofz6HC7QJMVtiRexW3u_onsT.rmsoerMcOQOu7KYPU80x%2FBiieqBESMNj%2FxuCvbbw%2BsQ", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:10 GMT" - }, - { - "name": "Content-Type", - "value": "text/plain; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "30" - }, - { - "name": "set-cookie", - "value": "foo1=bar1; Path=/" - }, - { - "name": "set-cookie", - "value": "foo2=bar2; Path=/" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3AlVpTnkb0ofz6HC7QJMVtiRexW3u_onsT.rmsoerMcOQOu7KYPU80x%2FBiieqBESMNj%2FxuCvbbw%2BsQ; Path=/; HttpOnly" - }, - { - "name": "Location", - "value": "/cookies" - }, - { - "name": "Vary", - "value": "Accept, Accept-Encoding" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 30, - "mimeType": "text/plain; charset=utf-8", - "text": "Found. Redirecting to /cookies" - }, - "redirectURL": "/cookies", - "headersSize": 0, - "bodySize": 30 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 988, - "ssl": 626, - "send": 0, - "wait": 301, - "receive": 0 - } - }, - { - "startedDateTime": "2021-10-16T15:05:10.405+08:00", - "time": 1191, - "request": { - "method": "GET", - "url": "https://postman-echo.com/cookies", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AlVpTnkb0ofz6HC7QJMVtiRexW3u_onsT.rmsoerMcOQOu7KYPU80x%2FBiieqBESMNj%2FxuCvbbw%2BsQ" - }, - { - "name": "foo1", - "value": "bar1" - }, - { - "name": "foo2", - "value": "bar2" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "ff927796-58d3-4f43-8701-8411747c4313" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AlVpTnkb0ofz6HC7QJMVtiRexW3u_onsT.rmsoerMcOQOu7KYPU80x%2FBiieqBESMNj%2FxuCvbbw%2BsQ; foo1=bar1; foo2=bar2" - }, - { - "name": "Referer", - "value": "https://postman-echo.com/cookies/set?foo1=bar1&foo2=bar2" - }, - { - "name": "Host", - "value": "postman-echo.com" - } - ], - "queryString": [], - "headersSize": 430, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3Avz13GzkqWaYvFuB3I35udi2vLsikZZgi.YgVWfqmyjPpEduyCIZDFGyDSPYY8%2FFM7HePC5Ok0hQM", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:11 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "41" - }, - { - "name": "ETag", - "value": "W/\"29-JRHqGq7F5tGozH71XMqVk/pLueo\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3Avz13GzkqWaYvFuB3I35udi2vLsikZZgi.YgVWfqmyjPpEduyCIZDFGyDSPYY8%2FFM7HePC5Ok0hQM; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 41, - "mimeType": "application/json; charset=utf-8", - "text": "eyJjb29raWVzIjp7ImZvbzEiOiJiYXIxIiwiZm9vMiI6ImJhcjIifX0=", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 41 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 902, - "ssl": 620, - "send": 0, - "wait": 287, - "receive": 1 - } - }, - { - "startedDateTime": "2021-10-16T15:05:11.630+08:00", - "time": 1172, - "request": { - "method": "GET", - "url": "https://postman-echo.com/cookies", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3Avz13GzkqWaYvFuB3I35udi2vLsikZZgi.YgVWfqmyjPpEduyCIZDFGyDSPYY8%2FFM7HePC5Ok0hQM" - }, - { - "name": "foo1", - "value": "bar1" - }, - { - "name": "foo2", - "value": "bar2" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "2dbc6d22-1713-4b96-a1a2-3358b1a1deaa" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3Avz13GzkqWaYvFuB3I35udi2vLsikZZgi.YgVWfqmyjPpEduyCIZDFGyDSPYY8%2FFM7HePC5Ok0hQM; foo1=bar1; foo2=bar2" - } - ], - "queryString": [], - "headersSize": 359, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AQ8MT5sT-2LAO0Rk7bNLLR18UQWgaJMsg.eOEyhDjqWGwn2rdqWeGLstPmrn5H1OUZGlDLuI%2F1Nng", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:12 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "41" - }, - { - "name": "ETag", - "value": "W/\"29-JRHqGq7F5tGozH71XMqVk/pLueo\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3AQ8MT5sT-2LAO0Rk7bNLLR18UQWgaJMsg.eOEyhDjqWGwn2rdqWeGLstPmrn5H1OUZGlDLuI%2F1Nng; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 41, - "mimeType": "application/json; charset=utf-8", - "text": "eyJjb29raWVzIjp7ImZvbzEiOiJiYXIxIiwiZm9vMiI6ImJhcjIifX0=", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 41 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 887, - "ssl": 607, - "send": 0, - "wait": 283, - "receive": 1 - } - }, - { - "startedDateTime": "2021-10-16T15:05:12.841+08:00", - "time": 1436, - "request": { - "method": "GET", - "url": "https://postman-echo.com/cookies/delete?foo1&foo2", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AQ8MT5sT-2LAO0Rk7bNLLR18UQWgaJMsg.eOEyhDjqWGwn2rdqWeGLstPmrn5H1OUZGlDLuI%2F1Nng" - }, - { - "name": "foo1", - "value": "bar1" - }, - { - "name": "foo2", - "value": "bar2" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "8837dd89-9db7-4f06-9187-e7a85a99b945" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AQ8MT5sT-2LAO0Rk7bNLLR18UQWgaJMsg.eOEyhDjqWGwn2rdqWeGLstPmrn5H1OUZGlDLuI%2F1Nng; foo1=bar1; foo2=bar2" - } - ], - "queryString": [ - { - "name": "foo1", - "value": "" - }, - { - "name": "foo2", - "value": "" - } - ], - "headersSize": 376, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 302, - "statusText": "Found", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "foo1", - "value": "", - "path": "/", - "domain": null, - "expires": "Thu, 01 Jan 1970 00:00:00 GMT", - "httpOnly": false, - "secure": false, - "comment": null, - "_maxAge": null - }, - { - "name": "foo2", - "value": "", - "path": "/", - "domain": null, - "expires": "Thu, 01 Jan 1970 00:00:00 GMT", - "httpOnly": false, - "secure": false, - "comment": null, - "_maxAge": null - }, - { - "name": "sails.sid", - "value": "s%3A1atMUPWbEEDiMqdbTqbddbqiFujSi1l2.6n40eqlOkTsKoB6K7xT98PrfQweiPlTjJTfZl%2FpAEsU", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:14 GMT" - }, - { - "name": "Content-Type", - "value": "text/plain; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "30" - }, - { - "name": "set-cookie", - "value": "foo1=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT" - }, - { - "name": "set-cookie", - "value": "foo2=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3A1atMUPWbEEDiMqdbTqbddbqiFujSi1l2.6n40eqlOkTsKoB6K7xT98PrfQweiPlTjJTfZl%2FpAEsU; Path=/; HttpOnly" - }, - { - "name": "Location", - "value": "/cookies" - }, - { - "name": "Vary", - "value": "Accept, Accept-Encoding" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 30, - "mimeType": "text/plain; charset=utf-8", - "text": "Found. Redirecting to /cookies" - }, - "redirectURL": "/cookies", - "headersSize": 0, - "bodySize": 30 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 1018, - "ssl": 694, - "send": 0, - "wait": 417, - "receive": 0 - } - }, - { - "startedDateTime": "2021-10-16T15:05:14.291+08:00", - "time": 1394, - "request": { - "method": "GET", - "url": "https://postman-echo.com/cookies", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3A1atMUPWbEEDiMqdbTqbddbqiFujSi1l2.6n40eqlOkTsKoB6K7xT98PrfQweiPlTjJTfZl%2FpAEsU" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "8837dd89-9db7-4f06-9187-e7a85a99b945" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3A1atMUPWbEEDiMqdbTqbddbqiFujSi1l2.6n40eqlOkTsKoB6K7xT98PrfQweiPlTjJTfZl%2FpAEsU" - }, - { - "name": "Referer", - "value": "https://postman-echo.com/cookies/delete?foo1&foo2" - }, - { - "name": "Host", - "value": "postman-echo.com" - } - ], - "queryString": [], - "headersSize": 397, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3A5p9FN9UVGZ9XJl6I9FXiz0AwIQRRU1ka.RFuMLR9arGQaLkM1gbvuPosvzPxsREHGEjjiVF4TXnQ", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:15 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "14" - }, - { - "name": "ETag", - "value": "W/\"e-HwHgMXOuquwNiBd0Mx9LHc/Rmfk\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3A5p9FN9UVGZ9XJl6I9FXiz0AwIQRRU1ka.RFuMLR9arGQaLkM1gbvuPosvzPxsREHGEjjiVF4TXnQ; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 14, - "mimeType": "application/json; charset=utf-8", - "text": "eyJjb29raWVzIjp7fX0=", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 14 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 1109, - "ssl": 715, - "send": 0, - "wait": 283, - "receive": 1 - } - }, - { - "startedDateTime": "2021-10-16T15:05:15.722+08:00", - "time": 1176, - "request": { - "method": "GET", - "url": "https://postman-echo.com/status/200", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3A5p9FN9UVGZ9XJl6I9FXiz0AwIQRRU1ka.RFuMLR9arGQaLkM1gbvuPosvzPxsREHGEjjiVF4TXnQ" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "5f4c6d97-d476-407e-bbf9-532480f618d8" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3A5p9FN9UVGZ9XJl6I9FXiz0AwIQRRU1ka.RFuMLR9arGQaLkM1gbvuPosvzPxsREHGEjjiVF4TXnQ" - } - ], - "queryString": [], - "headersSize": 338, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AFD7Hy01JAAenWz9SoQQhJxH4Qxel9sbP.%2Ba5JmTwqOpkc%2FAOLOzzsfStpK2MTfZCYXiCoA39Zt7w", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:17 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "14" - }, - { - "name": "ETag", - "value": "W/\"e-QlsUp1vTYvBgYHrHCBYe2n/q268\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3AFD7Hy01JAAenWz9SoQQhJxH4Qxel9sbP.%2Ba5JmTwqOpkc%2FAOLOzzsfStpK2MTfZCYXiCoA39Zt7w; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 14, - "mimeType": "application/json; charset=utf-8", - "text": "eyJzdGF0dXMiOjIwMH0=", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 14 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 2, - "connect": 887, - "ssl": 607, - "send": 0, - "wait": 287, - "receive": 0 - } - }, - { - "startedDateTime": "2021-10-16T15:05:16.933+08:00", - "time": 1223, - "request": { - "method": "GET", - "url": "https://postman-echo.com/stream/5", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AFD7Hy01JAAenWz9SoQQhJxH4Qxel9sbP.%2Ba5JmTwqOpkc%2FAOLOzzsfStpK2MTfZCYXiCoA39Zt7w" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "24ca01aa-6c3f-4a78-a437-33dfa8dadd0f" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AFD7Hy01JAAenWz9SoQQhJxH4Qxel9sbP.%2Ba5JmTwqOpkc%2FAOLOzzsfStpK2MTfZCYXiCoA39Zt7w" - } - ], - "queryString": [], - "headersSize": 340, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AqSePO9_VmCbBbVvsCMYMHm3lShKdFNWU.RFuwKJdlZHVyB0gF1x2Yt78v5jKbese6f8HNPIjI5AY", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:18 GMT" - }, - { - "name": "Transfer-Encoding", - "value": "chunked" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3AqSePO9_VmCbBbVvsCMYMHm3lShKdFNWU.RFuwKJdlZHVyB0gF1x2Yt78v5jKbese6f8HNPIjI5AY; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 2885, - "mimeType": null, - "text": "ewogICJhcmdzIjogewogICAgIm4iOiAiNSIKICB9LAogICJoZWFkZXJzIjogewogICAgIngtZm9yd2FyZGVkLXByb3RvIjogImh0dHBzIiwKICAgICJ4LWZvcndhcmRlZC1wb3J0IjogIjQ0MyIsCiAgICAiaG9zdCI6ICJwb3N0bWFuLWVjaG8uY29tIiwKICAgICJ4LWFtem4tdHJhY2UtaWQiOiAiUm9vdD0xLTYxNmE3OWFlLTZiNjY3YzdjMTBjNDI4Y2QzNWQ2ZTJhZCIsCiAgICAidXNlci1hZ2VudCI6ICJQb3N0bWFuUnVudGltZS83LjI4LjQiLAogICAgImFjY2VwdCI6ICIqLyoiLAogICAgImNhY2hlLWNvbnRyb2wiOiAibm8tY2FjaGUiLAogICAgInBvc3RtYW4tdG9rZW4iOiAiMjRjYTAxYWEtNmMzZi00YTc4LWE0MzctMzNkZmE4ZGFkZDBmIiwKICAgICJhY2NlcHQtZW5jb2RpbmciOiAiZ3ppcCwgZGVmbGF0ZSwgYnIiLAogICAgImNvb2tpZSI6ICJzYWlscy5zaWQ9cyUzQUZEN0h5MDFKQUFlbld6OVNvUVFoSnhINFF4ZWw5c2JQLiUyQmE1Sm1Ud3FPcGtjJTJGQU9MT3p6c2ZTdHBLMk1UZlpDWVhpQ29BMzladDd3IgogIH0sCiAgInVybCI6ICJodHRwczovL3Bvc3RtYW4tZWNoby5jb20vc3RyZWFtLzUiCn17CiAgImFyZ3MiOiB7CiAgICAibiI6ICI1IgogIH0sCiAgImhlYWRlcnMiOiB7CiAgICAieC1mb3J3YXJkZWQtcHJvdG8iOiAiaHR0cHMiLAogICAgIngtZm9yd2FyZGVkLXBvcnQiOiAiNDQzIiwKICAgICJob3N0IjogInBvc3RtYW4tZWNoby5jb20iLAogICAgIngtYW16bi10cmFjZS1pZCI6ICJSb290PTEtNjE2YTc5YWUtNmI2NjdjN2MxMGM0MjhjZDM1ZDZlMmFkIiwKICAgICJ1c2VyLWFnZW50IjogIlBvc3RtYW5SdW50aW1lLzcuMjguNCIsCiAgICAiYWNjZXB0IjogIiovKiIsCiAgICAiY2FjaGUtY29udHJvbCI6ICJuby1jYWNoZSIsCiAgICAicG9zdG1hbi10b2tlbiI6ICIyNGNhMDFhYS02YzNmLTRhNzgtYTQzNy0zM2RmYThkYWRkMGYiLAogICAgImFjY2VwdC1lbmNvZGluZyI6ICJnemlwLCBkZWZsYXRlLCBiciIsCiAgICAiY29va2llIjogInNhaWxzLnNpZD1zJTNBRkQ3SHkwMUpBQWVuV3o5U29RUWhKeEg0UXhlbDlzYlAuJTJCYTVKbVR3cU9wa2MlMkZBT0xPenpzZlN0cEsyTVRmWkNZWGlDb0EzOVp0N3ciCiAgfSwKICAidXJsIjogImh0dHBzOi8vcG9zdG1hbi1lY2hvLmNvbS9zdHJlYW0vNSIKfXsKICAiYXJncyI6IHsKICAgICJuIjogIjUiCiAgfSwKICAiaGVhZGVycyI6IHsKICAgICJ4LWZvcndhcmRlZC1wcm90byI6ICJodHRwcyIsCiAgICAieC1mb3J3YXJkZWQtcG9ydCI6ICI0NDMiLAogICAgImhvc3QiOiAicG9zdG1hbi1lY2hvLmNvbSIsCiAgICAieC1hbXpuLXRyYWNlLWlkIjogIlJvb3Q9MS02MTZhNzlhZS02YjY2N2M3YzEwYzQyOGNkMzVkNmUyYWQiLAogICAgInVzZXItYWdlbnQiOiAiUG9zdG1hblJ1bnRpbWUvNy4yOC40IiwKICAgICJhY2NlcHQiOiAiKi8qIiwKICAgICJjYWNoZS1jb250cm9sIjogIm5vLWNhY2hlIiwKICAgICJwb3N0bWFuLXRva2VuIjogIjI0Y2EwMWFhLTZjM2YtNGE3OC1hNDM3LTMzZGZhOGRhZGQwZiIsCiAgICAiYWNjZXB0LWVuY29kaW5nIjogImd6aXAsIGRlZmxhdGUsIGJyIiwKICAgICJjb29raWUiOiAic2FpbHMuc2lkPXMlM0FGRDdIeTAxSkFBZW5XejlTb1FRaEp4SDRReGVsOXNiUC4lMkJhNUptVHdxT3BrYyUyRkFPTE96enNmU3RwSzJNVGZaQ1lYaUNvQTM5WnQ3dyIKICB9LAogICJ1cmwiOiAiaHR0cHM6Ly9wb3N0bWFuLWVjaG8uY29tL3N0cmVhbS81Igp9ewogICJhcmdzIjogewogICAgIm4iOiAiNSIKICB9LAogICJoZWFkZXJzIjogewogICAgIngtZm9yd2FyZGVkLXByb3RvIjogImh0dHBzIiwKICAgICJ4LWZvcndhcmRlZC1wb3J0IjogIjQ0MyIsCiAgICAiaG9zdCI6ICJwb3N0bWFuLWVjaG8uY29tIiwKICAgICJ4LWFtem4tdHJhY2UtaWQiOiAiUm9vdD0xLTYxNmE3OWFlLTZiNjY3YzdjMTBjNDI4Y2QzNWQ2ZTJhZCIsCiAgICAidXNlci1hZ2VudCI6ICJQb3N0bWFuUnVudGltZS83LjI4LjQiLAogICAgImFjY2VwdCI6ICIqLyoiLAogICAgImNhY2hlLWNvbnRyb2wiOiAibm8tY2FjaGUiLAogICAgInBvc3RtYW4tdG9rZW4iOiAiMjRjYTAxYWEtNmMzZi00YTc4LWE0MzctMzNkZmE4ZGFkZDBmIiwKICAgICJhY2NlcHQtZW5jb2RpbmciOiAiZ3ppcCwgZGVmbGF0ZSwgYnIiLAogICAgImNvb2tpZSI6ICJzYWlscy5zaWQ9cyUzQUZEN0h5MDFKQUFlbld6OVNvUVFoSnhINFF4ZWw5c2JQLiUyQmE1Sm1Ud3FPcGtjJTJGQU9MT3p6c2ZTdHBLMk1UZlpDWVhpQ29BMzladDd3IgogIH0sCiAgInVybCI6ICJodHRwczovL3Bvc3RtYW4tZWNoby5jb20vc3RyZWFtLzUiCn17CiAgImFyZ3MiOiB7CiAgICAibiI6ICI1IgogIH0sCiAgImhlYWRlcnMiOiB7CiAgICAieC1mb3J3YXJkZWQtcHJvdG8iOiAiaHR0cHMiLAogICAgIngtZm9yd2FyZGVkLXBvcnQiOiAiNDQzIiwKICAgICJob3N0IjogInBvc3RtYW4tZWNoby5jb20iLAogICAgIngtYW16bi10cmFjZS1pZCI6ICJSb290PTEtNjE2YTc5YWUtNmI2NjdjN2MxMGM0MjhjZDM1ZDZlMmFkIiwKICAgICJ1c2VyLWFnZW50IjogIlBvc3RtYW5SdW50aW1lLzcuMjguNCIsCiAgICAiYWNjZXB0IjogIiovKiIsCiAgICAiY2FjaGUtY29udHJvbCI6ICJuby1jYWNoZSIsCiAgICAicG9zdG1hbi10b2tlbiI6ICIyNGNhMDFhYS02YzNmLTRhNzgtYTQzNy0zM2RmYThkYWRkMGYiLAogICAgImFjY2VwdC1lbmNvZGluZyI6ICJnemlwLCBkZWZsYXRlLCBiciIsCiAgICAiY29va2llIjogInNhaWxzLnNpZD1zJTNBRkQ3SHkwMUpBQWVuV3o5U29RUWhKeEg0UXhlbDlzYlAuJTJCYTVKbVR3cU9wa2MlMkZBT0xPenpzZlN0cEsyTVRmWkNZWGlDb0EzOVp0N3ciCiAgfSwKICAidXJsIjogImh0dHBzOi8vcG9zdG1hbi1lY2hvLmNvbS9zdHJlYW0vNSIKfQ==", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 2885 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 2, - "connect": 848, - "ssl": 570, - "send": 1, - "wait": 371, - "receive": 1 - } - }, - { - "startedDateTime": "2021-10-16T15:05:18.194+08:00", - "time": 3145, - "request": { - "method": "GET", - "url": "https://postman-echo.com/delay/2", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AqSePO9_VmCbBbVvsCMYMHm3lShKdFNWU.RFuwKJdlZHVyB0gF1x2Yt78v5jKbese6f8HNPIjI5AY" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "d2ade32f-4bb8-4e6d-90d3-5fa7560def12" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AqSePO9_VmCbBbVvsCMYMHm3lShKdFNWU.RFuwKJdlZHVyB0gF1x2Yt78v5jKbese6f8HNPIjI5AY" - } - ], - "queryString": [], - "headersSize": 335, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AXrCX-GaGzqizPQY2AdLTLNPO_cFgVsGD.BwOoj2gClsAzDrsP0%2FObypcumuYCfV%2F4vHCrKIWdTAQ", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:21 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "13" - }, - { - "name": "ETag", - "value": "W/\"d-vb8pS8uHJYunqF73qADGxcv0Je8\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3AXrCX-GaGzqizPQY2AdLTLNPO_cFgVsGD.BwOoj2gClsAzDrsP0%2FObypcumuYCfV%2F4vHCrKIWdTAQ; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 13, - "mimeType": "application/json; charset=utf-8", - "text": "eyJkZWxheSI6IjIifQ==", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 13 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 857, - "ssl": 572, - "send": 1, - "wait": 2285, - "receive": 1 - } - }, - { - "startedDateTime": "2021-10-16T15:05:21.376+08:00", - "time": 1182, - "request": { - "method": "GET", - "url": "https://postman-echo.com/encoding/utf8", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AXrCX-GaGzqizPQY2AdLTLNPO_cFgVsGD.BwOoj2gClsAzDrsP0%2FObypcumuYCfV%2F4vHCrKIWdTAQ" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "bd39f8e4-8072-4ec3-b498-3aaacb621544" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AXrCX-GaGzqizPQY2AdLTLNPO_cFgVsGD.BwOoj2gClsAzDrsP0%2FObypcumuYCfV%2F4vHCrKIWdTAQ" - } - ], - "queryString": [], - "headersSize": 345, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AdknETdvYiCwRbtxpWR58ZhmohmZJOqdI.SA8%2FR072CZkldOTuVv7TYyKpzEQWpkt%2F2YTTTBFn%2BzU", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:22 GMT" - }, - { - "name": "Content-Type", - "value": "text/html; charset=utf-8" - }, - { - "name": "Transfer-Encoding", - "value": "chunked" - }, - { - "name": "ETag", - "value": "W/\"3d0e-bb1Z6nxw+98ped7xrePAFKVeCtU\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "Content-Encoding", - "value": "gzip" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3AdknETdvYiCwRbtxpWR58ZhmohmZJOqdI.SA8%2FR072CZkldOTuVv7TYyKpzEQWpkt%2F2YTTTBFn%2BzU; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 15630, - "compression": 9411, - "mimeType": "text/html; charset=utf-8", - "text": "\n \n \n

Unicode Demo

\n\n

Taken from \n http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-demo.txt

\n\n
\n\n        UTF-8 encoded sample plain-text file\n        ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾\n\n        Markus Kuhn [ˈmaʳkʊs kuːn]  — 2002-07-25\n\n\n        The ASCII compatible UTF-8 encoding used in this plain-text file\n        is defined in Unicode, ISO 10646-1, and RFC 2279.\n\n\n        Using Unicode/UTF-8, you can write in emails and source code things such as\n\n        Mathematics and sciences:\n\n          ∮ E⋅da = Q,  n → ∞, ∑ f(i) = ∏ g(i),      ⎧⎡⎛┌─────┐⎞⎤⎫\n                                                    ⎪⎢⎜│a²+b³ ⎟⎥⎪\n          ∀x∈ℝ: ⌈x⌉ = −⌊−x⌋, α ∧ ¬β = ¬(¬α ∨ β),    ⎪⎢⎜│───── ⎟⎥⎪\n                                                    ⎪⎢⎜⎷ c₈   ⎟⎥⎪\n          ℕ ⊆ ℕ₀ ⊂ ℤ ⊂ ℚ ⊂ ℝ ⊂ ℂ,                   ⎨⎢⎜       ⎟⎥⎬\n                                                    ⎪⎢⎜ ∞     ⎟⎥⎪\n          ⊥ < a ≠ b ≡ c ≤ d ≪ ⊤ ⇒ (⟦A⟧ ⇔ ⟪B⟫),      ⎪⎢⎜ ⎲     ⎟⎥⎪\n                                                    ⎪⎢⎜ ⎳aⁱ-bⁱ⎟⎥⎪\n          2H₂ + O₂ ⇌ 2H₂O, R = 4.7 kΩ, ⌀ 200 mm     ⎩⎣⎝i=1    ⎠⎦⎭\n\n        Linguistics and dictionaries:\n\n          ði ıntəˈnæʃənəl fəˈnɛtık əsoʊsiˈeıʃn\n          Y [ˈʏpsilɔn], Yen [jɛn], Yoga [ˈjoːgɑ]\n\n        APL:\n\n          ((V⍳V)=⍳⍴V)/V←,V    ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈\n\n        Nicer typography in plain text files:\n\n          ╔══════════════════════════════════════════╗\n          ║                                          ║\n          ║   • ‘single’ and “double” quotes         ║\n          ║                                          ║\n          ║   • Curly apostrophes: “We’ve been here” ║\n          ║                                          ║\n          ║   • Latin-1 apostrophe and accents: '´`  ║\n          ║                                          ║\n          ║   • ‚deutsche‘ „Anführungszeichen“       ║\n          ║                                          ║\n          ║   • †, ‡, ‰, •, 3–4, —, −5/+5, ™, …      ║\n          ║                                          ║\n          ║   • ASCII safety test: 1lI|, 0OD, 8B     ║\n          ║                      ╭─────────╮         ║\n          ║   • the euro symbol: │ 14.95 € │         ║\n          ║                      ╰─────────╯         ║\n          ╚══════════════════════════════════════════╝\n\n        Combining characters:\n\n          STARGΛ̊TE SG-1, a = v̇ = r̈, a⃑ ⊥ b⃑\n\n        Greek (in Polytonic):\n\n          The Greek anthem:\n\n          Σὲ γνωρίζω ἀπὸ τὴν κόψη\n          τοῦ σπαθιοῦ τὴν τρομερή,\n          σὲ γνωρίζω ἀπὸ τὴν ὄψη\n          ποὺ μὲ βία μετράει τὴ γῆ.\n\n          ᾿Απ᾿ τὰ κόκκαλα βγαλμένη\n          τῶν ῾Ελλήνων τὰ ἱερά\n          καὶ σὰν πρῶτα ἀνδρειωμένη\n          χαῖρε, ὦ χαῖρε, ᾿Ελευθεριά!\n\n          From a speech of Demosthenes in the 4th century BC:\n\n          Οὐχὶ ταὐτὰ παρίσταταί μοι γιγνώσκειν, ὦ ἄνδρες ᾿Αθηναῖοι,\n          ὅταν τ᾿ εἰς τὰ πράγματα ἀποβλέψω καὶ ὅταν πρὸς τοὺς\n          λόγους οὓς ἀκούω· τοὺς μὲν γὰρ λόγους περὶ τοῦ\n          τιμωρήσασθαι Φίλιππον ὁρῶ γιγνομένους, τὰ δὲ πράγματ᾿\n          εἰς τοῦτο προήκοντα,  ὥσθ᾿ ὅπως μὴ πεισόμεθ᾿ αὐτοὶ\n          πρότερον κακῶς σκέψασθαι δέον. οὐδέν οὖν ἄλλο μοι δοκοῦσιν\n          οἱ τὰ τοιαῦτα λέγοντες ἢ τὴν ὑπόθεσιν, περὶ ἧς βουλεύεσθαι,\n          οὐχὶ τὴν οὖσαν παριστάντες ὑμῖν ἁμαρτάνειν. ἐγὼ δέ, ὅτι μέν\n          ποτ᾿ ἐξῆν τῇ πόλει καὶ τὰ αὑτῆς ἔχειν ἀσφαλῶς καὶ Φίλιππον\n          τιμωρήσασθαι, καὶ μάλ᾿ ἀκριβῶς οἶδα· ἐπ᾿ ἐμοῦ γάρ, οὐ πάλαι\n          γέγονεν ταῦτ᾿ ἀμφότερα· νῦν μέντοι πέπεισμαι τοῦθ᾿ ἱκανὸν\n          προλαβεῖν ἡμῖν εἶναι τὴν πρώτην, ὅπως τοὺς συμμάχους\n          σώσομεν. ἐὰν γὰρ τοῦτο βεβαίως ὑπάρξῃ, τότε καὶ περὶ τοῦ\n          τίνα τιμωρήσεταί τις καὶ ὃν τρόπον ἐξέσται σκοπεῖν· πρὶν δὲ\n          τὴν ἀρχὴν ὀρθῶς ὑποθέσθαι, μάταιον ἡγοῦμαι περὶ τῆς\n          τελευτῆς ὁντινοῦν ποιεῖσθαι λόγον.\n\n          Δημοσθένους, Γ´ ᾿Ολυνθιακὸς\n\n        Georgian:\n\n          From a Unicode conference invitation:\n\n          გთხოვთ ახლავე გაიაროთ რეგისტრაცია Unicode-ის მეათე საერთაშორისო\n          კონფერენციაზე დასასწრებად, რომელიც გაიმართება 10-12 მარტს,\n          ქ. მაინცში, გერმანიაში. კონფერენცია შეჰკრებს ერთად მსოფლიოს\n          ექსპერტებს ისეთ დარგებში როგორიცაა ინტერნეტი და Unicode-ი,\n          ინტერნაციონალიზაცია და ლოკალიზაცია, Unicode-ის გამოყენება\n          ოპერაციულ სისტემებსა, და გამოყენებით პროგრამებში, შრიფტებში,\n          ტექსტების დამუშავებასა და მრავალენოვან კომპიუტერულ სისტემებში.\n\n        Russian:\n\n          From a Unicode conference invitation:\n\n          Зарегистрируйтесь сейчас на Десятую Международную Конференцию по\n          Unicode, которая состоится 10-12 марта 1997 года в Майнце в Германии.\n          Конференция соберет широкий круг экспертов по  вопросам глобального\n          Интернета и Unicode, локализации и интернационализации, воплощению и\n          применению Unicode в различных операционных системах и программных\n          приложениях, шрифтах, верстке и многоязычных компьютерных системах.\n\n        Thai (UCS Level 2):\n\n          Excerpt from a poetry on The Romance of The Three Kingdoms (a Chinese\n          classic 'San Gua'):\n\n          [----------------------------|------------------------]\n            ๏ แผ่นดินฮั่นเสื่อมโทรมแสนสังเวช  พระปกเกศกองบู๊กู้ขึ้นใหม่\n          สิบสองกษัตริย์ก่อนหน้าแลถัดไป       สององค์ไซร้โง่เขลาเบาปัญญา\n            ทรงนับถือขันทีเป็นที่พึ่ง           บ้านเมืองจึงวิปริตเป็นนักหนา\n          โฮจิ๋นเรียกทัพทั่วหัวเมืองมา         หมายจะฆ่ามดชั่วตัวสำคัญ\n            เหมือนขับไสไล่เสือจากเคหา      รับหมาป่าเข้ามาเลยอาสัญ\n          ฝ่ายอ้องอุ้นยุแยกให้แตกกัน          ใช้สาวนั้นเป็นชนวนชื่นชวนใจ\n            พลันลิฉุยกุยกีกลับก่อเหตุ          ช่างอาเพศจริงหนาฟ้าร้องไห้\n          ต้องรบราฆ่าฟันจนบรรลัย           ฤๅหาใครค้ำชูกู้บรรลังก์ ฯ\n\n          (The above is a two-column text. If combining characters are handled\n          correctly, the lines of the second column should be aligned with the\n          | character above.)\n\n        Ethiopian:\n\n          Proverbs in the Amharic language:\n\n          ሰማይ አይታረስ ንጉሥ አይከሰስ።\n          ብላ ካለኝ እንደአባቴ በቆመጠኝ።\n          ጌጥ ያለቤቱ ቁምጥና ነው።\n          ደሀ በሕልሙ ቅቤ ባይጠጣ ንጣት በገደለው።\n          የአፍ ወለምታ በቅቤ አይታሽም።\n          አይጥ በበላ ዳዋ ተመታ።\n          ሲተረጉሙ ይደረግሙ።\n          ቀስ በቀስ፥ ዕንቁላል በእግሩ ይሄዳል።\n          ድር ቢያብር አንበሳ ያስር።\n          ሰው እንደቤቱ እንጅ እንደ ጉረቤቱ አይተዳደርም።\n          እግዜር የከፈተውን ጉሮሮ ሳይዘጋው አይድርም።\n          የጎረቤት ሌባ፥ ቢያዩት ይስቅ ባያዩት ያጠልቅ።\n          ሥራ ከመፍታት ልጄን ላፋታት።\n          ዓባይ ማደሪያ የለው፥ ግንድ ይዞ ይዞራል።\n          የእስላም አገሩ መካ የአሞራ አገሩ ዋርካ።\n          ተንጋሎ ቢተፉ ተመልሶ ባፉ።\n          ወዳጅህ ማር ቢሆን ጨርስህ አትላሰው።\n          እግርህን በፍራሽህ ልክ ዘርጋ።\n\n        Runes:\n\n          ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ\n\n          (Old English, which transcribed into Latin reads 'He cwaeth that he\n          bude thaem lande northweardum with tha Westsae.' and means 'He said\n          that he lived in the northern land near the Western Sea.')\n\n        Braille:\n\n          ⡌⠁⠧⠑ ⠼⠁⠒  ⡍⠜⠇⠑⠹⠰⠎ ⡣⠕⠌\n\n          ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠙⠑⠁⠙⠒ ⠞⠕ ⠃⠑⠛⠔ ⠺⠊⠹⠲ ⡹⠻⠑ ⠊⠎ ⠝⠕ ⠙⠳⠃⠞\n          ⠱⠁⠞⠑⠧⠻ ⠁⠃⠳⠞ ⠹⠁⠞⠲ ⡹⠑ ⠗⠑⠛⠊⠌⠻ ⠕⠋ ⠙⠊⠎ ⠃⠥⠗⠊⠁⠇ ⠺⠁⠎\n          ⠎⠊⠛⠝⠫ ⠃⠹ ⠹⠑ ⠊⠇⠻⠛⠹⠍⠁⠝⠂ ⠹⠑ ⠊⠇⠻⠅⠂ ⠹⠑ ⠥⠝⠙⠻⠞⠁⠅⠻⠂\n          ⠁⠝⠙ ⠹⠑ ⠡⠊⠑⠋ ⠍⠳⠗⠝⠻⠲ ⡎⠊⠗⠕⠕⠛⠑ ⠎⠊⠛⠝⠫ ⠊⠞⠲ ⡁⠝⠙\n          ⡎⠊⠗⠕⠕⠛⠑⠰⠎ ⠝⠁⠍⠑ ⠺⠁⠎ ⠛⠕⠕⠙ ⠥⠏⠕⠝ ⠰⡡⠁⠝⠛⠑⠂ ⠋⠕⠗ ⠁⠝⠹⠹⠔⠛ ⠙⠑\n          ⠡⠕⠎⠑ ⠞⠕ ⠏⠥⠞ ⠙⠊⠎ ⠙⠁⠝⠙ ⠞⠕⠲\n\n          ⡕⠇⠙ ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲\n\n          ⡍⠔⠙⠖ ⡊ ⠙⠕⠝⠰⠞ ⠍⠑⠁⠝ ⠞⠕ ⠎⠁⠹ ⠹⠁⠞ ⡊ ⠅⠝⠪⠂ ⠕⠋ ⠍⠹\n          ⠪⠝ ⠅⠝⠪⠇⠫⠛⠑⠂ ⠱⠁⠞ ⠹⠻⠑ ⠊⠎ ⠏⠜⠞⠊⠊⠥⠇⠜⠇⠹ ⠙⠑⠁⠙ ⠁⠃⠳⠞\n          ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ ⡊ ⠍⠊⠣⠞ ⠙⠁⠧⠑ ⠃⠑⠲ ⠔⠊⠇⠔⠫⠂ ⠍⠹⠎⠑⠇⠋⠂ ⠞⠕\n          ⠗⠑⠛⠜⠙ ⠁ ⠊⠕⠋⠋⠔⠤⠝⠁⠊⠇ ⠁⠎ ⠹⠑ ⠙⠑⠁⠙⠑⠌ ⠏⠊⠑⠊⠑ ⠕⠋ ⠊⠗⠕⠝⠍⠕⠝⠛⠻⠹\n          ⠔ ⠹⠑ ⠞⠗⠁⠙⠑⠲ ⡃⠥⠞ ⠹⠑ ⠺⠊⠎⠙⠕⠍ ⠕⠋ ⠳⠗ ⠁⠝⠊⠑⠌⠕⠗⠎\n          ⠊⠎ ⠔ ⠹⠑ ⠎⠊⠍⠊⠇⠑⠆ ⠁⠝⠙ ⠍⠹ ⠥⠝⠙⠁⠇⠇⠪⠫ ⠙⠁⠝⠙⠎\n          ⠩⠁⠇⠇ ⠝⠕⠞ ⠙⠊⠌⠥⠗⠃ ⠊⠞⠂ ⠕⠗ ⠹⠑ ⡊⠳⠝⠞⠗⠹⠰⠎ ⠙⠕⠝⠑ ⠋⠕⠗⠲ ⡹⠳\n          ⠺⠊⠇⠇ ⠹⠻⠑⠋⠕⠗⠑ ⠏⠻⠍⠊⠞ ⠍⠑ ⠞⠕ ⠗⠑⠏⠑⠁⠞⠂ ⠑⠍⠏⠙⠁⠞⠊⠊⠁⠇⠇⠹⠂ ⠹⠁⠞\n          ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲\n\n          (The first couple of paragraphs of \"A Christmas Carol\" by Dickens)\n\n        Compact font selection example text:\n\n          ABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789\n          abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ\n          –—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвгд\n          ∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi�⑀₂ἠḂӥẄɐː⍎אԱა\n\n        Greetings in various languages:\n\n          Hello world, Καλημέρα κόσμε, コンニチハ\n\n        Box drawing alignment tests:                                          █\n                                                                              ▉\n          ╔══╦══╗  ┌──┬──┐  ╭──┬──╮  ╭──┬──╮  ┏━━┳━━┓  ┎┒┏┑   ╷  ╻ ┏┯┓ ┌┰┐    ▊ ╱╲╱╲╳╳╳\n          ║┌─╨─┐║  │╔═╧═╗│  │╒═╪═╕│  │╓─╁─╖│  ┃┌─╂─┐┃  ┗╃╄┙  ╶┼╴╺╋╸┠┼┨ ┝╋┥    ▋ ╲╱╲╱╳╳╳\n          ║│╲ ╱│║  │║   ║│  ││ │ ││  │║ ┃ ║│  ┃│ ╿ │┃  ┍╅╆┓   ╵  ╹ ┗┷┛ └┸┘    ▌ ╱╲╱╲╳╳╳\n          ╠╡ ╳ ╞╣  ├╢   ╟┤  ├┼─┼─┼┤  ├╫─╂─╫┤  ┣┿╾┼╼┿┫  ┕┛┖┚     ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳\n          ║│╱ ╲│║  │║   ║│  ││ │ ││  │║ ┃ ║│  ┃│ ╽ │┃  ░░▒▒▓▓██ ┊  ┆ ╎ ╏  ┇ ┋ ▎\n          ║└─╥─┘║  │╚═╤═╝│  │╘═╪═╛│  │╙─╀─╜│  ┃└─╂─┘┃  ░░▒▒▓▓██ ┊  ┆ ╎ ╏  ┇ ┋ ▏\n          ╚══╩══╝  └──┴──┘  ╰──┴──╯  ╰──┴──╯  ┗━━┻━━┛  ▗▄▖▛▀▜   └╌╌┘ ╎ ┗╍╍┛ ┋  ▁▂▃▄▅▆▇█\n                                                       ▝▀▘▙▄▟\n\n        
\n \n \n " - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 6219 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 858, - "ssl": 576, - "send": 0, - "wait": 322, - "receive": 1 - } - }, - { - "startedDateTime": "2021-10-16T15:05:22.601+08:00", - "time": 1241, - "request": { - "method": "GET", - "url": "https://postman-echo.com/gzip", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AdknETdvYiCwRbtxpWR58ZhmohmZJOqdI.SA8%2FR072CZkldOTuVv7TYyKpzEQWpkt%2F2YTTTBFn%2BzU" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "ef40db18-75f9-4d0c-9fe8-94274a0a589e" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AdknETdvYiCwRbtxpWR58ZhmohmZJOqdI.SA8%2FR072CZkldOTuVv7TYyKpzEQWpkt%2F2YTTTBFn%2BzU" - } - ], - "queryString": [], - "headersSize": 338, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:23 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "381" - }, - { - "name": "Content-Encoding", - "value": "gzip" - }, - { - "name": "ETag", - "value": "W/\"17d-oe2gyqLr7HgZNpWMdAxjB727Dps\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 539, - "compression": 158, - "mimeType": "application/json; charset=utf-8", - "text": "ewogICJnemlwcGVkIjogdHJ1ZSwKICAiaGVhZGVycyI6IHsKICAgICJ4LWZvcndhcmRlZC1wcm90byI6ICJodHRwcyIsCiAgICAieC1mb3J3YXJkZWQtcG9ydCI6ICI0NDMiLAogICAgImhvc3QiOiAicG9zdG1hbi1lY2hvLmNvbSIsCiAgICAieC1hbXpuLXRyYWNlLWlkIjogIlJvb3Q9MS02MTZhNzliMy0yNjMyOTc4YjJlZWM0MDAwNDE2ZGY4NTAiLAogICAgInVzZXItYWdlbnQiOiAiUG9zdG1hblJ1bnRpbWUvNy4yOC40IiwKICAgICJhY2NlcHQiOiAiKi8qIiwKICAgICJjYWNoZS1jb250cm9sIjogIm5vLWNhY2hlIiwKICAgICJwb3N0bWFuLXRva2VuIjogImVmNDBkYjE4LTc1ZjktNGQwYy05ZmU4LTk0Mjc0YTBhNTg5ZSIsCiAgICAiYWNjZXB0LWVuY29kaW5nIjogImd6aXAsIGRlZmxhdGUsIGJyIiwKICAgICJjb29raWUiOiAic2FpbHMuc2lkPXMlM0Fka25FVGR2WWlDd1JidHhwV1I1OFpobW9obVpKT3FkSS5TQTglMkZSMDcyQ1prbGRPVHVWdjdUWXlLcHpFUVdwa3QlMkYyWVRUVEJGbiUyQnpVIgogIH0sCiAgIm1ldGhvZCI6ICJHRVQiCn0=", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 381 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 888, - "ssl": 608, - "send": 1, - "wait": 350, - "receive": 1 - } - }, - { - "startedDateTime": "2021-10-16T15:05:23.879+08:00", - "time": 1447, - "request": { - "method": "GET", - "url": "https://postman-echo.com/deflate", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AdknETdvYiCwRbtxpWR58ZhmohmZJOqdI.SA8%2FR072CZkldOTuVv7TYyKpzEQWpkt%2F2YTTTBFn%2BzU" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "06b47e94-9131-4ab7-8d0e-d0990f1a1144" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AdknETdvYiCwRbtxpWR58ZhmohmZJOqdI.SA8%2FR072CZkldOTuVv7TYyKpzEQWpkt%2F2YTTTBFn%2BzU" - } - ], - "queryString": [], - "headersSize": 341, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3A_sZ_Nn5QQ0b2Swfp9tMHX9CWKJb9X3is.fa%2FQ9D9WhuFBgpatC2Yo33cPynch4YqbG%2Fw9iB92Jxo", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:25 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "367" - }, - { - "name": "Content-Encoding", - "value": "deflate" - }, - { - "name": "ETag", - "value": "W/\"16f-6gmrv4fnhXu0S9HAifYY68xUiZc\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3A_sZ_Nn5QQ0b2Swfp9tMHX9CWKJb9X3is.fa%2FQ9D9WhuFBgpatC2Yo33cPynch4YqbG%2Fw9iB92Jxo; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 540, - "compression": 173, - "mimeType": "application/json; charset=utf-8", - "text": "ewogICJkZWZsYXRlZCI6IHRydWUsCiAgImhlYWRlcnMiOiB7CiAgICAieC1mb3J3YXJkZWQtcHJvdG8iOiAiaHR0cHMiLAogICAgIngtZm9yd2FyZGVkLXBvcnQiOiAiNDQzIiwKICAgICJob3N0IjogInBvc3RtYW4tZWNoby5jb20iLAogICAgIngtYW16bi10cmFjZS1pZCI6ICJSb290PTEtNjE2YTc5YjUtNDc1NDU5OWIxZmNkNTU1NTUwNDkxMDdlIiwKICAgICJ1c2VyLWFnZW50IjogIlBvc3RtYW5SdW50aW1lLzcuMjguNCIsCiAgICAiYWNjZXB0IjogIiovKiIsCiAgICAiY2FjaGUtY29udHJvbCI6ICJuby1jYWNoZSIsCiAgICAicG9zdG1hbi10b2tlbiI6ICIwNmI0N2U5NC05MTMxLTRhYjctOGQwZS1kMDk5MGYxYTExNDQiLAogICAgImFjY2VwdC1lbmNvZGluZyI6ICJnemlwLCBkZWZsYXRlLCBiciIsCiAgICAiY29va2llIjogInNhaWxzLnNpZD1zJTNBZGtuRVRkdllpQ3dSYnR4cFdSNThaaG1vaG1aSk9xZEkuU0E4JTJGUjA3MkNaa2xkT1R1VnY3VFl5S3B6RVFXcGt0JTJGMllUVFRCRm4lMkJ6VSIKICB9LAogICJtZXRob2QiOiAiR0VUIgp9", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 367 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 1044, - "ssl": 764, - "send": 0, - "wait": 401, - "receive": 1 - } - }, - { - "startedDateTime": "2021-10-16T15:05:25.364+08:00", - "time": 1177, - "request": { - "method": "GET", - "url": "https://postman-echo.com/ip", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3A_sZ_Nn5QQ0b2Swfp9tMHX9CWKJb9X3is.fa%2FQ9D9WhuFBgpatC2Yo33cPynch4YqbG%2Fw9iB92Jxo" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "246c423e-9285-4fad-b471-434bf4bf3369" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3A_sZ_Nn5QQ0b2Swfp9tMHX9CWKJb9X3is.fa%2FQ9D9WhuFBgpatC2Yo33cPynch4YqbG%2Fw9iB92Jxo" - } - ], - "queryString": [], - "headersSize": 334, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AFqdFnM7dGE1ds2DZfijQergoGKJKdivs.TZy6jaQuf3wKK7VHSuQRNwDrZuuvCx3pGhhj7lKouQs", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:26 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "22" - }, - { - "name": "ETag", - "value": "W/\"16-ZXKRURzaxajlwvm0ML1HZbz4Rfw\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3AFqdFnM7dGE1ds2DZfijQergoGKJKdivs.TZy6jaQuf3wKK7VHSuQRNwDrZuuvCx3pGhhj7lKouQs; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 22, - "mimeType": "application/json; charset=utf-8", - "text": "eyJpcCI6IjEyMi4xNC4yMjkuNzkifQ==", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 22 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 889, - "ssl": 606, - "send": 0, - "wait": 286, - "receive": 1 - } - }, - { - "startedDateTime": "2021-10-16T15:05:26.576+08:00", - "time": 1194, - "request": { - "method": "GET", - "url": "https://postman-echo.com/time/now", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AFqdFnM7dGE1ds2DZfijQergoGKJKdivs.TZy6jaQuf3wKK7VHSuQRNwDrZuuvCx3pGhhj7lKouQs" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "e1107fa9-80cb-4e69-b3dd-6fd0c92832b1" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AFqdFnM7dGE1ds2DZfijQergoGKJKdivs.TZy6jaQuf3wKK7VHSuQRNwDrZuuvCx3pGhhj7lKouQs" - } - ], - "queryString": [], - "headersSize": 336, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:27 GMT" - }, - { - "name": "Content-Type", - "value": "text/html; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "29" - }, - { - "name": "ETag", - "value": "W/\"1d-Tr20f4VzzgEG6gD2rRpoAaVOy+A\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 29, - "mimeType": "text/html; charset=utf-8", - "text": "Sat, 16 Oct 2021 07:05:27 GMT" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 29 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 909, - "ssl": 628, - "send": 0, - "wait": 283, - "receive": 1 - } - }, - { - "startedDateTime": "2021-10-16T15:05:27.800+08:00", - "time": 1315, - "request": { - "method": "GET", - "url": "https://postman-echo.com/time/valid?timestamp=2016-10-10", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AFqdFnM7dGE1ds2DZfijQergoGKJKdivs.TZy6jaQuf3wKK7VHSuQRNwDrZuuvCx3pGhhj7lKouQs" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "05eb8403-8a83-4bde-bdd4-67952910c00f" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AFqdFnM7dGE1ds2DZfijQergoGKJKdivs.TZy6jaQuf3wKK7VHSuQRNwDrZuuvCx3pGhhj7lKouQs" - } - ], - "queryString": [ - { - "name": "timestamp", - "value": "2016-10-10" - } - ], - "headersSize": 359, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3Ai_9yOOqBlD9Nq0-5kptXL_qLhgITKpaZ.HU5sTJC0jVIzJvykONaDFYTiMZrZpQgdiwMInhSADss", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:29 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "14" - }, - { - "name": "ETag", - "value": "W/\"e-3MDSGou3nIOvlBZElUyTiBbaRZY\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3Ai_9yOOqBlD9Nq0-5kptXL_qLhgITKpaZ.HU5sTJC0jVIzJvykONaDFYTiMZrZpQgdiwMInhSADss; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 14, - "mimeType": "application/json; charset=utf-8", - "text": "eyJ2YWxpZCI6dHJ1ZX0=", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 14 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 912, - "ssl": 612, - "send": 0, - "wait": 402, - "receive": 0 - } - }, - { - "startedDateTime": "2021-10-16T15:05:29.150+08:00", - "time": 1405, - "request": { - "method": "GET", - "url": "https://postman-echo.com/time/format?timestamp=2016-10-10&format=mm", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3Ai_9yOOqBlD9Nq0-5kptXL_qLhgITKpaZ.HU5sTJC0jVIzJvykONaDFYTiMZrZpQgdiwMInhSADss" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "7bab6bdc-6fe5-4eb8-aff0-3cfa08e5a823" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3Ai_9yOOqBlD9Nq0-5kptXL_qLhgITKpaZ.HU5sTJC0jVIzJvykONaDFYTiMZrZpQgdiwMInhSADss" - } - ], - "queryString": [ - { - "name": "timestamp", - "value": "2016-10-10" - }, - { - "name": "format", - "value": "mm" - } - ], - "headersSize": 370, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AlSI63UO-j2SWcK0YQfFAScLu2YKvhtlr.0wPoZkmPHUiNtTVy55Bdt9ulnQxk%2FahmG6a7%2BE6gtg8", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:30 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "15" - }, - { - "name": "ETag", - "value": "W/\"f-oSXEKZdRgFcBy3nxz+EFgc2p5wo\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3AlSI63UO-j2SWcK0YQfFAScLu2YKvhtlr.0wPoZkmPHUiNtTVy55Bdt9ulnQxk%2FahmG6a7%2BE6gtg8; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 15, - "mimeType": "application/json; charset=utf-8", - "text": "eyJmb3JtYXQiOiIyMCJ9", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 15 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 996, - "ssl": 715, - "send": 0, - "wait": 407, - "receive": 1 - } - }, - { - "startedDateTime": "2021-10-16T15:05:30.592+08:00", - "time": 1243, - "request": { - "method": "GET", - "url": "https://postman-echo.com/time/unit?timestamp=2016-10-10&unit=day", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AlSI63UO-j2SWcK0YQfFAScLu2YKvhtlr.0wPoZkmPHUiNtTVy55Bdt9ulnQxk%2FahmG6a7%2BE6gtg8" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "8dbb7595-3ff0-47cd-8883-4c1f24a840ef" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AlSI63UO-j2SWcK0YQfFAScLu2YKvhtlr.0wPoZkmPHUiNtTVy55Bdt9ulnQxk%2FahmG6a7%2BE6gtg8" - } - ], - "queryString": [ - { - "name": "timestamp", - "value": "2016-10-10" - }, - { - "name": "unit", - "value": "day" - } - ], - "headersSize": 371, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:32 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "10" - }, - { - "name": "ETag", - "value": "W/\"a-Tq86/bt7ViOhfxXgqKCTL6sompk\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 10, - "mimeType": "application/json; charset=utf-8", - "text": "eyJ1bml0IjoxfQ==", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 10 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 3, - "connect": 958, - "ssl": 586, - "send": 0, - "wait": 282, - "receive": 0 - } - }, - { - "startedDateTime": "2021-10-16T15:05:31.870+08:00", - "time": 1223, - "request": { - "method": "GET", - "url": "https://postman-echo.com/time/add?timestamp=2016-10-10&years=100", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AlSI63UO-j2SWcK0YQfFAScLu2YKvhtlr.0wPoZkmPHUiNtTVy55Bdt9ulnQxk%2FahmG6a7%2BE6gtg8" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "12c5137f-ee8e-48c2-b1b7-99c85f0667e4" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AlSI63UO-j2SWcK0YQfFAScLu2YKvhtlr.0wPoZkmPHUiNtTVy55Bdt9ulnQxk%2FahmG6a7%2BE6gtg8" - } - ], - "queryString": [ - { - "name": "timestamp", - "value": "2016-10-10" - }, - { - "name": "years", - "value": "100" - } - ], - "headersSize": 371, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3A5OS8kEURZ8ZYZzfO7we0KvxaGI1AdMRZ.L6C2S4%2B6rTQd5qdQufDhV9rDv9CJgENLudOAk9h0Yow", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:33 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "43" - }, - { - "name": "ETag", - "value": "W/\"2b-NI+s6dhyoOC4+MmZW5sCBgzsnMw\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3A5OS8kEURZ8ZYZzfO7we0KvxaGI1AdMRZ.L6C2S4%2B6rTQd5qdQufDhV9rDv9CJgENLudOAk9h0Yow; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 43, - "mimeType": "application/json; charset=utf-8", - "text": "eyJzdW0iOiJTYXQgT2N0IDEwIDIxMTYgMDA6MDA6MDAgR01UKzAwMDAifQ==", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 43 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 937, - "ssl": 637, - "send": 0, - "wait": 285, - "receive": 0 - } - }, - { - "startedDateTime": "2021-10-16T15:05:33.126+08:00", - "time": 1209, - "request": { - "method": "GET", - "url": "https://postman-echo.com/time/subtract?timestamp=2016-10-10&years=50", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3A5OS8kEURZ8ZYZzfO7we0KvxaGI1AdMRZ.L6C2S4%2B6rTQd5qdQufDhV9rDv9CJgENLudOAk9h0Yow" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "d903ee32-4361-44a4-af56-819e7fa10cc4" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3A5OS8kEURZ8ZYZzfO7we0KvxaGI1AdMRZ.L6C2S4%2B6rTQd5qdQufDhV9rDv9CJgENLudOAk9h0Yow" - } - ], - "queryString": [ - { - "name": "timestamp", - "value": "2016-10-10" - }, - { - "name": "years", - "value": "50" - } - ], - "headersSize": 373, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3A2PKCLJCVRo_5V_uagkV5b3Kn9dV0eQUm.Dp5OFZ%2FCtOcDKqB8y8yywFHO6LbN9oe10o4DQ%2FnoKRk", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:34 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "50" - }, - { - "name": "ETag", - "value": "W/\"32-PND5PkDaCj18RICDpWcSi9vkakY\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3A2PKCLJCVRo_5V_uagkV5b3Kn9dV0eQUm.Dp5OFZ%2FCtOcDKqB8y8yywFHO6LbN9oe10o4DQ%2FnoKRk; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 50, - "mimeType": "application/json; charset=utf-8", - "text": "eyJkaWZmZXJlbmNlIjoiTW9uIE9jdCAxMCAxOTY2IDAwOjAwOjAwIEdNVCswMDAwIn0=", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 50 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 868, - "ssl": 572, - "send": 0, - "wait": 339, - "receive": 1 - } - }, - { - "startedDateTime": "2021-10-16T15:05:34.370+08:00", - "time": 1298, - "request": { - "method": "GET", - "url": "https://postman-echo.com/time/start?timestamp=2016-10-10&unit=month", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3A2PKCLJCVRo_5V_uagkV5b3Kn9dV0eQUm.Dp5OFZ%2FCtOcDKqB8y8yywFHO6LbN9oe10o4DQ%2FnoKRk" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "2d666d32-2815-45be-ae8d-266eea519043" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3A2PKCLJCVRo_5V_uagkV5b3Kn9dV0eQUm.Dp5OFZ%2FCtOcDKqB8y8yywFHO6LbN9oe10o4DQ%2FnoKRk" - } - ], - "queryString": [ - { - "name": "timestamp", - "value": "2016-10-10" - }, - { - "name": "unit", - "value": "month" - } - ], - "headersSize": 374, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AWJZnlAAItW8H8a4UMGox8Iz7cv3TM5Zq.YRYNuDnd6fkHDDvlbilW9q4AkvSPwE8SsBs2JRC52HU", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:35 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "45" - }, - { - "name": "ETag", - "value": "W/\"2d-+DRNEGBPVvAa16PUC5AjHCOmq/0\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3AWJZnlAAItW8H8a4UMGox8Iz7cv3TM5Zq.YRYNuDnd6fkHDDvlbilW9q4AkvSPwE8SsBs2JRC52HU; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 45, - "mimeType": "application/json; charset=utf-8", - "text": "eyJzdGFydCI6IlNhdCBPY3QgMDEgMjAxNiAwMDowMDowMCBHTVQrMDAwMCJ9", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 45 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 893, - "ssl": 608, - "send": 0, - "wait": 403, - "receive": 1 - } - }, - { - "startedDateTime": "2021-10-16T15:05:35.701+08:00", - "time": 1137, - "request": { - "method": "GET", - "url": "https://postman-echo.com/time/object?timestamp=2016-10-10", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AWJZnlAAItW8H8a4UMGox8Iz7cv3TM5Zq.YRYNuDnd6fkHDDvlbilW9q4AkvSPwE8SsBs2JRC52HU" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "6ecae5c7-b9b4-450d-865c-10aea2f6384c" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AWJZnlAAItW8H8a4UMGox8Iz7cv3TM5Zq.YRYNuDnd6fkHDDvlbilW9q4AkvSPwE8SsBs2JRC52HU" - } - ], - "queryString": [ - { - "name": "timestamp", - "value": "2016-10-10" - } - ], - "headersSize": 360, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AJSsXggdxTpnvv6WVFqDrJ8Sjeuu77nE4.IcUuska8iBP1lkpKISqwIPOaqy5qLB%2F2o8v2Txs%2F5f8", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:37 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "86" - }, - { - "name": "ETag", - "value": "W/\"56-sbJq4ZMpg65IM+Xxb5GSE9GGvQc\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3AJSsXggdxTpnvv6WVFqDrJ8Sjeuu77nE4.IcUuska8iBP1lkpKISqwIPOaqy5qLB%2F2o8v2Txs%2F5f8; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 86, - "mimeType": "application/json; charset=utf-8", - "text": "eyJ5ZWFycyI6MjAxNiwibW9udGhzIjo5LCJkYXRlIjoxMCwiaG91cnMiOjAsIm1pbnV0ZXMiOjAsInNlY29uZHMiOjAsIm1pbGxpc2Vjb25kcyI6MH0=", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 86 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 847, - "ssl": 568, - "send": 0, - "wait": 284, - "receive": 5 - } - }, - { - "startedDateTime": "2021-10-16T15:05:36.869+08:00", - "time": 1156, - "request": { - "method": "GET", - "url": "https://postman-echo.com/time/before?timestamp=2016-10-10&target=2017-10-10", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AJSsXggdxTpnvv6WVFqDrJ8Sjeuu77nE4.IcUuska8iBP1lkpKISqwIPOaqy5qLB%2F2o8v2Txs%2F5f8" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "faaa8cb6-13c5-4d0c-a7d2-133520637dde" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AJSsXggdxTpnvv6WVFqDrJ8Sjeuu77nE4.IcUuska8iBP1lkpKISqwIPOaqy5qLB%2F2o8v2Txs%2F5f8" - } - ], - "queryString": [ - { - "name": "timestamp", - "value": "2016-10-10" - }, - { - "name": "target", - "value": "2017-10-10" - } - ], - "headersSize": 382, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AQ9JCfRzQhaoMt6eD7gx_qk3JQ8CWnAxO.g3tHBGmTN8Vc1mqWWnSqGV1VOQdmKk8HG3z29e%2FBzhA", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:38 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "15" - }, - { - "name": "ETag", - "value": "W/\"f-pYji1tDlxSR6vlOQLH4azAZGkpo\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3AQ9JCfRzQhaoMt6eD7gx_qk3JQ8CWnAxO.g3tHBGmTN8Vc1mqWWnSqGV1VOQdmKk8HG3z29e%2FBzhA; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 15, - "mimeType": "application/json; charset=utf-8", - "text": "eyJiZWZvcmUiOnRydWV9", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 15 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 850, - "ssl": 571, - "send": 0, - "wait": 304, - "receive": 1 - } - }, - { - "startedDateTime": "2021-10-16T15:05:38.058+08:00", - "time": 1296, - "request": { - "method": "GET", - "url": "https://postman-echo.com/time/after?timestamp=2016-10-10&target=2017-10-10", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AQ9JCfRzQhaoMt6eD7gx_qk3JQ8CWnAxO.g3tHBGmTN8Vc1mqWWnSqGV1VOQdmKk8HG3z29e%2FBzhA" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "28c6c8f1-bb76-4fce-986c-adc2fd5df80d" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AQ9JCfRzQhaoMt6eD7gx_qk3JQ8CWnAxO.g3tHBGmTN8Vc1mqWWnSqGV1VOQdmKk8HG3z29e%2FBzhA" - } - ], - "queryString": [ - { - "name": "timestamp", - "value": "2016-10-10" - }, - { - "name": "target", - "value": "2017-10-10" - } - ], - "headersSize": 379, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AYE-1ygWzH5aScrDeYC7-Q8-dC1A5zkJv.XyirbigQ0duqX6jD9om1q%2FS%2FqkhbFl43yu7HHYciXkI", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:39 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "15" - }, - { - "name": "ETag", - "value": "W/\"f-1yo7D9f7qelpng2aZyy3Vk9UAA8\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3AYE-1ygWzH5aScrDeYC7-Q8-dC1A5zkJv.XyirbigQ0duqX6jD9om1q%2FS%2FqkhbFl43yu7HHYciXkI; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 15, - "mimeType": "application/json; charset=utf-8", - "text": "eyJhZnRlciI6ZmFsc2V9", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 15 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 906, - "ssl": 624, - "send": 0, - "wait": 389, - "receive": 0 - } - }, - { - "startedDateTime": "2021-10-16T15:05:39.392+08:00", - "time": 1129, - "request": { - "method": "GET", - "url": "https://postman-echo.com/time/between?timestamp=2016-10-10&start=2017-10-10&end=2019-10-10", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AYE-1ygWzH5aScrDeYC7-Q8-dC1A5zkJv.XyirbigQ0duqX6jD9om1q%2FS%2FqkhbFl43yu7HHYciXkI" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "32aaca4e-02a8-4559-9368-5705a1a65e19" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AYE-1ygWzH5aScrDeYC7-Q8-dC1A5zkJv.XyirbigQ0duqX6jD9om1q%2FS%2FqkhbFl43yu7HHYciXkI" - } - ], - "queryString": [ - { - "name": "timestamp", - "value": "2016-10-10" - }, - { - "name": "start", - "value": "2017-10-10" - }, - { - "name": "end", - "value": "2019-10-10" - } - ], - "headersSize": 397, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:40 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "17" - }, - { - "name": "ETag", - "value": "W/\"11-Q5jSDN8J9UWiS3bMKjaPflikNDU\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 17, - "mimeType": "application/json; charset=utf-8", - "text": "eyJiZXR3ZWVuIjpmYWxzZX0=", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 17 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 843, - "ssl": 565, - "send": 0, - "wait": 283, - "receive": 2 - } - }, - { - "startedDateTime": "2021-10-16T15:05:40.555+08:00", - "time": 1174, - "request": { - "method": "GET", - "url": "https://postman-echo.com/time/leap?timestamp=2016-10-10", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AYE-1ygWzH5aScrDeYC7-Q8-dC1A5zkJv.XyirbigQ0duqX6jD9om1q%2FS%2FqkhbFl43yu7HHYciXkI" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "ff77428a-b157-463a-91e0-e5126d99d6c0" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AYE-1ygWzH5aScrDeYC7-Q8-dC1A5zkJv.XyirbigQ0duqX6jD9om1q%2FS%2FqkhbFl43yu7HHYciXkI" - } - ], - "queryString": [ - { - "name": "timestamp", - "value": "2016-10-10" - } - ], - "headersSize": 362, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AhLPrbCV0ByxRorQusdRky8bws0S2qQjf.V4SIDOu%2BdIgGVSCA5qvRYwhi3xR%2Bd0R9gL9RDUPdpI4", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:41 GMT" - }, - { - "name": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "name": "Content-Length", - "value": "13" - }, - { - "name": "ETag", - "value": "W/\"d-/cHbrs54NBQWs+BmYLn36yaGw/0\"" - }, - { - "name": "Vary", - "value": "Accept-Encoding" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3AhLPrbCV0ByxRorQusdRky8bws0S2qQjf.V4SIDOu%2BdIgGVSCA5qvRYwhi3xR%2Bd0R9gL9RDUPdpI4; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 13, - "mimeType": "application/json; charset=utf-8", - "text": "eyJsZWFwIjp0cnVlfQ==", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 13 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 849, - "ssl": 568, - "send": 0, - "wait": 324, - "receive": 0 - } - }, - { - "startedDateTime": "2021-10-16T15:05:41.763+08:00", - "time": 1378, - "request": { - "method": "GET", - "url": "https://postman-echo.com/digest-auth", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3AhLPrbCV0ByxRorQusdRky8bws0S2qQjf.V4SIDOu%2BdIgGVSCA5qvRYwhi3xR%2Bd0R9gL9RDUPdpI4" - } - ], - "headers": [ - { - "name": "User-Agent", - "value": "PostmanRuntime/7.28.4" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Cache-Control", - "value": "no-cache" - }, - { - "name": "Postman-Token", - "value": "8f6b453b-580c-44bc-8f9f-b2baa64ab530" - }, - { - "name": "Host", - "value": "postman-echo.com" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate, br" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Cookie", - "value": "sails.sid=s%3AhLPrbCV0ByxRorQusdRky8bws0S2qQjf.V4SIDOu%2BdIgGVSCA5qvRYwhi3xR%2Bd0R9gL9RDUPdpI4" - } - ], - "queryString": [], - "headersSize": 343, - "bodySize": 0 - }, - "response": { - "_charlesStatus": "COMPLETE", - "status": 401, - "statusText": "Unauthorized", - "httpVersion": "HTTP/1.1", - "cookies": [ - { - "name": "sails.sid", - "value": "s%3ACLdEI5FgDpez6LxwwGswSZNXbHEANDJJ.k3OW1SRe2w4ROpm83%2FNJ2xtPis%2FtcWVMsvX%2F3dUi3FE", - "path": "/", - "domain": null, - "expires": null, - "httpOnly": true, - "secure": false, - "comment": null, - "_maxAge": null - } - ], - "headers": [ - { - "name": "Date", - "value": "Sat, 16 Oct 2021 07:05:43 GMT" - }, - { - "name": "Transfer-Encoding", - "value": "chunked" - }, - { - "name": "WWW-Authenticate", - "value": "Digest realm=\"Users\", nonce=\"hWVYO1ts29HPxCpHoUhGVRzzsggQ3uCg\", qop=\"auth\"" - }, - { - "name": "set-cookie", - "value": "sails.sid=s%3ACLdEI5FgDpez6LxwwGswSZNXbHEANDJJ.k3OW1SRe2w4ROpm83%2FNJ2xtPis%2FtcWVMsvX%2F3dUi3FE; Path=/; HttpOnly" - }, - { - "name": "Connection", - "value": "keep-alive" - } - ], - "content": { - "size": 20, - "mimeType": null, - "text": "VW5hdXRob3JpemVk", - "encoding": "base64" - }, - "redirectURL": null, - "headersSize": 0, - "bodySize": 20 - }, - "serverIPAddress": "44.193.31.23", - "cache": {}, - "timings": { - "dns": 1, - "connect": 977, - "ssl": 696, - "send": 0, - "wait": 400, - "receive": 0 - } - } - ] - } -} \ No newline at end of file diff --git a/examples/data/postman/postman_collection.json b/examples/data/postman/postman_collection.json deleted file mode 100644 index 0f960843..00000000 --- a/examples/data/postman/postman_collection.json +++ /dev/null @@ -1,498 +0,0 @@ -{ - "info": { - "_postman_id": "0417a445-b206-4ea2-b1d2-5441afd6c6b9", - "name": "postman collection demo", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" - }, - "item": [ - { - "name": "folder1", - "item": [ - { - "name": "folder2", - "item": [ - { - "name": "Get with params", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "https://postman-echo.com/:path?k1=v1&k2=v2", - "protocol": "https", - "host": [ - "postman-echo", - "com" - ], - "path": [ - ":path" - ], - "query": [ - { - "key": "k1", - "value": "v1" - }, - { - "key": "k2", - "value": "v2" - }, - { - "key": "k3", - "value": "v3", - "disabled": true - } - ], - "variable": [ - { - "key": "path", - "value": "get" - } - ] - } - }, - "response": [ - { - "name": "Get with params case1", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "https://postman-echo.com/:path?k1=v1&k2=v2", - "protocol": "https", - "host": [ - "postman-echo", - "com" - ], - "path": [ - ":path" - ], - "query": [ - { - "key": "k1", - "value": "v1" - }, - { - "key": "k2", - "value": "v2" - }, - { - "key": "k3", - "value": "v3", - "disabled": true - } - ], - "variable": [ - { - "key": "path", - "value": "get" - } - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Date", - "value": "Mon, 16 May 2022 12:12:28 GMT" - }, - { - "key": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "key": "Content-Length", - "value": "508" - }, - { - "key": "Connection", - "value": "keep-alive" - }, - { - "key": "ETag", - "value": "W/\"1fc-x4EIPFQzoLX0HenCFPx6HNfG0lc\"" - }, - { - "key": "Vary", - "value": "Accept-Encoding" - }, - { - "key": "set-cookie", - "value": "sails.sid=s%3AX2aa_Z7gbcUqIWAjlBkytBRmQ4WCvc3D.pX9Qxh8aO9Ict0BL4CrRhdDJmz81UVmwFsV5Nx30Ils; Path=/; HttpOnly" - } - ], - "cookie": [], - "body": "{\n \"args\": {\n \"k1\": \"v1\",\n \"k2\": \"v2\"\n },\n \"headers\": {\n \"x-forwarded-proto\": \"https\",\n \"x-forwarded-port\": \"443\",\n \"host\": \"postman-echo.com\",\n \"user-agent\": \"PostmanRuntime/7.29.0\",\n \"accept\": \"*/*\",\n \"accept-encoding\": \"gzip, deflate, br\",\n \"cookie\": \"Cookie_1=c1; Cookie_2=c2; sails.sid=s%3AGX6aS9b_phvUSUk66w7ZBgWuOPI7IIKT.ayEGTaW4U35eAWyPz%2Fh6Q74DonNcbqw3H5Q5Zv%2BfKMY\"\n },\n \"url\": \"https://postman-echo.com/get?k1=v1&k2=v2\"\n}" - }, - { - "name": "Get with params case2", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "https://postman-echo.com/:path?k1=v1&k3=v3", - "protocol": "https", - "host": [ - "postman-echo", - "com" - ], - "path": [ - ":path" - ], - "query": [ - { - "key": "k1", - "value": "v1" - }, - { - "key": "k2", - "value": "v2", - "disabled": true - }, - { - "key": "k3", - "value": "v3" - } - ], - "variable": [ - { - "key": "path", - "value": "get" - } - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Date", - "value": "Mon, 16 May 2022 12:14:04 GMT" - }, - { - "key": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "key": "Content-Length", - "value": "504" - }, - { - "key": "Connection", - "value": "keep-alive" - }, - { - "key": "ETag", - "value": "W/\"1f8-tMaKs4xmwr+3su3I8mcgR0p+ucw\"" - }, - { - "key": "Vary", - "value": "Accept-Encoding" - }, - { - "key": "set-cookie", - "value": "sails.sid=s%3AMNuX_i0KgaP_KuuMpYB8RtCNipCGJWVw.4ETfPHxE81Omqb6Yli%2FezUU8CXyYBcN3%2Bxkx5htwh8Y; Path=/; HttpOnly" - } - ], - "cookie": [], - "body": "{\n \"args\": {\n \"k1\": \"v1\",\n \"k3\": \"v3\"\n },\n \"headers\": {\n \"x-forwarded-proto\": \"https\",\n \"x-forwarded-port\": \"443\",\n \"host\": \"postman-echo.com\",\n \"user-agent\": \"PostmanRuntime/7.29.0\",\n \"accept\": \"*/*\",\n \"accept-encoding\": \"gzip, deflate, br\",\n \"cookie\": \"Cookie_1=c1; Cookie_2=c2; sails.sid=s%3AX2aa_Z7gbcUqIWAjlBkytBRmQ4WCvc3D.pX9Qxh8aO9Ict0BL4CrRhdDJmz81UVmwFsV5Nx30Ils\"\n },\n \"url\": \"https://postman-echo.com/get?k1=v1&k3=v3\"\n}" - } - ] - } - ] - } - ] - }, - { - "name": "folder3", - "item": [ - { - "name": "Post form-data", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "formdata", - "formdata": [ - { - "key": "k1", - "value": "v1", - "type": "text" - }, - { - "key": "k2", - "value": "v2", - "type": "text" - }, - { - "key": "k3", - "value": "v3", - "type": "text", - "disabled": true - }, - { - "key": "intro_key", - "type": "file", - "src": "intro.txt" - }, - { - "key": "logo_key", - "type": "file", - "src": "logo.jpeg" - } - ] - }, - "url": { - "raw": "https://postman-echo.com/:path", - "protocol": "https", - "host": [ - "postman-echo", - "com" - ], - "path": [ - ":path" - ], - "variable": [ - { - "key": "path", - "value": "post" - } - ] - } - }, - "response": [] - }, - { - "name": "Post x-www-form-urlencoded", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "k1", - "value": "v1", - "type": "text" - }, - { - "key": "k2", - "value": "v2", - "type": "text" - }, - { - "key": "k3", - "value": "v3", - "type": "text", - "disabled": true - } - ] - }, - "url": { - "raw": "https://postman-echo.com/:path", - "protocol": "https", - "host": [ - "postman-echo", - "com" - ], - "path": [ - ":path" - ], - "variable": [ - { - "key": "path", - "value": "post" - } - ] - } - }, - "response": [] - }, - { - "name": "Post raw json", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"k1\": \"v1\",\n \"k2\": \"v2\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://postman-echo.com/:path", - "protocol": "https", - "host": [ - "postman-echo", - "com" - ], - "path": [ - ":path" - ], - "variable": [ - { - "key": "path", - "value": "post" - } - ] - } - }, - "response": [] - }, - { - "name": "Post raw text", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "have a nice day", - "options": { - "raw": { - "language": "text" - } - } - }, - "url": { - "raw": "https://postman-echo.com/:path", - "protocol": "https", - "host": [ - "postman-echo", - "com" - ], - "path": [ - ":path" - ], - "variable": [ - { - "key": "path", - "value": "post" - } - ] - } - }, - "response": [] - } - ] - }, - { - "name": "Get request headers", - "request": { - "method": "GET", - "header": [ - { - "key": "User-Agent", - "value": "HttpRunner", - "type": "text" - }, - { - "key": "User-Name", - "value": "bbx", - "type": "text", - "disabled": true - }, - { - "key": "Connection", - "value": "close", - "type": "text" - } - ], - "url": { - "raw": "https://postman-echo.com/:path", - "protocol": "https", - "host": [ - "postman-echo", - "com" - ], - "path": [ - ":path" - ], - "variable": [ - { - "key": "path", - "value": "headers" - } - ] - } - }, - "response": [ - { - "name": "Get request headers case1", - "originalRequest": { - "method": "GET", - "header": [ - { - "key": "User-Agent", - "value": "HttpRunner", - "type": "text" - }, - { - "key": "User-Name", - "value": "bbx", - "type": "text", - "disabled": true - }, - { - "key": "Cookie", - "value": "Cookie_1=c1; Cookie_2=c2; sails.sid=s%3AGX6aS9b_phvUSUk66w7ZBgWuOPI7IIKT.ayEGTaW4U35eAWyPz%2Fh6Q74DonNcbqw3H5Q5Zv%2BfKMY", - "type": "text" - } - ], - "url": { - "raw": "https://postman-echo.com/:path", - "protocol": "https", - "host": [ - "postman-echo", - "com" - ], - "path": [ - ":path" - ], - "variable": [ - { - "key": "path", - "value": "headers" - } - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Date", - "value": "Mon, 16 May 2022 12:14:25 GMT" - }, - { - "key": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "key": "Content-Length", - "value": "541" - }, - { - "key": "Connection", - "value": "keep-alive" - }, - { - "key": "ETag", - "value": "W/\"21d-ld5UvFTaRM6lihVnvCj6mZm5Of0\"" - }, - { - "key": "Vary", - "value": "Accept-Encoding" - } - ], - "cookie": [], - "body": "{\n \"headers\": {\n \"x-forwarded-proto\": \"https\",\n \"x-forwarded-port\": \"443\",\n \"host\": \"postman-echo.com\",\n \"user-agent\": \"HttpRunner\",\n \"cookie\": \"Cookie_1=c1; Cookie_2=c2; sails.sid=s%3AGX6aS9b_phvUSUk66w7ZBgWuOPI7IIKT.ayEGTaW4U35eAWyPz%2Fh6Q74DonNcbqw3H5Q5Zv%2BfKMY\",\n \"accept\": \"*/*\",\n \"accept-encoding\": \"gzip, deflate, br\"\n }\n}" - } - ] - } - ] -} \ No newline at end of file diff --git a/examples/data/postman/profile.yml b/examples/data/postman/profile.yml deleted file mode 100644 index c657b5ef..00000000 --- a/examples/data/postman/profile.yml +++ /dev/null @@ -1,4 +0,0 @@ -headers: - User-Agent: "this header will be created or updated" -cookies: - Cookie1: "this cookie will be created or updated" diff --git a/examples/data/postman/profile_override.yml b/examples/data/postman/profile_override.yml deleted file mode 100644 index bc620e50..00000000 --- a/examples/data/postman/profile_override.yml +++ /dev/null @@ -1,5 +0,0 @@ -override: true -headers: - Header1: "all original headers will be overridden" -cookies: - Cookie1: "all original cookies will be overridden" \ No newline at end of file diff --git a/examples/data/profile.yml b/examples/data/profile.yml new file mode 100644 index 00000000..69963ba2 --- /dev/null +++ b/examples/data/profile.yml @@ -0,0 +1,4 @@ +headers: + Content-Type: "application/x-www-form-urlencoded" +cookies: + UserName: "debugtalk" \ No newline at end of file diff --git a/examples/data/har/profile_override.yml b/examples/data/profile_override.yml similarity index 100% rename from examples/data/har/profile_override.yml rename to examples/data/profile_override.yml diff --git a/hrp/internal/convert/README.md b/hrp/internal/convert/README.md index da426350..963957c3 100644 --- a/hrp/internal/convert/README.md +++ b/hrp/internal/convert/README.md @@ -30,14 +30,18 @@ Global Flags: 1. `--to-json / --to-yaml / --to-gotest / --to-pytest` 用于将输入转化为对应形态的测试用例,四个选项中最多只能指定一个,如果不指定则默认会将输入转化为 JSON 形态的测试用例 2. `--output-dir` 后接测试用例的期望输出目录的路径,用于将转换生成的测试用例输出到对应的文件夹 3. `--profile` 后接 profile 配置文件的路径,目前支持替换(不存在则会创建)或者覆盖输入的外部脚本/测试用例中的 `Headers` 和 `Cookies` 信息,profile 文件的后缀可以为 `json/yaml/yml`,下面给出两类 profile 配置文件的示例: + - 根据 profile 替换指定的 `Headers` 和 `Cookies` 信息 + ```yaml headers: Header1: "this header will be created or updated" cookies: Cookie1: "this cookie will be created or updated" ``` + - 根据 profile 覆盖原有的 `Headers` 和 `Cookies` 信息 + ```yaml override: true headers: diff --git a/hrp/internal/convert/converter.go b/hrp/internal/convert/converter.go index 7bb11ed9..7f1128e9 100644 --- a/hrp/internal/convert/converter.go +++ b/hrp/internal/convert/converter.go @@ -21,43 +21,6 @@ const ( suffixPyTest = ".py" ) -type InputType int - -const ( - InputTypeUnknown InputType = iota // default input type: unknown - InputTypeHAR - InputTypePostman - InputTypeSwagger - InputTypeJMeter - InputTypeJSON - InputTypeYAML - InputTypeGoTest - InputTypePyTest -) - -func (inputType InputType) String() string { - switch inputType { - case InputTypeHAR: - return "har" - case InputTypePostman: - return "postman" - case InputTypeSwagger: - return "swagger" - case InputTypeJMeter: - return "jmeter" - case InputTypeJSON: - return "json testcase" - case InputTypeYAML: - return "yaml testcase" - case InputTypeGoTest: - return "gotest script" - case InputTypePyTest: - return "pytest script" - default: - return "unknown" - } -} - type OutputType int const ( @@ -80,15 +43,6 @@ func (outputType OutputType) String() string { } } -// TCaseConverter holds the common properties of case converter -type TCaseConverter struct { - InputPath string - OutputDir string - InputType InputType - OutputType OutputType - TCase *hrp.TCase -} - // Profile is used to override or update(create if not existed) original headers and cookies type Profile struct { Override bool `json:"override" yaml:"override"` @@ -96,6 +50,57 @@ type Profile struct { Cookies map[string]string `json:"cookies" yaml:"cookies"` } +func Run(outputType OutputType, outputDir, profilePath string, args []string) { + // report event + sdk.SendEvent(sdk.EventTracking{ + Category: "ConvertTests", + Action: fmt.Sprintf("hrp convert --to-%s", outputType.String()), + }) + + var outputFiles []string + for _, path := range args { + // loads source file and convert to TCase format + tCase, err := LoadTCase(path) + if err != nil { + log.Warn().Err(err).Str("path", path).Msg("construct case loader failed") + continue + } + + caseConverter := &TCaseConverter{ + SourcePath: path, + OutputDir: outputDir, + OutputType: outputType, + TCase: tCase, + } + + // override TCase with profile + if profilePath != "" { + caseConverter.overrideWithProfile(profilePath) + } + + // convert TCase format to target case format + var outputFile string + switch outputType { + case OutputTypeYAML: + outputFile, err = caseConverter.ToYAML() + case OutputTypeGoTest: + outputFile, err = caseConverter.ToGoTest() + case OutputTypePyTest: + outputFile, err = caseConverter.ToPyTest() + default: + outputFile, err = caseConverter.ToJSON() + } + if err != nil { + log.Error().Err(err). + Str("source path", path). + Msg("convert case failed") + continue + } + outputFiles = append(outputFiles, outputFile) + } + log.Info().Strs("output files", outputFiles).Msg("conversion completed") +} + // LoadTCase loads source file and convert to TCase type func LoadTCase(path string) (*hrp.TCase, error) { extName := filepath.Ext(path) @@ -156,19 +161,27 @@ func LoadTCase(path string) (*hrp.TCase, error) { return nil, fmt.Errorf("unsupported file type: %v", extName) } +// TCaseConverter holds the common properties of case converter +type TCaseConverter struct { + SourcePath string + OutputDir string + OutputType OutputType + TCase *hrp.TCase +} + func (c *TCaseConverter) genOutputPath(suffix string) string { - outFileFullName := builtin.GetOutputNameWithoutExtension(c.InputPath) + suffix + outFileFullName := builtin.GetOutputNameWithoutExtension(c.SourcePath) + suffix if c.OutputDir != "" { return filepath.Join(c.OutputDir, outFileFullName) } else { - return filepath.Join(filepath.Dir(c.InputPath), outFileFullName) + return filepath.Join(filepath.Dir(c.SourcePath), outFileFullName) } // TODO avoid outFileFullName conflict? } // convert TCase to pytest case func (c *TCaseConverter) ToPyTest() (string, error) { - args := append([]string{"make"}, c.InputPath) + args := append([]string{"make"}, c.SourcePath) err := builtin.ExecPython3Command("httprunner", args...) if err != nil { return "", err @@ -201,54 +214,6 @@ func (c *TCaseConverter) ToYAML() (string, error) { return yamlPath, nil } -func Run(outputType OutputType, outputDir, profilePath string, args []string) { - // report event - sdk.SendEvent(sdk.EventTracking{ - Category: "ConvertTests", - Action: fmt.Sprintf("hrp convert --to-%s", outputType.String()), - }) - - var outputFiles []string - for _, path := range args { - // loads source file in support types and convert to TCase format - tCase, err := LoadTCase(path) - if err != nil { - log.Warn().Err(err).Str("path", path).Msg("construct case loader failed") - continue - } - - caseConverter := TCaseConverter{ - OutputDir: outputDir, - OutputType: outputType, - TCase: tCase, - } - - // override TCase with profile - caseConverter.overrideWithProfile(profilePath) - - // convert TCase format to target case format - var outputFile string - switch outputType { - case OutputTypeYAML: - outputFile, err = caseConverter.ToYAML() - case OutputTypeGoTest: - outputFile, err = caseConverter.ToGoTest() - case OutputTypePyTest: - outputFile, err = caseConverter.ToPyTest() - default: - outputFile, err = caseConverter.ToJSON() - } - if err != nil { - log.Error().Err(err). - Str("source path", path). - Msg("convert case failed") - continue - } - outputFiles = append(outputFiles, outputFile) - } - log.Info().Strs("output files", outputFiles).Msg("conversion completed") -} - func (c *TCaseConverter) overrideWithProfile(path string) error { log.Info().Str("path", path).Msg("load profile") profile := new(Profile) @@ -259,6 +224,7 @@ func (c *TCaseConverter) overrideWithProfile(path string) error { return err } + log.Info().Interface("profile", profile).Msg("override with profile") for _, step := range c.TCase.TestSteps { // override original headers and cookies if profile.Override { diff --git a/hrp/internal/convert/converter_har_test.go b/hrp/internal/convert/converter_har_test.go index 711e191e..bd3fccd7 100644 --- a/hrp/internal/convert/converter_har_test.go +++ b/hrp/internal/convert/converter_har_test.go @@ -8,11 +8,7 @@ import ( "github.com/httprunner/httprunner/v4/hrp" ) -var ( - harPath = "../../../examples/data/har/demo.har" - harPath2 = "../../../examples/data/har/postman-echo.har" - harProfileOverridePath = "../../../examples/data/har/profile_override.yml" -) +var harPath = "../../../examples/data/har/demo.har" var caseHar *CaseHar diff --git a/hrp/internal/convert/converter_postman_test.go b/hrp/internal/convert/converter_postman_test.go index 2315a5bd..00e8a5d0 100644 --- a/hrp/internal/convert/converter_postman_test.go +++ b/hrp/internal/convert/converter_postman_test.go @@ -6,11 +6,7 @@ import ( "github.com/stretchr/testify/assert" ) -var ( - collectionPath = "../../../examples/data/postman/postman_collection.json" - collectionProfileOverridePath = "../../../examples/data/postman/profile_override.yml" - collectionProfilePath = "../../../examples/data/postman/profile.yml" -) +var collectionPath = "../../../examples/data/postman/postman_collection.json" func TestLoadCollection(t *testing.T) { casePostman, err := loadCasePostman(collectionPath) diff --git a/hrp/internal/convert/converter_test.go b/hrp/internal/convert/converter_test.go new file mode 100644 index 00000000..4c6c0f58 --- /dev/null +++ b/hrp/internal/convert/converter_test.go @@ -0,0 +1,140 @@ +package convert + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/httprunner/httprunner/v4/hrp" +) + +const ( + profilePath = "../../../examples/data/profile.yml" + profileOverridePath = "../../../examples/data/profile_override.yml" +) + +func TestLoadTCase(t *testing.T) { + tCase, err := LoadTCase(harPath) + if !assert.NoError(t, err) { + t.Fatal() + } + if !assert.NotEmpty(t, tCase) { + t.Fatal() + } +} + +func TestLoadHARWithProfileOverride(t *testing.T) { + tCase, err := LoadTCase(harPath) + if !assert.NoError(t, err) { + t.Fatal() + } + if !assert.NotEmpty(t, tCase) { + t.Fatal() + } + + caseConverter := &TCaseConverter{ + TCase: tCase, + } + + // override TCase with profile + err = caseConverter.overrideWithProfile(profileOverridePath) + if !assert.NoError(t, err) { + t.Fatal() + } + + for i := 0; i < 3; i++ { + if !assert.Equal(t, + map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + caseConverter.TCase.TestSteps[i].Request.Headers) { + t.FailNow() + } + if !assert.Equal(t, + map[string]string{"UserName": "debugtalk"}, + caseConverter.TCase.TestSteps[i].Request.Cookies) { + t.FailNow() + } + } +} + +func TestMakeRequestWithProfile(t *testing.T) { + caseConverter := &TCaseConverter{ + TCase: &hrp.TCase{ + TestSteps: []*hrp.TStep{ + { + Request: &hrp.Request{ + Method: hrp.HTTPMethod("POST"), + Headers: map[string]string{ + "Content-Type": "application/json; charset=utf-8", + "User-Agent": "hrp", + }, + Cookies: map[string]string{ + "abc": "123", + "UserName": "leolee", + }, + }, + }, + }, + }, + } + + err := caseConverter.overrideWithProfile(profilePath) + if !assert.NoError(t, err) { + t.Fatal() + } + if !assert.NoError(t, err) { + t.Fatal() + } + + if !assert.Equal(t, map[string]string{ + "Content-Type": "application/x-www-form-urlencoded", "User-Agent": "hrp", + }, caseConverter.TCase.TestSteps[0].Request.Headers) { + t.Fatal() + } + if !assert.Equal(t, map[string]string{ + "UserName": "debugtalk", "abc": "123", + }, caseConverter.TCase.TestSteps[0].Request.Cookies) { + t.Fatal() + } +} + +func TestMakeRequestWithProfileOverride(t *testing.T) { + caseConverter := &TCaseConverter{ + TCase: &hrp.TCase{ + TestSteps: []*hrp.TStep{ + { + Request: &hrp.Request{ + Method: hrp.HTTPMethod("POST"), + Headers: map[string]string{ + "Content-Type": "application/json; charset=utf-8", + "User-Agent": "hrp", + }, + Cookies: map[string]string{ + "abc": "123", + "UserName": "leolee", + }, + }, + }, + }, + }, + } + + // override TCase with profile + err := caseConverter.overrideWithProfile(profileOverridePath) + if !assert.NoError(t, err) { + t.Fatal() + } + if !assert.NoError(t, err) { + t.Fatal() + } + + if !assert.Equal(t, map[string]string{ + "Content-Type": "application/x-www-form-urlencoded", + }, caseConverter.TCase.TestSteps[0].Request.Headers) { + t.Fatal() + } + if !assert.Equal(t, map[string]string{ + "UserName": "debugtalk", + }, caseConverter.TCase.TestSteps[0].Request.Cookies) { + t.Fatal() + } +} From e816f8cb5f43df0ad0f07971fbffdda982313518 Mon Sep 17 00:00:00 2001 From: debugtalk Date: Mon, 27 Jun 2022 16:35:51 +0800 Subject: [PATCH 3/6] refactor: rename convert files --- examples/data/postman/postman_collection.json | 498 ++++++++++++++++++ .../{converter_gotest.go => from_gotest.go} | 0 .../convert/{converter_har.go => from_har.go} | 0 ...converter_har_test.go => from_har_test.go} | 0 .../{converter_json.go => from_json.go} | 0 .../{converter_postman.go => from_postman.go} | 0 ...r_postman_test.go => from_postman_test.go} | 0 .../{converter_pytest.go => from_pytest.go} | 0 .../{converter_swagger.go => from_swagger.go} | 0 .../{converter_yaml.go => from_yaml.go} | 0 10 files changed, 498 insertions(+) create mode 100644 examples/data/postman/postman_collection.json rename hrp/internal/convert/{converter_gotest.go => from_gotest.go} (100%) rename hrp/internal/convert/{converter_har.go => from_har.go} (100%) rename hrp/internal/convert/{converter_har_test.go => from_har_test.go} (100%) rename hrp/internal/convert/{converter_json.go => from_json.go} (100%) rename hrp/internal/convert/{converter_postman.go => from_postman.go} (100%) rename hrp/internal/convert/{converter_postman_test.go => from_postman_test.go} (100%) rename hrp/internal/convert/{converter_pytest.go => from_pytest.go} (100%) rename hrp/internal/convert/{converter_swagger.go => from_swagger.go} (100%) rename hrp/internal/convert/{converter_yaml.go => from_yaml.go} (100%) diff --git a/examples/data/postman/postman_collection.json b/examples/data/postman/postman_collection.json new file mode 100644 index 00000000..0f960843 --- /dev/null +++ b/examples/data/postman/postman_collection.json @@ -0,0 +1,498 @@ +{ + "info": { + "_postman_id": "0417a445-b206-4ea2-b1d2-5441afd6c6b9", + "name": "postman collection demo", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "folder1", + "item": [ + { + "name": "folder2", + "item": [ + { + "name": "Get with params", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "https://postman-echo.com/:path?k1=v1&k2=v2", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + ":path" + ], + "query": [ + { + "key": "k1", + "value": "v1" + }, + { + "key": "k2", + "value": "v2" + }, + { + "key": "k3", + "value": "v3", + "disabled": true + } + ], + "variable": [ + { + "key": "path", + "value": "get" + } + ] + } + }, + "response": [ + { + "name": "Get with params case1", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "https://postman-echo.com/:path?k1=v1&k2=v2", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + ":path" + ], + "query": [ + { + "key": "k1", + "value": "v1" + }, + { + "key": "k2", + "value": "v2" + }, + { + "key": "k3", + "value": "v3", + "disabled": true + } + ], + "variable": [ + { + "key": "path", + "value": "get" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Mon, 16 May 2022 12:12:28 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "508" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "ETag", + "value": "W/\"1fc-x4EIPFQzoLX0HenCFPx6HNfG0lc\"" + }, + { + "key": "Vary", + "value": "Accept-Encoding" + }, + { + "key": "set-cookie", + "value": "sails.sid=s%3AX2aa_Z7gbcUqIWAjlBkytBRmQ4WCvc3D.pX9Qxh8aO9Ict0BL4CrRhdDJmz81UVmwFsV5Nx30Ils; Path=/; HttpOnly" + } + ], + "cookie": [], + "body": "{\n \"args\": {\n \"k1\": \"v1\",\n \"k2\": \"v2\"\n },\n \"headers\": {\n \"x-forwarded-proto\": \"https\",\n \"x-forwarded-port\": \"443\",\n \"host\": \"postman-echo.com\",\n \"user-agent\": \"PostmanRuntime/7.29.0\",\n \"accept\": \"*/*\",\n \"accept-encoding\": \"gzip, deflate, br\",\n \"cookie\": \"Cookie_1=c1; Cookie_2=c2; sails.sid=s%3AGX6aS9b_phvUSUk66w7ZBgWuOPI7IIKT.ayEGTaW4U35eAWyPz%2Fh6Q74DonNcbqw3H5Q5Zv%2BfKMY\"\n },\n \"url\": \"https://postman-echo.com/get?k1=v1&k2=v2\"\n}" + }, + { + "name": "Get with params case2", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "https://postman-echo.com/:path?k1=v1&k3=v3", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + ":path" + ], + "query": [ + { + "key": "k1", + "value": "v1" + }, + { + "key": "k2", + "value": "v2", + "disabled": true + }, + { + "key": "k3", + "value": "v3" + } + ], + "variable": [ + { + "key": "path", + "value": "get" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Mon, 16 May 2022 12:14:04 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "504" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "ETag", + "value": "W/\"1f8-tMaKs4xmwr+3su3I8mcgR0p+ucw\"" + }, + { + "key": "Vary", + "value": "Accept-Encoding" + }, + { + "key": "set-cookie", + "value": "sails.sid=s%3AMNuX_i0KgaP_KuuMpYB8RtCNipCGJWVw.4ETfPHxE81Omqb6Yli%2FezUU8CXyYBcN3%2Bxkx5htwh8Y; Path=/; HttpOnly" + } + ], + "cookie": [], + "body": "{\n \"args\": {\n \"k1\": \"v1\",\n \"k3\": \"v3\"\n },\n \"headers\": {\n \"x-forwarded-proto\": \"https\",\n \"x-forwarded-port\": \"443\",\n \"host\": \"postman-echo.com\",\n \"user-agent\": \"PostmanRuntime/7.29.0\",\n \"accept\": \"*/*\",\n \"accept-encoding\": \"gzip, deflate, br\",\n \"cookie\": \"Cookie_1=c1; Cookie_2=c2; sails.sid=s%3AX2aa_Z7gbcUqIWAjlBkytBRmQ4WCvc3D.pX9Qxh8aO9Ict0BL4CrRhdDJmz81UVmwFsV5Nx30Ils\"\n },\n \"url\": \"https://postman-echo.com/get?k1=v1&k3=v3\"\n}" + } + ] + } + ] + } + ] + }, + { + "name": "folder3", + "item": [ + { + "name": "Post form-data", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "k1", + "value": "v1", + "type": "text" + }, + { + "key": "k2", + "value": "v2", + "type": "text" + }, + { + "key": "k3", + "value": "v3", + "type": "text", + "disabled": true + }, + { + "key": "intro_key", + "type": "file", + "src": "intro.txt" + }, + { + "key": "logo_key", + "type": "file", + "src": "logo.jpeg" + } + ] + }, + "url": { + "raw": "https://postman-echo.com/:path", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + ":path" + ], + "variable": [ + { + "key": "path", + "value": "post" + } + ] + } + }, + "response": [] + }, + { + "name": "Post x-www-form-urlencoded", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "k1", + "value": "v1", + "type": "text" + }, + { + "key": "k2", + "value": "v2", + "type": "text" + }, + { + "key": "k3", + "value": "v3", + "type": "text", + "disabled": true + } + ] + }, + "url": { + "raw": "https://postman-echo.com/:path", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + ":path" + ], + "variable": [ + { + "key": "path", + "value": "post" + } + ] + } + }, + "response": [] + }, + { + "name": "Post raw json", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"k1\": \"v1\",\n \"k2\": \"v2\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://postman-echo.com/:path", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + ":path" + ], + "variable": [ + { + "key": "path", + "value": "post" + } + ] + } + }, + "response": [] + }, + { + "name": "Post raw text", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "have a nice day", + "options": { + "raw": { + "language": "text" + } + } + }, + "url": { + "raw": "https://postman-echo.com/:path", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + ":path" + ], + "variable": [ + { + "key": "path", + "value": "post" + } + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Get request headers", + "request": { + "method": "GET", + "header": [ + { + "key": "User-Agent", + "value": "HttpRunner", + "type": "text" + }, + { + "key": "User-Name", + "value": "bbx", + "type": "text", + "disabled": true + }, + { + "key": "Connection", + "value": "close", + "type": "text" + } + ], + "url": { + "raw": "https://postman-echo.com/:path", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + ":path" + ], + "variable": [ + { + "key": "path", + "value": "headers" + } + ] + } + }, + "response": [ + { + "name": "Get request headers case1", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "User-Agent", + "value": "HttpRunner", + "type": "text" + }, + { + "key": "User-Name", + "value": "bbx", + "type": "text", + "disabled": true + }, + { + "key": "Cookie", + "value": "Cookie_1=c1; Cookie_2=c2; sails.sid=s%3AGX6aS9b_phvUSUk66w7ZBgWuOPI7IIKT.ayEGTaW4U35eAWyPz%2Fh6Q74DonNcbqw3H5Q5Zv%2BfKMY", + "type": "text" + } + ], + "url": { + "raw": "https://postman-echo.com/:path", + "protocol": "https", + "host": [ + "postman-echo", + "com" + ], + "path": [ + ":path" + ], + "variable": [ + { + "key": "path", + "value": "headers" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Mon, 16 May 2022 12:14:25 GMT" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "541" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "ETag", + "value": "W/\"21d-ld5UvFTaRM6lihVnvCj6mZm5Of0\"" + }, + { + "key": "Vary", + "value": "Accept-Encoding" + } + ], + "cookie": [], + "body": "{\n \"headers\": {\n \"x-forwarded-proto\": \"https\",\n \"x-forwarded-port\": \"443\",\n \"host\": \"postman-echo.com\",\n \"user-agent\": \"HttpRunner\",\n \"cookie\": \"Cookie_1=c1; Cookie_2=c2; sails.sid=s%3AGX6aS9b_phvUSUk66w7ZBgWuOPI7IIKT.ayEGTaW4U35eAWyPz%2Fh6Q74DonNcbqw3H5Q5Zv%2BfKMY\",\n \"accept\": \"*/*\",\n \"accept-encoding\": \"gzip, deflate, br\"\n }\n}" + } + ] + } + ] +} \ No newline at end of file diff --git a/hrp/internal/convert/converter_gotest.go b/hrp/internal/convert/from_gotest.go similarity index 100% rename from hrp/internal/convert/converter_gotest.go rename to hrp/internal/convert/from_gotest.go diff --git a/hrp/internal/convert/converter_har.go b/hrp/internal/convert/from_har.go similarity index 100% rename from hrp/internal/convert/converter_har.go rename to hrp/internal/convert/from_har.go diff --git a/hrp/internal/convert/converter_har_test.go b/hrp/internal/convert/from_har_test.go similarity index 100% rename from hrp/internal/convert/converter_har_test.go rename to hrp/internal/convert/from_har_test.go diff --git a/hrp/internal/convert/converter_json.go b/hrp/internal/convert/from_json.go similarity index 100% rename from hrp/internal/convert/converter_json.go rename to hrp/internal/convert/from_json.go diff --git a/hrp/internal/convert/converter_postman.go b/hrp/internal/convert/from_postman.go similarity index 100% rename from hrp/internal/convert/converter_postman.go rename to hrp/internal/convert/from_postman.go diff --git a/hrp/internal/convert/converter_postman_test.go b/hrp/internal/convert/from_postman_test.go similarity index 100% rename from hrp/internal/convert/converter_postman_test.go rename to hrp/internal/convert/from_postman_test.go diff --git a/hrp/internal/convert/converter_pytest.go b/hrp/internal/convert/from_pytest.go similarity index 100% rename from hrp/internal/convert/converter_pytest.go rename to hrp/internal/convert/from_pytest.go diff --git a/hrp/internal/convert/converter_swagger.go b/hrp/internal/convert/from_swagger.go similarity index 100% rename from hrp/internal/convert/converter_swagger.go rename to hrp/internal/convert/from_swagger.go diff --git a/hrp/internal/convert/converter_yaml.go b/hrp/internal/convert/from_yaml.go similarity index 100% rename from hrp/internal/convert/converter_yaml.go rename to hrp/internal/convert/from_yaml.go From d2c80cd2b70cb90f834d0e6c88c1d30cc84a2ac0 Mon Sep 17 00:00:00 2001 From: debugtalk Date: Mon, 27 Jun 2022 16:56:10 +0800 Subject: [PATCH 4/6] change: update docs --- docs/CHANGELOG.md | 2 +- docs/cmd/hrp.md | 2 +- docs/cmd/hrp_boom.md | 2 +- docs/cmd/hrp_build.md | 2 +- docs/cmd/hrp_convert.md | 2 +- docs/cmd/hrp_pytest.md | 2 +- docs/cmd/hrp_run.md | 2 +- docs/cmd/hrp_startproject.md | 2 +- docs/cmd/hrp_wiki.md | 2 +- examples/demo-empty-project/proj.json | 2 +- examples/demo-with-go-plugin/proj.json | 2 +- examples/demo-with-py-plugin/proj.json | 2 +- examples/demo-without-plugin/proj.json | 2 +- hrp/internal/convert/converter.go | 4 +--- hrp/internal/convert/from_json.go | 1 - hrp/internal/convert/from_swagger.go | 2 +- hrp/internal/convert/from_yaml.go | 1 - 17 files changed, 15 insertions(+), 19 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index ff38210a..2d2204ad 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,6 +1,6 @@ # Release History -## v4.1.5 (2022-06-26) +## v4.1.5 (2022-06-27) **go version** diff --git a/docs/cmd/hrp.md b/docs/cmd/hrp.md index 63fd18af..4273be35 100644 --- a/docs/cmd/hrp.md +++ b/docs/cmd/hrp.md @@ -37,4 +37,4 @@ Copyright 2017 debugtalk * [hrp startproject](hrp_startproject.md) - create a scaffold project * [hrp wiki](hrp_wiki.md) - visit https://httprunner.com -###### Auto generated by spf13/cobra on 26-Jun-2022 +###### Auto generated by spf13/cobra on 27-Jun-2022 diff --git a/docs/cmd/hrp_boom.md b/docs/cmd/hrp_boom.md index 692b09db..40cd994d 100644 --- a/docs/cmd/hrp_boom.md +++ b/docs/cmd/hrp_boom.md @@ -42,4 +42,4 @@ hrp boom [flags] * [hrp](hrp.md) - Next-Generation API Testing Solution. -###### Auto generated by spf13/cobra on 26-Jun-2022 +###### Auto generated by spf13/cobra on 27-Jun-2022 diff --git a/docs/cmd/hrp_build.md b/docs/cmd/hrp_build.md index 73b471c1..d8b6c97b 100644 --- a/docs/cmd/hrp_build.md +++ b/docs/cmd/hrp_build.md @@ -28,4 +28,4 @@ hrp build $path ... [flags] * [hrp](hrp.md) - Next-Generation API Testing Solution. -###### Auto generated by spf13/cobra on 26-Jun-2022 +###### Auto generated by spf13/cobra on 27-Jun-2022 diff --git a/docs/cmd/hrp_convert.md b/docs/cmd/hrp_convert.md index 5ac017df..75684067 100644 --- a/docs/cmd/hrp_convert.md +++ b/docs/cmd/hrp_convert.md @@ -22,4 +22,4 @@ hrp convert $path... [flags] * [hrp](hrp.md) - Next-Generation API Testing Solution. -###### Auto generated by spf13/cobra on 26-Jun-2022 +###### Auto generated by spf13/cobra on 27-Jun-2022 diff --git a/docs/cmd/hrp_pytest.md b/docs/cmd/hrp_pytest.md index 4aa4bcf7..5c70465b 100644 --- a/docs/cmd/hrp_pytest.md +++ b/docs/cmd/hrp_pytest.md @@ -16,4 +16,4 @@ hrp pytest $path ... [flags] * [hrp](hrp.md) - Next-Generation API Testing Solution. -###### Auto generated by spf13/cobra on 26-Jun-2022 +###### Auto generated by spf13/cobra on 27-Jun-2022 diff --git a/docs/cmd/hrp_run.md b/docs/cmd/hrp_run.md index b20e39e9..3b93507e 100644 --- a/docs/cmd/hrp_run.md +++ b/docs/cmd/hrp_run.md @@ -35,4 +35,4 @@ hrp run $path... [flags] * [hrp](hrp.md) - Next-Generation API Testing Solution. -###### Auto generated by spf13/cobra on 26-Jun-2022 +###### Auto generated by spf13/cobra on 27-Jun-2022 diff --git a/docs/cmd/hrp_startproject.md b/docs/cmd/hrp_startproject.md index 91a9d782..acfcb432 100644 --- a/docs/cmd/hrp_startproject.md +++ b/docs/cmd/hrp_startproject.md @@ -21,4 +21,4 @@ hrp startproject $project_name [flags] * [hrp](hrp.md) - Next-Generation API Testing Solution. -###### Auto generated by spf13/cobra on 26-Jun-2022 +###### Auto generated by spf13/cobra on 27-Jun-2022 diff --git a/docs/cmd/hrp_wiki.md b/docs/cmd/hrp_wiki.md index f07574a9..7614dbe6 100644 --- a/docs/cmd/hrp_wiki.md +++ b/docs/cmd/hrp_wiki.md @@ -16,4 +16,4 @@ hrp wiki [flags] * [hrp](hrp.md) - Next-Generation API Testing Solution. -###### Auto generated by spf13/cobra on 26-Jun-2022 +###### Auto generated by spf13/cobra on 27-Jun-2022 diff --git a/examples/demo-empty-project/proj.json b/examples/demo-empty-project/proj.json index 800fb120..7405d8a2 100644 --- a/examples/demo-empty-project/proj.json +++ b/examples/demo-empty-project/proj.json @@ -1,5 +1,5 @@ { "project_name": "demo-empty-project", - "create_time": "2022-06-26T11:26:24.132921+08:00", + "create_time": "2022-06-27T16:52:45.660111+08:00", "hrp_version": "v4.1.4" } diff --git a/examples/demo-with-go-plugin/proj.json b/examples/demo-with-go-plugin/proj.json index a6224191..33679c33 100644 --- a/examples/demo-with-go-plugin/proj.json +++ b/examples/demo-with-go-plugin/proj.json @@ -1,5 +1,5 @@ { "project_name": "demo-with-go-plugin", - "create_time": "2022-06-26T11:21:39.64233+08:00", + "create_time": "2022-06-27T16:51:52.779837+08:00", "hrp_version": "v4.1.4" } diff --git a/examples/demo-with-py-plugin/proj.json b/examples/demo-with-py-plugin/proj.json index a5eedc42..fca33a09 100644 --- a/examples/demo-with-py-plugin/proj.json +++ b/examples/demo-with-py-plugin/proj.json @@ -1,5 +1,5 @@ { "project_name": "demo-with-py-plugin", - "create_time": "2022-06-26T11:21:40.23509+08:00", + "create_time": "2022-06-27T16:51:54.32061+08:00", "hrp_version": "v4.1.4" } diff --git a/examples/demo-without-plugin/proj.json b/examples/demo-without-plugin/proj.json index 6b36d714..29065d5b 100644 --- a/examples/demo-without-plugin/proj.json +++ b/examples/demo-without-plugin/proj.json @@ -1,5 +1,5 @@ { "project_name": "demo-without-plugin", - "create_time": "2022-06-26T11:26:19.127696+08:00", + "create_time": "2022-06-27T16:52:45.363472+08:00", "hrp_version": "v4.1.4" } diff --git a/hrp/internal/convert/converter.go b/hrp/internal/convert/converter.go index 7f1128e9..be5d77de 100644 --- a/hrp/internal/convert/converter.go +++ b/hrp/internal/convert/converter.go @@ -62,14 +62,13 @@ func Run(outputType OutputType, outputDir, profilePath string, args []string) { // loads source file and convert to TCase format tCase, err := LoadTCase(path) if err != nil { - log.Warn().Err(err).Str("path", path).Msg("construct case loader failed") + log.Warn().Err(err).Str("path", path).Msg("convert source file failed") continue } caseConverter := &TCaseConverter{ SourcePath: path, OutputDir: outputDir, - OutputType: outputType, TCase: tCase, } @@ -165,7 +164,6 @@ func LoadTCase(path string) (*hrp.TCase, error) { type TCaseConverter struct { SourcePath string OutputDir string - OutputType OutputType TCase *hrp.TCase } diff --git a/hrp/internal/convert/from_json.go b/hrp/internal/convert/from_json.go index 0eaf1019..0dbc7208 100644 --- a/hrp/internal/convert/from_json.go +++ b/hrp/internal/convert/from_json.go @@ -20,7 +20,6 @@ func LoadJSONCase(path string) (*hrp.TCase, error) { return nil, errors.New("invalid json file") } - // convert json case to TCase err = caseJSON.MakeCompat() if err != nil { return nil, err diff --git a/hrp/internal/convert/from_swagger.go b/hrp/internal/convert/from_swagger.go index ce3c7557..0c7677e4 100644 --- a/hrp/internal/convert/from_swagger.go +++ b/hrp/internal/convert/from_swagger.go @@ -21,6 +21,6 @@ func LoadSwaggerCase(path string) (*hrp.TCase, error) { return nil, errors.New("invalid swagger file") } - // convert swagger to TCase + // TODO: convert swagger to TCase return nil, nil } diff --git a/hrp/internal/convert/from_yaml.go b/hrp/internal/convert/from_yaml.go index 93abc0f0..977e47de 100644 --- a/hrp/internal/convert/from_yaml.go +++ b/hrp/internal/convert/from_yaml.go @@ -20,7 +20,6 @@ func NewYAMLCase(path string) (*hrp.TCase, error) { return nil, errors.New("invalid yaml file") } - // convert json case to TCase err = caseJSON.MakeCompat() if err != nil { return nil, err From c6753998a2335416a5f54d8c6a222f84d0e22f63 Mon Sep 17 00:00:00 2001 From: debugtalk Date: Mon, 27 Jun 2022 18:55:06 +0800 Subject: [PATCH 5/6] fix: check case validation --- hrp/internal/convert/from_json.go | 7 +++---- hrp/internal/convert/from_postman.go | 4 ++-- hrp/internal/convert/from_swagger.go | 6 ++---- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/hrp/internal/convert/from_json.go b/hrp/internal/convert/from_json.go index 0dbc7208..8e40f88b 100644 --- a/hrp/internal/convert/from_json.go +++ b/hrp/internal/convert/from_json.go @@ -1,8 +1,6 @@ package convert import ( - "reflect" - "github.com/pkg/errors" "github.com/httprunner/httprunner/v4/hrp" @@ -16,8 +14,9 @@ func LoadJSONCase(path string) (*hrp.TCase, error) { if err != nil { return nil, errors.Wrap(err, "load json file failed") } - if reflect.ValueOf(*caseJSON).IsZero() { - return nil, errors.New("invalid json file") + + if caseJSON.TestSteps == nil { + return nil, errors.New("invalid json case file, missing teststeps") } err = caseJSON.MakeCompat() diff --git a/hrp/internal/convert/from_postman.go b/hrp/internal/convert/from_postman.go index 01d9f3e5..9dbbfa7c 100644 --- a/hrp/internal/convert/from_postman.go +++ b/hrp/internal/convert/from_postman.go @@ -129,8 +129,8 @@ func loadCasePostman(path string) (*CasePostman, error) { if err != nil { return nil, errors.Wrap(err, "load postman file failed") } - if reflect.ValueOf(*casePostman).IsZero() { - return nil, errors.New("invalid postman file") + if casePostman.Items == nil { + return nil, errors.New("invalid postman case file, missing items") } return casePostman, nil diff --git a/hrp/internal/convert/from_swagger.go b/hrp/internal/convert/from_swagger.go index 0c7677e4..b4f5ad5f 100644 --- a/hrp/internal/convert/from_swagger.go +++ b/hrp/internal/convert/from_swagger.go @@ -1,8 +1,6 @@ package convert import ( - "reflect" - "github.com/go-openapi/spec" "github.com/pkg/errors" @@ -17,8 +15,8 @@ func LoadSwaggerCase(path string) (*hrp.TCase, error) { if err != nil { return nil, errors.Wrap(err, "load swagger file failed") } - if reflect.ValueOf(*caseSwagger).IsZero() { - return nil, errors.New("invalid swagger file") + if caseSwagger.Definitions == nil { + return nil, errors.New("invalid swagger case file, missing definitions") } // TODO: convert swagger to TCase From 0a73f17e2b1945fdb255cc91b408576693b08fdd Mon Sep 17 00:00:00 2001 From: debugtalk Date: Mon, 27 Jun 2022 21:28:09 +0800 Subject: [PATCH 6/6] fix: convert postman to pytest --- hrp/internal/builtin/utils.go | 4 ++-- hrp/internal/convert/converter.go | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/hrp/internal/builtin/utils.go b/hrp/internal/builtin/utils.go index bdc40938..3b3a62b6 100644 --- a/hrp/internal/builtin/utils.go +++ b/hrp/internal/builtin/utils.go @@ -450,8 +450,8 @@ func ReadFile(path string) ([]byte, error) { return file, nil } -func GetOutputNameWithoutExtension(path string) string { +func GetFileNameWithoutExtension(path string) string { base := filepath.Base(path) ext := filepath.Ext(base) - return base[0:len(base)-len(ext)] + "_test" + return base[0 : len(base)-len(ext)] } diff --git a/hrp/internal/convert/converter.go b/hrp/internal/convert/converter.go index be5d77de..dd3f22b7 100644 --- a/hrp/internal/convert/converter.go +++ b/hrp/internal/convert/converter.go @@ -168,7 +168,7 @@ type TCaseConverter struct { } func (c *TCaseConverter) genOutputPath(suffix string) string { - outFileFullName := builtin.GetOutputNameWithoutExtension(c.SourcePath) + suffix + outFileFullName := builtin.GetFileNameWithoutExtension(c.SourcePath) + "_test" + suffix if c.OutputDir != "" { return filepath.Join(c.OutputDir, outFileFullName) } else { @@ -179,8 +179,13 @@ func (c *TCaseConverter) genOutputPath(suffix string) string { // convert TCase to pytest case func (c *TCaseConverter) ToPyTest() (string, error) { - args := append([]string{"make"}, c.SourcePath) - err := builtin.ExecPython3Command("httprunner", args...) + jsonPath, err := c.ToJSON() + if err != nil { + return "", errors.Wrap(err, "convert to JSON case failed") + } + + args := append([]string{"make"}, jsonPath) + err = builtin.ExecPython3Command("httprunner", args...) if err != nil { return "", err }