From 6234b40557f2b1b85b945c2b65d0dfd5e65b98e0 Mon Sep 17 00:00:00 2001 From: Andrey Ivanov Date: Wed, 22 Feb 2023 16:31:45 +0300 Subject: [PATCH 1/6] Initial code --- .drone.yml | 14 +++++ .gitignore | 4 ++ Makefile | 14 +++++ cmd/main.go | 26 +++++++++ go.mod | 5 ++ go.sum | 4 ++ golangci.yml | 102 ++++++++++++++++++++++++++++++++++ internal/scenario/models.go | 17 ++++++ internal/scenario/scenario.go | 21 +++++++ test/test.yaml | 14 +++++ 10 files changed, 221 insertions(+) create mode 100644 .drone.yml create mode 100644 Makefile create mode 100644 cmd/main.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 golangci.yml create mode 100644 internal/scenario/models.go create mode 100644 internal/scenario/scenario.go create mode 100644 test/test.yaml diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..0a8fd38 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,14 @@ +kind: pipeline +type: exec +name: pipeline + +steps: + - name: lint + image: golang + commands: + - make lint + + - name: test with race and cover + image: golang + commands: + - make test diff --git a/.gitignore b/.gitignore index adf8f72..3ab39f3 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,7 @@ # Go workspace file go.work +bin +.idea +.vscode + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c7f64ea --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +VERSION=$(shell date +%Y.%m) +PROJECT_NAME=w3back + +.PHONY: lint +lint: ## Линт всего проекта + curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s -- -b $(go env GOPATH)/bin v1.51.1 + golangci-lint run --config=./golangci.yml ./... + +.PHONY: test +test: ## Юнит тестирование всего проекта + go test -race -count 100 -timeout 30s ./... + +help: ## Print this help and exit + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..b9e8f05 --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,26 @@ +package main + +import ( + "context" + "flag" + "github.com/tiburon-777/w3back/internal/scenario" + "log" +) + +func main() { + // Парсим флаги приложения. + file := flag.String("scenario", "./test/test.yaml", "path to file with test scenario") + ctx := context.Background() + + // Читаем и валидируем файл сценария. + sc, err := scenario.New(ctx, *file) + if err != nil { + log.Fatalf("can't understand test scenario: %v ", err) + } + + for key, cs := range sc.Cases { + log.Printf("Case#%d - %s", key, cs.Name) + + } + +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..f1f076f --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/tiburon-777/w3back + +go 1.18 + +require gopkg.in/yaml.v2 v2.4.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..dd0bc19 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/golangci.yml b/golangci.yml new file mode 100644 index 0000000..d87ed9a --- /dev/null +++ b/golangci.yml @@ -0,0 +1,102 @@ +# This file contains all available configuration options +# with their default values. + +# options for analysis running +run: + # default concurrency is a available CPU number + #concurrency: 4 + + # timeout for analysis, e.g. 30s, 5m, default is 1m + deadline: 30m + + # include test files or not, default is true + tests: false + + # which dirs to skip: they won't be analyzed; + # can use regexp here: generated.*, regexp is applied on full path; + # default value is empty list, but next dirs are always skipped independently + # from this option's value: + # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ + skip-dirs: + - bin$ + - \.git$ + - etc$ + - protobuf$ + - scripts$ + - vendor$ + - ^benches/ + + # which files to skip: they will be analyzed, but issues from them + # won't be reported. Default value is empty list, but there is + # no need to include all autogenerated files, we confidently recognize + # autogenerated files. If it's not please let us know. + skip-files: + - "_easyjson.go" + - ".pb.go" + + # by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules": + # If invoked with -mod=readonly, the go command is disallowed from the implicit + # automatic updating of go.mod described above. Instead, it fails when any changes + # to go.mod are needed. This setting is most useful to check that go.mod does + # not need updates, such as in a continuous integration and testing system. + # If invoked with -mod=vendor, the go command assumes that the vendor + # directory holds the correct copies of dependencies and ignores + # the dependency descriptions in go.mod. + modules-download-mode: mod + +# all available settings of specific linters +linters-settings: + errcheck: + # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`; + # default is false: such cases aren't reported by default. + check-blank: true + govet: + # report about shadowed variables + check-shadowing: true + golint: + # minimal confidence for issues, default is 0.8 + min-confidence: 0.3 + gocyclo: + # minimal code complexity to report, 30 by default (but we recommend 10-20) + min-complexity: 20 + dupl: + # tokens count to trigger issue, 150 by default + threshold: 200 + lll: + # max line length, lines longer will be reported. Default is 120. + # '\t' is counted as 1 character by default, and can be changed with the tab-width option + line-length: 150 + funlen: + statements: 50 + lines: 150 + +linters: + enable-all: true + disable: + - gci + - exhaustivestruct + - exhaustruct + - gochecknoglobals + - whitespace + - wsl + - wrapcheck + - nlreturn + - gofmt + - gofumpt + fast: false + +issues: + max-issues-per-linter: 0 + max-same-issues: 0 + + exclude-rules: + # Exclude lll issues for long lines with go:generate + - linters: + - lll + source: "^//go:generate " + - linters: + - golint + text: "receiver name should be a reflection of its identity" + +output: + format: tab diff --git a/internal/scenario/models.go b/internal/scenario/models.go new file mode 100644 index 0000000..b6b9a6f --- /dev/null +++ b/internal/scenario/models.go @@ -0,0 +1,17 @@ +package scenario + +import "time" + +type Object struct { + Params Params `yaml:"params"` + Cases map[int]Case `yaml:"cases"` +} + +type Params struct { + Address string `yaml:"address"` + Timeout time.Duration `yaml:"timeout"` +} + +type Case struct { + Name string `yaml:"name"` +} diff --git a/internal/scenario/scenario.go b/internal/scenario/scenario.go new file mode 100644 index 0000000..08fb49d --- /dev/null +++ b/internal/scenario/scenario.go @@ -0,0 +1,21 @@ +package scenario + +import ( + "context" + "gopkg.in/yaml.v2" + "os" +) + +func New(ctx context.Context, file string) (*Object, error) { + var obj Object + yamlFile, err := os.ReadFile(file) + if err != nil { + return nil, err + } + + err = yaml.Unmarshal(yamlFile, &obj) + if err != nil { + return nil, err + } + return &obj, nil +} diff --git a/test/test.yaml b/test/test.yaml new file mode 100644 index 0000000..e4e3404 --- /dev/null +++ b/test/test.yaml @@ -0,0 +1,14 @@ +{ + params: { + address: "http://localhost:9090", + timeout: 10s, + }, + cases: { + 1: { + name: "case1", + }, + 2: { + name: "case2", + }, + }, +} \ No newline at end of file -- 2.47.2 From 2f996fbcb246fe32c8fc7d5504feaf6b3223074e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=98=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2?= Date: Wed, 22 Feb 2023 16:34:20 +0300 Subject: [PATCH 2/6] Initial code --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 0a8fd38..edd4343 100644 --- a/.drone.yml +++ b/.drone.yml @@ -11,4 +11,4 @@ steps: - name: test with race and cover image: golang commands: - - make test + - make test \ No newline at end of file -- 2.47.2 From f14095eb3de5e49c4e3410ebe95cc233210c80e8 Mon Sep 17 00:00:00 2001 From: Andrey Ivanov Date: Mon, 27 Feb 2023 18:52:59 +0300 Subject: [PATCH 3/6] Add logic --- cmd/main.go | 68 ++++++++++++++++++++++-- go.mod | 15 +++++- go.sum | 31 ++++++++++- internal/scenario/models.go | 32 +++++++++--- test/test.yaml | 100 +++++++++++++++++++++++++++++++++--- 5 files changed, 228 insertions(+), 18 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index b9e8f05..b77b2b9 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,26 +1,88 @@ package main +// validate doc - https://pkg.go.dev/github.com/go-playground/validator/v10 + import ( "context" "flag" + "fmt" + "github.com/go-playground/validator/v10" "github.com/tiburon-777/w3back/internal/scenario" "log" + "net/http" + "strings" ) func main() { // Парсим флаги приложения. file := flag.String("scenario", "./test/test.yaml", "path to file with test scenario") + flag.Parse() ctx := context.Background() - // Читаем и валидируем файл сценария. + // Читаем файл сценария. sc, err := scenario.New(ctx, *file) if err != nil { log.Fatalf("can't understand test scenario: %v ", err) } - for key, cs := range sc.Cases { - log.Printf("Case#%d - %s", key, cs.Name) + // Валидируем сценарий + if err := validator.New().Struct(sc); err != nil { + log.Fatalf("invalid scenario: %v ", err) + } + cli := http.Client{Timeout: sc.Params.Timeout} + + // Запускаем сценарий + for key, cs := range sc.Steps { + log.Printf("Step#%d - %s", key, cs.Name) + req, err := http.NewRequestWithContext(ctx, cs.Query.Method, fmt.Sprintf("%s%s", sc.Params.Address, cs.Query.URL), strings.NewReader(cs.Query.Data)) + if err != nil { + log.Fatalf("request error: %v ", err) + } + for hKey, hVal := range cs.Query.Headers { + req.Header.Add(hKey, hVal) + } + resp, err := cli.Do(req) + if err != nil { + log.Fatalf("client error: %v ", err) + } + var body []byte + if _, err := resp.Body.Read(body); err != nil { + log.Fatalf("client read body: %v ", err) + } + if cs.Response.Code != 0 && resp.StatusCode != cs.Response.Code { + log.Fatalf("wrong response code: %v ", err) + } + if len(cs.Response.Body) != 0 { + for _, sample := range cs.Response.Body { + switch sample.Function { + case "contains": + if !strings.Contains(string(body), sample.Text) { + log.Fatalf("wrong body") + } + case "not_contains": + if strings.Contains(string(body), sample.Text) { + log.Fatalf("wrong body") + } + case "begin": + if !strings.HasPrefix(string(body), sample.Text) { + log.Fatalf("wrong body") + } + case "not_begin": + if strings.HasPrefix(string(body), sample.Text) { + log.Fatalf("wrong body") + } + case "ends": + if !strings.HasSuffix(string(body), sample.Text) { + log.Fatalf("wrong body") + } + case "not_ends": + if strings.HasSuffix(string(body), sample.Text) { + log.Fatalf("wrong body") + } + } + } + } } } diff --git a/go.mod b/go.mod index f1f076f..87b5780 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,17 @@ module github.com/tiburon-777/w3back go 1.18 -require gopkg.in/yaml.v2 v2.4.0 +require ( + github.com/go-playground/validator/v10 v10.11.2 + gopkg.in/yaml.v2 v2.4.0 +) + +require ( + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/leodido/go-urn v1.2.1 // indirect + golang.org/x/crypto v0.5.0 // indirect + golang.org/x/sys v0.4.0 // indirect + golang.org/x/text v0.6.0 // indirect +) diff --git a/go.sum b/go.sum index dd0bc19..9544376 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,33 @@ -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= +github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= +golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= +golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/internal/scenario/models.go b/internal/scenario/models.go index b6b9a6f..ddbcd06 100644 --- a/internal/scenario/models.go +++ b/internal/scenario/models.go @@ -3,15 +3,35 @@ package scenario import "time" type Object struct { - Params Params `yaml:"params"` - Cases map[int]Case `yaml:"cases"` + Params Params `yaml:"params" validate:"required"` + Steps []Step `yaml:"steps" validate:"required,dive"` } type Params struct { - Address string `yaml:"address"` - Timeout time.Duration `yaml:"timeout"` + Address string `yaml:"address" validate:"required"` + Timeout time.Duration `yaml:"timeout" validate:"required"` } -type Case struct { - Name string `yaml:"name"` +type Step struct { + Name string `yaml:"name" validate:"required"` + Query Query `yaml:"query" validate:"required"` + Response Response `yaml:"response" validate:"required"` +} + +type Query struct { + Method string `yaml:"method" validate:"required"` + URL string `yaml:"url" validate:"required"` + Headers map[string]string `yaml:"headers"` + Data string `yaml:"data"` +} + +type Response struct { + Code int `yaml:"code" validate:"required_without=Body"` + Headers map[string]string `yaml:"headers"` + Body []Sample `yaml:"body" validate:"required_without=Code"` +} + +type Sample struct { + Function string `yaml:"function"` + Text string `yaml:"text"` } diff --git a/test/test.yaml b/test/test.yaml index e4e3404..f560300 100644 --- a/test/test.yaml +++ b/test/test.yaml @@ -1,14 +1,100 @@ { params: { address: "http://localhost:9090", - timeout: 10s, + timeout: 30s, }, - cases: { - 1: { - name: "case1", + steps: [ + { + name: "1.1 - попытка получить флаг intra_domain_share для несуществующего пользователя", + query: { + method: "GET", + url: "/api/v1/user/1/policy/ids", + headers: { + X-Request-ID: "1.1", + Content-Type: "application/json", + }, + }, + response: { + code: 404 + } }, - 2: { - name: "case2", + { + name: "1.2 - попытка установить флаг intra_domain_share для несуществующего пользователя", + query: { + method: "POST", + url: "/api/v1/user/1/policy/ids", + headers: { + X-Request-ID: "1.2", + Content-Type: "application/json", + }, + data: '{"PID":1,"intra_domain_share":true}', + }, + response: { + code: 200, + } }, - }, + { + name: "1.3 - попытка получить флаг intra_domain_share для пользователя, созданного в 1.2", + query: { + method: "GET", + url: "/api/v1/user/1/policy/ids", + headers: { + X-Request-ID: "1.3", + Content-Type: "application/json", + }, + }, + response: { + code: 200, + body: [ + { + function: "contains", + text: "intra_domain_share" + }, + { + function: "contains", + text: "true" + }, + ] + } + }, + { + name: "1.4 - попытка установить флаг intra_domain_share для массива несуществующих пользователей", + query: { + method: "POST", + url: "/api/v1/users/policy/ids", + headers: { + X-Request-ID: "1.4", + Content-Type: "application/json", + }, + data: '{"users":[1,2],"pid":1,"intra_domain_share":true}', + }, + response: { + code: 200, + } + }, + { + name: "1.5 - попытка получить флаг intra_domain_share для одного из пользователей, созданных в 1.4", + query: { + method: "GET", + url: "/api/v1/user/2/policy/ids", + headers: { + X-Request-ID: "1.5", + Content-Type: "application/json", + }, + }, + response: { + code: 200, + body: [ + { + function: "contains", + text: "intra_domain_share" + }, + { + function: "contains", + text: "true" + }, + ] + } + }, + ] } \ No newline at end of file -- 2.47.2 From 5b154fd269df8706edb26ff51bb3153a5a6649a2 Mon Sep 17 00:00:00 2001 From: Andrey Ivanov Date: Wed, 1 Mar 2023 08:42:48 +0300 Subject: [PATCH 4/6] Depastaficate --- cmd/main.go | 20 ++++++++------------ go.mod | 2 +- internal/config/config.go | 22 ++++++++++++++++++++++ internal/scenario/scenario.go | 8 ++++++-- 4 files changed, 37 insertions(+), 15 deletions(-) create mode 100644 internal/config/config.go diff --git a/cmd/main.go b/cmd/main.go index b77b2b9..1f9b7db 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -4,10 +4,9 @@ package main import ( "context" - "flag" "fmt" - "github.com/go-playground/validator/v10" - "github.com/tiburon-777/w3back/internal/scenario" + "github.com/tiburon-777/api-crowler/internal/config" + "github.com/tiburon-777/api-crowler/internal/scenario" "log" "net/http" "strings" @@ -15,21 +14,18 @@ import ( func main() { // Парсим флаги приложения. - file := flag.String("scenario", "./test/test.yaml", "path to file with test scenario") - flag.Parse() - ctx := context.Background() - - // Читаем файл сценария. - sc, err := scenario.New(ctx, *file) + conf, err := config.Get() if err != nil { - log.Fatalf("can't understand test scenario: %v ", err) + log.Fatalf("invalid config: %v ", err) } - // Валидируем сценарий - if err := validator.New().Struct(sc); err != nil { + // Читаем файл сценария. + sc, err := scenario.Get(conf.Scenario) + if err != nil { log.Fatalf("invalid scenario: %v ", err) } + ctx := context.Background() cli := http.Client{Timeout: sc.Params.Timeout} // Запускаем сценарий diff --git a/go.mod b/go.mod index 87b5780..3bf5026 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/tiburon-777/w3back +module github.com/tiburon-777/api-crowler go 1.18 diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000..740faf8 --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,22 @@ +package config + +import ( + "flag" + "github.com/go-playground/validator/v10" +) + +type Config struct { + Scenario string `validate:"required"` +} + +func Get() (*Config, error) { + conf := &Config{} + flag.StringVar(&conf.Scenario, "scenario", "", "URL base") + flag.Parse() + + // Валидируем параметры + if err := validator.New().Struct(conf); err != nil { + return nil, err + } + return conf, nil +} diff --git a/internal/scenario/scenario.go b/internal/scenario/scenario.go index 08fb49d..36c8d84 100644 --- a/internal/scenario/scenario.go +++ b/internal/scenario/scenario.go @@ -1,12 +1,12 @@ package scenario import ( - "context" + "github.com/go-playground/validator/v10" "gopkg.in/yaml.v2" "os" ) -func New(ctx context.Context, file string) (*Object, error) { +func Get(file string) (*Object, error) { var obj Object yamlFile, err := os.ReadFile(file) if err != nil { @@ -17,5 +17,9 @@ func New(ctx context.Context, file string) (*Object, error) { if err != nil { return nil, err } + + if err := validator.New().Struct(obj); err != nil { + return nil, err + } return &obj, nil } -- 2.47.2 From e37fd6e0379a3dac0c4c0670d5ffa36ea35b80e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=98=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2?= Date: Tue, 18 Apr 2023 17:07:36 +0300 Subject: [PATCH 5/6] Depastaficate --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index edd4343..b71f55f 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,5 +1,5 @@ kind: pipeline -type: exec +type: docker name: pipeline steps: -- 2.47.2 From 41ec43f0f41bfaabeee98ad4467fd9ae0f72a3bc Mon Sep 17 00:00:00 2001 From: Andrey Ivanov Date: Tue, 18 Apr 2023 17:25:09 +0300 Subject: [PATCH 6/6] Lint --- cmd/main.go | 55 ++++++++++++++++++++--------------- golangci.yml | 9 ++++++ internal/config/config.go | 1 + internal/scenario/scenario.go | 3 +- 4 files changed, 44 insertions(+), 24 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 1f9b7db..6904a73 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -5,13 +5,15 @@ package main import ( "context" "fmt" - "github.com/tiburon-777/api-crowler/internal/config" - "github.com/tiburon-777/api-crowler/internal/scenario" "log" "net/http" "strings" + + "github.com/tiburon-777/api-crowler/internal/config" + "github.com/tiburon-777/api-crowler/internal/scenario" ) +//nolint:gocognit,gocyclo,cyclop func main() { // Парсим флаги приложения. conf, err := config.Get() @@ -20,65 +22,72 @@ func main() { } // Читаем файл сценария. - sc, err := scenario.Get(conf.Scenario) + scenarios, err := scenario.Get(conf.Scenario) if err != nil { log.Fatalf("invalid scenario: %v ", err) } ctx := context.Background() - cli := http.Client{Timeout: sc.Params.Timeout} + cli := http.Client{Timeout: scenarios.Params.Timeout} // Запускаем сценарий - for key, cs := range sc.Steps { - log.Printf("Step#%d - %s", key, cs.Name) - req, err := http.NewRequestWithContext(ctx, cs.Query.Method, fmt.Sprintf("%s%s", sc.Params.Address, cs.Query.URL), strings.NewReader(cs.Query.Data)) + for key, step := range scenarios.Steps { + log.Printf("Step#%d - %s", key, step.Name) + req, err := http.NewRequestWithContext( + ctx, + step.Query.Method, + fmt.Sprintf("%s%s", scenarios.Params.Address, step.Query.URL), + strings.NewReader(step.Query.Data), + ) if err != nil { - log.Fatalf("request error: %v ", err) + log.Printf("request error: %v ", err) } - for hKey, hVal := range cs.Query.Headers { + defer req.Body.Close() + for hKey, hVal := range step.Query.Headers { req.Header.Add(hKey, hVal) } resp, err := cli.Do(req) if err != nil { - log.Fatalf("client error: %v ", err) + log.Printf("client error: %v ", err) } + defer resp.Body.Close() var body []byte - if _, err := resp.Body.Read(body); err != nil { - log.Fatalf("client read body: %v ", err) + if _, err = resp.Body.Read(body); err != nil { + log.Printf("client read body: %v ", err) } - if cs.Response.Code != 0 && resp.StatusCode != cs.Response.Code { - log.Fatalf("wrong response code: %v ", err) + if step.Response.Code != 0 && resp.StatusCode != step.Response.Code { + log.Printf("wrong response code: %v ", err) } - if len(cs.Response.Body) != 0 { - for _, sample := range cs.Response.Body { + //nolint:nestif + if len(step.Response.Body) != 0 { + for _, sample := range step.Response.Body { switch sample.Function { case "contains": if !strings.Contains(string(body), sample.Text) { - log.Fatalf("wrong body") + log.Printf("wrong body") } case "not_contains": if strings.Contains(string(body), sample.Text) { - log.Fatalf("wrong body") + log.Printf("wrong body") } case "begin": if !strings.HasPrefix(string(body), sample.Text) { - log.Fatalf("wrong body") + log.Printf("wrong body") } case "not_begin": if strings.HasPrefix(string(body), sample.Text) { - log.Fatalf("wrong body") + log.Printf("wrong body") } case "ends": if !strings.HasSuffix(string(body), sample.Text) { - log.Fatalf("wrong body") + log.Printf("wrong body") } case "not_ends": if strings.HasSuffix(string(body), sample.Text) { - log.Fatalf("wrong body") + log.Printf("wrong body") } } } } } - } diff --git a/golangci.yml b/golangci.yml index d87ed9a..9b45172 100644 --- a/golangci.yml +++ b/golangci.yml @@ -83,6 +83,15 @@ linters: - nlreturn - gofmt - gofumpt + - varcheck + - golint + - structcheck + - nosnakecase + - maligned + - interfacer + - deadcode + - scopelint + - ifshort fast: false issues: diff --git a/internal/config/config.go b/internal/config/config.go index 740faf8..b88bd92 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -2,6 +2,7 @@ package config import ( "flag" + "github.com/go-playground/validator/v10" ) diff --git a/internal/scenario/scenario.go b/internal/scenario/scenario.go index 36c8d84..f41866b 100644 --- a/internal/scenario/scenario.go +++ b/internal/scenario/scenario.go @@ -1,9 +1,10 @@ package scenario import ( + "os" + "github.com/go-playground/validator/v10" "gopkg.in/yaml.v2" - "os" ) func Get(file string) (*Object, error) { -- 2.47.2