From 89d0d4bb96c22276473e227ab3726c78f4a13f55 Mon Sep 17 00:00:00 2001 From: "lilong.129" Date: Mon, 19 Aug 2024 22:42:53 +0800 Subject: [PATCH] refactor: move LoadFile to hrp/loader --- go.mod | 2 +- hrp/internal/builtin/utils.go | 64 ------------------------------ hrp/loader.go | 70 +++++++++++++++++++++++++++++++++ hrp/loader_test.go | 26 ++++++++++++ hrp/pkg/convert/from_har.go | 3 +- hrp/pkg/convert/from_json.go | 3 +- hrp/pkg/convert/from_postman.go | 3 +- hrp/pkg/convert/from_swagger.go | 3 +- hrp/pkg/convert/from_yaml.go | 3 +- hrp/pkg/convert/main.go | 2 +- hrp/step_api.go | 4 +- hrp/testcase.go | 4 +- hrp/testcase_test.go | 28 ------------- 13 files changed, 106 insertions(+), 109 deletions(-) diff --git a/go.mod b/go.mod index 6cc068cb..8a8f3c43 100644 --- a/go.mod +++ b/go.mod @@ -30,6 +30,7 @@ require ( golang.org/x/oauth2 v0.8.0 google.golang.org/grpc v1.57.0 google.golang.org/protobuf v1.32.0 + gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 howett.net/plist v1.0.0 ) @@ -77,7 +78,6 @@ require ( golang.org/x/text v0.14.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect ) // replace github.com/httprunner/funplugin => ../funplugin diff --git a/hrp/internal/builtin/utils.go b/hrp/internal/builtin/utils.go index 918530b3..0f6614e2 100644 --- a/hrp/internal/builtin/utils.go +++ b/hrp/internal/builtin/utils.go @@ -235,70 +235,6 @@ func InterfaceType(raw interface{}) string { return reflect.TypeOf(raw).String() } -// LoadFile loads file content with file extension and assigns to structObj -func LoadFile(path string, structObj interface{}) (err error) { - log.Info().Str("path", path).Msg("load file") - file, err := ReadFile(path) - if err != nil { - return errors.Wrap(err, "read file failed") - } - // remove BOM at the beginning of file - file = bytes.TrimLeft(file, "\xef\xbb\xbf") - ext := filepath.Ext(path) - switch ext { - case ".json", ".har": - decoder := json.NewDecoder(bytes.NewReader(file)) - decoder.UseNumber() - err = decoder.Decode(structObj) - if err != nil { - err = errors.Wrap(code.LoadJSONError, err.Error()) - } - case ".yaml", ".yml": - err = yaml.Unmarshal(file, structObj) - if err != nil { - err = errors.Wrap(code.LoadYAMLError, err.Error()) - } - case ".env": - err = parseEnvContent(file, structObj) - if err != nil { - err = errors.Wrap(code.LoadEnvError, err.Error()) - } - default: - err = code.UnsupportedFileExtension - } - return err -} - -func parseEnvContent(file []byte, obj interface{}) error { - envMap := obj.(map[string]string) - lines := strings.Split(string(file), "\n") - for _, line := range lines { - line = strings.TrimSpace(line) - if line == "" || strings.HasPrefix(line, "#") { - // empty line or comment line - continue - } - var kv []string - if strings.Contains(line, "=") { - kv = strings.SplitN(line, "=", 2) - } else if strings.Contains(line, ":") { - kv = strings.SplitN(line, ":", 2) - } - if len(kv) != 2 { - return errors.New(".env format error") - } - - key := strings.TrimSpace(kv[0]) - value := strings.TrimSpace(kv[1]) - envMap[key] = value - - // set env - log.Info().Str("key", key).Msg("set env") - os.Setenv(key, value) - } - return nil -} - func loadFromCSV(path string) []map[string]interface{} { log.Info().Str("path", path).Msg("load csv file") file, err := ReadFile(path) diff --git a/hrp/loader.go b/hrp/loader.go index 392631c4..a79212be 100644 --- a/hrp/loader.go +++ b/hrp/loader.go @@ -1,6 +1,7 @@ package hrp import ( + "bytes" "io/fs" "os" "path/filepath" @@ -8,6 +9,11 @@ import ( "github.com/pkg/errors" "github.com/rs/zerolog/log" + "gopkg.in/yaml.v2" + + "github.com/httprunner/httprunner/v4/hrp/internal/builtin" + "github.com/httprunner/httprunner/v4/hrp/internal/code" + "github.com/httprunner/httprunner/v4/hrp/internal/json" ) // LoadTestCases load testcases from TestCasePath or TestCase @@ -63,3 +69,67 @@ func LoadTestCases(tests ...ITestCase) ([]*TestCase, error) { log.Info().Int("count", len(testCases)).Msg("load testcases successfully") return testCases, nil } + +// LoadFile loads file content with file extension and assigns to structObj +func LoadFile(path string, structObj interface{}) (err error) { + log.Info().Str("path", path).Msg("load file") + file, err := builtin.ReadFile(path) + if err != nil { + return errors.Wrap(err, "read file failed") + } + // remove BOM at the beginning of file + file = bytes.TrimLeft(file, "\xef\xbb\xbf") + ext := filepath.Ext(path) + switch ext { + case ".json", ".har": + decoder := json.NewDecoder(bytes.NewReader(file)) + decoder.UseNumber() + err = decoder.Decode(structObj) + if err != nil { + err = errors.Wrap(code.LoadJSONError, err.Error()) + } + case ".yaml", ".yml": + err = yaml.Unmarshal(file, structObj) + if err != nil { + err = errors.Wrap(code.LoadYAMLError, err.Error()) + } + case ".env": + err = parseEnvContent(file, structObj) + if err != nil { + err = errors.Wrap(code.LoadEnvError, err.Error()) + } + default: + err = code.UnsupportedFileExtension + } + return err +} + +func parseEnvContent(file []byte, obj interface{}) error { + envMap := obj.(map[string]string) + lines := strings.Split(string(file), "\n") + for _, line := range lines { + line = strings.TrimSpace(line) + if line == "" || strings.HasPrefix(line, "#") { + // empty line or comment line + continue + } + var kv []string + if strings.Contains(line, "=") { + kv = strings.SplitN(line, "=", 2) + } else if strings.Contains(line, ":") { + kv = strings.SplitN(line, ":", 2) + } + if len(kv) != 2 { + return errors.New(".env format error") + } + + key := strings.TrimSpace(kv[0]) + value := strings.TrimSpace(kv[1]) + envMap[key] = value + + // set env + log.Info().Str("key", key).Msg("set env") + os.Setenv(key, value) + } + return nil +} diff --git a/hrp/loader_test.go b/hrp/loader_test.go index a419a984..68ac67e2 100644 --- a/hrp/loader_test.go +++ b/hrp/loader_test.go @@ -49,3 +49,29 @@ func TestLoadTestCases(t *testing.T) { t.Fatal() } } + +func TestLoadCase(t *testing.T) { + tcJSON := &TestCase{} + tcYAML := &TestCase{} + err := LoadFile(demoTestCaseWithPluginJSONPath, tcJSON) + if !assert.NoError(t, err) { + t.Fatal() + } + err = LoadFile(demoTestCaseWithPluginYAMLPath, tcYAML) + if !assert.NoError(t, err) { + t.Fatal() + } + + if !assert.Equal(t, tcJSON.Config.Name, tcYAML.Config.Name) { + t.Fatal() + } + if !assert.Equal(t, tcJSON.Config.BaseURL, tcYAML.Config.BaseURL) { + t.Fatal() + } + if !assert.Equal(t, tcJSON.Steps[1].Name, tcYAML.Steps[1].Name) { + t.Fatal() + } + if !assert.Equal(t, tcJSON.Steps[1].Request, tcYAML.Steps[1].Request) { + t.Fatal() + } +} diff --git a/hrp/pkg/convert/from_har.go b/hrp/pkg/convert/from_har.go index 6247584b..7b4f1ef1 100644 --- a/hrp/pkg/convert/from_har.go +++ b/hrp/pkg/convert/from_har.go @@ -13,7 +13,6 @@ import ( "github.com/rs/zerolog/log" "github.com/httprunner/httprunner/v4/hrp" - "github.com/httprunner/httprunner/v4/hrp/internal/builtin" "github.com/httprunner/httprunner/v4/hrp/internal/json" ) @@ -371,7 +370,7 @@ func LoadHARCase(path string) (*hrp.TestCase, error) { func loadCaseHAR(path string) (*CaseHar, error) { caseHAR := new(CaseHar) - err := builtin.LoadFile(path, caseHAR) + err := hrp.LoadFile(path, caseHAR) if err != nil { return nil, errors.Wrap(err, "load har file failed") } diff --git a/hrp/pkg/convert/from_json.go b/hrp/pkg/convert/from_json.go index 283bd012..b0725118 100644 --- a/hrp/pkg/convert/from_json.go +++ b/hrp/pkg/convert/from_json.go @@ -5,13 +5,12 @@ import ( "github.com/rs/zerolog/log" "github.com/httprunner/httprunner/v4/hrp" - "github.com/httprunner/httprunner/v4/hrp/internal/builtin" ) func LoadJSONCase(path string) (*hrp.TestCase, error) { log.Info().Str("path", path).Msg("load json case file") caseJSON := new(hrp.TestCase) - err := builtin.LoadFile(path, caseJSON) + err := hrp.LoadFile(path, caseJSON) if err != nil { return nil, errors.Wrap(err, "load json file failed") } diff --git a/hrp/pkg/convert/from_postman.go b/hrp/pkg/convert/from_postman.go index a8e7861e..f1f8eac2 100644 --- a/hrp/pkg/convert/from_postman.go +++ b/hrp/pkg/convert/from_postman.go @@ -10,7 +10,6 @@ import ( "github.com/rs/zerolog/log" "github.com/httprunner/httprunner/v4/hrp" - "github.com/httprunner/httprunner/v4/hrp/internal/builtin" "github.com/httprunner/httprunner/v4/hrp/internal/json" ) @@ -125,7 +124,7 @@ func LoadPostmanCase(path string) (*hrp.TestCase, error) { func loadCasePostman(path string) (*CasePostman, error) { casePostman := new(CasePostman) - err := builtin.LoadFile(path, casePostman) + err := hrp.LoadFile(path, casePostman) if err != nil { return nil, errors.Wrap(err, "load postman file failed") } diff --git a/hrp/pkg/convert/from_swagger.go b/hrp/pkg/convert/from_swagger.go index 7ec80cfc..ab5a974c 100644 --- a/hrp/pkg/convert/from_swagger.go +++ b/hrp/pkg/convert/from_swagger.go @@ -5,13 +5,12 @@ import ( "github.com/pkg/errors" "github.com/httprunner/httprunner/v4/hrp" - "github.com/httprunner/httprunner/v4/hrp/internal/builtin" ) func LoadSwaggerCase(path string) (*hrp.TestCase, error) { // load swagger file caseSwagger := new(spec.Swagger) - err := builtin.LoadFile(path, caseSwagger) + err := hrp.LoadFile(path, caseSwagger) if err != nil { return nil, errors.Wrap(err, "load swagger file failed") } diff --git a/hrp/pkg/convert/from_yaml.go b/hrp/pkg/convert/from_yaml.go index b9095851..e2acb54d 100644 --- a/hrp/pkg/convert/from_yaml.go +++ b/hrp/pkg/convert/from_yaml.go @@ -6,13 +6,12 @@ import ( "github.com/pkg/errors" "github.com/httprunner/httprunner/v4/hrp" - "github.com/httprunner/httprunner/v4/hrp/internal/builtin" ) func LoadYAMLCase(path string) (*hrp.TestCase, error) { // load yaml case file caseJSON := new(hrp.TestCase) - err := builtin.LoadFile(path, caseJSON) + err := hrp.LoadFile(path, caseJSON) if err != nil { return nil, errors.Wrap(err, "load yaml file failed") } diff --git a/hrp/pkg/convert/main.go b/hrp/pkg/convert/main.go index 31e72b8b..c1c73e59 100644 --- a/hrp/pkg/convert/main.go +++ b/hrp/pkg/convert/main.go @@ -198,7 +198,7 @@ func (c *TCaseConverter) genOutputPath(suffix string) string { func (c *TCaseConverter) overrideWithProfile(path string) error { log.Info().Str("path", path).Msg("load profile") profile := new(Profile) - err := builtin.LoadFile(path, profile) + err := hrp.LoadFile(path, profile) if err != nil { log.Warn().Str("path", path). Msg("failed to load profile, ignore!") diff --git a/hrp/step_api.go b/hrp/step_api.go index f6640332..9e85d000 100644 --- a/hrp/step_api.go +++ b/hrp/step_api.go @@ -5,8 +5,6 @@ import ( "github.com/jinzhu/copier" "github.com/rs/zerolog/log" - - "github.com/httprunner/httprunner/v4/hrp/internal/builtin" ) // IAPI represents interface for api, @@ -46,7 +44,7 @@ func (path *APIPath) GetPath() string { func (path *APIPath) ToAPI() (*API, error) { api := &API{} apiPath := path.GetPath() - err := builtin.LoadFile(apiPath, api) + err := LoadFile(apiPath, api) if err != nil { return nil, err } diff --git a/hrp/testcase.go b/hrp/testcase.go index 989d0862..853d2ea2 100644 --- a/hrp/testcase.go +++ b/hrp/testcase.go @@ -27,7 +27,7 @@ type TestCasePath string func (path *TestCasePath) GetTestCase() (*TestCase, error) { tc := &TestCase{} casePath := string(*path) - err := builtin.LoadFile(casePath, tc) + err := LoadFile(casePath, tc) if err != nil { return nil, err } @@ -137,7 +137,7 @@ func (tc *TestCase) loadISteps() (*TestCase, error) { dotEnvPath := filepath.Join(projectRootDir, ".env") if builtin.IsFilePathExists(dotEnvPath) { envVars := make(map[string]string) - err = builtin.LoadFile(dotEnvPath, envVars) + err = LoadFile(dotEnvPath, envVars) if err != nil { return nil, errors.Wrap(err, "failed to load .env file") } diff --git a/hrp/testcase_test.go b/hrp/testcase_test.go index 8a6cb63d..b0c15dbb 100644 --- a/hrp/testcase_test.go +++ b/hrp/testcase_test.go @@ -5,8 +5,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - - "github.com/httprunner/httprunner/v4/hrp/internal/builtin" ) const ( @@ -175,32 +173,6 @@ func TestGenDemoTestCase(t *testing.T) { } } -func TestLoadCase(t *testing.T) { - tcJSON := &TestCase{} - tcYAML := &TestCase{} - err := builtin.LoadFile(demoTestCaseWithPluginJSONPath, tcJSON) - if !assert.NoError(t, err) { - t.Fatal() - } - err = builtin.LoadFile(demoTestCaseWithPluginYAMLPath, tcYAML) - if !assert.NoError(t, err) { - t.Fatal() - } - - if !assert.Equal(t, tcJSON.Config.Name, tcYAML.Config.Name) { - t.Fatal() - } - if !assert.Equal(t, tcJSON.Config.BaseURL, tcYAML.Config.BaseURL) { - t.Fatal() - } - if !assert.Equal(t, tcJSON.Steps[1].Name, tcYAML.Steps[1].Name) { - t.Fatal() - } - if !assert.Equal(t, tcJSON.Steps[1].Request, tcYAML.Steps[1].Request) { - t.Fatal() - } -} - func TestConvertCheckExpr(t *testing.T) { exprs := []struct { before string