From 57fc6f33f4e7ac4c72d6e25e55eec7dd31dfec65 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Fri, 10 Dec 2021 17:29:08 +0100 Subject: [PATCH 01/92] Ignore temporary project files --- .dockerignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.dockerignore b/.dockerignore index 038456e..bd6a53f 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,4 +1,7 @@ /.git/ +main +aye-and-nay +coverage.txt /badger/ /build/badger/ /build/caddy/ From 2d7ea605c4f84a80c367b8aeaa0195852de85a1c Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sat, 11 Dec 2021 12:06:32 +0100 Subject: [PATCH 02/92] Use docker compose v2 --- Makefile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index efccf7c..64afff1 100644 --- a/Makefile +++ b/Makefile @@ -21,25 +21,25 @@ test-int-ci: gen go test -v -race -shuffle=on -count=1 -tags=integration -failfast -coverprofile=coverage.txt -covermode=atomic ./... dev-up: - docker-compose --file ./build/docker-compose-dev.yml up -d --build + docker compose --file ./build/docker-compose-dev.yml up -d --build dev-down: - docker-compose --file ./build/docker-compose-dev.yml down --rmi all -v + docker compose --file ./build/docker-compose-dev.yml down --rmi all -v prod-loadtest: go run ./cmd/loadtest/main.go -verbose=false prod-up: - docker-compose --file ./build/docker-compose-prod.yml up -d --build + docker compose --file ./build/docker-compose-prod.yml up -d --build prod-down: - docker-compose --file ./build/docker-compose-prod.yml down --rmi all -v + docker compose --file ./build/docker-compose-prod.yml down --rmi all -v embed-loadtest: go run ./cmd/loadtest/main.go -verbose=false -api-address "http://localhost:8001" -minio-address "" embed-up: - docker-compose --file ./build/docker-compose-embed.yml up -d --build + docker compose --file ./build/docker-compose-embed.yml up -d --build embed-down: - docker-compose --file ./build/docker-compose-embed.yml down --rmi all -v + docker compose --file ./build/docker-compose-embed.yml down --rmi all -v From 510ede0559753765e07c798f19d5b0bc2dbffa8a Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Tue, 14 Dec 2021 17:25:28 +0100 Subject: [PATCH 03/92] Use canonical header key --- delivery/http/controller.go | 8 ++++---- delivery/http/error.go | 4 ++-- delivery/http/middleware_test.go | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/delivery/http/controller.go b/delivery/http/controller.go index 7ae7a7c..221f7b1 100644 --- a/delivery/http/controller.go +++ b/delivery/http/controller.go @@ -111,7 +111,7 @@ func (c *controller) handleAlbum() httprouter.Handle { return resp, nil } output := func(ctx context.Context, w http.ResponseWriter, resp albumResponse) error { - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set(http.CanonicalHeaderKey("Content-Type"), "application/json; charset=utf-8") w.WriteHeader(201) err := json.NewEncoder(w).Encode(resp) if err != nil { @@ -159,7 +159,7 @@ func (c *controller) handleReady() httprouter.Handle { return resp, nil } output := func(ctx context.Context, w http.ResponseWriter, resp readyResponse) error { - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set(http.CanonicalHeaderKey("Content-Type"), "application/json; charset=utf-8") err := json.NewEncoder(w).Encode(resp) if err != nil { return errors.Wrap(err) @@ -211,7 +211,7 @@ func (c *controller) handlePair() httprouter.Handle { return resp, nil } output := func(ctx context.Context, w http.ResponseWriter, resp pairResponse) error { - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set(http.CanonicalHeaderKey("Content-Type"), "application/json; charset=utf-8") err := json.NewEncoder(w).Encode(resp) if err != nil { return errors.Wrap(err) @@ -319,7 +319,7 @@ func (c *controller) handleTop() httprouter.Handle { return resp, nil } output := func(ctx context.Context, w http.ResponseWriter, resp topResponse) error { - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set(http.CanonicalHeaderKey("Content-Type"), "application/json; charset=utf-8") err := json.NewEncoder(w).Encode(resp) if err != nil { return errors.Wrap(err) diff --git a/delivery/http/error.go b/delivery/http/error.go index 95d26af..768c52e 100644 --- a/delivery/http/error.go +++ b/delivery/http/error.go @@ -40,8 +40,8 @@ func handleError(w http.ResponseWriter, err error) { func handleOuterError(w http.ResponseWriter, err error) { resp := errorResponse{} defer func() { - w.Header().Set("Content-Type", "application/json; charset=utf-8") - w.Header().Set("X-Content-Type-Options", "nosniff") + w.Header().Set(http.CanonicalHeaderKey("Content-Type"), "application/json; charset=utf-8") + w.Header().Set(http.CanonicalHeaderKey("X-Content-Type-Options"), "nosniff") w.WriteHeader(resp.Error.statusCode) _ = json.NewEncoder(w).Encode(resp) }() diff --git a/delivery/http/middleware_test.go b/delivery/http/middleware_test.go index 6b8e005..3ae4ef7 100644 --- a/delivery/http/middleware_test.go +++ b/delivery/http/middleware_test.go @@ -28,7 +28,7 @@ func (l limiterMockNeg) Allow(_ context.Context, _ uint64) (bool, error) { func TestMiddlewareRecover(t *testing.T) { t.Run("Positive", func(t *testing.T) { fn := func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.Header().Set(http.CanonicalHeaderKey("Content-Type"), "text/plain; charset=utf-8") w.WriteHeader(418) _, _ = io.WriteString(w, "I'm a teapot") } @@ -61,7 +61,7 @@ func TestMiddlewareRecover(t *testing.T) { func TestMiddlewareLimit(t *testing.T) { t.Run("Positive", func(t *testing.T) { fn := func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.Header().Set(http.CanonicalHeaderKey("Content-Type"), "text/plain; charset=utf-8") w.WriteHeader(418) _, _ = io.WriteString(w, "I'm a teapot") } @@ -77,7 +77,7 @@ func TestMiddlewareLimit(t *testing.T) { }) t.Run("Negative", func(t *testing.T) { fn := func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.Header().Set(http.CanonicalHeaderKey("Content-Type"), "text/plain; charset=utf-8") w.WriteHeader(418) _, _ = io.WriteString(w, "I'm a teapot") } From 2969c2525d72004da27c6d62b6d9ce24c1800ad0 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Wed, 15 Dec 2021 16:44:58 +0100 Subject: [PATCH 04/92] Implement temporary links --- build/config-dev.yml | 1 + build/config-embed.yml | 3 +- build/config-prod.yml | 1 + build/swagger.yml | 89 ++++++----------- config.yml | 1 + delivery/http/controller.go | 62 ++++++++++++ delivery/http/controller_test.go | 3 + delivery/http/requests.go | 6 ++ delivery/http/responses.go | 8 ++ delivery/http/router.go | 1 + domain/domain/interface.go | 6 +- domain/service/config.go | 2 + domain/service/mock.go | 17 ++++ domain/service/service.go | 95 +++++++++++++------ domain/service/service_integration_test.go | 3 + domain/service/service_test.go | 3 + infrastructure/cache/mem.go | 22 +++-- infrastructure/cache/mem_test.go | 13 ++- infrastructure/cache/redis.go | 43 ++++++--- .../cache/redis_integration_test.go | 16 ++-- internal/config/config.go | 1 + 21 files changed, 270 insertions(+), 126 deletions(-) diff --git a/build/config-dev.yml b/build/config-dev.yml index 315a254..07f8e87 100644 --- a/build/config-dev.yml +++ b/build/config-dev.yml @@ -20,6 +20,7 @@ controller: maxNumberOfFiles: 100 maxFileSize: 5242880 # 5 MB service: + tempLinks: true numberOfWorkersCalc: 8 numberOfWorkersComp: 8 accuracy: 0.625 diff --git a/build/config-embed.yml b/build/config-embed.yml index 6f664d0..d54d493 100644 --- a/build/config-embed.yml +++ b/build/config-embed.yml @@ -20,6 +20,7 @@ controller: maxNumberOfFiles: 100 maxFileSize: 5242880 # 5 MB service: + tempLinks: true numberOfWorkersCalc: 8 numberOfWorkersComp: 8 accuracy: 0.625 @@ -84,4 +85,4 @@ storage: pause: 5s timeout: 30s location: eu-central-1 - prefix: /s3 + prefix: http://localhost:9000 diff --git a/build/config-prod.yml b/build/config-prod.yml index a18210b..57b9051 100644 --- a/build/config-prod.yml +++ b/build/config-prod.yml @@ -20,6 +20,7 @@ controller: maxNumberOfFiles: 100 maxFileSize: 5242880 # 5 MB service: + tempLinks: true numberOfWorkersCalc: 8 numberOfWorkersComp: 8 accuracy: 0.625 diff --git a/build/swagger.yml b/build/swagger.yml index beef5fa..e9f5c76 100644 --- a/build/swagger.yml +++ b/build/swagger.yml @@ -22,19 +22,11 @@ paths: responses: '201': $ref: '#/components/responses/AlbumResponse' - '400': - $ref: '#/components/responses/BadRequest' - '413': - $ref: '#/components/responses/PayloadTooLarge' - '415': - $ref: '#/components/responses/UnsupportedMediaType' - '429': - $ref: '#/components/responses/TooManyRequests' '500': $ref: '#/components/responses/InternalServerError' '503': $ref: '#/components/responses/ServiceUnavailable' - /api/albums/{id}/ready/: + /api/albums/{album}/ready/: get: description: > Second request in a sequence (optional). It informs about @@ -46,15 +38,11 @@ paths: responses: '200': $ref: '#/components/responses/ReadyResponse' - '404': - $ref: '#/components/responses/NotFound' - '429': - $ref: '#/components/responses/TooManyRequests' '500': $ref: '#/components/responses/InternalServerError' '503': $ref: '#/components/responses/ServiceUnavailable' - /api/albums/{id}/pair/: + /api/albums/{album}/pair/: get: description: > Third request in a sequence. Response consists of 2 image @@ -64,15 +52,26 @@ paths: responses: '200': $ref: '#/components/responses/PairResponse' - '404': - $ref: '#/components/responses/NotFound' - '429': - $ref: '#/components/responses/TooManyRequests' '500': $ref: '#/components/responses/InternalServerError' '503': $ref: '#/components/responses/ServiceUnavailable' - /api/albums/{id}/vote/: + /api/images/{token}/: + get: + description: > + Irure quis ad enim deserunt magna anim ut laborum aliqua commodo + nisi voluptate fugiat incididunt esse exercitation aliqua in in + voluptate ea deserunt mollit aliqua exercitation ea laborum + parameters: + - $ref: '#/components/parameters/tokenParam' + responses: + '200': + $ref: '#/components/responses/PairResponse' + '500': + $ref: '#/components/responses/InternalServerError' + '503': + $ref: '#/components/responses/ServiceUnavailable' + /api/albums/{album}/vote/: patch: description: > Fourth request in a sequence. Request specifies a value transfer @@ -86,17 +85,11 @@ paths: responses: '200': $ref: '#/components/responses/VoteResponse' - '404': - $ref: '#/components/responses/NotFound' - '415': - $ref: '#/components/responses/UnsupportedMediaType' - '429': - $ref: '#/components/responses/TooManyRequests' '500': $ref: '#/components/responses/InternalServerError' '503': $ref: '#/components/responses/ServiceUnavailable' - /api/albums/{id}/top/: + /api/albums/{album}/top/: get: description: > Fifth request in a sequence. Returns a list of all images in an @@ -107,10 +100,6 @@ paths: responses: '200': $ref: '#/components/responses/TopResponse' - '404': - $ref: '#/components/responses/NotFound' - '429': - $ref: '#/components/responses/TooManyRequests' '500': $ref: '#/components/responses/InternalServerError' '503': @@ -208,12 +197,20 @@ components: error: type: object properties: + code: + type: integer msg: type: string parameters: albumParam: in: path - name: id + name: album + required: true + schema: + $ref: '#/components/schemas/Id' + tokenParam: + in: path + name: token required: true schema: $ref: '#/components/schemas/Id' @@ -255,36 +252,6 @@ components: application/json: schema: $ref: '#/components/schemas/TopResponse' - BadRequest: - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - NotFound: - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - PayloadTooLarge: - description: Payload Too Large - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - UnsupportedMediaType: - description: Unsupported Media Type - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - TooManyRequests: - description: Too Many Requests - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' InternalServerError: description: Internal Server Error content: diff --git a/config.yml b/config.yml index ea4bdd5..fb40f41 100644 --- a/config.yml +++ b/config.yml @@ -20,6 +20,7 @@ controller: maxNumberOfFiles: 100 maxFileSize: 5242880 # 5 MB service: + tempLinks: true numberOfWorkersCalc: 8 numberOfWorkersComp: 8 accuracy: 0.625 diff --git a/delivery/http/controller.go b/delivery/http/controller.go index 221f7b1..93d8f2f 100644 --- a/delivery/http/controller.go +++ b/delivery/http/controller.go @@ -1,10 +1,13 @@ package http import ( + "bytes" "context" "encoding/json" "io" + "mime/multipart" "net/http" + "os" "strings" "time" @@ -14,6 +17,7 @@ import ( "github.com/zitryss/aye-and-nay/domain/model" "github.com/zitryss/aye-and-nay/pkg/base64" "github.com/zitryss/aye-and-nay/pkg/errors" + "github.com/zitryss/aye-and-nay/pkg/pool" ) func newController( @@ -237,6 +241,64 @@ func (c *controller) handlePair() httprouter.Handle { ) } +func (c *controller) handleImage() httprouter.Handle { + input := func(r *http.Request, ps httprouter.Params) (context.Context, imageRequest, error) { + ctx := r.Context() + req := imageRequest{} + req.image.token = ps.ByName("token") + return ctx, req, nil + } + process := func(ctx context.Context, req imageRequest) (imageResponse, error) { + token, err := base64.ToUint64(req.image.token) + if err != nil { + return imageResponse{}, errors.Wrap(err) + } + f, err := c.serv.Image(ctx, token) + if err != nil { + return imageResponse{}, errors.Wrap(err) + } + resp := imageResponse{f} + return resp, nil + } + output := func(ctx context.Context, w http.ResponseWriter, resp imageResponse) error { + defer func() { + switch v := resp.f.Reader.(type) { + case *os.File: + _ = v.Close() + _ = os.Remove(v.Name()) + case multipart.File: + _ = v.Close() + case *bytes.Buffer: + pool.PutBuffer(v) + default: + panic(errors.Wrap(domain.ErrUnknown)) + } + }() + _, err := io.Copy(w, resp.f) + if err != nil { + return errors.Wrap(err) + } + return nil + } + return handleHttpRouterError( + func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) error { + ctx, req, err := input(r, ps) + if err != nil { + return errors.Wrap(err) + } + resp, err := process(ctx, req) + if err != nil { + return errors.Wrap(err) + } + err = output(ctx, w, resp) + if err != nil { + return errors.Wrap(err) + } + return nil + }, + ) +} + func (c *controller) handleVote() httprouter.Handle { input := func(r *http.Request, ps httprouter.Params) (context.Context, voteRequest, error) { ctx := r.Context() diff --git a/delivery/http/controller_test.go b/delivery/http/controller_test.go index 59bd77a..a707bfd 100644 --- a/delivery/http/controller_test.go +++ b/delivery/http/controller_test.go @@ -724,6 +724,9 @@ func TestControllerHandlePair(t *testing.T) { } } +func TestControllerHandleImage(t *testing.T) { +} + func TestControllerHandleVote(t *testing.T) { type give struct { err error diff --git a/delivery/http/requests.go b/delivery/http/requests.go index 5e49342..85b95e5 100644 --- a/delivery/http/requests.go +++ b/delivery/http/requests.go @@ -27,6 +27,12 @@ type pairRequest struct { } } +type imageRequest struct { + image struct { + token string + } +} + //easyjson:json type voteRequest struct { Album struct { diff --git a/delivery/http/responses.go b/delivery/http/responses.go index e02a76d..38a8d2c 100644 --- a/delivery/http/responses.go +++ b/delivery/http/responses.go @@ -2,6 +2,10 @@ package http +import ( + "github.com/zitryss/aye-and-nay/domain/model" +) + //easyjson:json type albumResponse struct { Album struct { @@ -30,6 +34,10 @@ type pairResponse struct { } `json:"album"` } +type imageResponse struct { + f model.File +} + type voteResponse struct { } diff --git a/delivery/http/router.go b/delivery/http/router.go index 46dad5e..c336a75 100644 --- a/delivery/http/router.go +++ b/delivery/http/router.go @@ -11,6 +11,7 @@ func newRouter(contr controller) http.Handler { router.POST("/api/albums/", contr.handleAlbum()) router.GET("/api/albums/:album/ready/", contr.handleReady()) router.GET("/api/albums/:album/pair/", contr.handlePair()) + router.GET("/api/images/:token/", contr.handleImage()) router.PATCH("/api/albums/:album/vote/", contr.handleVote()) router.GET("/api/albums/:album/top/", contr.handleTop()) return router diff --git a/domain/domain/interface.go b/domain/domain/interface.go index e0151a1..58a4967 100644 --- a/domain/domain/interface.go +++ b/domain/domain/interface.go @@ -10,6 +10,7 @@ import ( type Servicer interface { Album(ctx context.Context, ff []model.File, dur time.Duration) (uint64, error) Pair(ctx context.Context, album uint64) (model.Image, model.Image, error) + Image(ctx context.Context, token uint64) (model.File, error) Vote(ctx context.Context, album uint64, tokenFrom uint64, tokenTo uint64) error Top(ctx context.Context, album uint64) ([]model.Image, error) Progress(ctx context.Context, album uint64) (float64, error) @@ -70,6 +71,7 @@ type Stacker interface { } type Tokener interface { - Set(ctx context.Context, album uint64, token uint64, image uint64) error - Get(ctx context.Context, album uint64, token uint64) (uint64, error) + Set(ctx context.Context, token uint64, album uint64, image uint64) error + Get(ctx context.Context, token uint64) (uint64, uint64, error) + Del(ctx context.Context, token uint64) error } diff --git a/domain/service/config.go b/domain/service/config.go index 29bb564..2bdc5c9 100644 --- a/domain/service/config.go +++ b/domain/service/config.go @@ -6,6 +6,7 @@ import ( func newServiceConfig() serviceConfig { return serviceConfig{ + tempLinks: viper.GetBool("service.tempLinks"), numberOfWorkersCalc: viper.GetInt("service.numberOfWorkersCalc"), numberOfWorkersComp: viper.GetInt("service.numberOfWorkersComp"), accuracy: viper.GetFloat64("service.accuracy"), @@ -13,6 +14,7 @@ func newServiceConfig() serviceConfig { } type serviceConfig struct { + tempLinks bool numberOfWorkersCalc int numberOfWorkersComp int accuracy float64 diff --git a/domain/service/mock.go b/domain/service/mock.go index b3dbfa9..0148421 100644 --- a/domain/service/mock.go +++ b/domain/service/mock.go @@ -2,9 +2,13 @@ package service import ( "context" + "io" "time" "github.com/zitryss/aye-and-nay/domain/model" + . "github.com/zitryss/aye-and-nay/internal/testing" + "github.com/zitryss/aye-and-nay/pkg/errors" + "github.com/zitryss/aye-and-nay/pkg/pool" ) func NewMock(err error) *Mock { @@ -38,6 +42,19 @@ func (m *Mock) Pair(_ context.Context, _ uint64) (model.Image, model.Image, erro return img1, img2, nil } +func (m *Mock) Image(_ context.Context, _ uint64) (model.File, error) { + if m.err != nil { + return model.File{}, m.err + } + buf := pool.GetBuffer() + f := Png() + n, err := io.CopyN(buf, f, f.Size) + if err != nil { + return model.File{}, errors.Wrap(err) + } + return model.File{Reader: buf, Size: n}, nil +} + func (m *Mock) Vote(_ context.Context, _ uint64, _ uint64, _ uint64) error { if m.err != nil { return m.err diff --git a/domain/service/service.go b/domain/service/service.go index 0fcf1da..c2aafb1 100644 --- a/domain/service/service.go +++ b/domain/service/service.go @@ -7,6 +7,7 @@ import ( "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/model" + "github.com/zitryss/aye-and-nay/pkg/base64" "github.com/zitryss/aye-and-nay/pkg/errors" myrand "github.com/zitryss/aye-and-nay/pkg/rand" ) @@ -198,33 +199,56 @@ func (s *Service) Pair(ctx context.Context, album uint64) (model.Image, model.Im if err != nil { return model.Image{}, model.Image{}, errors.Wrap(err) } - src1, err := s.pers.GetImageSrc(ctx, album, image1) - if err != nil { - return model.Image{}, model.Image{}, errors.Wrap(err) - } - src2, err := s.pers.GetImageSrc(ctx, album, image2) - if err != nil { - return model.Image{}, model.Image{}, errors.Wrap(err) - } - token1, err := s.rand.id() - if err != nil { - return model.Image{}, model.Image{}, errors.Wrap(err) - } - err = s.token.Set(ctx, album, token1, image1) - if err != nil { - return model.Image{}, model.Image{}, errors.Wrap(err) + src1 := "" + src2 := "" + token1 := image1 + token2 := image2 + if s.conf.tempLinks { + token1, err = s.rand.id() + if err != nil { + return model.Image{}, model.Image{}, errors.Wrap(err) + } + err = s.token.Set(ctx, token1, album, image1) + if err != nil { + return model.Image{}, model.Image{}, errors.Wrap(err) + } + token1B64 := base64.FromUint64(token1) + src1 = "/api/images/" + token1B64 + token2, err = s.rand.id() + if err != nil { + return model.Image{}, model.Image{}, errors.Wrap(err) + } + err = s.token.Set(ctx, token2, album, image2) + if err != nil { + return model.Image{}, model.Image{}, errors.Wrap(err) + } + token2B64 := base64.FromUint64(token2) + src2 = "/api/images/" + token2B64 + } else { + src1, err = s.pers.GetImageSrc(ctx, album, image1) + if err != nil { + return model.Image{}, model.Image{}, errors.Wrap(err) + } + src2, err = s.pers.GetImageSrc(ctx, album, image2) + if err != nil { + return model.Image{}, model.Image{}, errors.Wrap(err) + } } - token2, err := s.rand.id() + img1 := model.Image{Id: image1, Src: src1, Token: token1} + img2 := model.Image{Id: image2, Src: src2, Token: token2} + return img1, img2, nil +} + +func (s *Service) Image(ctx context.Context, token uint64) (model.File, error) { + album, image, err := s.token.Get(ctx, token) if err != nil { - return model.Image{}, model.Image{}, errors.Wrap(err) + return model.File{}, errors.Wrap(err) } - err = s.token.Set(ctx, album, token2, image2) + f, err := s.stor.Get(ctx, album, image) if err != nil { - return model.Image{}, model.Image{}, errors.Wrap(err) + return model.File{}, errors.Wrap(err) } - img1 := model.Image{Id: image1, Src: src1, Token: token1} - img2 := model.Image{Id: image2, Src: src2, Token: token2} - return img1, img2, nil + return f, nil } func (s *Service) genPairs(ctx context.Context, album uint64) error { @@ -249,13 +273,26 @@ func (s *Service) genPairs(ctx context.Context, album uint64) error { } func (s *Service) Vote(ctx context.Context, album uint64, tokenFrom uint64, tokenTo uint64) error { - imageFrom, err := s.token.Get(ctx, album, tokenFrom) - if err != nil { - return errors.Wrap(err) - } - imageTo, err := s.token.Get(ctx, album, tokenTo) - if err != nil { - return errors.Wrap(err) + imageFrom := tokenFrom + imageTo := tokenTo + err := error(nil) + if s.conf.tempLinks { + _, imageFrom, err = s.token.Get(ctx, tokenFrom) + if err != nil { + return errors.Wrap(err) + } + err = s.token.Del(ctx, tokenFrom) + if err != nil { + return errors.Wrap(err) + } + _, imageTo, err = s.token.Get(ctx, tokenTo) + if err != nil { + return errors.Wrap(err) + } + err = s.token.Del(ctx, tokenTo) + if err != nil { + return errors.Wrap(err) + } } err = s.pers.SaveVote(ctx, album, imageFrom, imageTo) if err != nil { diff --git a/domain/service/service_integration_test.go b/domain/service/service_integration_test.go index 8fb76d7..550a708 100644 --- a/domain/service/service_integration_test.go +++ b/domain/service/service_integration_test.go @@ -337,6 +337,9 @@ func TestServiceIntegrationPair(t *testing.T) { }) } +func TestServiceIntegrationImage(t *testing.T) { +} + func TestServiceIntegrationVote(t *testing.T) { t.Run("Positive", func(t *testing.T) { fn1 := func() func() (uint64, error) { diff --git a/domain/service/service_test.go b/domain/service/service_test.go index 4471f39..7bbbc04 100644 --- a/domain/service/service_test.go +++ b/domain/service/service_test.go @@ -268,6 +268,9 @@ func TestServicePair(t *testing.T) { }) } +func TestServiceImage(t *testing.T) { +} + func TestServiceVote(t *testing.T) { t.Run("Positive", func(t *testing.T) { fn1 := func() func() (uint64, error) { diff --git a/infrastructure/cache/mem.go b/infrastructure/cache/mem.go index 95ca012..94e199c 100644 --- a/infrastructure/cache/mem.go +++ b/infrastructure/cache/mem.go @@ -92,7 +92,8 @@ type syncTokens struct { } type tokenTime struct { - token uint64 + album uint64 + image uint64 seen time.Time } @@ -289,7 +290,7 @@ func (m *Mem) Pop(_ context.Context, album uint64) (uint64, uint64, error) { return images[0], images[1], nil } -func (m *Mem) Set(_ context.Context, _ uint64, token uint64, image uint64) error { +func (m *Mem) Set(_ context.Context, token uint64, album uint64, image uint64) error { m.syncTokens.Lock() defer m.syncTokens.Unlock() _, ok := m.tokens[token] @@ -297,19 +298,26 @@ func (m *Mem) Set(_ context.Context, _ uint64, token uint64, image uint64) error return errors.Wrap(domain.ErrTokenAlreadyExists) } t := &tokenTime{} - t.token = image + t.album = album + t.image = image t.seen = time.Now() m.tokens[token] = t return nil } -func (m *Mem) Get(_ context.Context, _ uint64, token uint64) (uint64, error) { +func (m *Mem) Get(_ context.Context, token uint64) (uint64, uint64, error) { m.syncTokens.Lock() defer m.syncTokens.Unlock() - image, ok := m.tokens[token] + t, ok := m.tokens[token] if !ok { - return 0x0, errors.Wrap(domain.ErrTokenNotFound) + return 0x0, 0x0, errors.Wrap(domain.ErrTokenNotFound) } + return t.album, t.image, nil +} + +func (m *Mem) Del(_ context.Context, token uint64) error { + m.syncTokens.Lock() + defer m.syncTokens.Unlock() delete(m.tokens, token) - return image.token, nil + return nil } diff --git a/infrastructure/cache/mem_test.go b/infrastructure/cache/mem_test.go index 6139247..f5cf3d6 100644 --- a/infrastructure/cache/mem_test.go +++ b/infrastructure/cache/mem_test.go @@ -78,10 +78,13 @@ func TestMemToken(t *testing.T) { if err != nil { t.Error(err) } - image, err := mem.Get(context.Background(), 0xC2E7, 0xB41C) + album, image, err := mem.Get(context.Background(), 0xC2E7) if err != nil { t.Error(err) } + if album != 0xB41C { + t.Error("image != 0x52BD") + } if image != 0x52BD { t.Error("image != 0x52BD") } @@ -99,7 +102,7 @@ func TestMemToken(t *testing.T) { }) t.Run("Negative2", func(t *testing.T) { mem := NewMem() - _, err := mem.Get(context.Background(), 0x1C4A, 0xC4F8) + _, _, err := mem.Get(context.Background(), 0xC4F8) if !errors.Is(err, domain.ErrTokenNotFound) { t.Error(err) } @@ -110,11 +113,11 @@ func TestMemToken(t *testing.T) { if err != nil { t.Error(err) } - _, err = mem.Get(context.Background(), 0xEB96, 0xC67F) + _, _, err = mem.Get(context.Background(), 0xC67F) if err != nil { t.Error(err) } - _, err = mem.Get(context.Background(), 0xEB96, 0xC67F) + _, _, err = mem.Get(context.Background(), 0xC67F) if !errors.Is(err, domain.ErrTokenNotFound) { t.Error(err) } @@ -130,7 +133,7 @@ func TestMemToken(t *testing.T) { time.Sleep(mem.conf.timeToLive) CheckChannel(t, heartbeatToken) CheckChannel(t, heartbeatToken) - _, err = mem.Get(context.Background(), 0xE0AF, 0xCF1E) + _, _, err = mem.Get(context.Background(), 0xCF1E) if !errors.Is(err, domain.ErrTokenNotFound) { t.Error(err) } diff --git a/infrastructure/cache/redis.go b/infrastructure/cache/redis.go index ff789fe..93dd0f9 100644 --- a/infrastructure/cache/redis.go +++ b/infrastructure/cache/redis.go @@ -202,11 +202,11 @@ func (r *Redis) Pop(ctx context.Context, album uint64) (uint64, uint64, error) { return image0, image1, nil } -func (r *Redis) Set(ctx context.Context, album uint64, token uint64, image uint64) error { - albumB64 := base64.FromUint64(album) +func (r *Redis) Set(ctx context.Context, token uint64, album uint64, image uint64) error { tokenB64 := base64.FromUint64(token) + albumB64 := base64.FromUint64(album) imageB64 := base64.FromUint64(image) - key := "album:" + albumB64 + ":token:" + tokenB64 + ":image" + key := "token:" + tokenB64 n, err := r.client.Exists(ctx, key).Result() if err != nil { return errors.Wrap(err) @@ -214,33 +214,46 @@ func (r *Redis) Set(ctx context.Context, album uint64, token uint64, image uint6 if n == 1 { return errors.Wrap(domain.ErrTokenAlreadyExists) } - err = r.client.Set(ctx, key, imageB64, r.conf.timeToLive).Err() + err = r.client.Set(ctx, key, albumB64+":"+imageB64, r.conf.timeToLive).Err() if err != nil { return errors.Wrap(err) } return nil } -func (r *Redis) Get(ctx context.Context, album uint64, token uint64) (uint64, error) { - albumB64 := base64.FromUint64(album) +func (r *Redis) Get(ctx context.Context, token uint64) (uint64, uint64, error) { tokenB64 := base64.FromUint64(token) - key := "album:" + albumB64 + ":token:" + tokenB64 + ":image" - imageB64, err := r.client.Get(ctx, key).Result() + key := "token:" + tokenB64 + s, err := r.client.Get(ctx, key).Result() if errors.Is(err, redisdb.Nil) { - return 0x0, errors.Wrap(domain.ErrTokenNotFound) + return 0x0, 0x0, errors.Wrap(domain.ErrTokenNotFound) } if err != nil { - return 0x0, errors.Wrap(err) + return 0x0, 0x0, errors.Wrap(err) } - err = r.client.Del(ctx, key).Err() + ss := strings.Split(s, ":") + if len(ss) != 2 { + return 0x0, 0x0, errors.Wrap(domain.ErrUnknown) + } + album, err := base64.ToUint64(ss[0]) if err != nil { - return 0x0, errors.Wrap(err) + return 0x0, 0x0, errors.Wrap(err) } - image, err := base64.ToUint64(imageB64) + image, err := base64.ToUint64(ss[1]) if err != nil { - return 0x0, errors.Wrap(err) + return 0x0, 0x0, errors.Wrap(err) } - return image, nil + return album, image, nil +} + +func (r *Redis) Del(ctx context.Context, token uint64) error { + tokenB64 := base64.FromUint64(token) + key := "token:" + tokenB64 + err := r.client.Del(ctx, key).Err() + if err != nil { + return errors.Wrap(err) + } + return nil } func (r *Redis) Close() error { diff --git a/infrastructure/cache/redis_integration_test.go b/infrastructure/cache/redis_integration_test.go index ca5b6e6..230e0ce 100644 --- a/infrastructure/cache/redis_integration_test.go +++ b/infrastructure/cache/redis_integration_test.go @@ -303,16 +303,20 @@ func TestRedisToken(t *testing.T) { if err != nil { t.Fatal(err) } - image1 := uint64(0x52BD) token := uint64(0xB41C) - err = redis.Set(context.Background(), 0xC2E7, token, image1) + album1 := uint64(0xC2E7) + image1 := uint64(0x52BD) + err = redis.Set(context.Background(), token, album1, image1) if err != nil { t.Error(err) } - image2, err := redis.Get(context.Background(), 0xC2E7, token) + album2, image2, err := redis.Get(context.Background(), token) if err != nil { t.Error(err) } + if album1 != album2 { + t.Error("album1 != album2") + } if image1 != image2 { t.Error("image1 != image2") } @@ -338,7 +342,7 @@ func TestRedisToken(t *testing.T) { if err != nil { t.Fatal(err) } - _, err = redis.Get(context.Background(), 0x1C4A, 0xC4F8) + _, _, err = redis.Get(context.Background(), 0xC4F8) if !errors.Is(err, domain.ErrTokenNotFound) { t.Error(err) } @@ -354,11 +358,11 @@ func TestRedisToken(t *testing.T) { if err != nil { t.Error(err) } - _, err = redis.Get(context.Background(), 0xEB96, token) + _, _, err = redis.Get(context.Background(), token) if err != nil { t.Error(err) } - _, err = redis.Get(context.Background(), 0xEB96, token) + _, _, err = redis.Get(context.Background(), token) if !errors.Is(err, domain.ErrTokenNotFound) { t.Error(err) } diff --git a/internal/config/config.go b/internal/config/config.go index dabb422..451c76c 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -12,6 +12,7 @@ func init() { viper.Set("controller.maxNumberOfFiles", 3) viper.Set("controller.maxFileSize", 512*unit.KB) viper.Set("service.numberOfWorkersCalc", 2) + viper.Set("service.tempLinks", false) viper.Set("service.numberOfWorkersComp", 2) viper.Set("service.accuracy", 0.625) viper.Set("cache.redis.host", "localhost") From 02e419348608d3a12ddaf3fcda446d3954631166 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sun, 19 Dec 2021 21:27:49 +0100 Subject: [PATCH 05/92] Hide image ID by using temporary links --- Makefile | 2 +- build/config-prod.yml | 2 +- build/swagger.yml | 6 +- cmd/loadtest/main.go | 8 +- delivery/http/controller_test.go | 179 ++++++++++++++++++ domain/service/service_integration_test.go | 93 +++++++++ domain/service/service_test.go | 69 +++++++ infrastructure/cache/mem_test.go | 57 ++++-- .../cache/redis_integration_test.go | 38 +++- 9 files changed, 425 insertions(+), 29 deletions(-) diff --git a/Makefile b/Makefile index 64afff1..6fa786b 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ prod-down: docker compose --file ./build/docker-compose-prod.yml down --rmi all -v embed-loadtest: - go run ./cmd/loadtest/main.go -verbose=false -api-address "http://localhost:8001" -minio-address "" + go run ./cmd/loadtest/main.go -verbose=false -api-address "http://localhost:8001" -minio-address "http://localhost:8001" embed-up: docker compose --file ./build/docker-compose-embed.yml up -d --build diff --git a/build/config-prod.yml b/build/config-prod.yml index 57b9051..f3d8a57 100644 --- a/build/config-prod.yml +++ b/build/config-prod.yml @@ -20,7 +20,7 @@ controller: maxNumberOfFiles: 100 maxFileSize: 5242880 # 5 MB service: - tempLinks: true + tempLinks: false numberOfWorkersCalc: 8 numberOfWorkersComp: 8 accuracy: 0.625 diff --git a/build/swagger.yml b/build/swagger.yml index e9f5c76..f6efca7 100644 --- a/build/swagger.yml +++ b/build/swagger.yml @@ -59,9 +59,9 @@ paths: /api/images/{token}/: get: description: > - Irure quis ad enim deserunt magna anim ut laborum aliqua commodo - nisi voluptate fugiat incididunt esse exercitation aliqua in in - voluptate ea deserunt mollit aliqua exercitation ea laborum + If the backend is configured to hide an image ID, it will return + a temporary link to a file which can be requested under this + endpoint. parameters: - $ref: '#/components/parameters/tokenParam' responses: diff --git a/cmd/loadtest/main.go b/cmd/loadtest/main.go index f283403..b1651db 100644 --- a/cmd/loadtest/main.go +++ b/cmd/loadtest/main.go @@ -25,6 +25,7 @@ var ( n int apiAddress string minioAddress string + htmlAddress string connections int testdata string verbose bool @@ -36,6 +37,7 @@ func main() { flag.IntVar(&n, "n", 2, "#albums") flag.StringVar(&apiAddress, "api-address", "https://localhost", "") flag.StringVar(&minioAddress, "minio-address", "https://localhost", "") + flag.StringVar(&htmlAddress, "html-address", "https://localhost", "") flag.IntVar(&connections, "connections", 2, "") flag.StringVar(&testdata, "testdata", "./testdata", "") flag.BoolVar(&verbose, "verbose", true, "") @@ -253,10 +255,10 @@ func topMinio(src []string) { } func html(page string) { - if apiAddress != minioAddress { + if htmlAddress == "" { return } - req, err := http.NewRequest("GET", apiAddress+page, nil) + req, err := http.NewRequest("GET", htmlAddress+page, nil) if err != nil { return } @@ -264,6 +266,7 @@ func html(page string) { if err != nil { return } + debug.Assert(resp.StatusCode == 200) _, _ = io.Copy(io.Discard, resp.Body) _ = resp.Body.Close() } @@ -280,6 +283,7 @@ func minio(src string) { if err != nil { return } + debug.Assert(resp.StatusCode == 200) _, _ = io.Copy(io.Discard, resp.Body) _ = resp.Body.Close() } diff --git a/delivery/http/controller_test.go b/delivery/http/controller_test.go index a707bfd..acdeb4a 100644 --- a/delivery/http/controller_test.go +++ b/delivery/http/controller_test.go @@ -5,6 +5,7 @@ package http import ( "bytes" "context" + "io" "mime/multipart" "net/http" "net/http/httptest" @@ -725,6 +726,184 @@ func TestControllerHandlePair(t *testing.T) { } func TestControllerHandleImage(t *testing.T) { + body, _ := io.ReadAll(Png()) + type give struct { + err error + } + type want struct { + code int + typ string + body string + } + tests := []struct { + give + want + }{ + { + give: give{ + err: nil, + }, + want: want{ + code: 200, + typ: "image/png", + body: string(body), + }, + }, + { + give: give{ + err: domain.ErrTooManyRequests, + }, + want: want{ + code: 429, + typ: "application/json; charset=utf-8", + body: `{"error":{"code":0,"msg":"too many requests"}}` + "\n", + }, + }, + { + give: give{ + err: domain.ErrBodyTooLarge, + }, + want: want{ + code: 413, + typ: "application/json; charset=utf-8", + body: `{"error":{"code":1,"msg":"body too large"}}` + "\n", + }, + }, + { + give: give{ + err: domain.ErrWrongContentType, + }, + want: want{ + code: 415, + typ: "application/json; charset=utf-8", + body: `{"error":{"code":2,"msg":"unsupported media type"}}` + "\n", + }, + }, + { + give: give{ + err: domain.ErrNotEnoughImages, + }, + want: want{ + code: 400, + typ: "application/json; charset=utf-8", + body: `{"error":{"code":3,"msg":"not enough images"}}` + "\n", + }, + }, + { + give: give{ + err: domain.ErrTooManyImages, + }, + want: want{ + code: 413, + typ: "application/json; charset=utf-8", + body: `{"error":{"code":4,"msg":"too many images"}}` + "\n", + }, + }, + { + give: give{ + err: domain.ErrImageTooLarge, + }, + want: want{ + code: 413, + typ: "application/json; charset=utf-8", + body: `{"error":{"code":5,"msg":"image too large"}}` + "\n", + }, + }, + { + give: give{ + err: domain.ErrNotImage, + }, + want: want{ + code: 415, + typ: "application/json; charset=utf-8", + body: `{"error":{"code":6,"msg":"unsupported media type"}}` + "\n", + }, + }, + { + give: give{ + err: domain.ErrDurationNotSet, + }, + want: want{ + code: 400, + typ: "application/json; charset=utf-8", + body: `{"error":{"code":7,"msg":"duration not set"}}` + "\n", + }, + }, + { + give: give{ + err: domain.ErrDurationInvalid, + }, + want: want{ + code: 400, + typ: "application/json; charset=utf-8", + body: `{"error":{"code":8,"msg":"duration invalid"}}` + "\n", + }, + }, + { + give: give{ + err: domain.ErrAlbumNotFound, + }, + want: want{ + code: 404, + typ: "application/json; charset=utf-8", + body: `{"error":{"code":9,"msg":"album not found"}}` + "\n", + }, + }, + { + give: give{ + err: domain.ErrTokenNotFound, + }, + want: want{ + code: 404, + typ: "application/json; charset=utf-8", + body: `{"error":{"code":11,"msg":"token not found"}}` + "\n", + }, + }, + { + give: give{ + err: domain.ErrThirdPartyUnavailable, + }, + want: want{ + code: 500, + typ: "application/json; charset=utf-8", + body: `{"error":{"code":16,"msg":"internal server error"}}` + "\n", + }, + }, + { + give: give{ + err: context.Canceled, + }, + want: want{ + code: 500, + typ: "application/json; charset=utf-8", + body: `{"error":{"code":-1,"msg":"internal server error"}}` + "\n", + }, + }, + { + give: give{ + err: context.DeadlineExceeded, + }, + want: want{ + code: 500, + typ: "application/json; charset=utf-8", + body: `{"error":{"code":-2,"msg":"internal server error"}}` + "\n", + }, + }, + } + for _, tt := range tests { + t.Run("", func(t *testing.T) { + serv := service.NewMock(tt.give.err) + contr := newController(serv) + fn := contr.handleImage() + w := httptest.NewRecorder() + r := httptest.NewRequest(http.MethodGet, "/api/images/8v7AAAAAAAA/", nil) + ps := httprouter.Params{httprouter.Param{Key: "token", Value: "8v7AAAAAAAA"}} + fn(w, r, ps) + CheckStatusCode(t, w, tt.want.code) + CheckContentType(t, w, tt.want.typ) + CheckBody(t, w, tt.want.body) + }) + } } func TestControllerHandleVote(t *testing.T) { diff --git a/domain/service/service_integration_test.go b/domain/service/service_integration_test.go index 550a708..b6220fc 100644 --- a/domain/service/service_integration_test.go +++ b/domain/service/service_integration_test.go @@ -10,6 +10,7 @@ import ( "testing" "time" + "github.com/spf13/viper" "golang.org/x/sync/errgroup" "github.com/zitryss/aye-and-nay/domain/domain" @@ -338,6 +339,98 @@ func TestServiceIntegrationPair(t *testing.T) { } func TestServiceIntegrationImage(t *testing.T) { + viper.Set("service.tempLinks", true) + defer viper.Set("service.tempLinks", false) + t.Run("Positive", func(t *testing.T) { + fn1 := func() func() (uint64, error) { + i := uint64(0) + return func() (uint64, error) { + i++ + return 0xA83F + i, nil + } + }() + fn2 := func(n int, swap func(i int, j int)) { + } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + imaginary, err := compressor.NewImaginary() + if err != nil { + t.Fatal(err) + } + minio, err := storage.NewMinio() + if err != nil { + t.Fatal(err) + } + mongo, err := database.NewMongo() + if err != nil { + t.Fatal(err) + } + redis, err := cache.NewRedis() + if err != nil { + t.Fatal(err) + } + qCalc := &QueueCalc{} + qCalc.Monitor(ctx) + qComp := &QueueComp{} + qComp.Monitor(ctx) + qDel := &QueueDel{} + qDel.Monitor(ctx) + serv := New(imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + files := []model.File{Png(), Png()} + album, err := serv.Album(ctx, files, 0*time.Millisecond) + if err != nil { + t.Error(err) + } + img1, img2, err := serv.Pair(ctx, album) + if err != nil { + t.Error(err) + } + f, err := serv.Image(ctx, img1.Token) + if err != nil { + t.Error(err) + } + if f.Reader == nil { + t.Error("f.Reader == nil") + } + f, err = serv.Image(ctx, img2.Token) + if err != nil { + t.Error(err) + } + if f.Reader == nil { + t.Error("f.Reader == nil") + } + }) + t.Run("Negative", func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + imaginary, err := compressor.NewImaginary() + if err != nil { + t.Fatal(err) + } + minio, err := storage.NewMinio() + if err != nil { + t.Fatal(err) + } + mongo, err := database.NewMongo() + if err != nil { + t.Fatal(err) + } + redis, err := cache.NewRedis() + if err != nil { + t.Fatal(err) + } + qCalc := &QueueCalc{} + qCalc.Monitor(ctx) + qComp := &QueueComp{} + qComp.Monitor(ctx) + qDel := &QueueDel{} + qDel.Monitor(ctx) + serv := New(imaginary, minio, mongo, redis, qCalc, qComp, qDel) + _, err = serv.Image(ctx, 0xE283) + if !errors.Is(err, domain.ErrTokenNotFound) { + t.Error(err) + } + }) } func TestServiceIntegrationVote(t *testing.T) { diff --git a/domain/service/service_test.go b/domain/service/service_test.go index 7bbbc04..8adb654 100644 --- a/domain/service/service_test.go +++ b/domain/service/service_test.go @@ -8,6 +8,7 @@ import ( "testing" "time" + "github.com/spf13/viper" "golang.org/x/sync/errgroup" "github.com/zitryss/aye-and-nay/domain/domain" @@ -269,6 +270,74 @@ func TestServicePair(t *testing.T) { } func TestServiceImage(t *testing.T) { + viper.Set("service.tempLinks", true) + defer viper.Set("service.tempLinks", false) + t.Run("Positive", func(t *testing.T) { + fn1 := func() func() (uint64, error) { + i := uint64(0) + return func() (uint64, error) { + i++ + return 0xA83F + i, nil + } + }() + fn2 := func(n int, swap func(i int, j int)) { + } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + comp := compressor.NewMock() + stor := storage.NewMock() + mDb := database.NewMem() + mCache := cache.NewMem() + qCalc := &QueueCalc{} + qCalc.Monitor(ctx) + qComp := &QueueComp{} + qComp.Monitor(ctx) + qDel := &QueueDel{} + qDel.Monitor(ctx) + serv := New(comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + files := []model.File{Png(), Png()} + album, err := serv.Album(ctx, files, 0*time.Millisecond) + if err != nil { + t.Error(err) + } + img1, img2, err := serv.Pair(ctx, album) + if err != nil { + t.Error(err) + } + f, err := serv.Image(ctx, img1.Token) + if err != nil { + t.Error(err) + } + if f.Reader == nil { + t.Error("f.Reader == nil") + } + f, err = serv.Image(ctx, img2.Token) + if err != nil { + t.Error(err) + } + if f.Reader == nil { + t.Error("f.Reader == nil") + } + }) + t.Run("Negative", func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + comp := compressor.NewMock() + stor := storage.NewMock() + mDb := database.NewMem() + mCache := cache.NewMem() + qCalc := &QueueCalc{} + qCalc.Monitor(ctx) + qComp := &QueueComp{} + qComp.Monitor(ctx) + qDel := &QueueDel{} + qDel.Monitor(ctx) + serv := New(comp, stor, mDb, mCache, qCalc, qComp, qDel) + _, err := serv.Image(ctx, 0xE283) + if !errors.Is(err, domain.ErrTokenNotFound) { + t.Error(err) + } + }) } func TestServiceVote(t *testing.T) { diff --git a/infrastructure/cache/mem_test.go b/infrastructure/cache/mem_test.go index f5cf3d6..d35deab 100644 --- a/infrastructure/cache/mem_test.go +++ b/infrastructure/cache/mem_test.go @@ -74,66 +74,95 @@ func TestMemPair(t *testing.T) { func TestMemToken(t *testing.T) { t.Run("Positive", func(t *testing.T) { mem := NewMem() - err := mem.Set(context.Background(), 0xC2E7, 0xB41C, 0x52BD) + token := uint64(0xC2E7) + album1 := uint64(0xB41C) + image1 := uint64(0x52BD) + err := mem.Set(context.Background(), token, album1, image1) if err != nil { t.Error(err) } - album, image, err := mem.Get(context.Background(), 0xC2E7) + album2, image2, err := mem.Get(context.Background(), token) if err != nil { t.Error(err) } - if album != 0xB41C { - t.Error("image != 0x52BD") + if album1 != album2 { + t.Error("album1 != album2") } - if image != 0x52BD { - t.Error("image != 0x52BD") + if image1 != image2 { + t.Error("image1 != image2") } }) t.Run("Negative1", func(t *testing.T) { mem := NewMem() - err := mem.Set(context.Background(), 0x1C4A, 0xF0EE, 0x583C) + token := uint64(0x1C4A) + album := uint64(0xF0EE) + image := uint64(0x583C) + err := mem.Set(context.Background(), token, album, image) if err != nil { t.Error(err) } - err = mem.Set(context.Background(), 0x1C4A, 0xF0EE, 0x583C) + err = mem.Set(context.Background(), token, album, image) if !errors.Is(err, domain.ErrTokenAlreadyExists) { t.Error(err) } }) t.Run("Negative2", func(t *testing.T) { mem := NewMem() - _, _, err := mem.Get(context.Background(), 0xC4F8) + token := uint64(0xC4F8) + _, _, err := mem.Get(context.Background(), token) if !errors.Is(err, domain.ErrTokenNotFound) { t.Error(err) } }) t.Run("Negative3", func(t *testing.T) { mem := NewMem() - err := mem.Set(context.Background(), 0xEB96, 0xC67F, 0x7C45) + token := uint64(0xEB96) + album := uint64(0xC67F) + image := uint64(0x7C45) + err := mem.Set(context.Background(), token, album, image) if err != nil { t.Error(err) } - _, _, err = mem.Get(context.Background(), 0xC67F) + _, _, err = mem.Get(context.Background(), token) if err != nil { t.Error(err) } - _, _, err = mem.Get(context.Background(), 0xC67F) + err = mem.Del(context.Background(), token) + if err != nil { + t.Error(err) + } + err = mem.Del(context.Background(), token) + if err != nil { + t.Error(err) + } + _, _, err = mem.Get(context.Background(), token) if !errors.Is(err, domain.ErrTokenNotFound) { t.Error(err) } }) t.Run("Negative4", func(t *testing.T) { + mem := NewMem() + token := uint64(0xD3BF) + err := mem.Del(context.Background(), token) + if err != nil { + t.Error(err) + } + }) + t.Run("Negative5", func(t *testing.T) { heartbeatToken := make(chan interface{}) mem := NewMem(WithHeartbeatToken(heartbeatToken)) mem.Monitor() - err := mem.Set(context.Background(), 0xE0AF, 0xCF1E, 0xDD0A) + token := uint64(0xE0AF) + album := uint64(0xCF1E) + image := uint64(0xDD0A) + err := mem.Set(context.Background(), token, album, image) if err != nil { t.Error(err) } time.Sleep(mem.conf.timeToLive) CheckChannel(t, heartbeatToken) CheckChannel(t, heartbeatToken) - _, _, err = mem.Get(context.Background(), 0xCF1E) + _, _, err = mem.Get(context.Background(), token) if !errors.Is(err, domain.ErrTokenNotFound) { t.Error(err) } diff --git a/infrastructure/cache/redis_integration_test.go b/infrastructure/cache/redis_integration_test.go index 230e0ce..7c11e00 100644 --- a/infrastructure/cache/redis_integration_test.go +++ b/infrastructure/cache/redis_integration_test.go @@ -303,8 +303,8 @@ func TestRedisToken(t *testing.T) { if err != nil { t.Fatal(err) } - token := uint64(0xB41C) - album1 := uint64(0xC2E7) + token := uint64(0xC2E7) + album1 := uint64(0xB41C) image1 := uint64(0x52BD) err = redis.Set(context.Background(), token, album1, image1) if err != nil { @@ -326,13 +326,14 @@ func TestRedisToken(t *testing.T) { if err != nil { t.Fatal(err) } + token := uint64(0x1C4A) + album := uint64(0xF0EE) image := uint64(0x583C) - token := uint64(0xF0EE) - err = redis.Set(context.Background(), 0x1C4A, token, image) + err = redis.Set(context.Background(), token, album, image) if err != nil { t.Error(err) } - err = redis.Set(context.Background(), 0x1C4A, token, image) + err = redis.Set(context.Background(), token, album, image) if !errors.Is(err, domain.ErrTokenAlreadyExists) { t.Error(err) } @@ -342,7 +343,8 @@ func TestRedisToken(t *testing.T) { if err != nil { t.Fatal(err) } - _, _, err = redis.Get(context.Background(), 0xC4F8) + token := uint64(0xC4F8) + _, _, err = redis.Get(context.Background(), token) if !errors.Is(err, domain.ErrTokenNotFound) { t.Error(err) } @@ -352,9 +354,10 @@ func TestRedisToken(t *testing.T) { if err != nil { t.Fatal(err) } + token := uint64(0xEB96) + album := uint64(0xC67F) image := uint64(0x7C45) - token := uint64(0xC67F) - err = redis.Set(context.Background(), 0xEB96, token, image) + err = redis.Set(context.Background(), token, album, image) if err != nil { t.Error(err) } @@ -362,9 +365,28 @@ func TestRedisToken(t *testing.T) { if err != nil { t.Error(err) } + err = redis.Del(context.Background(), token) + if err != nil { + t.Error(err) + } + err = redis.Del(context.Background(), token) + if err != nil { + t.Error(err) + } _, _, err = redis.Get(context.Background(), token) if !errors.Is(err, domain.ErrTokenNotFound) { t.Error(err) } }) + t.Run("Negative4", func(t *testing.T) { + redis, err := NewRedis() + if err != nil { + t.Fatal(err) + } + token := uint64(0xD3BF) + err = redis.Del(context.Background(), token) + if err != nil { + t.Error(err) + } + }) } From d8e26e053fdba3ea166801800030f62046b10fa4 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sun, 19 Dec 2021 21:33:04 +0100 Subject: [PATCH 06/92] Use http.NoBody --- cmd/loadtest/main.go | 10 +++++----- delivery/http/controller_test.go | 8 ++++---- delivery/http/middleware_test.go | 8 ++++---- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/cmd/loadtest/main.go b/cmd/loadtest/main.go index b1651db..70f6e37 100644 --- a/cmd/loadtest/main.go +++ b/cmd/loadtest/main.go @@ -139,7 +139,7 @@ func albumApi() string { } func readyApi(album string) { - req, err := http.NewRequest("GET", apiAddress+"/api/albums/"+album+"/ready/", nil) + req, err := http.NewRequest("GET", apiAddress+"/api/albums/"+album+"/ready/", http.NoBody) debug.Check(err) resp, err := http.DefaultClient.Do(req) @@ -164,7 +164,7 @@ func pairHtml() { } func pairApi(album string) (string, string, string, string) { - req, err := http.NewRequest("GET", apiAddress+"/api/albums/"+album+"/pair/", nil) + req, err := http.NewRequest("GET", apiAddress+"/api/albums/"+album+"/pair/", http.NoBody) debug.Check(err) resp, err := http.DefaultClient.Do(req) @@ -218,7 +218,7 @@ func topHtml() { } func topApi(album string) []string { - req, err := http.NewRequest("GET", apiAddress+"/api/albums/"+album+"/top/", nil) + req, err := http.NewRequest("GET", apiAddress+"/api/albums/"+album+"/top/", http.NoBody) debug.Check(err) resp, err := http.DefaultClient.Do(req) @@ -258,7 +258,7 @@ func html(page string) { if htmlAddress == "" { return } - req, err := http.NewRequest("GET", htmlAddress+page, nil) + req, err := http.NewRequest("GET", htmlAddress+page, http.NoBody) if err != nil { return } @@ -275,7 +275,7 @@ func minio(src string) { if minioAddress == "" { return } - req, err := http.NewRequest("GET", minioAddress+src, nil) + req, err := http.NewRequest("GET", minioAddress+src, http.NoBody) if err != nil { return } diff --git a/delivery/http/controller_test.go b/delivery/http/controller_test.go index acdeb4a..712bba6 100644 --- a/delivery/http/controller_test.go +++ b/delivery/http/controller_test.go @@ -535,7 +535,7 @@ func TestControllerHandleReady(t *testing.T) { contr := newController(serv) fn := contr.handleReady() w := httptest.NewRecorder() - r := httptest.NewRequest(http.MethodGet, "/api/albums/rRsAAAAAAAA/ready", nil) + r := httptest.NewRequest(http.MethodGet, "/api/albums/rRsAAAAAAAA/ready", http.NoBody) ps := httprouter.Params{httprouter.Param{Key: "album", Value: "rRsAAAAAAAA"}} fn(w, r, ps) CheckStatusCode(t, w, tt.want.code) @@ -715,7 +715,7 @@ func TestControllerHandlePair(t *testing.T) { contr := newController(serv) fn := contr.handlePair() w := httptest.NewRecorder() - r := httptest.NewRequest(http.MethodGet, "/api/albums/nkUAAAAAAAA/", nil) + r := httptest.NewRequest(http.MethodGet, "/api/albums/nkUAAAAAAAA/", http.NoBody) ps := httprouter.Params{httprouter.Param{Key: "album", Value: "nkUAAAAAAAA"}} fn(w, r, ps) CheckStatusCode(t, w, tt.want.code) @@ -896,7 +896,7 @@ func TestControllerHandleImage(t *testing.T) { contr := newController(serv) fn := contr.handleImage() w := httptest.NewRecorder() - r := httptest.NewRequest(http.MethodGet, "/api/images/8v7AAAAAAAA/", nil) + r := httptest.NewRequest(http.MethodGet, "/api/images/8v7AAAAAAAA/", http.NoBody) ps := httprouter.Params{httprouter.Param{Key: "token", Value: "8v7AAAAAAAA"}} fn(w, r, ps) CheckStatusCode(t, w, tt.want.code) @@ -1258,7 +1258,7 @@ func TestControllerHandleTop(t *testing.T) { contr := newController(serv) fn := contr.handleTop() w := httptest.NewRecorder() - r := httptest.NewRequest(http.MethodGet, "/api/albums/byYAAAAAAAA/top/", nil) + r := httptest.NewRequest(http.MethodGet, "/api/albums/byYAAAAAAAA/top/", http.NoBody) ps := httprouter.Params{httprouter.Param{Key: "album", Value: "byYAAAAAAAA"}} fn(w, r, ps) CheckStatusCode(t, w, tt.want.code) diff --git a/delivery/http/middleware_test.go b/delivery/http/middleware_test.go index 3ae4ef7..d067fd6 100644 --- a/delivery/http/middleware_test.go +++ b/delivery/http/middleware_test.go @@ -36,7 +36,7 @@ func TestMiddlewareRecover(t *testing.T) { middle := NewMiddleware(lim) handler := middle.recover(http.HandlerFunc(fn)) w := httptest.NewRecorder() - r := httptest.NewRequest(http.MethodGet, "/", nil) + r := httptest.NewRequest(http.MethodGet, "/", http.NoBody) handler.ServeHTTP(w, r) CheckStatusCode(t, w, 418) CheckContentType(t, w, "text/plain; charset=utf-8") @@ -50,7 +50,7 @@ func TestMiddlewareRecover(t *testing.T) { middle := NewMiddleware(lim) handler := middle.recover(http.HandlerFunc(fn)) w := httptest.NewRecorder() - r := httptest.NewRequest(http.MethodGet, "/", nil) + r := httptest.NewRequest(http.MethodGet, "/", http.NoBody) handler.ServeHTTP(w, r) CheckStatusCode(t, w, 500) CheckContentType(t, w, "application/json; charset=utf-8") @@ -69,7 +69,7 @@ func TestMiddlewareLimit(t *testing.T) { middle := NewMiddleware(lim) handler := middle.limit(http.HandlerFunc(fn)) w := httptest.NewRecorder() - r := httptest.NewRequest(http.MethodGet, "/", nil) + r := httptest.NewRequest(http.MethodGet, "/", http.NoBody) handler.ServeHTTP(w, r) CheckStatusCode(t, w, 418) CheckContentType(t, w, "text/plain; charset=utf-8") @@ -85,7 +85,7 @@ func TestMiddlewareLimit(t *testing.T) { middle := NewMiddleware(lim) handler := middle.limit(http.HandlerFunc(fn)) w := httptest.NewRecorder() - r := httptest.NewRequest(http.MethodGet, "/", nil) + r := httptest.NewRequest(http.MethodGet, "/", http.NoBody) handler.ServeHTTP(w, r) CheckStatusCode(t, w, 429) CheckContentType(t, w, "application/json; charset=utf-8") From 15f9b00274ed0e08db12198b4e2e649a7271061f Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sun, 19 Dec 2021 21:40:03 +0100 Subject: [PATCH 07/92] Uppercase constants --- domain/service/service_integration_test.go | 2 +- .../cache/cache_integration_test.go | 2 +- .../compressor/compressor_integration_test.go | 2 +- .../database/database_integration_test.go | 2 +- .../storage/storage_integration_test.go | 2 +- pkg/log/log.go | 42 +++++++++---------- pkg/log/log_test.go | 12 +++--- 7 files changed, 32 insertions(+), 32 deletions(-) diff --git a/domain/service/service_integration_test.go b/domain/service/service_integration_test.go index b6220fc..479ff6a 100644 --- a/domain/service/service_integration_test.go +++ b/domain/service/service_integration_test.go @@ -31,7 +31,7 @@ func TestMain(m *testing.M) { _, err := env.Lookup("CONTINUOUS_INTEGRATION") if err != nil { log.SetOutput(os.Stderr) - log.SetLevel(log.Lcritical) + log.SetLevel(log.CRITICAL) docker := dockertest.New() docker.RunRedis() docker.RunImaginary() diff --git a/infrastructure/cache/cache_integration_test.go b/infrastructure/cache/cache_integration_test.go index 8f9231d..cf151b1 100644 --- a/infrastructure/cache/cache_integration_test.go +++ b/infrastructure/cache/cache_integration_test.go @@ -16,7 +16,7 @@ func TestMain(m *testing.M) { _, err := env.Lookup("CONTINUOUS_INTEGRATION") if err != nil { log.SetOutput(os.Stderr) - log.SetLevel(log.Lcritical) + log.SetLevel(log.CRITICAL) docker := dockertest.New() docker.RunRedis() log.SetOutput(io.Discard) diff --git a/infrastructure/compressor/compressor_integration_test.go b/infrastructure/compressor/compressor_integration_test.go index 4f7add6..03600e1 100644 --- a/infrastructure/compressor/compressor_integration_test.go +++ b/infrastructure/compressor/compressor_integration_test.go @@ -16,7 +16,7 @@ func TestMain(m *testing.M) { _, err := env.Lookup("CONTINUOUS_INTEGRATION") if err != nil { log.SetOutput(os.Stderr) - log.SetLevel(log.Lcritical) + log.SetLevel(log.CRITICAL) docker := dockertest.New() docker.RunImaginary() log.SetOutput(io.Discard) diff --git a/infrastructure/database/database_integration_test.go b/infrastructure/database/database_integration_test.go index acc37f4..e6de19a 100644 --- a/infrastructure/database/database_integration_test.go +++ b/infrastructure/database/database_integration_test.go @@ -16,7 +16,7 @@ func TestMain(m *testing.M) { _, err := env.Lookup("CONTINUOUS_INTEGRATION") if err != nil { log.SetOutput(os.Stderr) - log.SetLevel(log.Lcritical) + log.SetLevel(log.CRITICAL) docker := dockertest.New() docker.RunMongo() log.SetOutput(io.Discard) diff --git a/infrastructure/storage/storage_integration_test.go b/infrastructure/storage/storage_integration_test.go index 496bea8..5e8c62a 100644 --- a/infrastructure/storage/storage_integration_test.go +++ b/infrastructure/storage/storage_integration_test.go @@ -16,7 +16,7 @@ func TestMain(m *testing.M) { _, err := env.Lookup("CONTINUOUS_INTEGRATION") if err != nil { log.SetOutput(os.Stderr) - log.SetLevel(log.Lcritical) + log.SetLevel(log.CRITICAL) docker := dockertest.New() docker.RunMinio() log.SetOutput(io.Discard) diff --git a/pkg/log/log.go b/pkg/log/log.go index a1e8bc9..a72320d 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -11,11 +11,11 @@ import ( type Level int const ( - ldisabled Level = iota - Ldebug // debug - Linfo // info - Lerror // error - Lcritical // critical + disabled Level = iota + DEBUG // debug + INFO // info + ERROR // error + CRITICAL // critical ) var ( @@ -41,10 +41,10 @@ func SetFlags(flag int) { func SetLevel(lvl interface{}) { oldLevel := l.lvl - newLevel := ldisabled + newLevel := disabled switch v := lvl.(type) { case Level: - if Ldebug <= v && v <= Lcritical { + if DEBUG <= v && v <= CRITICAL { newLevel = v } else { newLevel = oldLevel @@ -53,13 +53,13 @@ func SetLevel(lvl interface{}) { v = strings.ToLower(v) switch v { case "debug": - newLevel = Ldebug + newLevel = DEBUG case "info": - newLevel = Linfo + newLevel = INFO case "error": - newLevel = Lerror + newLevel = ERROR case "critical": - newLevel = Lcritical + newLevel = CRITICAL default: newLevel = oldLevel } @@ -70,45 +70,45 @@ func SetLevel(lvl interface{}) { } func Println(level Level, v ...interface{}) { - if Ldebug <= level && level <= Lcritical && l.lvl <= level { + if DEBUG <= level && level <= CRITICAL && l.lvl <= level { l.Println(append([]interface{}{fmt.Sprint(level) + ":"}, v...)...) } } func Printf(level Level, format string, v ...interface{}) { - if Ldebug <= level && level <= Lcritical && l.lvl <= level { + if DEBUG <= level && level <= CRITICAL && l.lvl <= level { l.Printf("%s: "+format, append([]interface{}{level}, v...)...) } } func Debug(v ...interface{}) { - Println(Ldebug, v...) + Println(DEBUG, v...) } func Debugf(format string, v ...interface{}) { - Printf(Ldebug, format, v...) + Printf(DEBUG, format, v...) } func Info(v ...interface{}) { - Println(Linfo, v...) + Println(INFO, v...) } func Infof(format string, v ...interface{}) { - Printf(Linfo, format, v...) + Printf(INFO, format, v...) } func Error(v ...interface{}) { - Println(Lerror, v...) + Println(ERROR, v...) } func Errorf(format string, v ...interface{}) { - Printf(Lerror, format, v...) + Printf(ERROR, format, v...) } func Critical(v ...interface{}) { - Println(Lcritical, v...) + Println(CRITICAL, v...) } func Criticalf(format string, v ...interface{}) { - Printf(Lcritical, format, v...) + Printf(CRITICAL, format, v...) } diff --git a/pkg/log/log_test.go b/pkg/log/log_test.go index c12883b..da02832 100644 --- a/pkg/log/log_test.go +++ b/pkg/log/log_test.go @@ -31,19 +31,19 @@ func TestLogLevelPositive(t *testing.T) { want: "critical: message7\ncritical: message8: ju iv\n", }, { - level: log.Ldebug, + level: log.DEBUG, want: "debug: message1\ndebug: message2: 60 95\ninfo: message3\ninfo: message4: mx 12\nerror: message5\nerror: message6: 80 dq\ncritical: message7\ncritical: message8: ju iv\n", }, { - level: log.Linfo, + level: log.INFO, want: "info: message3\ninfo: message4: mx 12\nerror: message5\nerror: message6: 80 dq\ncritical: message7\ncritical: message8: ju iv\n", }, { - level: log.Lerror, + level: log.ERROR, want: "error: message5\nerror: message6: 80 dq\ncritical: message7\ncritical: message8: ju iv\n", }, { - level: log.Lcritical, + level: log.CRITICAL, want: "critical: message7\ncritical: message8: ju iv\n", }, } @@ -94,7 +94,7 @@ func TestLogLevelNegative(t *testing.T) { log.SetOutput(&w) log.SetPrefix("") log.SetFlags(0) - log.SetLevel(log.Ldebug) + log.SetLevel(log.DEBUG) log.Debug("message1") log.Debugf("message2: %d %d", 60, 95) log.Info("message3") @@ -106,7 +106,7 @@ func TestLogLevelNegative(t *testing.T) { log.Criticalf("message8: %s %s", "ju", "iv") got := w.String() if got != tt.want { - t.Errorf("level = %v; got %v; want %v", log.Ldebug, got, tt.want) + t.Errorf("level = %v; got %v; want %v", log.DEBUG, got, tt.want) } }) } From 1ee56dfbaa5a5e958c69a0578a89d126882cadd8 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sun, 19 Dec 2021 21:47:52 +0100 Subject: [PATCH 08/92] Log application name --- build/config-dev.yml | 1 + build/config-embed.yml | 1 + build/config-prod.yml | 1 + config.yml | 1 + main.go | 6 ++++-- 5 files changed, 8 insertions(+), 2 deletions(-) diff --git a/build/config-dev.yml b/build/config-dev.yml index 07f8e87..f1c01b7 100644 --- a/build/config-dev.yml +++ b/build/config-dev.yml @@ -1,4 +1,5 @@ app: + name: config-dev ballast: 0 log: info server: diff --git a/build/config-embed.yml b/build/config-embed.yml index d54d493..bc186a7 100644 --- a/build/config-embed.yml +++ b/build/config-embed.yml @@ -1,4 +1,5 @@ app: + name: config-embed ballast: 0 log: info server: diff --git a/build/config-prod.yml b/build/config-prod.yml index f3d8a57..ebfb465 100644 --- a/build/config-prod.yml +++ b/build/config-prod.yml @@ -1,4 +1,5 @@ app: + name: config-prod ballast: 0 log: info server: diff --git a/config.yml b/config.yml index fb40f41..44519da 100644 --- a/config.yml +++ b/config.yml @@ -1,4 +1,5 @@ app: + name: config ballast: 0 log: info server: diff --git a/main.go b/main.go index 4ef53cd..5b10cc2 100644 --- a/main.go +++ b/main.go @@ -44,9 +44,11 @@ func main() { ballast = make([]byte, viper.GetInt64("app.ballast")) - lvl := viper.GetString("app.log") + p := viper.GetString("app.name") + l := viper.GetString("app.log") log.SetOutput(os.Stderr) - log.SetLevel(lvl) + log.SetPrefix(p) + log.SetLevel(l) log.Info("logging initialized") ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) From 54497f9669cddff55f1cd9651b8dfaa6a7779ada Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sun, 19 Dec 2021 22:55:30 +0100 Subject: [PATCH 09/92] Stop using LimitReader --- domain/service/mock.go | 2 +- infrastructure/compressor/imaginary.go | 2 +- infrastructure/compressor/mock.go | 2 +- infrastructure/compressor/shortpixel.go | 4 ++-- infrastructure/storage/mock.go | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/domain/service/mock.go b/domain/service/mock.go index 0148421..d201dbb 100644 --- a/domain/service/mock.go +++ b/domain/service/mock.go @@ -48,7 +48,7 @@ func (m *Mock) Image(_ context.Context, _ uint64) (model.File, error) { } buf := pool.GetBuffer() f := Png() - n, err := io.CopyN(buf, f, f.Size) + n, err := io.Copy(buf, f) if err != nil { return model.File{}, errors.Wrap(err) } diff --git a/infrastructure/compressor/imaginary.go b/infrastructure/compressor/imaginary.go index 1bedbc3..48b87e3 100644 --- a/infrastructure/compressor/imaginary.go +++ b/infrastructure/compressor/imaginary.go @@ -81,7 +81,7 @@ func (im *Imaginary) Compress(ctx context.Context, f model.File) (model.File, er if err != nil { return model.File{}, errors.Wrap(err) } - n, err := io.CopyN(part, tee, tee.Size) + n, err := io.Copy(part, tee) if err != nil { return model.File{}, errors.Wrap(err) } diff --git a/infrastructure/compressor/mock.go b/infrastructure/compressor/mock.go index c217c16..bb3b2e7 100644 --- a/infrastructure/compressor/mock.go +++ b/infrastructure/compressor/mock.go @@ -35,7 +35,7 @@ func (m *Mock) Compress(_ context.Context, f model.File) (model.File, error) { } }() buf := pool.GetBuffer() - n, err := io.CopyN(buf, f, f.Size) + n, err := io.Copy(buf, f) if err != nil { return model.File{}, errors.Wrap(err) } diff --git a/infrastructure/compressor/shortpixel.go b/infrastructure/compressor/shortpixel.go index 1063554..b4c71b5 100644 --- a/infrastructure/compressor/shortpixel.go +++ b/infrastructure/compressor/shortpixel.go @@ -90,7 +90,7 @@ func (sp *Shortpixel) Compress(ctx context.Context, f model.File) (model.File, e }() if atomic.LoadUint32(&sp.done) != 0 { buf := pool.GetBuffer() - n, err := io.CopyN(buf, f, f.Size) + n, err := io.Copy(buf, f) if err != nil { return model.File{}, errors.Wrap(err) } @@ -169,7 +169,7 @@ func (sp *Shortpixel) upload(ctx context.Context, f model.File) (string, error) if err != nil { return "", errors.Wrap(err) } - _, err = io.CopyN(part, f, f.Size) + _, err = io.Copy(part, f) if err != nil { return "", errors.Wrap(err) } diff --git a/infrastructure/storage/mock.go b/infrastructure/storage/mock.go index a4c069b..b44a469 100644 --- a/infrastructure/storage/mock.go +++ b/infrastructure/storage/mock.go @@ -46,7 +46,7 @@ func (m *Mock) Put(_ context.Context, album uint64, image uint64, f model.File) func (m *Mock) Get(_ context.Context, _ uint64, _ uint64) (model.File, error) { buf := pool.GetBuffer() f := Png() - n, err := io.CopyN(buf, f, f.Size) + n, err := io.Copy(buf, f) if err != nil { return model.File{}, errors.Wrap(err) } From c1f331754e4b3eaf01431be66bc10b5b6b5187ef Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Mon, 20 Dec 2021 19:12:25 +0100 Subject: [PATCH 10/92] Switch to the right endpoint --- cmd/loadtest/main.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cmd/loadtest/main.go b/cmd/loadtest/main.go index 70f6e37..4fd4d39 100644 --- a/cmd/loadtest/main.go +++ b/cmd/loadtest/main.go @@ -272,10 +272,15 @@ func html(page string) { } func minio(src string) { - if minioAddress == "" { + address := minioAddress + if strings.HasPrefix(src, "/api/images/") { + address = apiAddress + } + if minioAddress == "" && address == "" { return } - req, err := http.NewRequest("GET", minioAddress+src, http.NoBody) + fmt.Println(address + src) + req, err := http.NewRequest("GET", address+src, http.NoBody) if err != nil { return } From a47bbc77c42cd38b4b73bebe4fdd59f06422dac4 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Mon, 20 Dec 2021 19:12:59 +0100 Subject: [PATCH 11/92] Fix loadtest parameters --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6fa786b..331cfb4 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ prod-down: docker compose --file ./build/docker-compose-prod.yml down --rmi all -v embed-loadtest: - go run ./cmd/loadtest/main.go -verbose=false -api-address "http://localhost:8001" -minio-address "http://localhost:8001" + go run ./cmd/loadtest/main.go -verbose=false -api-address "http://localhost:8001" -minio-address "http://localhost:9000" -html-address "" embed-up: docker compose --file ./build/docker-compose-embed.yml up -d --build From 8033b88f39850450f608875f506bca183d978662 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Mon, 20 Dec 2021 19:13:14 +0100 Subject: [PATCH 12/92] Fix log output --- cmd/loadtest/main.go | 1 - pkg/log/log.go | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd/loadtest/main.go b/cmd/loadtest/main.go index 4fd4d39..fa95ff6 100644 --- a/cmd/loadtest/main.go +++ b/cmd/loadtest/main.go @@ -279,7 +279,6 @@ func minio(src string) { if minioAddress == "" && address == "" { return } - fmt.Println(address + src) req, err := http.NewRequest("GET", address+src, http.NoBody) if err != nil { return diff --git a/pkg/log/log.go b/pkg/log/log.go index a72320d..38bfc5a 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -32,7 +32,7 @@ func SetOutput(w io.Writer) { } func SetPrefix(prefix string) { - l.SetPrefix(prefix) + l.SetPrefix(prefix + ": ") } func SetFlags(flag int) { From 16345de3e514d39e46e419e83eca0953609321f3 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Mon, 20 Dec 2021 22:00:55 +0100 Subject: [PATCH 13/92] Mimic minio --- infrastructure/storage/mock.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/infrastructure/storage/mock.go b/infrastructure/storage/mock.go index b44a469..5157dbf 100644 --- a/infrastructure/storage/mock.go +++ b/infrastructure/storage/mock.go @@ -1,6 +1,7 @@ package storage import ( + "bufio" "bytes" "context" "io" @@ -39,6 +40,8 @@ func (m *Mock) Put(_ context.Context, album uint64, image uint64, f model.File) albumB64 := base64.FromUint64(album) imageB64 := base64.FromUint64(image) filename := "albums/" + albumB64 + "/images/" + imageB64 + buf := bufio.NewReader(f) + _, _ = io.Copy(io.Discard, buf) src := "/aye-and-nay/" + filename return src, nil } From c3fd15356758cd6ed185610b1f57b6d72eca6eb9 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Tue, 21 Dec 2021 23:15:03 +0100 Subject: [PATCH 14/92] Grow buffer before use --- domain/service/mock.go | 2 +- infrastructure/compressor/imaginary.go | 4 ++-- infrastructure/compressor/mock.go | 2 +- infrastructure/compressor/shortpixel.go | 10 +++++----- infrastructure/storage/minio.go | 6 +++++- infrastructure/storage/mock.go | 2 +- pkg/pool/pool.go | 12 ++++++++++++ 7 files changed, 27 insertions(+), 11 deletions(-) diff --git a/domain/service/mock.go b/domain/service/mock.go index d201dbb..152622e 100644 --- a/domain/service/mock.go +++ b/domain/service/mock.go @@ -46,8 +46,8 @@ func (m *Mock) Image(_ context.Context, _ uint64) (model.File, error) { if m.err != nil { return model.File{}, m.err } - buf := pool.GetBuffer() f := Png() + buf := pool.GetBufferN(f.Size) n, err := io.Copy(buf, f) if err != nil { return model.File{}, errors.Wrap(err) diff --git a/infrastructure/compressor/imaginary.go b/infrastructure/compressor/imaginary.go index 48b87e3..8e0b00f 100644 --- a/infrastructure/compressor/imaginary.go +++ b/infrastructure/compressor/imaginary.go @@ -69,12 +69,12 @@ func (im *Imaginary) Compress(ctx context.Context, f model.File) (model.File, er panic(errors.Wrap(domain.ErrUnknown)) } }() - buf := pool.GetBuffer() + buf := pool.GetBufferN(f.Size) tee := model.File{ Reader: io.TeeReader(f.Reader, buf), Size: f.Size, } - body := pool.GetBuffer() + body := pool.GetBufferN(f.Size) defer pool.PutBuffer(body) multi := multipart.NewWriter(body) part, err := multi.CreateFormFile("file", "non-empty-field") diff --git a/infrastructure/compressor/mock.go b/infrastructure/compressor/mock.go index bb3b2e7..b5140b0 100644 --- a/infrastructure/compressor/mock.go +++ b/infrastructure/compressor/mock.go @@ -34,7 +34,7 @@ func (m *Mock) Compress(_ context.Context, f model.File) (model.File, error) { panic(errors.Wrap(domain.ErrUnknown)) } }() - buf := pool.GetBuffer() + buf := pool.GetBufferN(f.Size) n, err := io.Copy(buf, f) if err != nil { return model.File{}, errors.Wrap(err) diff --git a/infrastructure/compressor/shortpixel.go b/infrastructure/compressor/shortpixel.go index b4c71b5..32ae315 100644 --- a/infrastructure/compressor/shortpixel.go +++ b/infrastructure/compressor/shortpixel.go @@ -89,7 +89,7 @@ func (sp *Shortpixel) Compress(ctx context.Context, f model.File) (model.File, e } }() if atomic.LoadUint32(&sp.done) != 0 { - buf := pool.GetBuffer() + buf := pool.GetBufferN(f.Size) n, err := io.Copy(buf, f) if err != nil { return model.File{}, errors.Wrap(err) @@ -122,7 +122,7 @@ func (sp *Shortpixel) compress(ctx context.Context, f model.File) (model.File, e } func (sp *Shortpixel) upload(ctx context.Context, f model.File) (string, error) { - body := pool.GetBuffer() + body := pool.GetBufferN(f.Size) defer pool.PutBuffer(body) multi := multipart.NewWriter(body) part, err := multi.CreateFormField("key") @@ -199,7 +199,7 @@ func (sp *Shortpixel) upload(ctx context.Context, f model.File) (string, error) if err != nil { return "", errors.Wrap(err) } - buf := pool.GetBuffer() + buf := pool.GetBufferN(resp.ContentLength) defer pool.PutBuffer(buf) _, err = io.Copy(buf, resp.Body) if err != nil { @@ -293,7 +293,7 @@ func (sp *Shortpixel) repeat(ctx context.Context, src string) (string, error) { if err != nil { return "", errors.Wrap(err) } - buf := pool.GetBuffer() + buf := pool.GetBufferN(resp.ContentLength) defer pool.PutBuffer(buf) _, err = io.Copy(buf, resp.Body) if err != nil { @@ -360,7 +360,7 @@ func (sp *Shortpixel) download(ctx context.Context, src string) (model.File, err if err != nil { return model.File{}, errors.Wrap(err) } - buf := pool.GetBuffer() + buf := pool.GetBufferN(resp.ContentLength) n, err := io.Copy(buf, resp.Body) if err != nil { _, _ = io.Copy(io.Discard, resp.Body) diff --git a/infrastructure/storage/minio.go b/infrastructure/storage/minio.go index 80ecce7..86afcac 100644 --- a/infrastructure/storage/minio.go +++ b/infrastructure/storage/minio.go @@ -144,7 +144,11 @@ func (m *Minio) Get(ctx context.Context, album uint64, image uint64) (model.File if err != nil { return model.File{}, errors.Wrap(err) } - buf := pool.GetBuffer() + info, err := obj.Stat() + if err != nil { + return model.File{}, errors.Wrap(err) + } + buf := pool.GetBufferN(info.Size) n, err := io.Copy(buf, obj) if err != nil { return model.File{}, errors.Wrap(err) diff --git a/infrastructure/storage/mock.go b/infrastructure/storage/mock.go index 5157dbf..66bd0e5 100644 --- a/infrastructure/storage/mock.go +++ b/infrastructure/storage/mock.go @@ -47,8 +47,8 @@ func (m *Mock) Put(_ context.Context, album uint64, image uint64, f model.File) } func (m *Mock) Get(_ context.Context, _ uint64, _ uint64) (model.File, error) { - buf := pool.GetBuffer() f := Png() + buf := pool.GetBufferN(f.Size) n, err := io.Copy(buf, f) if err != nil { return model.File{}, errors.Wrap(err) diff --git a/pkg/pool/pool.go b/pkg/pool/pool.go index 9dc5688..d606f7c 100644 --- a/pkg/pool/pool.go +++ b/pkg/pool/pool.go @@ -17,6 +17,18 @@ func GetBuffer() *bytes.Buffer { return p.Get().(*bytes.Buffer) } +func GetBufferN(n int64) *bytes.Buffer { + if n <= 0 { + return GetBuffer() + } + buf := GetBuffer() + delta := buf.Cap() - int(n) + if delta < 0 { + buf.Grow(-delta) + } + return buf +} + func PutBuffer(buf *bytes.Buffer) { buf.Reset() p.Put(buf) From 5742f2c4bdb6a2ac20ccc255883a98134dc99083 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Wed, 22 Dec 2021 13:33:00 +0100 Subject: [PATCH 15/92] Pass an internal interface --- delivery/http/controller.go | 2 +- domain/service/mock.go | 2 +- infrastructure/compressor/imaginary.go | 2 +- infrastructure/compressor/mock.go | 2 +- infrastructure/compressor/shortpixel.go | 4 ++-- infrastructure/storage/minio.go | 5 ++--- infrastructure/storage/mock.go | 6 ++---- 7 files changed, 10 insertions(+), 13 deletions(-) diff --git a/delivery/http/controller.go b/delivery/http/controller.go index 93d8f2f..e711840 100644 --- a/delivery/http/controller.go +++ b/delivery/http/controller.go @@ -274,7 +274,7 @@ func (c *controller) handleImage() httprouter.Handle { panic(errors.Wrap(domain.ErrUnknown)) } }() - _, err := io.Copy(w, resp.f) + _, err := io.Copy(w, resp.f.Reader) if err != nil { return errors.Wrap(err) } diff --git a/domain/service/mock.go b/domain/service/mock.go index 152622e..c291d24 100644 --- a/domain/service/mock.go +++ b/domain/service/mock.go @@ -48,7 +48,7 @@ func (m *Mock) Image(_ context.Context, _ uint64) (model.File, error) { } f := Png() buf := pool.GetBufferN(f.Size) - n, err := io.Copy(buf, f) + n, err := io.Copy(buf, f.Reader) if err != nil { return model.File{}, errors.Wrap(err) } diff --git a/infrastructure/compressor/imaginary.go b/infrastructure/compressor/imaginary.go index 8e0b00f..3a46ae7 100644 --- a/infrastructure/compressor/imaginary.go +++ b/infrastructure/compressor/imaginary.go @@ -81,7 +81,7 @@ func (im *Imaginary) Compress(ctx context.Context, f model.File) (model.File, er if err != nil { return model.File{}, errors.Wrap(err) } - n, err := io.Copy(part, tee) + n, err := io.Copy(part, tee.Reader) if err != nil { return model.File{}, errors.Wrap(err) } diff --git a/infrastructure/compressor/mock.go b/infrastructure/compressor/mock.go index b5140b0..aba5f87 100644 --- a/infrastructure/compressor/mock.go +++ b/infrastructure/compressor/mock.go @@ -35,7 +35,7 @@ func (m *Mock) Compress(_ context.Context, f model.File) (model.File, error) { } }() buf := pool.GetBufferN(f.Size) - n, err := io.Copy(buf, f) + n, err := io.Copy(buf, f.Reader) if err != nil { return model.File{}, errors.Wrap(err) } diff --git a/infrastructure/compressor/shortpixel.go b/infrastructure/compressor/shortpixel.go index 32ae315..b60508a 100644 --- a/infrastructure/compressor/shortpixel.go +++ b/infrastructure/compressor/shortpixel.go @@ -90,7 +90,7 @@ func (sp *Shortpixel) Compress(ctx context.Context, f model.File) (model.File, e }() if atomic.LoadUint32(&sp.done) != 0 { buf := pool.GetBufferN(f.Size) - n, err := io.Copy(buf, f) + n, err := io.Copy(buf, f.Reader) if err != nil { return model.File{}, errors.Wrap(err) } @@ -169,7 +169,7 @@ func (sp *Shortpixel) upload(ctx context.Context, f model.File) (string, error) if err != nil { return "", errors.Wrap(err) } - _, err = io.Copy(part, f) + _, err = io.Copy(part, f.Reader) if err != nil { return "", errors.Wrap(err) } diff --git a/infrastructure/storage/minio.go b/infrastructure/storage/minio.go index 86afcac..f5d6c2d 100644 --- a/infrastructure/storage/minio.go +++ b/infrastructure/storage/minio.go @@ -1,7 +1,6 @@ package storage import ( - "bufio" "bytes" "context" "io" @@ -127,8 +126,7 @@ func (m *Minio) Put(ctx context.Context, album uint64, image uint64, f model.Fil albumB64 := base64.FromUint64(album) imageB64 := base64.FromUint64(image) filename := "albums/" + albumB64 + "/images/" + imageB64 - buf := bufio.NewReader(f) - _, err := m.client.PutObject(ctx, "aye-and-nay", filename, buf, f.Size, minios3.PutObjectOptions{}) + _, err := m.client.PutObject(ctx, "aye-and-nay", filename, f.Reader, f.Size, minios3.PutObjectOptions{}) if err != nil { return "", errors.Wrap(err) } @@ -144,6 +142,7 @@ func (m *Minio) Get(ctx context.Context, album uint64, image uint64) (model.File if err != nil { return model.File{}, errors.Wrap(err) } + defer obj.Close() info, err := obj.Stat() if err != nil { return model.File{}, errors.Wrap(err) diff --git a/infrastructure/storage/mock.go b/infrastructure/storage/mock.go index 66bd0e5..c1c32df 100644 --- a/infrastructure/storage/mock.go +++ b/infrastructure/storage/mock.go @@ -1,7 +1,6 @@ package storage import ( - "bufio" "bytes" "context" "io" @@ -40,8 +39,7 @@ func (m *Mock) Put(_ context.Context, album uint64, image uint64, f model.File) albumB64 := base64.FromUint64(album) imageB64 := base64.FromUint64(image) filename := "albums/" + albumB64 + "/images/" + imageB64 - buf := bufio.NewReader(f) - _, _ = io.Copy(io.Discard, buf) + _, _ = io.Copy(io.Discard, f.Reader) src := "/aye-and-nay/" + filename return src, nil } @@ -49,7 +47,7 @@ func (m *Mock) Put(_ context.Context, album uint64, image uint64, f model.File) func (m *Mock) Get(_ context.Context, _ uint64, _ uint64) (model.File, error) { f := Png() buf := pool.GetBufferN(f.Size) - n, err := io.Copy(buf, f) + n, err := io.Copy(buf, f.Reader) if err != nil { return model.File{}, errors.Wrap(err) } From f8827aff86bf6fa351d604ec2c897d0243096957 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Thu, 23 Dec 2021 00:02:03 +0100 Subject: [PATCH 16/92] Attach instructions on how to close file --- delivery/http/controller.go | 34 ++++++++++++------------- domain/model/file.go | 14 +++++++++- infrastructure/compressor/imaginary.go | 22 +++++----------- infrastructure/compressor/mock.go | 24 +++++------------ infrastructure/compressor/shortpixel.go | 22 +++++----------- infrastructure/storage/minio.go | 24 +++++------------ infrastructure/storage/mock.go | 24 +++++------------ 7 files changed, 59 insertions(+), 105 deletions(-) diff --git a/delivery/http/controller.go b/delivery/http/controller.go index e711840..8f41ded 100644 --- a/delivery/http/controller.go +++ b/delivery/http/controller.go @@ -1,7 +1,6 @@ package http import ( - "bytes" "context" "encoding/json" "io" @@ -17,7 +16,6 @@ import ( "github.com/zitryss/aye-and-nay/domain/model" "github.com/zitryss/aye-and-nay/pkg/base64" "github.com/zitryss/aye-and-nay/pkg/errors" - "github.com/zitryss/aye-and-nay/pkg/pool" ) func newController( @@ -57,7 +55,7 @@ func (c *controller) handleAlbum() httprouter.Handle { req := albumRequest{ff: make([]model.File, 0, len(fhs)), multi: r.MultipartForm} defer func() { for _, f := range req.ff { - _ = f.Reader.(io.Closer).Close() + _ = f.Close() } _ = req.multi.RemoveAll() }() @@ -85,7 +83,19 @@ func (c *controller) handleAlbum() httprouter.Handle { _ = f.Close() return nil, albumRequest{}, errors.Wrap(domain.ErrNotImage) } - req.ff = append(req.ff, model.File{Reader: f, Size: fh.Size}) + closeFn := func() error { + switch v := f.(type) { + case *os.File: + _ = v.Close() + _ = os.Remove(v.Name()) + case multipart.File: + _ = v.Close() + default: + panic(errors.Wrap(domain.ErrUnknown)) + } + return nil + } + req.ff = append(req.ff, model.NewFile(f, closeFn, fh.Size)) } vals := r.MultipartForm.Value["duration"] if len(vals) == 0 { @@ -101,7 +111,7 @@ func (c *controller) handleAlbum() httprouter.Handle { process := func(ctx context.Context, req albumRequest) (albumResponse, error) { defer func() { for _, f := range req.ff { - _ = f.Reader.(io.Closer).Close() + _ = f.Close() } _ = req.multi.RemoveAll() }() @@ -261,19 +271,7 @@ func (c *controller) handleImage() httprouter.Handle { return resp, nil } output := func(ctx context.Context, w http.ResponseWriter, resp imageResponse) error { - defer func() { - switch v := resp.f.Reader.(type) { - case *os.File: - _ = v.Close() - _ = os.Remove(v.Name()) - case multipart.File: - _ = v.Close() - case *bytes.Buffer: - pool.PutBuffer(v) - default: - panic(errors.Wrap(domain.ErrUnknown)) - } - }() + defer resp.f.Close() _, err := io.Copy(w, resp.f.Reader) if err != nil { return errors.Wrap(err) diff --git a/domain/model/file.go b/domain/model/file.go index 6074086..b21f318 100644 --- a/domain/model/file.go +++ b/domain/model/file.go @@ -4,7 +4,19 @@ import ( "io" ) +func NewFile(reader io.Reader, close func() error, size int64) File { + return File{reader, close, size} +} + type File struct { io.Reader - Size int64 + close func() error + Size int64 +} + +func (f File) Close() error { + if f.close == nil { + return nil + } + return f.close() } diff --git a/infrastructure/compressor/imaginary.go b/infrastructure/compressor/imaginary.go index 3a46ae7..7364673 100644 --- a/infrastructure/compressor/imaginary.go +++ b/infrastructure/compressor/imaginary.go @@ -1,12 +1,10 @@ package compressor import ( - "bytes" "context" "io" "mime/multipart" "net/http" - "os" "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/model" @@ -56,19 +54,7 @@ type Imaginary struct { } func (im *Imaginary) Compress(ctx context.Context, f model.File) (model.File, error) { - defer func() { - switch v := f.Reader.(type) { - case *os.File: - _ = v.Close() - _ = os.Remove(v.Name()) - case multipart.File: - _ = v.Close() - case *bytes.Buffer: - pool.PutBuffer(v) - default: - panic(errors.Wrap(domain.ErrUnknown)) - } - }() + defer f.Close() buf := pool.GetBufferN(f.Size) tee := model.File{ Reader: io.TeeReader(f.Reader, buf), @@ -131,5 +117,9 @@ func (im *Imaginary) Compress(ctx context.Context, f model.File) (model.File, er if err != nil { return model.File{}, errors.Wrap(err) } - return model.File{Reader: buf, Size: n}, nil + closeFn := func() error { + pool.PutBuffer(buf) + return nil + } + return model.NewFile(buf, closeFn, n), nil } diff --git a/infrastructure/compressor/mock.go b/infrastructure/compressor/mock.go index aba5f87..e68e1e0 100644 --- a/infrastructure/compressor/mock.go +++ b/infrastructure/compressor/mock.go @@ -1,13 +1,9 @@ package compressor import ( - "bytes" "context" "io" - "mime/multipart" - "os" - "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/model" "github.com/zitryss/aye-and-nay/pkg/errors" "github.com/zitryss/aye-and-nay/pkg/pool" @@ -21,23 +17,15 @@ type Mock struct { } func (m *Mock) Compress(_ context.Context, f model.File) (model.File, error) { - defer func() { - switch v := f.Reader.(type) { - case *os.File: - _ = v.Close() - _ = os.Remove(v.Name()) - case multipart.File: - _ = v.Close() - case *bytes.Buffer: - pool.PutBuffer(v) - default: - panic(errors.Wrap(domain.ErrUnknown)) - } - }() + defer f.Close() buf := pool.GetBufferN(f.Size) n, err := io.Copy(buf, f.Reader) if err != nil { return model.File{}, errors.Wrap(err) } - return model.File{Reader: buf, Size: n}, nil + closeFn := func() error { + pool.PutBuffer(buf) + return nil + } + return model.NewFile(buf, closeFn, n), nil } diff --git a/infrastructure/compressor/shortpixel.go b/infrastructure/compressor/shortpixel.go index b60508a..a00699b 100644 --- a/infrastructure/compressor/shortpixel.go +++ b/infrastructure/compressor/shortpixel.go @@ -1,13 +1,11 @@ package compressor import ( - "bytes" "context" "encoding/json" "io" "mime/multipart" "net/http" - "os" "sync/atomic" "time" @@ -75,19 +73,7 @@ func (sp *Shortpixel) Monitor() { } func (sp *Shortpixel) Compress(ctx context.Context, f model.File) (model.File, error) { - defer func() { - switch v := f.Reader.(type) { - case *os.File: - _ = v.Close() - _ = os.Remove(v.Name()) - case multipart.File: - _ = v.Close() - case *bytes.Buffer: - pool.PutBuffer(v) - default: - panic(errors.Wrap(domain.ErrUnknown)) - } - }() + defer f.Close() if atomic.LoadUint32(&sp.done) != 0 { buf := pool.GetBufferN(f.Size) n, err := io.Copy(buf, f.Reader) @@ -371,5 +357,9 @@ func (sp *Shortpixel) download(ctx context.Context, src string) (model.File, err if err != nil { return model.File{}, errors.Wrap(err) } - return model.File{Reader: buf, Size: n}, nil + closeFn := func() error { + pool.PutBuffer(buf) + return nil + } + return model.NewFile(buf, closeFn, n), nil } diff --git a/infrastructure/storage/minio.go b/infrastructure/storage/minio.go index f5d6c2d..7397ab1 100644 --- a/infrastructure/storage/minio.go +++ b/infrastructure/storage/minio.go @@ -1,17 +1,13 @@ package storage import ( - "bytes" "context" "io" - "mime/multipart" "net/http" - "os" minios3 "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" - "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/model" "github.com/zitryss/aye-and-nay/pkg/base64" "github.com/zitryss/aye-and-nay/pkg/errors" @@ -110,19 +106,7 @@ type Minio struct { } func (m *Minio) Put(ctx context.Context, album uint64, image uint64, f model.File) (string, error) { - defer func() { - switch v := f.Reader.(type) { - case *os.File: - _ = v.Close() - _ = os.Remove(v.Name()) - case multipart.File: - _ = v.Close() - case *bytes.Buffer: - pool.PutBuffer(v) - default: - panic(errors.Wrap(domain.ErrUnknown)) - } - }() + defer f.Close() albumB64 := base64.FromUint64(album) imageB64 := base64.FromUint64(image) filename := "albums/" + albumB64 + "/images/" + imageB64 @@ -152,7 +136,11 @@ func (m *Minio) Get(ctx context.Context, album uint64, image uint64) (model.File if err != nil { return model.File{}, errors.Wrap(err) } - return model.File{Reader: buf, Size: n}, nil + closeFn := func() error { + pool.PutBuffer(buf) + return nil + } + return model.NewFile(buf, closeFn, n), nil } func (m *Minio) Remove(ctx context.Context, album uint64, image uint64) error { diff --git a/infrastructure/storage/mock.go b/infrastructure/storage/mock.go index c1c32df..724a22f 100644 --- a/infrastructure/storage/mock.go +++ b/infrastructure/storage/mock.go @@ -1,13 +1,9 @@ package storage import ( - "bytes" "context" "io" - "mime/multipart" - "os" - "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/model" . "github.com/zitryss/aye-and-nay/internal/testing" "github.com/zitryss/aye-and-nay/pkg/base64" @@ -23,19 +19,7 @@ type Mock struct { } func (m *Mock) Put(_ context.Context, album uint64, image uint64, f model.File) (string, error) { - defer func() { - switch v := f.Reader.(type) { - case *os.File: - _ = v.Close() - _ = os.Remove(v.Name()) - case multipart.File: - _ = v.Close() - case *bytes.Buffer: - pool.PutBuffer(v) - default: - panic(errors.Wrap(domain.ErrUnknown)) - } - }() + defer f.Close() albumB64 := base64.FromUint64(album) imageB64 := base64.FromUint64(image) filename := "albums/" + albumB64 + "/images/" + imageB64 @@ -51,7 +35,11 @@ func (m *Mock) Get(_ context.Context, _ uint64, _ uint64) (model.File, error) { if err != nil { return model.File{}, errors.Wrap(err) } - return model.File{Reader: buf, Size: n}, nil + closeFn := func() error { + pool.PutBuffer(buf) + return nil + } + return model.NewFile(buf, closeFn, n), nil } func (m *Mock) Remove(_ context.Context, _ uint64, _ uint64) error { From 45f17b46b1f4d8c1f683ed17ed320f727b517fa1 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sun, 26 Dec 2021 20:42:05 +0100 Subject: [PATCH 17/92] Provide health endpoint --- delivery/http/controller.go | 12 +++ delivery/http/router.go | 1 + domain/domain/error.go | 46 +++++++++- domain/domain/interface.go | 9 ++ domain/service/mock.go | 4 + domain/service/service.go | 22 +++++ infrastructure/cache/mem.go | 4 + infrastructure/cache/redis.go | 13 ++- infrastructure/compressor/compressor.go | 4 +- infrastructure/compressor/imaginary.go | 51 +++++++----- infrastructure/compressor/mock.go | 4 + infrastructure/compressor/shortpixel.go | 12 ++- infrastructure/database/badger.go | 4 + infrastructure/database/mem.go | 4 + infrastructure/database/mongo.go | 27 ++++-- infrastructure/storage/minio.go | 106 +++++++++++++----------- infrastructure/storage/mock.go | 4 + 17 files changed, 243 insertions(+), 84 deletions(-) diff --git a/delivery/http/controller.go b/delivery/http/controller.go index 8f41ded..96fbd46 100644 --- a/delivery/http/controller.go +++ b/delivery/http/controller.go @@ -404,3 +404,15 @@ func (c *controller) handleTop() httprouter.Handle { }, ) } + +func (c *controller) handleHealth() httprouter.Handle { + return handleHttpRouterError( + func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) error { + _, err := c.serv.Health(r.Context()) + if err != nil { + return errors.Wrap(err) + } + return nil + }, + ) +} diff --git a/delivery/http/router.go b/delivery/http/router.go index c336a75..e1f2486 100644 --- a/delivery/http/router.go +++ b/delivery/http/router.go @@ -14,5 +14,6 @@ func newRouter(contr controller) http.Handler { router.GET("/api/images/:token/", contr.handleImage()) router.PATCH("/api/albums/:album/vote/", contr.handleVote()) router.GET("/api/albums/:album/top/", contr.handleTop()) + router.GET("/api/health/", contr.handleHealth()) return router } diff --git a/domain/domain/error.go b/domain/domain/error.go index 7f56197..5cfba1b 100644 --- a/domain/domain/error.go +++ b/domain/domain/error.go @@ -198,7 +198,51 @@ var ( }, innerError: innerError{ Level: lcritical, - DevMsg: "third party unavailable", + DevMsg: "third party is unavailable", + }, + } + ErrBadHealthCompressor = &domainError{ + outerError: outerError{ + StatusCode: http.StatusInternalServerError, + AppCode: 0x11, + UserMsg: "internal server error", + }, + innerError: innerError{ + Level: lcritical, + DevMsg: "compressor is unavailable", + }, + } + ErrBadHealthStorage = &domainError{ + outerError: outerError{ + StatusCode: http.StatusInternalServerError, + AppCode: 0x12, + UserMsg: "internal server error", + }, + innerError: innerError{ + Level: lcritical, + DevMsg: "storage is unavailable", + }, + } + ErrBadHealthDatabase = &domainError{ + outerError: outerError{ + StatusCode: http.StatusInternalServerError, + AppCode: 0x13, + UserMsg: "internal server error", + }, + innerError: innerError{ + Level: lcritical, + DevMsg: "database is unavailable", + }, + } + ErrBadHealthCache = &domainError{ + outerError: outerError{ + StatusCode: http.StatusInternalServerError, + AppCode: 0x14, + UserMsg: "internal server error", + }, + innerError: innerError{ + Level: lcritical, + DevMsg: "cache is unavailable", }, } ErrUnknown = &domainError{ diff --git a/domain/domain/interface.go b/domain/domain/interface.go index 58a4967..b2a8b96 100644 --- a/domain/domain/interface.go +++ b/domain/domain/interface.go @@ -14,16 +14,19 @@ type Servicer interface { Vote(ctx context.Context, album uint64, tokenFrom uint64, tokenTo uint64) error Top(ctx context.Context, album uint64) ([]model.Image, error) Progress(ctx context.Context, album uint64) (float64, error) + Checker } type Compresser interface { Compress(ctx context.Context, f model.File) (model.File, error) + Checker } type Storager interface { Put(ctx context.Context, album uint64, image uint64, f model.File) (string, error) Get(ctx context.Context, album uint64, image uint64) (model.File, error) Remove(ctx context.Context, album uint64, image uint64) error + Checker } type Databaser interface { @@ -39,6 +42,7 @@ type Databaser interface { GetImagesOrdered(ctx context.Context, album uint64) ([]model.Image, error) DeleteAlbum(ctx context.Context, album uint64) error AlbumsToBeDeleted(ctx context.Context) ([]model.Album, error) + Checker } type Cacher interface { @@ -47,6 +51,7 @@ type Cacher interface { PQueuer Stacker Tokener + Checker } type Limiter interface { @@ -75,3 +80,7 @@ type Tokener interface { Get(ctx context.Context, token uint64) (uint64, uint64, error) Del(ctx context.Context, token uint64) error } + +type Checker interface { + Health(ctx context.Context) (bool, error) +} diff --git a/domain/service/mock.go b/domain/service/mock.go index c291d24..8728e19 100644 --- a/domain/service/mock.go +++ b/domain/service/mock.go @@ -71,3 +71,7 @@ func (m *Mock) Top(_ context.Context, _ uint64) ([]model.Image, error) { imgs := []model.Image{img1, img2} return imgs, nil } + +func (m *Mock) Health(_ context.Context) (bool, error) { + return true, nil +} diff --git a/domain/service/service.go b/domain/service/service.go index c2aafb1..cc8afa1 100644 --- a/domain/service/service.go +++ b/domain/service/service.go @@ -30,6 +30,7 @@ func New( pers: pers, pair: temp, token: temp, + cache: temp, queue: struct { calc *QueueCalc comp *QueueComp @@ -116,6 +117,7 @@ type Service struct { pers domain.Databaser pair domain.Stacker token domain.Tokener + cache domain.Checker queue struct { calc *QueueCalc comp *QueueComp @@ -313,6 +315,26 @@ func (s *Service) Top(ctx context.Context, album uint64) ([]model.Image, error) return imgs, nil } +func (s *Service) Health(ctx context.Context) (bool, error) { + _, err := s.comp.Health(ctx) + if err != nil { + return false, errors.Wrap(err) + } + _, err = s.stor.Health(ctx) + if err != nil { + return false, errors.Wrap(err) + } + _, err = s.pers.Health(ctx) + if err != nil { + return false, errors.Wrap(err) + } + _, err = s.cache.Health(ctx) + if err != nil { + return false, errors.Wrap(err) + } + return true, nil +} + func (s *Service) CleanUp(ctx context.Context) error { albs, err := s.pers.AlbumsToBeDeleted(ctx) if err != nil { diff --git a/infrastructure/cache/mem.go b/infrastructure/cache/mem.go index 94e199c..2fc2af1 100644 --- a/infrastructure/cache/mem.go +++ b/infrastructure/cache/mem.go @@ -321,3 +321,7 @@ func (m *Mem) Del(_ context.Context, token uint64) error { delete(m.tokens, token) return nil } + +func (m *Mem) Health(_ context.Context) (bool, error) { + return true, nil +} diff --git a/infrastructure/cache/redis.go b/infrastructure/cache/redis.go index 93dd0f9..f1b4edd 100644 --- a/infrastructure/cache/redis.go +++ b/infrastructure/cache/redis.go @@ -17,10 +17,11 @@ import ( func NewRedis() (*Redis, error) { conf := newRedisConfig() client := redisdb.NewClient(&redisdb.Options{Addr: conf.host + ":" + conf.port}) + r := &Redis{conf, client} ctx, cancel := context.WithTimeout(context.Background(), conf.timeout) defer cancel() err := retry.Do(conf.times, conf.pause, func() error { - err := client.Ping(ctx).Err() + _, err := r.Health(ctx) if err != nil { return errors.Wrap(err) } @@ -29,7 +30,7 @@ func NewRedis() (*Redis, error) { if err != nil { return &Redis{}, errors.Wrap(err) } - return &Redis{conf, client}, nil + return r, nil } type Redis struct { @@ -256,6 +257,14 @@ func (r *Redis) Del(ctx context.Context, token uint64) error { return nil } +func (r *Redis) Health(ctx context.Context) (bool, error) { + err := r.client.Ping(ctx).Err() + if err != nil { + return false, errors.Wrapf(domain.ErrBadHealthCache, "%s", err) + } + return true, nil +} + func (r *Redis) Close() error { err := r.client.Close() if err != nil { diff --git a/infrastructure/compressor/compressor.go b/infrastructure/compressor/compressor.go index 2d04c6f..9ff55ff 100644 --- a/infrastructure/compressor/compressor.go +++ b/infrastructure/compressor/compressor.go @@ -1,6 +1,8 @@ package compressor import ( + "context" + "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/pkg/log" ) @@ -13,7 +15,7 @@ func New(s string) (domain.Compresser, error) { case "shortpixel": log.Info("connecting to compressor") sp := NewShortPixel() - err := sp.Ping() + err := sp.Ping(context.Background()) if err != nil { return nil, err } diff --git a/infrastructure/compressor/imaginary.go b/infrastructure/compressor/imaginary.go index 7364673..d246025 100644 --- a/infrastructure/compressor/imaginary.go +++ b/infrastructure/compressor/imaginary.go @@ -15,38 +15,20 @@ import ( func NewImaginary() (*Imaginary, error) { conf := newImaginaryConfig() + im := &Imaginary{conf} ctx, cancel := context.WithTimeout(context.Background(), conf.timeout) defer cancel() err := retry.Do(conf.times, conf.pause, func() error { - url := "http://" + conf.host + ":" + conf.port + "/health" - body := io.Reader(nil) - req, err := http.NewRequestWithContext(ctx, "GET", url, body) + _, err := im.Health(ctx) if err != nil { return errors.Wrap(err) } - c := http.Client{} - resp, err := c.Do(req) - if err != nil { - return errors.Wrap(err) - } - _, err = io.Copy(io.Discard, resp.Body) - if err != nil { - _ = resp.Body.Close() - return errors.Wrap(err) - } - err = resp.Body.Close() - if err != nil { - return errors.Wrap(err) - } - if resp.StatusCode < 200 || resp.StatusCode > 299 { - return errors.Wrap(errors.New("no connection to imaginary")) - } return nil }) if err != nil { return &Imaginary{}, errors.Wrap(err) } - return &Imaginary{conf}, nil + return im, nil } type Imaginary struct { @@ -123,3 +105,30 @@ func (im *Imaginary) Compress(ctx context.Context, f model.File) (model.File, er } return model.NewFile(buf, closeFn, n), nil } + +func (im *Imaginary) Health(ctx context.Context) (bool, error) { + url := "http://" + im.conf.host + ":" + im.conf.port + "/health" + body := io.Reader(nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, body) + if err != nil { + return false, errors.Wrapf(domain.ErrBadHealthCompressor, "%s", err) + } + c := http.Client{Timeout: im.conf.timeout} + resp, err := c.Do(req) + if err != nil { + return false, errors.Wrapf(domain.ErrBadHealthCompressor, "%s", err) + } + _, err = io.Copy(io.Discard, resp.Body) + if err != nil { + _ = resp.Body.Close() + return false, errors.Wrapf(domain.ErrBadHealthCompressor, "%s", err) + } + err = resp.Body.Close() + if err != nil { + return false, errors.Wrapf(domain.ErrBadHealthCompressor, "%s", err) + } + if resp.StatusCode < 200 || resp.StatusCode > 299 { + return false, errors.Wrapf(domain.ErrBadHealthCompressor, "%s", "no connection to imaginary") + } + return true, nil +} diff --git a/infrastructure/compressor/mock.go b/infrastructure/compressor/mock.go index e68e1e0..2d888ea 100644 --- a/infrastructure/compressor/mock.go +++ b/infrastructure/compressor/mock.go @@ -29,3 +29,7 @@ func (m *Mock) Compress(_ context.Context, f model.File) (model.File, error) { } return model.NewFile(buf, closeFn, n), nil } + +func (m *Mock) Health(_ context.Context) (bool, error) { + return true, nil +} diff --git a/infrastructure/compressor/shortpixel.go b/infrastructure/compressor/shortpixel.go index a00699b..6efaa81 100644 --- a/infrastructure/compressor/shortpixel.go +++ b/infrastructure/compressor/shortpixel.go @@ -46,8 +46,8 @@ type Shortpixel struct { } } -func (sp *Shortpixel) Ping() error { - ctx, cancel := context.WithTimeout(context.Background(), sp.conf.timeout) +func (sp *Shortpixel) Ping(ctx context.Context) error { + ctx, cancel := context.WithTimeout(ctx, sp.conf.timeout) defer cancel() _, err := sp.upload(ctx, Png()) if err != nil { @@ -363,3 +363,11 @@ func (sp *Shortpixel) download(ctx context.Context, src string) (model.File, err } return model.NewFile(buf, closeFn, n), nil } + +func (sp *Shortpixel) Health(ctx context.Context) (bool, error) { + err := sp.Ping(ctx) + if err != nil { + return false, errors.Wrapf(domain.ErrBadHealthCompressor, "%s", err) + } + return true, nil +} diff --git a/infrastructure/database/badger.go b/infrastructure/database/badger.go index ff7ae81..8d54c8d 100644 --- a/infrastructure/database/badger.go +++ b/infrastructure/database/badger.go @@ -345,6 +345,10 @@ func (b *Badger) lruAdd(album uint64) error { return nil } +func (b *Badger) Health(_ context.Context) (bool, error) { + return true, nil +} + func (b *Badger) Close() error { err := b.db.Close() if err != nil { diff --git a/infrastructure/database/mem.go b/infrastructure/database/mem.go index 34a6bc8..12f23d3 100644 --- a/infrastructure/database/mem.go +++ b/infrastructure/database/mem.go @@ -215,3 +215,7 @@ func (m *Mem) AlbumsToBeDeleted(_ context.Context) ([]model.Album, error) { } return albs, nil } + +func (m *Mem) Health(_ context.Context) (bool, error) { + return true, nil +} diff --git a/infrastructure/database/mongo.go b/infrastructure/database/mongo.go index 634ff75..cc5413f 100644 --- a/infrastructure/database/mongo.go +++ b/infrastructure/database/mongo.go @@ -44,8 +44,16 @@ func NewMongo() (*Mongo, error) { if err != nil { return &Mongo{}, errors.Wrap(err) } + db := client.Database("aye-and-nay") + images := db.Collection("images") + edges := db.Collection("edges") + cache, err := lru.New(conf.lru) + if err != nil { + return &Mongo{}, errors.Wrap(err) + } + m := &Mongo{conf, client, db, images, edges, cache} err = retry.Do(conf.times, conf.pause, func() error { - err := client.Ping(ctx, readpref.Primary()) + _, err := m.Health(ctx) if err != nil { return errors.Wrap(err) } @@ -54,14 +62,7 @@ func NewMongo() (*Mongo, error) { if err != nil { return &Mongo{}, errors.Wrap(err) } - db := client.Database("aye-and-nay") - images := db.Collection("images") - edges := db.Collection("edges") - cache, err := lru.New(conf.lru) - if err != nil { - return &Mongo{}, errors.Wrap(err) - } - return &Mongo{conf, client, db, images, edges, cache}, nil + return m, nil } type Mongo struct { @@ -341,6 +342,14 @@ func (m *Mongo) lruAdd(ctx context.Context, album uint64) error { return nil } +func (m *Mongo) Health(ctx context.Context) (bool, error) { + err := m.client.Ping(ctx, readpref.Primary()) + if err != nil { + return false, errors.Wrapf(domain.ErrBadHealthDatabase, "%s", err) + } + return true, err +} + func (m *Mongo) Close() error { ctx, cancel := context.WithTimeout(context.Background(), m.conf.timeout) defer cancel() diff --git a/infrastructure/storage/minio.go b/infrastructure/storage/minio.go index 7397ab1..e4ed851 100644 --- a/infrastructure/storage/minio.go +++ b/infrastructure/storage/minio.go @@ -8,6 +8,7 @@ import ( minios3 "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" + "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/model" "github.com/zitryss/aye-and-nay/pkg/base64" "github.com/zitryss/aye-and-nay/pkg/errors" @@ -24,56 +25,11 @@ func NewMinio() (*Minio, error) { if err != nil { return &Minio{}, errors.Wrap(err) } + m := &Minio{conf, client} ctx, cancel := context.WithTimeout(context.Background(), conf.timeout) defer cancel() err = retry.Do(conf.times, conf.pause, func() error { - c := http.Client{} - url := "http://" + conf.host + ":" + conf.port + "/minio/health/live" - body := io.Reader(nil) - req, err := http.NewRequestWithContext(ctx, "GET", url, body) - if err != nil { - return errors.Wrap(err) - } - resp, err := c.Do(req) - if err != nil { - return errors.Wrap(err) - } - _, err = io.Copy(io.Discard, resp.Body) - if err != nil { - _ = resp.Body.Close() - return errors.Wrap(err) - } - err = resp.Body.Close() - if err != nil { - return errors.Wrap(err) - } - if resp.StatusCode < 200 || resp.StatusCode > 299 { - return errors.Wrap(errors.New("no connection to minio")) - } - c = http.Client{} - url = "http://" + conf.host + ":" + conf.port + "/minio/health/ready" - body = io.Reader(nil) - req, err = http.NewRequestWithContext(ctx, "GET", url, body) - if err != nil { - return errors.Wrap(err) - } - resp, err = c.Do(req) - if err != nil { - return errors.Wrap(err) - } - _, err = io.Copy(io.Discard, resp.Body) - if err != nil { - _ = resp.Body.Close() - return errors.Wrap(err) - } - err = resp.Body.Close() - if err != nil { - return errors.Wrap(err) - } - if resp.StatusCode < 200 || resp.StatusCode > 299 { - return errors.Wrap(errors.New("minio is not ready")) - } - _, err = client.ListBuckets(ctx) + _, err := m.Health(ctx) if err != nil { return errors.Wrap(err) } @@ -97,7 +53,7 @@ func NewMinio() (*Minio, error) { return &Minio{}, errors.Wrap(err) } } - return &Minio{conf, client}, nil + return m, nil } type Minio struct { @@ -153,3 +109,57 @@ func (m *Minio) Remove(ctx context.Context, album uint64, image uint64) error { } return nil } + +func (m *Minio) Health(ctx context.Context) (bool, error) { + url := "http://" + m.conf.host + ":" + m.conf.port + "/minio/health/live" + body := io.Reader(nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, body) + if err != nil { + return false, errors.Wrapf(domain.ErrBadHealthStorage, "%s", err) + } + c := http.Client{Timeout: m.conf.timeout} + resp, err := c.Do(req) + if err != nil { + return false, errors.Wrapf(domain.ErrBadHealthStorage, "%s", err) + } + _, err = io.Copy(io.Discard, resp.Body) + if err != nil { + _ = resp.Body.Close() + return false, errors.Wrapf(domain.ErrBadHealthStorage, "%s", err) + } + err = resp.Body.Close() + if err != nil { + return false, errors.Wrapf(domain.ErrBadHealthStorage, "%s", err) + } + if resp.StatusCode < 200 || resp.StatusCode > 299 { + return false, errors.Wrapf(domain.ErrBadHealthStorage, "%s", "no connection to minio") + } + url = "http://" + m.conf.host + ":" + m.conf.port + "/minio/health/ready" + body = io.Reader(nil) + req, err = http.NewRequestWithContext(ctx, http.MethodGet, url, body) + if err != nil { + return false, errors.Wrapf(domain.ErrBadHealthStorage, "%s", err) + } + c = http.Client{Timeout: m.conf.timeout} + resp, err = c.Do(req) + if err != nil { + return false, errors.Wrapf(domain.ErrBadHealthStorage, "%s", err) + } + _, err = io.Copy(io.Discard, resp.Body) + if err != nil { + _ = resp.Body.Close() + return false, errors.Wrapf(domain.ErrBadHealthStorage, "%s", err) + } + err = resp.Body.Close() + if err != nil { + return false, errors.Wrapf(domain.ErrBadHealthStorage, "%s", err) + } + if resp.StatusCode < 200 || resp.StatusCode > 299 { + return false, errors.Wrapf(domain.ErrBadHealthStorage, "%s", "minio is not ready") + } + _, err = m.client.ListBuckets(ctx) + if err != nil { + return false, errors.Wrapf(domain.ErrBadHealthStorage, "%s", err) + } + return true, nil +} diff --git a/infrastructure/storage/mock.go b/infrastructure/storage/mock.go index 724a22f..d0e7ed2 100644 --- a/infrastructure/storage/mock.go +++ b/infrastructure/storage/mock.go @@ -45,3 +45,7 @@ func (m *Mock) Get(_ context.Context, _ uint64, _ uint64) (model.File, error) { func (m *Mock) Remove(_ context.Context, _ uint64, _ uint64) error { return nil } + +func (m *Mock) Health(_ context.Context) (bool, error) { + return true, nil +} From 795bfeb7efd1f2f3cf007fba86ce05b4dc341a2a Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sun, 26 Dec 2021 20:47:19 +0100 Subject: [PATCH 18/92] Use std contants --- cmd/loadtest/main.go | 14 +++++++------- infrastructure/compressor/imaginary.go | 2 +- infrastructure/compressor/shortpixel.go | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cmd/loadtest/main.go b/cmd/loadtest/main.go index fa95ff6..5cba2da 100644 --- a/cmd/loadtest/main.go +++ b/cmd/loadtest/main.go @@ -115,7 +115,7 @@ func albumHtml() { func albumApi() string { body := bytes.NewReader(b) - req, err := http.NewRequest("POST", apiAddress+"/api/albums/", body) + req, err := http.NewRequest(http.MethodPost, apiAddress+"/api/albums/", body) debug.Check(err) req.Header.Set("Content-Type", sep) @@ -139,7 +139,7 @@ func albumApi() string { } func readyApi(album string) { - req, err := http.NewRequest("GET", apiAddress+"/api/albums/"+album+"/ready/", http.NoBody) + req, err := http.NewRequest(http.MethodGet, apiAddress+"/api/albums/"+album+"/ready/", http.NoBody) debug.Check(err) resp, err := http.DefaultClient.Do(req) @@ -164,7 +164,7 @@ func pairHtml() { } func pairApi(album string) (string, string, string, string) { - req, err := http.NewRequest("GET", apiAddress+"/api/albums/"+album+"/pair/", http.NoBody) + req, err := http.NewRequest(http.MethodGet, apiAddress+"/api/albums/"+album+"/pair/", http.NoBody) debug.Check(err) resp, err := http.DefaultClient.Do(req) @@ -200,7 +200,7 @@ func pairMinio(src1 string, src2 string) { func voteApi(album string, token1 string, token2 string) { body := strings.NewReader("{\"album\":{\"imgFrom\":{\"token\":\"" + token1 + "\"},\"imgTo\":{\"token\":\"" + token2 + "\"}}}") - req, err := http.NewRequest("PATCH", apiAddress+"/api/albums/"+album+"/vote/", body) + req, err := http.NewRequest(http.MethodPatch, apiAddress+"/api/albums/"+album+"/vote/", body) debug.Check(err) req.Header.Set("Content-Type", "application/json; charset=utf-8") @@ -218,7 +218,7 @@ func topHtml() { } func topApi(album string) []string { - req, err := http.NewRequest("GET", apiAddress+"/api/albums/"+album+"/top/", http.NoBody) + req, err := http.NewRequest(http.MethodGet, apiAddress+"/api/albums/"+album+"/top/", http.NoBody) debug.Check(err) resp, err := http.DefaultClient.Do(req) @@ -258,7 +258,7 @@ func html(page string) { if htmlAddress == "" { return } - req, err := http.NewRequest("GET", htmlAddress+page, http.NoBody) + req, err := http.NewRequest(http.MethodGet, htmlAddress+page, http.NoBody) if err != nil { return } @@ -279,7 +279,7 @@ func minio(src string) { if minioAddress == "" && address == "" { return } - req, err := http.NewRequest("GET", address+src, http.NoBody) + req, err := http.NewRequest(http.MethodGet, address+src, http.NoBody) if err != nil { return } diff --git a/infrastructure/compressor/imaginary.go b/infrastructure/compressor/imaginary.go index d246025..e422b9e 100644 --- a/infrastructure/compressor/imaginary.go +++ b/infrastructure/compressor/imaginary.go @@ -58,7 +58,7 @@ func (im *Imaginary) Compress(ctx context.Context, f model.File) (model.File, er return model.File{}, errors.Wrap(err) } url := "http://" + im.conf.host + ":" + im.conf.port + "/convert?type=png&compression=9" - req, err := http.NewRequestWithContext(ctx, "POST", url, body) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, body) if err != nil { return model.File{}, errors.Wrap(err) } diff --git a/infrastructure/compressor/shortpixel.go b/infrastructure/compressor/shortpixel.go index 6efaa81..1d8f3bf 100644 --- a/infrastructure/compressor/shortpixel.go +++ b/infrastructure/compressor/shortpixel.go @@ -164,7 +164,7 @@ func (sp *Shortpixel) upload(ctx context.Context, f model.File) (string, error) return "", errors.Wrap(err) } c := http.Client{Timeout: sp.conf.uploadTimeout} - req, err := http.NewRequestWithContext(ctx, "POST", sp.conf.url, body) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, sp.conf.url, body) if err != nil { return "", errors.Wrap(err) } @@ -259,7 +259,7 @@ func (sp *Shortpixel) repeat(ctx context.Context, src string) (string, error) { return "", errors.Wrap(err) } c := http.Client{Timeout: sp.conf.uploadTimeout} - req, err := http.NewRequestWithContext(ctx, "POST", sp.conf.url2, body) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, sp.conf.url2, body) if err != nil { return "", errors.Wrap(err) } @@ -326,7 +326,7 @@ func (sp *Shortpixel) repeat(ctx context.Context, src string) (string, error) { func (sp *Shortpixel) download(ctx context.Context, src string) (model.File, error) { c := http.Client{Timeout: sp.conf.downloadTimeout} body := io.Reader(nil) - req, err := http.NewRequestWithContext(ctx, "GET", src, body) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, src, body) if err != nil { return model.File{}, errors.Wrap(err) } From 4eadc49b1c3d9a3615b4a42d84a8684994d867f3 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Tue, 28 Dec 2021 15:53:58 +0100 Subject: [PATCH 19/92] Test health endpoint --- build/swagger.yml | 11 +++ cmd/loadtest/main.go | 13 +++ delivery/http/controller_test.go | 80 +++++++++++++++++++ domain/service/mock.go | 3 + domain/service/service_integration_test.go | 32 ++++++++ domain/service/service_test.go | 20 +++++ .../compressor/imaginary_integration_test.go | 11 +++ .../storage/minio_integration_test.go | 11 +++ 8 files changed, 181 insertions(+) diff --git a/build/swagger.yml b/build/swagger.yml index f6efca7..a34ae97 100644 --- a/build/swagger.yml +++ b/build/swagger.yml @@ -104,6 +104,17 @@ paths: $ref: '#/components/responses/InternalServerError' '503': $ref: '#/components/responses/ServiceUnavailable' + /api/health/: + get: + description: > + Returns the health of the service and its dependencies. + responses: + '200': + description: OK + '500': + $ref: '#/components/responses/InternalServerError' + '503': + $ref: '#/components/responses/ServiceUnavailable' components: schemas: Id: diff --git a/cmd/loadtest/main.go b/cmd/loadtest/main.go index 5cba2da..e7c87b4 100644 --- a/cmd/loadtest/main.go +++ b/cmd/loadtest/main.go @@ -76,6 +76,7 @@ func main() { bar.Increment() topMinio(src) } + healthApi() }() } for i := 0; i < connections; i++ { @@ -254,6 +255,18 @@ func topMinio(src []string) { } } +func healthApi() { + req, err := http.NewRequest(http.MethodGet, apiAddress+"/api/health/", http.NoBody) + debug.Check(err) + resp, err := http.DefaultClient.Do(req) + debug.Check(err) + debug.Assert(resp.StatusCode == 200) + _, err = io.Copy(io.Discard, resp.Body) + debug.Check(err) + err = resp.Body.Close() + debug.Check(err) +} + func html(page string) { if htmlAddress == "" { return diff --git a/delivery/http/controller_test.go b/delivery/http/controller_test.go index 712bba6..d4e04c1 100644 --- a/delivery/http/controller_test.go +++ b/delivery/http/controller_test.go @@ -1267,3 +1267,83 @@ func TestControllerHandleTop(t *testing.T) { }) } } + +func TestControllerHandleHealth(t *testing.T) { + type give struct { + err error + } + type want struct { + code int + typ string + body string + } + tests := []struct { + give + want + }{ + { + give: give{ + err: nil, + }, + want: want{ + code: 200, + typ: "", + body: ``, + }, + }, + { + give: give{ + err: domain.ErrBadHealthCompressor, + }, + want: want{ + code: 500, + typ: "application/json; charset=utf-8", + body: `{"error":{"code":17,"msg":"internal server error"}}` + "\n", + }, + }, + { + give: give{ + err: domain.ErrBadHealthStorage, + }, + want: want{ + code: 500, + typ: "application/json; charset=utf-8", + body: `{"error":{"code":18,"msg":"internal server error"}}` + "\n", + }, + }, + { + give: give{ + err: domain.ErrBadHealthDatabase, + }, + want: want{ + code: 500, + typ: "application/json; charset=utf-8", + body: `{"error":{"code":19,"msg":"internal server error"}}` + "\n", + }, + }, + { + give: give{ + err: domain.ErrBadHealthCache, + }, + want: want{ + code: 500, + typ: "application/json; charset=utf-8", + body: `{"error":{"code":20,"msg":"internal server error"}}` + "\n", + }, + }, + } + for _, tt := range tests { + t.Run("", func(t *testing.T) { + serv := service.NewMock(tt.give.err) + contr := newController(serv) + fn := contr.handleHealth() + w := httptest.NewRecorder() + r := httptest.NewRequest(http.MethodGet, "/api/health/", http.NoBody) + ps := httprouter.Params{} + fn(w, r, ps) + CheckStatusCode(t, w, tt.want.code) + CheckContentType(t, w, tt.want.typ) + CheckBody(t, w, tt.want.body) + }) + } +} diff --git a/domain/service/mock.go b/domain/service/mock.go index 8728e19..cb45f4d 100644 --- a/domain/service/mock.go +++ b/domain/service/mock.go @@ -73,5 +73,8 @@ func (m *Mock) Top(_ context.Context, _ uint64) ([]model.Image, error) { } func (m *Mock) Health(_ context.Context) (bool, error) { + if m.err != nil { + return false, m.err + } return true, nil } diff --git a/domain/service/service_integration_test.go b/domain/service/service_integration_test.go index 479ff6a..23033d6 100644 --- a/domain/service/service_integration_test.go +++ b/domain/service/service_integration_test.go @@ -835,3 +835,35 @@ func TestServiceIntegrationDelete(t *testing.T) { } }) } + +func TestServiceIntegrationHealth(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + imaginary, err := compressor.NewImaginary() + if err != nil { + t.Fatal(err) + } + minio, err := storage.NewMinio() + if err != nil { + t.Fatal(err) + } + mongo, err := database.NewMongo() + if err != nil { + t.Fatal(err) + } + redis, err := cache.NewRedis() + if err != nil { + t.Fatal(err) + } + qCalc := &QueueCalc{} + qCalc.Monitor(ctx) + qComp := &QueueComp{} + qComp.Monitor(ctx) + qDel := &QueueDel{} + qDel.Monitor(ctx) + serv := New(imaginary, minio, mongo, redis, qCalc, qComp, qDel) + _, err = serv.Health(ctx) + if err != nil { + t.Error(err) + } +} diff --git a/domain/service/service_test.go b/domain/service/service_test.go index 8adb654..ef0e3b6 100644 --- a/domain/service/service_test.go +++ b/domain/service/service_test.go @@ -642,3 +642,23 @@ func TestServiceDelete(t *testing.T) { } }) } + +func TestServiceHealth(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + comp := compressor.NewMock() + stor := storage.NewMock() + mDb := database.NewMem() + mCache := cache.NewMem() + qCalc := &QueueCalc{} + qCalc.Monitor(ctx) + qComp := &QueueComp{} + qComp.Monitor(ctx) + qDel := &QueueDel{} + qDel.Monitor(ctx) + serv := New(comp, stor, mDb, mCache, qCalc, qComp, qDel) + _, err := serv.Health(ctx) + if err != nil { + t.Error(err) + } +} diff --git a/infrastructure/compressor/imaginary_integration_test.go b/infrastructure/compressor/imaginary_integration_test.go index b82e111..b42870c 100644 --- a/infrastructure/compressor/imaginary_integration_test.go +++ b/infrastructure/compressor/imaginary_integration_test.go @@ -78,3 +78,14 @@ func TestImaginaryNegative(t *testing.T) { t.Error("f1.Size != f2.Size") } } + +func TestImaginaryHealth(t *testing.T) { + im, err := NewImaginary() + if err != nil { + t.Fatal(err) + } + _, err = im.Health(context.Background()) + if err != nil { + t.Error(err) + } +} diff --git a/infrastructure/storage/minio_integration_test.go b/infrastructure/storage/minio_integration_test.go index 15ff9a9..3b2955c 100644 --- a/infrastructure/storage/minio_integration_test.go +++ b/infrastructure/storage/minio_integration_test.go @@ -86,3 +86,14 @@ func TestMinio(t *testing.T) { } }) } + +func TestMinioHealth(t *testing.T) { + minio, err := NewMinio() + if err != nil { + t.Fatal(err) + } + _, err = minio.Health(context.Background()) + if err != nil { + t.Error(err) + } +} From be2b8fcb0caa85e75436bbed2b12a6fe193248c1 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Wed, 29 Dec 2021 21:59:55 +0100 Subject: [PATCH 20/92] Test edge cases --- domain/service/service_integration_test.go | 162 +++++++++++++++++++-- domain/service/service_test.go | 136 +++++++++++++++-- internal/config/config.go | 2 +- pkg/log/log.go | 4 +- 4 files changed, 281 insertions(+), 23 deletions(-) diff --git a/domain/service/service_integration_test.go b/domain/service/service_integration_test.go index 23033d6..6beb0de 100644 --- a/domain/service/service_integration_test.go +++ b/domain/service/service_integration_test.go @@ -216,7 +216,7 @@ func TestServiceIntegrationAlbum(t *testing.T) { } func TestServiceIntegrationPair(t *testing.T) { - t.Run("Positive", func(t *testing.T) { + t.Run("Positive1", func(t *testing.T) { fn1 := func() func() (uint64, error) { i := uint64(0) return func() (uint64, error) { @@ -260,8 +260,99 @@ func TestServiceIntegrationPair(t *testing.T) { if err != nil { t.Error(err) } - img1 := model.Image{Id: 0x3BC7, Token: 0x3BC9, Src: "/aye-and-nay/albums/xjsAAAAAAAA/images/xzsAAAAAAAA"} - img2 := model.Image{Id: 0x3BC8, Token: 0x3BCA, Src: "/aye-and-nay/albums/xjsAAAAAAAA/images/yDsAAAAAAAA"} + img1 := model.Image{Id: 0x3BC7, Token: 0x3BC9, Src: "/api/images/yTsAAAAAAAA"} + img2 := model.Image{Id: 0x3BC8, Token: 0x3BCA, Src: "/api/images/yjsAAAAAAAA"} + imgs1 := []model.Image{img1, img2} + if reflect.DeepEqual(img7, img8) { + t.Error("img7 == img8") + } + if !IsIn(img7, imgs1) { + t.Error("img7 is not in imgs") + } + if !IsIn(img8, imgs1) { + t.Error("img8 is not in imgs") + } + img9, img10, err := serv.Pair(ctx, album) + if err != nil { + t.Error(err) + } + img3 := model.Image{Id: 0x3BC8, Token: 0x3BCB, Src: "/api/images/yzsAAAAAAAA"} + img4 := model.Image{Id: 0x3BC7, Token: 0x3BCC, Src: "/api/images/zDsAAAAAAAA"} + imgs2 := []model.Image{img3, img4} + if reflect.DeepEqual(img9, img10) { + t.Error("img9 == img10") + } + if !IsIn(img9, imgs2) { + t.Error("img9 is not in imgs") + } + if !IsIn(img10, imgs2) { + t.Error("img10 is not in imgs") + } + img11, img12, err := serv.Pair(ctx, album) + if err != nil { + t.Error(err) + } + img5 := model.Image{Id: 0x3BC7, Token: 0x3BCD, Src: "/api/images/zTsAAAAAAAA"} + img6 := model.Image{Id: 0x3BC8, Token: 0x3BCE, Src: "/api/images/zjsAAAAAAAA"} + imgs3 := []model.Image{img5, img6} + if reflect.DeepEqual(img11, img12) { + t.Error("img11 == img12") + } + if !IsIn(img11, imgs3) { + t.Error("img11 is not in imgs") + } + if !IsIn(img12, imgs3) { + t.Error("img12 is not in imgs") + } + }) + t.Run("Positive2", func(t *testing.T) { + viper.Set("service.tempLinks", false) + defer viper.Set("service.tempLinks", true) + fn1 := func() func() (uint64, error) { + i := uint64(0) + return func() (uint64, error) { + i++ + return 0xFAFD + i, nil + } + }() + fn2 := func(n int, swap func(i int, j int)) { + } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + imaginary, err := compressor.NewImaginary() + if err != nil { + t.Fatal(err) + } + minio, err := storage.NewMinio() + if err != nil { + t.Fatal(err) + } + mongo, err := database.NewMongo() + if err != nil { + t.Fatal(err) + } + redis, err := cache.NewRedis() + if err != nil { + t.Fatal(err) + } + qCalc := &QueueCalc{} + qCalc.Monitor(ctx) + qComp := &QueueComp{} + qComp.Monitor(ctx) + qDel := &QueueDel{} + qDel.Monitor(ctx) + serv := New(imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + files := []model.File{Png(), Png()} + album, err := serv.Album(ctx, files, 0*time.Millisecond) + if err != nil { + t.Error(err) + } + img7, img8, err := serv.Pair(ctx, album) + if err != nil { + t.Error(err) + } + img1 := model.Image{Id: 0xFAFF, Token: 0xFAFF, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/__oAAAAAAAA"} + img2 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} imgs1 := []model.Image{img1, img2} if reflect.DeepEqual(img7, img8) { t.Error("img7 == img8") @@ -276,8 +367,8 @@ func TestServiceIntegrationPair(t *testing.T) { if err != nil { t.Error(err) } - img3 := model.Image{Id: 0x3BC8, Token: 0x3BCB, Src: "/aye-and-nay/albums/xjsAAAAAAAA/images/yDsAAAAAAAA"} - img4 := model.Image{Id: 0x3BC7, Token: 0x3BCC, Src: "/aye-and-nay/albums/xjsAAAAAAAA/images/xzsAAAAAAAA"} + img3 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} + img4 := model.Image{Id: 0xFAFF, Token: 0xFAFF, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/__oAAAAAAAA"} imgs2 := []model.Image{img3, img4} if reflect.DeepEqual(img9, img10) { t.Error("img9 == img10") @@ -292,8 +383,8 @@ func TestServiceIntegrationPair(t *testing.T) { if err != nil { t.Error(err) } - img5 := model.Image{Id: 0x3BC7, Token: 0x3BCD, Src: "/aye-and-nay/albums/xjsAAAAAAAA/images/xzsAAAAAAAA"} - img6 := model.Image{Id: 0x3BC8, Token: 0x3BCE, Src: "/aye-and-nay/albums/xjsAAAAAAAA/images/yDsAAAAAAAA"} + img5 := model.Image{Id: 0xFAFF, Token: 0xFAFF, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/__oAAAAAAAA"} + img6 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} imgs3 := []model.Image{img5, img6} if reflect.DeepEqual(img11, img12) { t.Error("img11 == img12") @@ -339,8 +430,6 @@ func TestServiceIntegrationPair(t *testing.T) { } func TestServiceIntegrationImage(t *testing.T) { - viper.Set("service.tempLinks", true) - defer viper.Set("service.tempLinks", false) t.Run("Positive", func(t *testing.T) { fn1 := func() func() (uint64, error) { i := uint64(0) @@ -434,7 +523,7 @@ func TestServiceIntegrationImage(t *testing.T) { } func TestServiceIntegrationVote(t *testing.T) { - t.Run("Positive", func(t *testing.T) { + t.Run("Positive1", func(t *testing.T) { fn1 := func() func() (uint64, error) { i := uint64(0) return func() (uint64, error) { @@ -483,6 +572,57 @@ func TestServiceIntegrationVote(t *testing.T) { t.Error(err) } }) + t.Run("Positive2", func(t *testing.T) { + viper.Set("service.tempLinks", false) + defer viper.Set("service.tempLinks", true) + fn1 := func() func() (uint64, error) { + i := uint64(0) + return func() (uint64, error) { + i++ + return 0x1E58 + i, nil + } + }() + fn2 := func(n int, swap func(i int, j int)) { + } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + imaginary, err := compressor.NewImaginary() + if err != nil { + t.Fatal(err) + } + minio, err := storage.NewMinio() + if err != nil { + t.Fatal(err) + } + mongo, err := database.NewMongo() + if err != nil { + t.Fatal(err) + } + redis, err := cache.NewRedis() + if err != nil { + t.Fatal(err) + } + qCalc := &QueueCalc{} + qCalc.Monitor(ctx) + qComp := &QueueComp{} + qComp.Monitor(ctx) + qDel := &QueueDel{} + qDel.Monitor(ctx) + serv := New(imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + files := []model.File{Png(), Png()} + album, err := serv.Album(ctx, files, 0*time.Millisecond) + if err != nil { + t.Error(err) + } + img1, img2, err := serv.Pair(ctx, album) + if err != nil { + t.Error(err) + } + err = serv.Vote(ctx, album, img1.Token, img2.Token) + if err != nil { + t.Error(err) + } + }) t.Run("Negative1", func(t *testing.T) { fn1 := func() func() (uint64, error) { i := uint64(0) @@ -528,7 +668,7 @@ func TestServiceIntegrationVote(t *testing.T) { t.Error(err) } err = serv.Vote(ctx, 0x12E6, img1.Token, img2.Token) - if !errors.Is(err, domain.ErrTokenNotFound) { + if !errors.Is(err, domain.ErrAlbumNotFound) { t.Error(err) } }) diff --git a/domain/service/service_test.go b/domain/service/service_test.go index ef0e3b6..fe07842 100644 --- a/domain/service/service_test.go +++ b/domain/service/service_test.go @@ -171,7 +171,7 @@ func TestServiceAlbum(t *testing.T) { } func TestServicePair(t *testing.T) { - t.Run("Positive", func(t *testing.T) { + t.Run("Positive1", func(t *testing.T) { fn1 := func() func() (uint64, error) { i := uint64(0) return func() (uint64, error) { @@ -203,8 +203,87 @@ func TestServicePair(t *testing.T) { if err != nil { t.Error(err) } - img1 := model.Image{Id: 0x3BC7, Token: 0x3BC9, Src: "/aye-and-nay/albums/xjsAAAAAAAA/images/xzsAAAAAAAA"} - img2 := model.Image{Id: 0x3BC8, Token: 0x3BCA, Src: "/aye-and-nay/albums/xjsAAAAAAAA/images/yDsAAAAAAAA"} + img1 := model.Image{Id: 0x3BC7, Token: 0x3BC9, Src: "/api/images/yTsAAAAAAAA"} + img2 := model.Image{Id: 0x3BC8, Token: 0x3BCA, Src: "/api/images/yjsAAAAAAAA"} + imgs1 := []model.Image{img1, img2} + if reflect.DeepEqual(img7, img8) { + t.Error("img7 == img8") + } + if !IsIn(img7, imgs1) { + t.Error("img7 is not in imgs") + } + if !IsIn(img8, imgs1) { + t.Error("img8 is not in imgs") + } + img9, img10, err := serv.Pair(ctx, album) + if err != nil { + t.Error(err) + } + img3 := model.Image{Id: 0x3BC8, Token: 0x3BCB, Src: "/api/images/yzsAAAAAAAA"} + img4 := model.Image{Id: 0x3BC7, Token: 0x3BCC, Src: "/api/images/zDsAAAAAAAA"} + imgs2 := []model.Image{img3, img4} + if reflect.DeepEqual(img9, img10) { + t.Error("img9 == img10") + } + if !IsIn(img9, imgs2) { + t.Error("img9 is not in imgs") + } + if !IsIn(img10, imgs2) { + t.Error("img10 is not in imgs") + } + img11, img12, err := serv.Pair(ctx, album) + if err != nil { + t.Error(err) + } + img5 := model.Image{Id: 0x3BC7, Token: 0x3BCD, Src: "/api/images/zTsAAAAAAAA"} + img6 := model.Image{Id: 0x3BC8, Token: 0x3BCE, Src: "/api/images/zjsAAAAAAAA"} + imgs3 := []model.Image{img5, img6} + if reflect.DeepEqual(img11, img12) { + t.Error("img11 == img12") + } + if !IsIn(img11, imgs3) { + t.Error("img11 is not in imgs") + } + if !IsIn(img12, imgs3) { + t.Error("img12 is not in imgs") + } + }) + t.Run("Positive2", func(t *testing.T) { + viper.Set("service.tempLinks", false) + defer viper.Set("service.tempLinks", true) + fn1 := func() func() (uint64, error) { + i := uint64(0) + return func() (uint64, error) { + i++ + return 0xFAFD + i, nil + } + }() + fn2 := func(n int, swap func(i int, j int)) { + } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + comp := compressor.NewMock() + stor := storage.NewMock() + mDb := database.NewMem() + mCache := cache.NewMem() + qCalc := &QueueCalc{} + qCalc.Monitor(ctx) + qComp := &QueueComp{} + qComp.Monitor(ctx) + qDel := &QueueDel{} + qDel.Monitor(ctx) + serv := New(comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + files := []model.File{Png(), Png()} + album, err := serv.Album(ctx, files, 0*time.Millisecond) + if err != nil { + t.Error(err) + } + img7, img8, err := serv.Pair(ctx, album) + if err != nil { + t.Error(err) + } + img1 := model.Image{Id: 0xFAFF, Token: 0xFAFF, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/__oAAAAAAAA"} + img2 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} imgs1 := []model.Image{img1, img2} if reflect.DeepEqual(img7, img8) { t.Error("img7 == img8") @@ -219,8 +298,8 @@ func TestServicePair(t *testing.T) { if err != nil { t.Error(err) } - img3 := model.Image{Id: 0x3BC8, Token: 0x3BCB, Src: "/aye-and-nay/albums/xjsAAAAAAAA/images/yDsAAAAAAAA"} - img4 := model.Image{Id: 0x3BC7, Token: 0x3BCC, Src: "/aye-and-nay/albums/xjsAAAAAAAA/images/xzsAAAAAAAA"} + img3 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} + img4 := model.Image{Id: 0xFAFF, Token: 0xFAFF, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/__oAAAAAAAA"} imgs2 := []model.Image{img3, img4} if reflect.DeepEqual(img9, img10) { t.Error("img9 == img10") @@ -235,8 +314,8 @@ func TestServicePair(t *testing.T) { if err != nil { t.Error(err) } - img5 := model.Image{Id: 0x3BC7, Token: 0x3BCD, Src: "/aye-and-nay/albums/xjsAAAAAAAA/images/xzsAAAAAAAA"} - img6 := model.Image{Id: 0x3BC8, Token: 0x3BCE, Src: "/aye-and-nay/albums/xjsAAAAAAAA/images/yDsAAAAAAAA"} + img5 := model.Image{Id: 0xFAFF, Token: 0xFAFF, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/__oAAAAAAAA"} + img6 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} imgs3 := []model.Image{img5, img6} if reflect.DeepEqual(img11, img12) { t.Error("img11 == img12") @@ -270,8 +349,6 @@ func TestServicePair(t *testing.T) { } func TestServiceImage(t *testing.T) { - viper.Set("service.tempLinks", true) - defer viper.Set("service.tempLinks", false) t.Run("Positive", func(t *testing.T) { fn1 := func() func() (uint64, error) { i := uint64(0) @@ -341,7 +418,7 @@ func TestServiceImage(t *testing.T) { } func TestServiceVote(t *testing.T) { - t.Run("Positive", func(t *testing.T) { + t.Run("Positive1", func(t *testing.T) { fn1 := func() func() (uint64, error) { i := uint64(0) return func() (uint64, error) { @@ -378,6 +455,45 @@ func TestServiceVote(t *testing.T) { t.Error(err) } }) + t.Run("Positive2", func(t *testing.T) { + viper.Set("service.tempLinks", false) + defer viper.Set("service.tempLinks", true) + fn1 := func() func() (uint64, error) { + i := uint64(0) + return func() (uint64, error) { + i++ + return 0x1E58 + i, nil + } + }() + fn2 := func(n int, swap func(i int, j int)) { + } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + comp := compressor.NewMock() + stor := storage.NewMock() + mDb := database.NewMem() + mCache := cache.NewMem() + qCalc := &QueueCalc{} + qCalc.Monitor(ctx) + qComp := &QueueComp{} + qComp.Monitor(ctx) + qDel := &QueueDel{} + qDel.Monitor(ctx) + serv := New(comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + files := []model.File{Png(), Png()} + album, err := serv.Album(ctx, files, 0*time.Millisecond) + if err != nil { + t.Error(err) + } + img1, img2, err := serv.Pair(ctx, album) + if err != nil { + t.Error(err) + } + err = serv.Vote(ctx, album, img1.Token, img2.Token) + if err != nil { + t.Error(err) + } + }) t.Run("Negative1", func(t *testing.T) { fn1 := func() func() (uint64, error) { i := uint64(0) diff --git a/internal/config/config.go b/internal/config/config.go index 451c76c..311ae79 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -12,7 +12,7 @@ func init() { viper.Set("controller.maxNumberOfFiles", 3) viper.Set("controller.maxFileSize", 512*unit.KB) viper.Set("service.numberOfWorkersCalc", 2) - viper.Set("service.tempLinks", false) + viper.Set("service.tempLinks", true) viper.Set("service.numberOfWorkersComp", 2) viper.Set("service.accuracy", 0.625) viper.Set("cache.redis.host", "localhost") diff --git a/pkg/log/log.go b/pkg/log/log.go index 38bfc5a..d5c18d5 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -32,7 +32,9 @@ func SetOutput(w io.Writer) { } func SetPrefix(prefix string) { - l.SetPrefix(prefix + ": ") + if len(prefix) > 0 { + l.SetPrefix(prefix + ": ") + } } func SetFlags(flag int) { From ca9db6dca28f041b59be75cc869f63760b1076e4 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Thu, 30 Dec 2021 16:00:01 +0100 Subject: [PATCH 21/92] Check health --- Makefile | 5 +++- build/Caddyfile | 4 ++++ build/Dockerfile-app | 9 ++++++- build/Dockerfile-caddy | 6 +++++ build/Dockerfile-imaginary | 13 ++++++++++ build/Dockerfile-minio | 5 ++++ build/Dockerfile-mongo | 6 +++++ build/Dockerfile-redis | 6 +++++ build/Dockerfile-swagger | 2 ++ build/docker-compose-dev.yml | 24 +++++++++---------- build/docker-compose-embed.yml | 4 ++-- build/docker-compose-prod.yml | 20 ++++++++-------- cmd/healthcheck/main.go | 44 ++++++++++++++++++++++++++++++++++ main.go | 8 +------ 14 files changed, 122 insertions(+), 34 deletions(-) create mode 100644 cmd/healthcheck/main.go diff --git a/Makefile b/Makefile index 331cfb4..37715f8 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: gen compile test-unit test-int test-unit-ci test-int-ci dev-up dev-down prod-loadtest prod-up prod-down embed-loadtest embed-up embed-down +.PHONY: gen compile compile-health test-unit test-int test-unit-ci test-int-ci dev-up dev-down prod-loadtest prod-up prod-down embed-loadtest embed-up embed-down gen: go install github.com/mailru/easyjson/easyjson@latest @@ -8,6 +8,9 @@ gen: compile: gen CGO_ENABLED=0 go build -ldflags="-s -w" +compile-health: + CGO_ENABLED=0 go build -ldflags="-s -w" -o healthcheck ./cmd/healthcheck/main.go + test-unit: gen go test -v -race -shuffle=on -count=1 -short -tags=unit -cover ./... diff --git a/build/Caddyfile b/build/Caddyfile index 4a45a3a..84615e6 100644 --- a/build/Caddyfile +++ b/build/Caddyfile @@ -18,3 +18,7 @@ localhost { # www.aye-and-nay.de { # redir https://aye-and-nay.de{uri} permanent # } + +:8080 { + respond /health 200 +} diff --git a/build/Dockerfile-app b/build/Dockerfile-app index 46cda98..2652222 100644 --- a/build/Dockerfile-app +++ b/build/Dockerfile-app @@ -5,11 +5,18 @@ WORKDIR /app/ COPY go.mod go.sum ./ RUN go mod download COPY . . -RUN make compile +RUN make compile compile-health FROM scratch COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ COPY --from=builder /etc/passwd /etc/ COPY --from=builder /app/aye-and-nay / +COPY --from=builder /app/config.yml / +COPY --from=builder /app/healthcheck / USER appuser ENTRYPOINT ["/aye-and-nay"] +HEALTHCHECK \ + --interval=1m \ + --timeout=30s \ + --retries=3 \ + CMD ["/healthcheck"] diff --git a/build/Dockerfile-caddy b/build/Dockerfile-caddy index 984a644..9dfd962 100644 --- a/build/Dockerfile-caddy +++ b/build/Dockerfile-caddy @@ -1 +1,7 @@ FROM caddy:2-alpine +COPY ./build/Caddyfile /etc/caddy/Caddyfile +HEALTHCHECK \ + --interval=1m \ + --timeout=30s \ + --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1 diff --git a/build/Dockerfile-imaginary b/build/Dockerfile-imaginary index db91e5c..04da83b 100644 --- a/build/Dockerfile-imaginary +++ b/build/Dockerfile-imaginary @@ -1,2 +1,15 @@ FROM h2non/imaginary:1 +USER root +RUN \ + apt-get update && \ + apt-get install --no-install-recommends --yes curl && \ + apt-get autoremove --yes && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* +USER nobody ENV PORT=9001 +HEALTHCHECK \ + --interval=1m \ + --timeout=30s \ + --retries=3 \ + CMD curl -f http://localhost:9001/health || exit 1 diff --git a/build/Dockerfile-minio b/build/Dockerfile-minio index 46816c4..1704de2 100644 --- a/build/Dockerfile-minio +++ b/build/Dockerfile-minio @@ -1,3 +1,8 @@ FROM minio/minio:RELEASE.2021-11-24T23-19-33Z ENV MINIO_ROOT_USER=12345678 MINIO_ROOT_PASSWORD=qwertyui CMD ["server", "/data", "--console-address", ":9090"] +HEALTHCHECK \ + --interval=1m \ + --timeout=30s \ + --retries=3 \ + CMD curl -f http://localhost:9000/minio/health/live || exit 1 diff --git a/build/Dockerfile-mongo b/build/Dockerfile-mongo index 2c06b63..78b5255 100644 --- a/build/Dockerfile-mongo +++ b/build/Dockerfile-mongo @@ -1,2 +1,8 @@ FROM mongo:5 +COPY ./build/mongo.js /docker-entrypoint-initdb.d/mongo.js ENV MONGO_INITDB_DATABASE=aye-and-nay +HEALTHCHECK \ + --interval=1m \ + --timeout=30s \ + --retries=3 \ + CMD test $(echo 'db.runCommand("ping").ok' | mongo --quiet) -eq 1 || exit 1 diff --git a/build/Dockerfile-redis b/build/Dockerfile-redis index e25ea9c..f301408 100644 --- a/build/Dockerfile-redis +++ b/build/Dockerfile-redis @@ -1,2 +1,8 @@ FROM redis:6-alpine +COPY ./build/redis.conf /usr/local/etc/redis/redis.conf CMD ["redis-server", "/usr/local/etc/redis/redis.conf"] +HEALTHCHECK \ + --interval=1m \ + --timeout=30s \ + --retries=3 \ + CMD test $(redis-cli ping) = "PONG" || exit 1 diff --git a/build/Dockerfile-swagger b/build/Dockerfile-swagger index 681dd8b..1f033f8 100644 --- a/build/Dockerfile-swagger +++ b/build/Dockerfile-swagger @@ -1 +1,3 @@ FROM swaggerapi/swagger-ui:v4.1.2 +COPY ./build/swagger.yml /swagger.yml +ENV SWAGGER_JSON=/swagger.yml diff --git a/build/docker-compose-dev.yml b/build/docker-compose-dev.yml index 208d541..f8a4ba5 100644 --- a/build/docker-compose-dev.yml +++ b/build/docker-compose-dev.yml @@ -2,8 +2,8 @@ services: redis: build: - context: . - dockerfile: Dockerfile-redis + context: ./../ + dockerfile: ./build/Dockerfile-redis container_name: dev-redis ports: - "6379:6379" @@ -12,16 +12,16 @@ services: imaginary: build: - context: . - dockerfile: Dockerfile-imaginary + context: ./../ + dockerfile: ./build/Dockerfile-imaginary container_name: dev-imaginary ports: - "9001:9001" mongo: build: - context: . - dockerfile: Dockerfile-mongo + context: ./../ + dockerfile: ./build/Dockerfile-mongo container_name: dev-mongo ports: - "27017:27017" @@ -30,8 +30,8 @@ services: minio: build: - context: . - dockerfile: Dockerfile-minio + context: ./../ + dockerfile: ./build/Dockerfile-minio container_name: dev-minio ports: - "9000:9000" @@ -39,12 +39,10 @@ services: swagger: build: - context: . - dockerfile: Dockerfile-swagger + context: ./../ + dockerfile: ./build/Dockerfile-swagger container_name: dev-swagger ports: - - "8080:8080" + - "8081:8081" volumes: - "./swagger.yml:/swagger.yml" - environment: - - SWAGGER_JSON=/swagger.yml diff --git a/build/docker-compose-embed.yml b/build/docker-compose-embed.yml index 2656f18..8a191d8 100644 --- a/build/docker-compose-embed.yml +++ b/build/docker-compose-embed.yml @@ -15,8 +15,8 @@ services: minio: build: - context: . - dockerfile: Dockerfile-minio + context: ./../ + dockerfile: ./build/Dockerfile-minio container_name: embed-minio volumes: - "./minio/data/:/data/" diff --git a/build/docker-compose-prod.yml b/build/docker-compose-prod.yml index b361595..6230081 100644 --- a/build/docker-compose-prod.yml +++ b/build/docker-compose-prod.yml @@ -2,8 +2,8 @@ services: caddy: build: - context: . - dockerfile: Dockerfile-caddy + context: ./../ + dockerfile: ./build/Dockerfile-caddy container_name: prod-caddy ports: - "80:80" @@ -31,22 +31,22 @@ services: redis: build: - context: . - dockerfile: Dockerfile-redis + context: ./../ + dockerfile: ./build/Dockerfile-redis container_name: prod-redis volumes: - "./redis.conf:/usr/local/etc/redis/redis.conf" imaginary: build: - context: . - dockerfile: Dockerfile-imaginary + context: ./../ + dockerfile: ./build/Dockerfile-imaginary container_name: prod-imaginary mongo: build: - context: . - dockerfile: Dockerfile-mongo + context: ./../ + dockerfile: ./build/Dockerfile-mongo container_name: prod-mongo volumes: - "./mongo.js:/docker-entrypoint-initdb.d/mongo.js" @@ -62,8 +62,8 @@ services: minio: build: - context: . - dockerfile: Dockerfile-minio + context: ./../ + dockerfile: ./build/Dockerfile-minio container_name: prod-minio volumes: - "./minio/data/:/data/" diff --git a/cmd/healthcheck/main.go b/cmd/healthcheck/main.go new file mode 100644 index 0000000..9a3cdb1 --- /dev/null +++ b/cmd/healthcheck/main.go @@ -0,0 +1,44 @@ +package main + +import ( + "flag" + "io" + "net/http" + "os" + + "github.com/spf13/viper" +) + +func main() { + conf := "" + flag.StringVar(&conf, "config", "./config.yml", "relative filepath to a config file") + flag.Parse() + viper.SetConfigFile(conf) + err := viper.ReadInConfig() + if err != nil { + os.Exit(1) + } + port := viper.GetString("server.port") + req, err := http.NewRequest(http.MethodGet, "http://localhost:"+port+"/api/health/", http.NoBody) + if err != nil { + os.Exit(1) + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + os.Exit(1) + } + if resp.StatusCode != 200 { + _, _ = io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + os.Exit(1) + } + _, err = io.Copy(io.Discard, resp.Body) + if err != nil { + _ = resp.Body.Close() + os.Exit(1) + } + err = resp.Body.Close() + if err != nil { + os.Exit(1) + } +} diff --git a/main.go b/main.go index 5b10cc2..13e2da6 100644 --- a/main.go +++ b/main.go @@ -6,8 +6,6 @@ import ( "fmt" "os" "os/signal" - "path" - "strings" "syscall" "github.com/spf13/viper" @@ -31,11 +29,7 @@ func main() { conf := "" flag.StringVar(&conf, "config", "./config.yml", "relative filepath to a config file") flag.Parse() - dir, file := path.Split(conf) - base := strings.TrimSuffix(file, path.Ext(file)) - - viper.SetConfigName(base) - viper.AddConfigPath(dir) + viper.SetConfigFile(conf) err := viper.ReadInConfig() if err != nil { _, _ = fmt.Fprintln(os.Stderr, "critical:", err) From 202aa038dcfbb494ff6b5f2be9cbb87be853b7a7 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Tue, 4 Jan 2022 15:17:40 +0100 Subject: [PATCH 22/92] Change configuration method --- build/Dockerfile-app | 2 +- build/config-dev.env | 85 ++++++ build/config-dev.yml | 89 ------- build/config-embed.env | 85 ++++++ build/config-embed.yml | 89 ------- build/config-prod.env | 85 ++++++ build/config-prod.yml | 89 ------- build/docker-compose-embed.yml | 2 +- build/docker-compose-prod.yml | 2 +- cmd/healthcheck/main.go | 4 +- config.env | 85 ++++++ config.yml | 89 ------- delivery/http/config.go | 63 ++--- delivery/http/controller.go | 10 +- delivery/http/controller_test.go | 15 +- delivery/http/middleware.go | 10 +- delivery/http/middleware_test.go | 9 +- delivery/http/server.go | 26 +- domain/service/config.go | 30 +-- domain/service/queue_integration_test.go | 2 +- domain/service/queue_test.go | 2 +- domain/service/service.go | 8 +- domain/service/service_integration_test.go | 198 +++++++------- domain/service/service_test.go | 114 ++++---- domain/service/workerpool.go | 6 +- go.mod | 4 + go.sum | 6 + infrastructure/cache/cache.go | 12 +- .../cache/cache_integration_test.go | 4 +- infrastructure/cache/config.go | 71 ++--- infrastructure/cache/mem.go | 19 +- infrastructure/cache/mem_test.go | 25 +- infrastructure/cache/redis.go | 23 +- .../cache/redis_integration_test.go | 29 +-- infrastructure/compressor/compressor.go | 14 +- .../compressor/compressor_integration_test.go | 4 +- infrastructure/compressor/config.go | 89 ++++--- infrastructure/compressor/imaginary.go | 19 +- .../compressor/imaginary_integration_test.go | 8 +- infrastructure/compressor/shortpixel.go | 35 ++- infrastructure/compressor/shortpixel_test.go | 130 +++++----- infrastructure/database/badger.go | 26 +- infrastructure/database/badger_test.go | 47 ++-- infrastructure/database/config.go | 81 +++--- infrastructure/database/database.go | 14 +- .../database/database_integration_test.go | 4 +- infrastructure/database/mem.go | 7 +- infrastructure/database/mem_test.go | 45 ++-- infrastructure/database/mongo.go | 19 +- .../database/mongo_integration_test.go | 47 ++-- infrastructure/storage/config.go | 59 +++-- infrastructure/storage/minio.go | 27 +- .../storage/minio_integration_test.go | 7 +- infrastructure/storage/storage.go | 8 +- .../storage/storage_integration_test.go | 6 +- internal/config/config.go | 128 ++++++--- internal/dockertest/dockertest.go | 43 ++- main.go | 245 ++++++++++-------- 58 files changed, 1284 insertions(+), 1220 deletions(-) create mode 100644 build/config-dev.env delete mode 100644 build/config-dev.yml create mode 100644 build/config-embed.env delete mode 100644 build/config-embed.yml create mode 100644 build/config-prod.env delete mode 100644 build/config-prod.yml create mode 100644 config.env delete mode 100644 config.yml diff --git a/build/Dockerfile-app b/build/Dockerfile-app index 2652222..e6d4f08 100644 --- a/build/Dockerfile-app +++ b/build/Dockerfile-app @@ -11,7 +11,7 @@ FROM scratch COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ COPY --from=builder /etc/passwd /etc/ COPY --from=builder /app/aye-and-nay / -COPY --from=builder /app/config.yml / +COPY --from=builder /app/config.env / COPY --from=builder /app/healthcheck / USER appuser ENTRYPOINT ["/aye-and-nay"] diff --git a/build/config-dev.env b/build/config-dev.env new file mode 100644 index 0000000..3673281 --- /dev/null +++ b/build/config-dev.env @@ -0,0 +1,85 @@ +# APP +APP_NAME=config-dev +APP_BALLAST=0 +APP_LOG=info + +# SERVER +SERVER_DOMAIN= +SERVER_HOST=localhost +SERVER_PORT=8001 +SERVER_H2C=false +SERVER_READ_TIMEOUT=60s +SERVER_WRITE_TIMEOUT=120s +SERVER_IDLE_TIMEOUT=120s +SERVER_SHUTDOWN_TIMEOUT=10s + +# MIDDLEWARE +MIDDLEWARE_CORS_ALLOW_ORIGIN=* +MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=10000 # per minute in case of redis cache +MIDDLEWARE_LIMITER_BURST=10 + +# CONTROLLER +CONTROLLER_MAX_NUMBER_OF_FILES=100 +CONTROLLER_MAX_FILE_SIZE=5242880 # 5 MB + +# SERVICE +SERVICE_TEMP_LINKS=true +SERVICE_NUMBER_OF_WORKERS_CALC=8 +SERVICE_NUMBER_OF_WORKERS_COMP=8 +SERVICE_ACCURACY=0.625 + +# CACHE: [mem, redis] +CACHE=redis +CACHE_MEM_CLEANUP_INTERVAL=15m +CACHE_REDIS_HOST=localhost +CACHE_REDIS_PORT=6379 +CACHE_REDIS_RETRY_TIMES=4 +CACHE_REDIS_RETRY_PAUSE=5s +CACHE_REDIS_TIMEOUT=30s +CACHE_REDIS_TIME_TO_LIVE=15m + +# COMPRESSOR: [mock, shortpixel, imaginary] +COMPRESSOR=imaginary +COMPRESSOR_SHORTPIXEL_URL=https://api.shortpixel.com/v2/post-reducer.php +COMPRESSOR_SHORTPIXEL_URL2=https://api.shortpixel.com/v2/reducer.php +COMPRESSOR_SHORTPIXEL_API_KEY=abcdefghijklmnopqrst +COMPRESSOR_SHORTPIXEL_RETRY_TIMES=2 +COMPRESSOR_SHORTPIXEL_RETRY_PAUSE=10s +COMPRESSOR_SHORTPIXEL_TIMEOUT=30s +COMPRESSOR_SHORTPIXEL_WAIT=30 +COMPRESSOR_SHORTPIXEL_UPLOAD_TIMEOUT=60s +COMPRESSOR_SHORTPIXEL_DOWNLOAD_TIMEOUT=60s +COMPRESSOR_SHORTPIXEL_REPEAT_IN=10s +COMPRESSOR_SHORTPIXEL_RESTART_IN=15m +COMPRESSOR_IMAGINARY_HOST=localhost +COMPRESSOR_IMAGINARY_PORT=9001 +COMPRESSOR_IMAGINARY_RETRY_TIMES=4 +COMPRESSOR_IMAGINARY_RETRY_PAUSE=5s +COMPRESSOR_IMAGINARY_TIMEOUT=30s + +# DATABASE: [mem, mongo, badger] +DATABASE=mongo +DATABASE_MONGO_HOST=localhost +DATABASE_MONGO_PORT=27017 +DATABASE_MONGO_RETRY_TIMES=4 +DATABASE_MONGO_RETRY_PAUSE=5s +DATABASE_MONGO_TIMEOUT=30s +DATABASE_MONGO_LRU=100 +DATABASE_BADGER_IN_MEMORY=false +DATABASE_BADGER_GC_RATIO=0.7 +DATABASE_BADGER_CLEANUP_INTERVAL=5m +DATABASE_BADGER_LRU=100 + +# STORAGE: [mock, minio] +STORAGE=minio +STORAGE_MINIO_HOST=localhost +STORAGE_MINIO_PORT=9000 +STORAGE_MINIO_ACCESS_KEY=12345678 +STORAGE_MINIO_SECRET_KEY=qwertyui +STORAGE_MINIO_TOKEN= +STORAGE_MINIO_SECURE=false +STORAGE_MINIO_RETRY_TIMES=4 +STORAGE_MINIO_RETRY_PAUSE=5s +STORAGE_MINIO_TIMEOUT=30s +STORAGE_MINIO_LOCATION=eu-central-1 +STORAGE_MINIO_PREFIX=http://localhost:9000 diff --git a/build/config-dev.yml b/build/config-dev.yml deleted file mode 100644 index f1c01b7..0000000 --- a/build/config-dev.yml +++ /dev/null @@ -1,89 +0,0 @@ -app: - name: config-dev - ballast: 0 - log: info -server: - domain: - host: localhost - port: 8001 - h2c: false - readTimeout: 60s - writeTimeout: 120s - idleTimeout: 120s - shutdownTimeout: 10s -middleware: - cors: - allowOrigin: "*" - limiter: - requestsPerSecond: 10000 - burst: 10 -controller: - maxNumberOfFiles: 100 - maxFileSize: 5242880 # 5 MB -service: - tempLinks: true - numberOfWorkersCalc: 8 - numberOfWorkersComp: 8 - accuracy: 0.625 -cache: - use: redis - redis: - host: localhost - port: 6379 - retry: - times: 4 - pause: 5s - timeout: 30s - timeToLive: 15m - cleanupInterval: 15m -compressor: - use: imaginary - imaginary: - host: localhost - port: 9001 - retry: - times: 4 - pause: 5s - timeout: 30s - shortpixel: - url: https://api.shortpixel.com/v2/post-reducer.php - url2: https://api.shortpixel.com/v2/reducer.php - apiKey: abcdefghijklmnopqrst - retry: - times: 2 - pause: 10s - timeout: 30s - wait: 30 - uploadTimeout: 60s - downloadTimeout: 60s - repeatIn: 10s - restartIn: 15m -database: - use: mongo - mongo: - host: localhost - port: 27017 - retry: - times: 4 - pause: 5s - timeout: 30s - lru: 100 - badger: - gcRatio: 0.7 - cleanupInterval: 5m - lru: 100 -storage: - use: minio - minio: - host: localhost - port: 9000 - accessKey: 12345678 - secretKey: qwertyui - token: - secure: false - retry: - times: 4 - pause: 5s - timeout: 30s - location: eu-central-1 - prefix: http://localhost:9000 diff --git a/build/config-embed.env b/build/config-embed.env new file mode 100644 index 0000000..973c253 --- /dev/null +++ b/build/config-embed.env @@ -0,0 +1,85 @@ +# APP +APP_NAME=config-embed +APP_BALLAST=0 +APP_LOG=info + +# SERVER +SERVER_DOMAIN= +SERVER_HOST= +SERVER_PORT=8001 +SERVER_H2C=false +SERVER_READ_TIMEOUT=60s +SERVER_WRITE_TIMEOUT=120s +SERVER_IDLE_TIMEOUT=120s +SERVER_SHUTDOWN_TIMEOUT=10s + +# MIDDLEWARE +MIDDLEWARE_CORS_ALLOW_ORIGIN=* +MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=10000 # per minute in case of redis cache +MIDDLEWARE_LIMITER_BURST=10 + +# CONTROLLER +CONTROLLER_MAX_NUMBER_OF_FILES=100 +CONTROLLER_MAX_FILE_SIZE=5242880 # 5 MB + +# SERVICE +SERVICE_TEMP_LINKS=false +SERVICE_NUMBER_OF_WORKERS_CALC=8 +SERVICE_NUMBER_OF_WORKERS_COMP=8 +SERVICE_ACCURACY=0.625 + +# CACHE: [mem, redis] +CACHE=mem +CACHE_MEM_CLEANUP_INTERVAL=15m +CACHE_REDIS_HOST=localhost +CACHE_REDIS_PORT=6379 +CACHE_REDIS_RETRY_TIMES=4 +CACHE_REDIS_RETRY_PAUSE=5s +CACHE_REDIS_TIMEOUT=30s +CACHE_REDIS_TIME_TO_LIVE=15m + +# COMPRESSOR: [mock, shortpixel, imaginary] +COMPRESSOR=mock +COMPRESSOR_SHORTPIXEL_URL=https://api.shortpixel.com/v2/post-reducer.php +COMPRESSOR_SHORTPIXEL_URL2=https://api.shortpixel.com/v2/reducer.php +COMPRESSOR_SHORTPIXEL_API_KEY=abcdefghijklmnopqrst +COMPRESSOR_SHORTPIXEL_RETRY_TIMES=2 +COMPRESSOR_SHORTPIXEL_RETRY_PAUSE=10s +COMPRESSOR_SHORTPIXEL_TIMEOUT=30s +COMPRESSOR_SHORTPIXEL_WAIT=30 +COMPRESSOR_SHORTPIXEL_UPLOAD_TIMEOUT=60s +COMPRESSOR_SHORTPIXEL_DOWNLOAD_TIMEOUT=60s +COMPRESSOR_SHORTPIXEL_REPEAT_IN=10s +COMPRESSOR_SHORTPIXEL_RESTART_IN=15m +COMPRESSOR_IMAGINARY_HOST=localhost +COMPRESSOR_IMAGINARY_PORT=9001 +COMPRESSOR_IMAGINARY_RETRY_TIMES=4 +COMPRESSOR_IMAGINARY_RETRY_PAUSE=5s +COMPRESSOR_IMAGINARY_TIMEOUT=30s + +# DATABASE: [mem, mongo, badger] +DATABASE=badger +DATABASE_MONGO_HOST=localhost +DATABASE_MONGO_PORT=27017 +DATABASE_MONGO_RETRY_TIMES=4 +DATABASE_MONGO_RETRY_PAUSE=5s +DATABASE_MONGO_TIMEOUT=30s +DATABASE_MONGO_LRU=100 +DATABASE_BADGER_IN_MEMORY=false +DATABASE_BADGER_GC_RATIO=0.7 +DATABASE_BADGER_CLEANUP_INTERVAL=5m +DATABASE_BADGER_LRU=100 + +# STORAGE: [mock, minio] +STORAGE=minio +STORAGE_MINIO_HOST=embed-minio +STORAGE_MINIO_PORT=9000 +STORAGE_MINIO_ACCESS_KEY=12345678 +STORAGE_MINIO_SECRET_KEY=qwertyui +STORAGE_MINIO_TOKEN= +STORAGE_MINIO_SECURE=false +STORAGE_MINIO_RETRY_TIMES=4 +STORAGE_MINIO_RETRY_PAUSE=5s +STORAGE_MINIO_TIMEOUT=30s +STORAGE_MINIO_LOCATION=eu-central-1 +STORAGE_MINIO_PREFIX= diff --git a/build/config-embed.yml b/build/config-embed.yml deleted file mode 100644 index bc186a7..0000000 --- a/build/config-embed.yml +++ /dev/null @@ -1,89 +0,0 @@ -app: - name: config-embed - ballast: 0 - log: info -server: - domain: - host: - port: 8001 - h2c: false - readTimeout: 60s - writeTimeout: 120s - idleTimeout: 120s - shutdownTimeout: 10s -middleware: - cors: - allowOrigin: "*" - limiter: - requestsPerSecond: 10000 - burst: 10 -controller: - maxNumberOfFiles: 100 - maxFileSize: 5242880 # 5 MB -service: - tempLinks: true - numberOfWorkersCalc: 8 - numberOfWorkersComp: 8 - accuracy: 0.625 -cache: - use: mem - redis: - host: embed-redis - port: 6379 - retry: - times: 4 - pause: 5s - timeout: 30s - timeToLive: 15m - cleanupInterval: 15m -compressor: - use: mock - imaginary: - host: embed-imaginary - port: 9001 - retry: - times: 4 - pause: 5s - timeout: 30s - shortpixel: - url: https://api.shortpixel.com/v2/post-reducer.php - url2: https://api.shortpixel.com/v2/reducer.php - apiKey: abcdefghijklmnopqrst - retry: - times: 2 - pause: 10s - timeout: 30s - wait: 30 - uploadTimeout: 60s - downloadTimeout: 60s - repeatIn: 10s - restartIn: 15m -database: - use: badger - mongo: - host: embed-mongo - port: 27017 - retry: - times: 4 - pause: 5s - timeout: 30s - lru: 100 - badger: - gcRatio: 0.7 - cleanupInterval: 5m - lru: 100 -storage: - use: minio - minio: - host: embed-minio - port: 9000 - accessKey: 12345678 - secretKey: qwertyui - token: - secure: false - retry: - times: 4 - pause: 5s - timeout: 30s - location: eu-central-1 - prefix: http://localhost:9000 diff --git a/build/config-prod.env b/build/config-prod.env new file mode 100644 index 0000000..b0aa3ed --- /dev/null +++ b/build/config-prod.env @@ -0,0 +1,85 @@ +# APP +APP_NAME=config-prod +APP_BALLAST=0 +APP_LOG=info + +# SERVER +SERVER_DOMAIN= +SERVER_HOST= +SERVER_PORT=8001 +SERVER_H2C=true +SERVER_READ_TIMEOUT=60s +SERVER_WRITE_TIMEOUT=120s +SERVER_IDLE_TIMEOUT=120s +SERVER_SHUTDOWN_TIMEOUT=10s + +# MIDDLEWARE +MIDDLEWARE_CORS_ALLOW_ORIGIN=* +MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=10000 # per minute in case of redis cache +MIDDLEWARE_LIMITER_BURST=10 + +# CONTROLLER +CONTROLLER_MAX_NUMBER_OF_FILES=100 +CONTROLLER_MAX_FILE_SIZE=5242880 # 5 MB + +# SERVICE +SERVICE_TEMP_LINKS=false +SERVICE_NUMBER_OF_WORKERS_CALC=8 +SERVICE_NUMBER_OF_WORKERS_COMP=8 +SERVICE_ACCURACY=0.625 + +# CACHE: [mem, redis] +CACHE=redis +CACHE_MEM_CLEANUP_INTERVAL=15m +CACHE_REDIS_HOST=prod-redis +CACHE_REDIS_PORT=6379 +CACHE_REDIS_RETRY_TIMES=4 +CACHE_REDIS_RETRY_PAUSE=5s +CACHE_REDIS_TIMEOUT=30s +CACHE_REDIS_TIME_TO_LIVE=15m + +# COMPRESSOR: [mock, shortpixel, imaginary] +COMPRESSOR=imaginary +COMPRESSOR_SHORTPIXEL_URL=https://api.shortpixel.com/v2/post-reducer.php +COMPRESSOR_SHORTPIXEL_URL2=https://api.shortpixel.com/v2/reducer.php +COMPRESSOR_SHORTPIXEL_API_KEY=abcdefghijklmnopqrst +COMPRESSOR_SHORTPIXEL_RETRY_TIMES=2 +COMPRESSOR_SHORTPIXEL_RETRY_PAUSE=10s +COMPRESSOR_SHORTPIXEL_TIMEOUT=30s +COMPRESSOR_SHORTPIXEL_WAIT=30 +COMPRESSOR_SHORTPIXEL_UPLOAD_TIMEOUT=60s +COMPRESSOR_SHORTPIXEL_DOWNLOAD_TIMEOUT=60s +COMPRESSOR_SHORTPIXEL_REPEAT_IN=10s +COMPRESSOR_SHORTPIXEL_RESTART_IN=15m +COMPRESSOR_IMAGINARY_HOST=prod-imaginary +COMPRESSOR_IMAGINARY_PORT=9001 +COMPRESSOR_IMAGINARY_RETRY_TIMES=4 +COMPRESSOR_IMAGINARY_RETRY_PAUSE=5s +COMPRESSOR_IMAGINARY_TIMEOUT=30s + +# DATABASE: [mem, mongo, badger] +DATABASE=mongo +DATABASE_MONGO_HOST=prod-mongo +DATABASE_MONGO_PORT=27017 +DATABASE_MONGO_RETRY_TIMES=4 +DATABASE_MONGO_RETRY_PAUSE=5s +DATABASE_MONGO_TIMEOUT=30s +DATABASE_MONGO_LRU=100 +DATABASE_BADGER_IN_MEMORY=false +DATABASE_BADGER_GC_RATIO=0.7 +DATABASE_BADGER_CLEANUP_INTERVAL=5m +DATABASE_BADGER_LRU=100 + +# STORAGE: [mock, minio] +STORAGE=minio +STORAGE_MINIO_HOST=prod-minio +STORAGE_MINIO_PORT=9000 +STORAGE_MINIO_ACCESS_KEY=12345678 +STORAGE_MINIO_SECRET_KEY=qwertyui +STORAGE_MINIO_TOKEN= +STORAGE_MINIO_SECURE=false +STORAGE_MINIO_RETRY_TIMES=4 +STORAGE_MINIO_RETRY_PAUSE=5s +STORAGE_MINIO_TIMEOUT=30s +STORAGE_MINIO_LOCATION=eu-central-1 +STORAGE_MINIO_PREFIX=/s3 diff --git a/build/config-prod.yml b/build/config-prod.yml deleted file mode 100644 index ebfb465..0000000 --- a/build/config-prod.yml +++ /dev/null @@ -1,89 +0,0 @@ -app: - name: config-prod - ballast: 0 - log: info -server: - domain: - host: - port: 8001 - h2c: true - readTimeout: 60s - writeTimeout: 120s - idleTimeout: 120s - shutdownTimeout: 10s -middleware: - cors: - allowOrigin: "*" - limiter: - requestsPerSecond: 10000 - burst: 10 -controller: - maxNumberOfFiles: 100 - maxFileSize: 5242880 # 5 MB -service: - tempLinks: false - numberOfWorkersCalc: 8 - numberOfWorkersComp: 8 - accuracy: 0.625 -cache: - use: redis - redis: - host: prod-redis - port: 6379 - retry: - times: 4 - pause: 5s - timeout: 30s - timeToLive: 15m - cleanupInterval: 15m -compressor: - use: imaginary - imaginary: - host: prod-imaginary - port: 9001 - retry: - times: 4 - pause: 5s - timeout: 30s - shortpixel: - url: https://api.shortpixel.com/v2/post-reducer.php - url2: https://api.shortpixel.com/v2/reducer.php - apiKey: abcdefghijklmnopqrst - retry: - times: 2 - pause: 10s - timeout: 30s - wait: 30 - uploadTimeout: 60s - downloadTimeout: 60s - repeatIn: 10s - restartIn: 15m -database: - use: mongo - mongo: - host: prod-mongo - port: 27017 - retry: - times: 4 - pause: 5s - timeout: 30s - lru: 100 - badger: - gcRatio: 0.7 - cleanupInterval: 5m - lru: 100 -storage: - use: minio - minio: - host: prod-minio - port: 9000 - accessKey: 12345678 - secretKey: qwertyui - token: - secure: false - retry: - times: 4 - pause: 5s - timeout: 30s - location: eu-central-1 - prefix: /s3 diff --git a/build/docker-compose-embed.yml b/build/docker-compose-embed.yml index 8a191d8..0d91530 100644 --- a/build/docker-compose-embed.yml +++ b/build/docker-compose-embed.yml @@ -8,7 +8,7 @@ services: ports: - "8001:8001" volumes: - - "./config-embed.yml:/config.yml" + - "./config-embed.env:/config.env" - "./badger/:/badger/" depends_on: - minio diff --git a/build/docker-compose-prod.yml b/build/docker-compose-prod.yml index 6230081..57ca656 100644 --- a/build/docker-compose-prod.yml +++ b/build/docker-compose-prod.yml @@ -22,7 +22,7 @@ services: dockerfile: ./build/Dockerfile-app container_name: prod-app volumes: - - "./config-prod.yml:/config.yml" + - "./config-prod.env:/config.env" depends_on: - redis - imaginary diff --git a/cmd/healthcheck/main.go b/cmd/healthcheck/main.go index 9a3cdb1..274292a 100644 --- a/cmd/healthcheck/main.go +++ b/cmd/healthcheck/main.go @@ -11,14 +11,14 @@ import ( func main() { conf := "" - flag.StringVar(&conf, "config", "./config.yml", "relative filepath to a config file") + flag.StringVar(&conf, "config", "./config.env", "relative filepath to a config file") flag.Parse() viper.SetConfigFile(conf) err := viper.ReadInConfig() if err != nil { os.Exit(1) } - port := viper.GetString("server.port") + port := viper.GetString("server_port") req, err := http.NewRequest(http.MethodGet, "http://localhost:"+port+"/api/health/", http.NoBody) if err != nil { os.Exit(1) diff --git a/config.env b/config.env new file mode 100644 index 0000000..47bf888 --- /dev/null +++ b/config.env @@ -0,0 +1,85 @@ +# APP +APP_NAME=config +APP_BALLAST=0 +APP_LOG=info + +# SERVER +SERVER_DOMAIN= +SERVER_HOST=localhost +SERVER_PORT=8001 +SERVER_H2C=false +SERVER_READ_TIMEOUT=60s +SERVER_WRITE_TIMEOUT=120s +SERVER_IDLE_TIMEOUT=120s +SERVER_SHUTDOWN_TIMEOUT=10s + +# MIDDLEWARE +MIDDLEWARE_CORS_ALLOW_ORIGIN=* +MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=10000 # per minute in case of redis cache +MIDDLEWARE_LIMITER_BURST=10 + +# CONTROLLER +CONTROLLER_MAX_NUMBER_OF_FILES=100 +CONTROLLER_MAX_FILE_SIZE=5242880 # 5 MB + +# SERVICE +SERVICE_TEMP_LINKS=true +SERVICE_NUMBER_OF_WORKERS_CALC=8 +SERVICE_NUMBER_OF_WORKERS_COMP=8 +SERVICE_ACCURACY=0.625 + +# CACHE: [mem, redis] +CACHE=mem +CACHE_MEM_CLEANUP_INTERVAL=15m +CACHE_REDIS_HOST=localhost +CACHE_REDIS_PORT=6379 +CACHE_REDIS_RETRY_TIMES=4 +CACHE_REDIS_RETRY_PAUSE=5s +CACHE_REDIS_TIMEOUT=30s +CACHE_REDIS_TIME_TO_LIVE=15m + +# COMPRESSOR: [mock, shortpixel, imaginary] +COMPRESSOR=mock +COMPRESSOR_SHORTPIXEL_URL=https://api.shortpixel.com/v2/post-reducer.php +COMPRESSOR_SHORTPIXEL_URL2=https://api.shortpixel.com/v2/reducer.php +COMPRESSOR_SHORTPIXEL_API_KEY=abcdefghijklmnopqrst +COMPRESSOR_SHORTPIXEL_RETRY_TIMES=2 +COMPRESSOR_SHORTPIXEL_RETRY_PAUSE=10s +COMPRESSOR_SHORTPIXEL_TIMEOUT=30s +COMPRESSOR_SHORTPIXEL_WAIT=30 +COMPRESSOR_SHORTPIXEL_UPLOAD_TIMEOUT=60s +COMPRESSOR_SHORTPIXEL_DOWNLOAD_TIMEOUT=60s +COMPRESSOR_SHORTPIXEL_REPEAT_IN=10s +COMPRESSOR_SHORTPIXEL_RESTART_IN=15m +COMPRESSOR_IMAGINARY_HOST=localhost +COMPRESSOR_IMAGINARY_PORT=9001 +COMPRESSOR_IMAGINARY_RETRY_TIMES=4 +COMPRESSOR_IMAGINARY_RETRY_PAUSE=5s +COMPRESSOR_IMAGINARY_TIMEOUT=30s + +# DATABASE: [mem, mongo, badger] +DATABASE=mem +DATABASE_MONGO_HOST=localhost +DATABASE_MONGO_PORT=27017 +DATABASE_MONGO_RETRY_TIMES=4 +DATABASE_MONGO_RETRY_PAUSE=5s +DATABASE_MONGO_TIMEOUT=30s +DATABASE_MONGO_LRU=100 +DATABASE_BADGER_IN_MEMORY=false +DATABASE_BADGER_GC_RATIO=0.7 +DATABASE_BADGER_CLEANUP_INTERVAL=5m +DATABASE_BADGER_LRU=100 + +# STORAGE: [mock, minio] +STORAGE=mock +STORAGE_MINIO_HOST=localhost +STORAGE_MINIO_PORT=9000 +STORAGE_MINIO_ACCESS_KEY=12345678 +STORAGE_MINIO_SECRET_KEY=qwertyui +STORAGE_MINIO_TOKEN= +STORAGE_MINIO_SECURE=false +STORAGE_MINIO_RETRY_TIMES=4 +STORAGE_MINIO_RETRY_PAUSE=5s +STORAGE_MINIO_TIMEOUT=30s +STORAGE_MINIO_LOCATION=eu-central-1 +STORAGE_MINIO_PREFIX= diff --git a/config.yml b/config.yml deleted file mode 100644 index 44519da..0000000 --- a/config.yml +++ /dev/null @@ -1,89 +0,0 @@ -app: - name: config - ballast: 0 - log: info -server: - domain: - host: localhost - port: 8001 - h2c: false - readTimeout: 60s - writeTimeout: 120s - idleTimeout: 120s - shutdownTimeout: 10s -middleware: - cors: - allowOrigin: "*" - limiter: - requestsPerSecond: 10000 - burst: 10 -controller: - maxNumberOfFiles: 100 - maxFileSize: 5242880 # 5 MB -service: - tempLinks: true - numberOfWorkersCalc: 8 - numberOfWorkersComp: 8 - accuracy: 0.625 -cache: - use: mem - redis: - host: localhost - port: 6379 - retry: - times: 4 - pause: 5s - timeout: 30s - timeToLive: 15m - cleanupInterval: 15m -compressor: - use: mock - imaginary: - host: localhost - port: 9001 - retry: - times: 4 - pause: 5s - timeout: 30s - shortpixel: - url: https://api.shortpixel.com/v2/post-reducer.php - url2: https://api.shortpixel.com/v2/reducer.php - apiKey: abcdefghijklmnopqrst - retry: - times: 2 - pause: 10s - timeout: 30s - wait: 30 - uploadTimeout: 60s - downloadTimeout: 60s - repeatIn: 10s - restartIn: 15m -database: - use: mem - mongo: - host: localhost - port: 27017 - retry: - times: 4 - pause: 5s - timeout: 30s - lru: 100 - badger: - gcRatio: 0.7 - cleanupInterval: 5m - lru: 100 -storage: - use: mock - minio: - host: localhost - port: 9000 - accessKey: 12345678 - secretKey: qwertyui - token: - secure: false - retry: - times: 4 - pause: 5s - timeout: 30s - location: eu-central-1 - prefix: diff --git a/delivery/http/config.go b/delivery/http/config.go index afa5ba9..55862fb 100644 --- a/delivery/http/config.go +++ b/delivery/http/config.go @@ -3,51 +3,36 @@ package http import ( "time" - "github.com/spf13/viper" + "github.com/zitryss/aye-and-nay/pkg/unit" ) -func newServerConfig() serverConfig { - return serverConfig{ - domain: viper.GetString("server.domain"), - host: viper.GetString("server.host"), - port: viper.GetString("server.port"), - h2c: viper.GetBool("server.h2c"), - readTimeout: viper.GetDuration("server.readTimeout"), - writeTimeout: viper.GetDuration("server.writeTimeout"), - idleTimeout: viper.GetDuration("server.idleTimeout"), - shutdownTimeout: viper.GetDuration("server.shutdownTimeout"), - } +type ServerConfig struct { + Domain string `mapstructure:"SERVER_DOMAIN"` + Host string `mapstructure:"SERVER_HOST"` + Port string `mapstructure:"SERVER_PORT" validate:"required"` + H2C bool `mapstructure:"SERVER_H2C"` + ReadTimeout time.Duration `mapstructure:"SERVER_READ_TIMEOUT" validate:"required"` + WriteTimeout time.Duration `mapstructure:"SERVER_WRITE_TIMEOUT" validate:"required"` + IdleTimeout time.Duration `mapstructure:"SERVER_IDLE_TIMEOUT" validate:"required"` + ShutdownTimeout time.Duration `mapstructure:"SERVER_SHUTDOWN_TIMEOUT" validate:"required"` + Controller ControllerConfig `mapstructure:",squash"` } -type serverConfig struct { - domain string - host string - port string - h2c bool - readTimeout time.Duration - writeTimeout time.Duration - idleTimeout time.Duration - shutdownTimeout time.Duration +type MiddlewareConfig struct { + CorsAllowOrigin string `mapstructure:"MIDDLEWARE_CORS_ALLOW_ORIGIN" validate:"required"` } -func newMiddlewareConfig() middlewareConfig { - return middlewareConfig{ - corsAllowOrigin: viper.GetString("middleware.cors.allowOrigin"), - } +type ControllerConfig struct { + MaxNumberOfFiles int `mapstructure:"CONTROLLER_MAX_NUMBER_OF_FILES" validate:"required"` + MaxFileSize int64 `mapstructure:"CONTROLLER_MAX_FILE_SIZE" validate:"required"` } -type middlewareConfig struct { - corsAllowOrigin string -} - -func newContrConfig() contrConfig { - return contrConfig{ - maxNumberOfFiles: viper.GetInt("controller.maxNumberOfFiles"), - maxFileSize: viper.GetInt64("controller.maxFileSize"), +var ( + DefaultMiddlewareConfig = MiddlewareConfig{ + CorsAllowOrigin: "", } -} - -type contrConfig struct { - maxNumberOfFiles int - maxFileSize int64 -} + DefaultControllerConfig = ControllerConfig{ + MaxNumberOfFiles: 3, + MaxFileSize: 512 * unit.KB, + } +) diff --git a/delivery/http/controller.go b/delivery/http/controller.go index 96fbd46..85bce44 100644 --- a/delivery/http/controller.go +++ b/delivery/http/controller.go @@ -19,14 +19,14 @@ import ( ) func newController( + conf ControllerConfig, serv domain.Servicer, ) controller { - conf := newContrConfig() return controller{conf, serv} } type controller struct { - conf contrConfig + conf ControllerConfig serv domain.Servicer } @@ -37,7 +37,7 @@ func (c *controller) handleAlbum() httprouter.Handle { if !strings.HasPrefix(ct, "multipart/form-data") { return nil, albumRequest{}, errors.Wrap(domain.ErrWrongContentType) } - maxBodySize := int64(c.conf.maxNumberOfFiles) * c.conf.maxFileSize + maxBodySize := int64(c.conf.MaxNumberOfFiles) * c.conf.MaxFileSize if r.ContentLength > maxBodySize { return nil, albumRequest{}, errors.Wrap(domain.ErrBodyTooLarge) } @@ -49,7 +49,7 @@ func (c *controller) handleAlbum() httprouter.Handle { if len(fhs) < 2 { return nil, albumRequest{}, errors.Wrap(domain.ErrNotEnoughImages) } - if len(fhs) > c.conf.maxNumberOfFiles { + if len(fhs) > c.conf.MaxNumberOfFiles { return nil, albumRequest{}, errors.Wrap(domain.ErrTooManyImages) } req := albumRequest{ff: make([]model.File, 0, len(fhs)), multi: r.MultipartForm} @@ -60,7 +60,7 @@ func (c *controller) handleAlbum() httprouter.Handle { _ = req.multi.RemoveAll() }() for _, fh := range fhs { - if fh.Size > c.conf.maxFileSize { + if fh.Size > c.conf.MaxFileSize { return nil, albumRequest{}, errors.Wrap(domain.ErrImageTooLarge) } f, err := fh.Open() diff --git a/delivery/http/controller_test.go b/delivery/http/controller_test.go index d4e04c1..3f8b954 100644 --- a/delivery/http/controller_test.go +++ b/delivery/http/controller_test.go @@ -17,7 +17,6 @@ import ( "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/service" - _ "github.com/zitryss/aye-and-nay/internal/config" . "github.com/zitryss/aye-and-nay/internal/testing" ) @@ -326,7 +325,7 @@ func TestControllerHandleAlbum(t *testing.T) { for _, tt := range tests { t.Run("", func(t *testing.T) { serv := service.NewMock(tt.give.err) - contr := newController(serv) + contr := newController(DefaultControllerConfig, serv) fn := contr.handleAlbum() w := httptest.NewRecorder() body := bytes.Buffer{} @@ -532,7 +531,7 @@ func TestControllerHandleReady(t *testing.T) { for _, tt := range tests { t.Run("", func(t *testing.T) { serv := service.NewMock(tt.give.err) - contr := newController(serv) + contr := newController(DefaultControllerConfig, serv) fn := contr.handleReady() w := httptest.NewRecorder() r := httptest.NewRequest(http.MethodGet, "/api/albums/rRsAAAAAAAA/ready", http.NoBody) @@ -712,7 +711,7 @@ func TestControllerHandlePair(t *testing.T) { for _, tt := range tests { t.Run("", func(t *testing.T) { serv := service.NewMock(tt.give.err) - contr := newController(serv) + contr := newController(DefaultControllerConfig, serv) fn := contr.handlePair() w := httptest.NewRecorder() r := httptest.NewRequest(http.MethodGet, "/api/albums/nkUAAAAAAAA/", http.NoBody) @@ -893,7 +892,7 @@ func TestControllerHandleImage(t *testing.T) { for _, tt := range tests { t.Run("", func(t *testing.T) { serv := service.NewMock(tt.give.err) - contr := newController(serv) + contr := newController(DefaultControllerConfig, serv) fn := contr.handleImage() w := httptest.NewRecorder() r := httptest.NewRequest(http.MethodGet, "/api/images/8v7AAAAAAAA/", http.NoBody) @@ -1073,7 +1072,7 @@ func TestControllerHandleVote(t *testing.T) { for _, tt := range tests { t.Run("", func(t *testing.T) { serv := service.NewMock(tt.give.err) - contr := newController(serv) + contr := newController(DefaultControllerConfig, serv) fn := contr.handleVote() w := httptest.NewRecorder() json := strings.NewReader(`{"album":{"imgFrom":{"token":"fYIAAAAAAAA"},"imgTo":{"token":"foIAAAAAAAA"}}}`) @@ -1255,7 +1254,7 @@ func TestControllerHandleTop(t *testing.T) { for _, tt := range tests { t.Run("", func(t *testing.T) { serv := service.NewMock(tt.give.err) - contr := newController(serv) + contr := newController(DefaultControllerConfig, serv) fn := contr.handleTop() w := httptest.NewRecorder() r := httptest.NewRequest(http.MethodGet, "/api/albums/byYAAAAAAAA/top/", http.NoBody) @@ -1335,7 +1334,7 @@ func TestControllerHandleHealth(t *testing.T) { for _, tt := range tests { t.Run("", func(t *testing.T) { serv := service.NewMock(tt.give.err) - contr := newController(serv) + contr := newController(DefaultControllerConfig, serv) fn := contr.handleHealth() w := httptest.NewRecorder() r := httptest.NewRequest(http.MethodGet, "/api/health/", http.NoBody) diff --git a/delivery/http/middleware.go b/delivery/http/middleware.go index 22d312b..c3efb8b 100644 --- a/delivery/http/middleware.go +++ b/delivery/http/middleware.go @@ -11,19 +11,21 @@ import ( "github.com/zitryss/aye-and-nay/pkg/errors" ) -func NewMiddleware(lim domain.Limiter) *Middleware { - conf := newMiddlewareConfig() +func NewMiddleware( + conf MiddlewareConfig, + lim domain.Limiter, +) *Middleware { return &Middleware{conf, lim} } type Middleware struct { - conf middlewareConfig + conf MiddlewareConfig lim domain.Limiter } func (m *Middleware) Chain(h http.Handler) http.Handler { c := cors.New(cors.Options{ - AllowedOrigins: []string{m.conf.corsAllowOrigin}, + AllowedOrigins: []string{m.conf.CorsAllowOrigin}, AllowedMethods: []string{http.MethodGet, http.MethodPost, http.MethodPatch}, }) return c.Handler(m.recover(m.limit(h))) diff --git a/delivery/http/middleware_test.go b/delivery/http/middleware_test.go index d067fd6..6149e40 100644 --- a/delivery/http/middleware_test.go +++ b/delivery/http/middleware_test.go @@ -9,7 +9,6 @@ import ( "net/http/httptest" "testing" - _ "github.com/zitryss/aye-and-nay/internal/config" . "github.com/zitryss/aye-and-nay/internal/testing" ) @@ -33,7 +32,7 @@ func TestMiddlewareRecover(t *testing.T) { _, _ = io.WriteString(w, "I'm a teapot") } lim := limiterMockPos{} - middle := NewMiddleware(lim) + middle := NewMiddleware(DefaultMiddlewareConfig, lim) handler := middle.recover(http.HandlerFunc(fn)) w := httptest.NewRecorder() r := httptest.NewRequest(http.MethodGet, "/", http.NoBody) @@ -47,7 +46,7 @@ func TestMiddlewareRecover(t *testing.T) { panic("don't") } lim := limiterMockPos{} - middle := NewMiddleware(lim) + middle := NewMiddleware(DefaultMiddlewareConfig, lim) handler := middle.recover(http.HandlerFunc(fn)) w := httptest.NewRecorder() r := httptest.NewRequest(http.MethodGet, "/", http.NoBody) @@ -66,7 +65,7 @@ func TestMiddlewareLimit(t *testing.T) { _, _ = io.WriteString(w, "I'm a teapot") } lim := limiterMockPos{} - middle := NewMiddleware(lim) + middle := NewMiddleware(DefaultMiddlewareConfig, lim) handler := middle.limit(http.HandlerFunc(fn)) w := httptest.NewRecorder() r := httptest.NewRequest(http.MethodGet, "/", http.NoBody) @@ -82,7 +81,7 @@ func TestMiddlewareLimit(t *testing.T) { _, _ = io.WriteString(w, "I'm a teapot") } lim := limiterMockNeg{} - middle := NewMiddleware(lim) + middle := NewMiddleware(DefaultMiddlewareConfig, lim) handler := middle.limit(http.HandlerFunc(fn)) w := httptest.NewRecorder() r := httptest.NewRequest(http.MethodGet, "/", http.NoBody) diff --git a/delivery/http/server.go b/delivery/http/server.go index 1675aac..935c444 100644 --- a/delivery/http/server.go +++ b/delivery/http/server.go @@ -18,12 +18,12 @@ var ( ) func NewServer( + conf ServerConfig, middle func(http.Handler) http.Handler, serv domain.Servicer, serverWait chan<- error, ) (*Server, error) { - conf := newServerConfig() - contr := newController(serv) + contr := newController(conf.Controller, serv) router := newRouter(contr) handler := middle(router) srv, err := newServer(conf, handler) @@ -33,29 +33,29 @@ func NewServer( return &Server{conf, srv, serverWait}, nil } -func newServer(conf serverConfig, handler http.Handler) (*http.Server, error) { +func newServer(conf ServerConfig, handler http.Handler) (*http.Server, error) { srv := &http.Server{ - Addr: conf.host + ":" + conf.port, - Handler: http.TimeoutHandler(handler, conf.writeTimeout, ""), - ReadTimeout: conf.readTimeout, - WriteTimeout: conf.writeTimeout + 1*time.Second, - IdleTimeout: conf.idleTimeout, + Addr: conf.Host + ":" + conf.Port, + Handler: http.TimeoutHandler(handler, conf.WriteTimeout, ""), + ReadTimeout: conf.ReadTimeout, + WriteTimeout: conf.WriteTimeout + 1*time.Second, + IdleTimeout: conf.IdleTimeout, } - if conf.domain != "" { - tlsConfig, err := certmagic.TLS([]string{conf.domain}) + if conf.Domain != "" { + tlsConfig, err := certmagic.TLS([]string{conf.Domain}) if err != nil { return nil, errors.Wrap(err) } srv.TLSConfig = tlsConfig } - if conf.h2c { + if conf.H2C { srv.Handler = h2c.NewHandler(srv.Handler, &http2.Server{}) } return srv, nil } type Server struct { - conf serverConfig + conf ServerConfig srv *http.Server serverWait chan<- error } @@ -76,7 +76,7 @@ func (s *Server) Start() error { } func (s *Server) shutdown() { - ctx, cancel := context.WithTimeout(context.Background(), s.conf.shutdownTimeout) + ctx, cancel := context.WithTimeout(context.Background(), s.conf.ShutdownTimeout) defer cancel() err := s.srv.Shutdown(ctx) s.serverWait <- err diff --git a/domain/service/config.go b/domain/service/config.go index 2bdc5c9..7331dd1 100644 --- a/domain/service/config.go +++ b/domain/service/config.go @@ -1,21 +1,17 @@ package service -import ( - "github.com/spf13/viper" -) - -func newServiceConfig() serviceConfig { - return serviceConfig{ - tempLinks: viper.GetBool("service.tempLinks"), - numberOfWorkersCalc: viper.GetInt("service.numberOfWorkersCalc"), - numberOfWorkersComp: viper.GetInt("service.numberOfWorkersComp"), - accuracy: viper.GetFloat64("service.accuracy"), - } +type ServiceConfig struct { + TempLinks bool `mapstructure:"SERVICE_TEMP_LINKS"` + NumberOfWorkersCalc int `mapstructure:"SERVICE_NUMBER_OF_WORKERS_CALC" validate:"required"` + NumberOfWorkersComp int `mapstructure:"SERVICE_NUMBER_OF_WORKERS_COMP" validate:"required"` + Accuracy float64 `mapstructure:"SERVICE_ACCURACY" validate:"required"` } -type serviceConfig struct { - tempLinks bool - numberOfWorkersCalc int - numberOfWorkersComp int - accuracy float64 -} +var ( + DefaultServiceConfig = ServiceConfig{ + TempLinks: true, + NumberOfWorkersCalc: 2, + NumberOfWorkersComp: 2, + Accuracy: 0.625, + } +) diff --git a/domain/service/queue_integration_test.go b/domain/service/queue_integration_test.go index 4bee3b5..a55ae47 100644 --- a/domain/service/queue_integration_test.go +++ b/domain/service/queue_integration_test.go @@ -11,7 +11,7 @@ import ( ) func TestPQueueIntegration(t *testing.T) { - redis, err := cache.NewRedis() + redis, err := cache.NewRedis(cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } diff --git a/domain/service/queue_test.go b/domain/service/queue_test.go index fedc571..df29b57 100644 --- a/domain/service/queue_test.go +++ b/domain/service/queue_test.go @@ -11,7 +11,7 @@ import ( ) func TestPQueue(t *testing.T) { - mem := cache.NewMem() + mem := cache.NewMem(cache.DefaultMemConfig) pq := newPQueue(0xFE28, mem) ctx, cancel := context.WithCancel(context.Background()) defer cancel() diff --git a/domain/service/service.go b/domain/service/service.go index cc8afa1..f900602 100644 --- a/domain/service/service.go +++ b/domain/service/service.go @@ -13,6 +13,7 @@ import ( ) func New( + conf ServiceConfig, comp domain.Compresser, stor domain.Storager, pers domain.Databaser, @@ -22,7 +23,6 @@ func New( qDel *QueueDel, opts ...options, ) *Service { - conf := newServiceConfig() s := &Service{ conf: conf, comp: comp, @@ -111,7 +111,7 @@ func WithHeartbeatDel(ch chan<- interface{}) options { } type Service struct { - conf serviceConfig + conf ServiceConfig comp domain.Compresser stor domain.Storager pers domain.Databaser @@ -205,7 +205,7 @@ func (s *Service) Pair(ctx context.Context, album uint64) (model.Image, model.Im src2 := "" token1 := image1 token2 := image2 - if s.conf.tempLinks { + if s.conf.TempLinks { token1, err = s.rand.id() if err != nil { return model.Image{}, model.Image{}, errors.Wrap(err) @@ -278,7 +278,7 @@ func (s *Service) Vote(ctx context.Context, album uint64, tokenFrom uint64, toke imageFrom := tokenFrom imageTo := tokenTo err := error(nil) - if s.conf.tempLinks { + if s.conf.TempLinks { _, imageFrom, err = s.token.Get(ctx, tokenFrom) if err != nil { return errors.Wrap(err) diff --git a/domain/service/service_integration_test.go b/domain/service/service_integration_test.go index 6beb0de..017a3e3 100644 --- a/domain/service/service_integration_test.go +++ b/domain/service/service_integration_test.go @@ -10,7 +10,6 @@ import ( "testing" "time" - "github.com/spf13/viper" "golang.org/x/sync/errgroup" "github.com/zitryss/aye-and-nay/domain/domain" @@ -19,7 +18,6 @@ import ( "github.com/zitryss/aye-and-nay/infrastructure/compressor" "github.com/zitryss/aye-and-nay/infrastructure/database" "github.com/zitryss/aye-and-nay/infrastructure/storage" - _ "github.com/zitryss/aye-and-nay/internal/config" "github.com/zitryss/aye-and-nay/internal/dockertest" . "github.com/zitryss/aye-and-nay/internal/testing" "github.com/zitryss/aye-and-nay/pkg/env" @@ -33,10 +31,20 @@ func TestMain(m *testing.M) { log.SetOutput(os.Stderr) log.SetLevel(log.CRITICAL) docker := dockertest.New() - docker.RunRedis() - docker.RunImaginary() - docker.RunMongo() - docker.RunMinio() + host := &cache.DefaultRedisConfig.Host + port := &cache.DefaultRedisConfig.Port + docker.RunRedis(host, port) + host = &compressor.DefaultImaginaryConfig.Host + port = &compressor.DefaultImaginaryConfig.Port + docker.RunImaginary(host, port) + host = &database.DefaultMongoConfig.Host + port = &database.DefaultMongoConfig.Port + docker.RunMongo(host, port) + host = &storage.DefaultMinioConfig.Host + port = &storage.DefaultMinioConfig.Port + accessKey := storage.DefaultMinioConfig.AccessKey + secretKey := storage.DefaultMinioConfig.SecretKey + docker.RunMinio(host, port, accessKey, secretKey) log.SetOutput(io.Discard) code := m.Run() docker.Purge() @@ -57,19 +65,19 @@ func TestServiceIntegrationAlbum(t *testing.T) { }() ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary() + imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio() + minio, err := storage.NewMinio(storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo() + mongo, err := database.NewMongo(database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis() + redis, err := cache.NewRedis(cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -80,7 +88,7 @@ func TestServiceIntegrationAlbum(t *testing.T) { qDel := &QueueDel{} qDel.Monitor(ctx) heartbeatComp := make(chan interface{}) - serv := New(imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithHeartbeatComp(heartbeatComp)) + serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithHeartbeatComp(heartbeatComp)) gComp, ctxComp := errgroup.WithContext(ctx) serv.StartWorkingPoolComp(ctxComp, gComp) files := []model.File{Png(), Png()} @@ -116,17 +124,17 @@ func TestServiceIntegrationAlbum(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() heartbeatRestart := make(chan interface{}) - comp := compressor.NewShortPixel(compressor.WithHeartbeatRestart(heartbeatRestart)) + comp := compressor.NewShortpixel(compressor.DefaultShortpixelConfig, compressor.WithHeartbeatRestart(heartbeatRestart)) comp.Monitor() - minio, err := storage.NewMinio() + minio, err := storage.NewMinio(storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo() + mongo, err := database.NewMongo(database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis() + redis, err := cache.NewRedis(cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -137,7 +145,7 @@ func TestServiceIntegrationAlbum(t *testing.T) { qDel := &QueueDel{} qDel.Monitor(ctx) heartbeatComp := make(chan interface{}) - serv := New(comp, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithHeartbeatComp(heartbeatComp)) + serv := New(DefaultServiceConfig, comp, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithHeartbeatComp(heartbeatComp)) gComp, ctxComp := errgroup.WithContext(ctx) serv.StartWorkingPoolComp(ctxComp, gComp) files := []model.File{Png(), Png()} @@ -228,19 +236,19 @@ func TestServiceIntegrationPair(t *testing.T) { } ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary() + imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio() + minio, err := storage.NewMinio(storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo() + mongo, err := database.NewMongo(database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis() + redis, err := cache.NewRedis(cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -250,7 +258,7 @@ func TestServiceIntegrationPair(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) if err != nil { @@ -306,8 +314,6 @@ func TestServiceIntegrationPair(t *testing.T) { } }) t.Run("Positive2", func(t *testing.T) { - viper.Set("service.tempLinks", false) - defer viper.Set("service.tempLinks", true) fn1 := func() func() (uint64, error) { i := uint64(0) return func() (uint64, error) { @@ -319,19 +325,19 @@ func TestServiceIntegrationPair(t *testing.T) { } ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary() + imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio() + minio, err := storage.NewMinio(storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo() + mongo, err := database.NewMongo(database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis() + redis, err := cache.NewRedis(cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -341,7 +347,9 @@ func TestServiceIntegrationPair(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + conf := DefaultServiceConfig + conf.TempLinks = false + serv := New(conf, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) if err != nil { @@ -399,19 +407,19 @@ func TestServiceIntegrationPair(t *testing.T) { t.Run("Negative", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary() + imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio() + minio, err := storage.NewMinio(storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo() + mongo, err := database.NewMongo(database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis() + redis, err := cache.NewRedis(cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -421,7 +429,7 @@ func TestServiceIntegrationPair(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(imaginary, minio, mongo, redis, qCalc, qComp, qDel) + serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel) _, _, err = serv.Pair(ctx, 0xEB46) if !errors.Is(err, domain.ErrAlbumNotFound) { t.Error(err) @@ -442,19 +450,19 @@ func TestServiceIntegrationImage(t *testing.T) { } ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary() + imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio() + minio, err := storage.NewMinio(storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo() + mongo, err := database.NewMongo(database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis() + redis, err := cache.NewRedis(cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -464,7 +472,7 @@ func TestServiceIntegrationImage(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) if err != nil { @@ -492,19 +500,19 @@ func TestServiceIntegrationImage(t *testing.T) { t.Run("Negative", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary() + imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio() + minio, err := storage.NewMinio(storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo() + mongo, err := database.NewMongo(database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis() + redis, err := cache.NewRedis(cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -514,7 +522,7 @@ func TestServiceIntegrationImage(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(imaginary, minio, mongo, redis, qCalc, qComp, qDel) + serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel) _, err = serv.Image(ctx, 0xE283) if !errors.Is(err, domain.ErrTokenNotFound) { t.Error(err) @@ -535,19 +543,19 @@ func TestServiceIntegrationVote(t *testing.T) { } ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary() + imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio() + minio, err := storage.NewMinio(storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo() + mongo, err := database.NewMongo(database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis() + redis, err := cache.NewRedis(cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -557,7 +565,7 @@ func TestServiceIntegrationVote(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) if err != nil { @@ -573,8 +581,6 @@ func TestServiceIntegrationVote(t *testing.T) { } }) t.Run("Positive2", func(t *testing.T) { - viper.Set("service.tempLinks", false) - defer viper.Set("service.tempLinks", true) fn1 := func() func() (uint64, error) { i := uint64(0) return func() (uint64, error) { @@ -586,19 +592,19 @@ func TestServiceIntegrationVote(t *testing.T) { } ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary() + imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio() + minio, err := storage.NewMinio(storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo() + mongo, err := database.NewMongo(database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis() + redis, err := cache.NewRedis(cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -608,7 +614,9 @@ func TestServiceIntegrationVote(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + conf := DefaultServiceConfig + conf.TempLinks = false + serv := New(conf, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) if err != nil { @@ -635,19 +643,19 @@ func TestServiceIntegrationVote(t *testing.T) { } ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary() + imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio() + minio, err := storage.NewMinio(storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo() + mongo, err := database.NewMongo(database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis() + redis, err := cache.NewRedis(cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -657,7 +665,7 @@ func TestServiceIntegrationVote(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) if err != nil { @@ -684,19 +692,19 @@ func TestServiceIntegrationVote(t *testing.T) { } ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary() + imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio() + minio, err := storage.NewMinio(storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo() + mongo, err := database.NewMongo(database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis() + redis, err := cache.NewRedis(cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -706,7 +714,7 @@ func TestServiceIntegrationVote(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) if err != nil { @@ -736,19 +744,19 @@ func TestServiceIntegrationTop(t *testing.T) { } ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary() + imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio() + minio, err := storage.NewMinio(storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo() + mongo, err := database.NewMongo(database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis() + redis, err := cache.NewRedis(cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -759,7 +767,7 @@ func TestServiceIntegrationTop(t *testing.T) { qDel := &QueueDel{} qDel.Monitor(ctx) heartbeatCalc := make(chan interface{}) - serv := New(imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2), WithHeartbeatCalc(heartbeatCalc)) + serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2), WithHeartbeatCalc(heartbeatCalc)) gCalc, ctxCalc := errgroup.WithContext(ctx) serv.StartWorkingPoolCalc(ctxCalc, gCalc) files := []model.File{Png(), Png()} @@ -799,19 +807,19 @@ func TestServiceIntegrationTop(t *testing.T) { t.Run("Negative", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary() + imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio() + minio, err := storage.NewMinio(storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo() + mongo, err := database.NewMongo(database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis() + redis, err := cache.NewRedis(cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -821,7 +829,7 @@ func TestServiceIntegrationTop(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(imaginary, minio, mongo, redis, qCalc, qComp, qDel) + serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel) _, err = serv.Top(ctx, 0x83CD) if !errors.Is(err, domain.ErrAlbumNotFound) { t.Error(err) @@ -833,19 +841,19 @@ func TestServiceIntegrationDelete(t *testing.T) { t.Run("Positive1", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary() + imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio() + minio, err := storage.NewMinio(storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo() + mongo, err := database.NewMongo(database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis() + redis, err := cache.NewRedis(cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -868,7 +876,7 @@ func TestServiceIntegrationDelete(t *testing.T) { t.Error(err) } heartbeatDel := make(chan interface{}) - serv := New(imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) + serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) err = serv.CleanUp(ctx) if err != nil { t.Error(err) @@ -891,19 +899,19 @@ func TestServiceIntegrationDelete(t *testing.T) { t.Run("Positive2", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary() + imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio() + minio, err := storage.NewMinio(storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo() + mongo, err := database.NewMongo(database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis() + redis, err := cache.NewRedis(cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -914,7 +922,7 @@ func TestServiceIntegrationDelete(t *testing.T) { qDel := &QueueDel{newPQueue(0xEF3F, redis)} qDel.Monitor(ctx) heartbeatDel := make(chan interface{}) - serv := New(imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) + serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) gDel, ctxDel := errgroup.WithContext(ctx) serv.StartWorkingPoolDel(ctxDel, gDel) files := []model.File{Png(), Png()} @@ -932,19 +940,19 @@ func TestServiceIntegrationDelete(t *testing.T) { t.Run("Negative", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary() + imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio() + minio, err := storage.NewMinio(storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo() + mongo, err := database.NewMongo(database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis() + redis, err := cache.NewRedis(cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -955,7 +963,7 @@ func TestServiceIntegrationDelete(t *testing.T) { qDel := &QueueDel{newPQueue(0xEF3F, redis)} qDel.Monitor(ctx) heartbeatDel := make(chan interface{}) - serv := New(imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) + serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) gDel, ctxDel := errgroup.WithContext(ctx) serv.StartWorkingPoolDel(ctxDel, gDel) files := []model.File{Png(), Png()} @@ -979,19 +987,19 @@ func TestServiceIntegrationDelete(t *testing.T) { func TestServiceIntegrationHealth(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary() + imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio() + minio, err := storage.NewMinio(storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo() + mongo, err := database.NewMongo(database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis() + redis, err := cache.NewRedis(cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -1001,7 +1009,7 @@ func TestServiceIntegrationHealth(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(imaginary, minio, mongo, redis, qCalc, qComp, qDel) + serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel) _, err = serv.Health(ctx) if err != nil { t.Error(err) diff --git a/domain/service/service_test.go b/domain/service/service_test.go index fe07842..778793e 100644 --- a/domain/service/service_test.go +++ b/domain/service/service_test.go @@ -8,7 +8,6 @@ import ( "testing" "time" - "github.com/spf13/viper" "golang.org/x/sync/errgroup" "github.com/zitryss/aye-and-nay/domain/domain" @@ -17,7 +16,6 @@ import ( "github.com/zitryss/aye-and-nay/infrastructure/compressor" "github.com/zitryss/aye-and-nay/infrastructure/database" "github.com/zitryss/aye-and-nay/infrastructure/storage" - _ "github.com/zitryss/aye-and-nay/internal/config" . "github.com/zitryss/aye-and-nay/internal/testing" "github.com/zitryss/aye-and-nay/pkg/errors" ) @@ -35,8 +33,8 @@ func TestServiceAlbum(t *testing.T) { defer cancel() comp := compressor.NewMock() stor := storage.NewMock() - mDb := database.NewMem() - mCache := cache.NewMem() + mDb := database.NewMem(database.DefaultMemConfig) + mCache := cache.NewMem(cache.DefaultMemConfig) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{newQueue(0xB273, mCache)} @@ -44,7 +42,7 @@ func TestServiceAlbum(t *testing.T) { qDel := &QueueDel{} qDel.Monitor(ctx) heartbeatComp := make(chan interface{}) - serv := New(comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithHeartbeatComp(heartbeatComp)) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithHeartbeatComp(heartbeatComp)) gComp, ctxComp := errgroup.WithContext(ctx) serv.StartWorkingPoolComp(ctxComp, gComp) files := []model.File{Png(), Png()} @@ -80,11 +78,11 @@ func TestServiceAlbum(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() heartbeatRestart := make(chan interface{}) - comp := compressor.NewShortPixel(compressor.WithHeartbeatRestart(heartbeatRestart)) + comp := compressor.NewShortpixel(compressor.DefaultShortpixelConfig, compressor.WithHeartbeatRestart(heartbeatRestart)) comp.Monitor() stor := storage.NewMock() - mDb := database.NewMem() - mCache := cache.NewMem() + mDb := database.NewMem(database.DefaultMemConfig) + mCache := cache.NewMem(cache.DefaultMemConfig) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{newQueue(0x88AB, mCache)} @@ -92,7 +90,7 @@ func TestServiceAlbum(t *testing.T) { qDel := &QueueDel{} qDel.Monitor(ctx) heartbeatComp := make(chan interface{}) - serv := New(comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithHeartbeatComp(heartbeatComp)) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithHeartbeatComp(heartbeatComp)) gComp, ctxComp := errgroup.WithContext(ctx) serv.StartWorkingPoolComp(ctxComp, gComp) files := []model.File{Png(), Png()} @@ -185,15 +183,15 @@ func TestServicePair(t *testing.T) { defer cancel() comp := compressor.NewMock() stor := storage.NewMock() - mDb := database.NewMem() - mCache := cache.NewMem() + mDb := database.NewMem(database.DefaultMemConfig) + mCache := cache.NewMem(cache.DefaultMemConfig) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) if err != nil { @@ -249,8 +247,6 @@ func TestServicePair(t *testing.T) { } }) t.Run("Positive2", func(t *testing.T) { - viper.Set("service.tempLinks", false) - defer viper.Set("service.tempLinks", true) fn1 := func() func() (uint64, error) { i := uint64(0) return func() (uint64, error) { @@ -264,15 +260,17 @@ func TestServicePair(t *testing.T) { defer cancel() comp := compressor.NewMock() stor := storage.NewMock() - mDb := database.NewMem() - mCache := cache.NewMem() + mDb := database.NewMem(database.DefaultMemConfig) + mCache := cache.NewMem(cache.DefaultMemConfig) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + conf := DefaultServiceConfig + conf.TempLinks = false + serv := New(conf, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) if err != nil { @@ -332,15 +330,15 @@ func TestServicePair(t *testing.T) { defer cancel() comp := compressor.NewMock() stor := storage.NewMock() - mDb := database.NewMem() - mCache := cache.NewMem() + mDb := database.NewMem(database.DefaultMemConfig) + mCache := cache.NewMem(cache.DefaultMemConfig) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(comp, stor, mDb, mCache, qCalc, qComp, qDel) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel) _, _, err := serv.Pair(ctx, 0xEB46) if !errors.Is(err, domain.ErrAlbumNotFound) { t.Error(err) @@ -363,15 +361,15 @@ func TestServiceImage(t *testing.T) { defer cancel() comp := compressor.NewMock() stor := storage.NewMock() - mDb := database.NewMem() - mCache := cache.NewMem() + mDb := database.NewMem(database.DefaultMemConfig) + mCache := cache.NewMem(cache.DefaultMemConfig) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) if err != nil { @@ -401,15 +399,15 @@ func TestServiceImage(t *testing.T) { defer cancel() comp := compressor.NewMock() stor := storage.NewMock() - mDb := database.NewMem() - mCache := cache.NewMem() + mDb := database.NewMem(database.DefaultMemConfig) + mCache := cache.NewMem(cache.DefaultMemConfig) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(comp, stor, mDb, mCache, qCalc, qComp, qDel) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel) _, err := serv.Image(ctx, 0xE283) if !errors.Is(err, domain.ErrTokenNotFound) { t.Error(err) @@ -432,15 +430,15 @@ func TestServiceVote(t *testing.T) { defer cancel() comp := compressor.NewMock() stor := storage.NewMock() - mDb := database.NewMem() - mCache := cache.NewMem() + mDb := database.NewMem(database.DefaultMemConfig) + mCache := cache.NewMem(cache.DefaultMemConfig) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) if err != nil { @@ -456,8 +454,6 @@ func TestServiceVote(t *testing.T) { } }) t.Run("Positive2", func(t *testing.T) { - viper.Set("service.tempLinks", false) - defer viper.Set("service.tempLinks", true) fn1 := func() func() (uint64, error) { i := uint64(0) return func() (uint64, error) { @@ -471,15 +467,17 @@ func TestServiceVote(t *testing.T) { defer cancel() comp := compressor.NewMock() stor := storage.NewMock() - mDb := database.NewMem() - mCache := cache.NewMem() + mDb := database.NewMem(database.DefaultMemConfig) + mCache := cache.NewMem(cache.DefaultMemConfig) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + conf := DefaultServiceConfig + conf.TempLinks = false + serv := New(conf, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) if err != nil { @@ -508,15 +506,15 @@ func TestServiceVote(t *testing.T) { defer cancel() comp := compressor.NewMock() stor := storage.NewMock() - mDb := database.NewMem() - mCache := cache.NewMem() + mDb := database.NewMem(database.DefaultMemConfig) + mCache := cache.NewMem(cache.DefaultMemConfig) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) if err != nil { @@ -545,15 +543,15 @@ func TestServiceVote(t *testing.T) { defer cancel() comp := compressor.NewMock() stor := storage.NewMock() - mDb := database.NewMem() - mCache := cache.NewMem() + mDb := database.NewMem(database.DefaultMemConfig) + mCache := cache.NewMem(cache.DefaultMemConfig) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) if err != nil { @@ -585,8 +583,8 @@ func TestServiceTop(t *testing.T) { defer cancel() comp := compressor.NewMock() stor := storage.NewMock() - mDb := database.NewMem() - mCache := cache.NewMem() + mDb := database.NewMem(database.DefaultMemConfig) + mCache := cache.NewMem(cache.DefaultMemConfig) qCalc := &QueueCalc{newQueue(0x1A01, mCache)} qCalc.Monitor(ctx) qComp := &QueueComp{} @@ -594,7 +592,7 @@ func TestServiceTop(t *testing.T) { qDel := &QueueDel{} qDel.Monitor(ctx) heartbeatCalc := make(chan interface{}) - serv := New(comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2), WithHeartbeatCalc(heartbeatCalc)) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2), WithHeartbeatCalc(heartbeatCalc)) gCalc, ctxCalc := errgroup.WithContext(ctx) serv.StartWorkingPoolCalc(ctxCalc, gCalc) files := []model.File{Png(), Png()} @@ -636,15 +634,15 @@ func TestServiceTop(t *testing.T) { defer cancel() comp := compressor.NewMock() stor := storage.NewMock() - mDb := database.NewMem() - mCache := cache.NewMem() + mDb := database.NewMem(database.DefaultMemConfig) + mCache := cache.NewMem(cache.DefaultMemConfig) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(comp, stor, mDb, mCache, qCalc, qComp, qDel) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel) _, err := serv.Top(ctx, 0x83CD) if !errors.Is(err, domain.ErrAlbumNotFound) { t.Error(err) @@ -658,8 +656,8 @@ func TestServiceDelete(t *testing.T) { defer cancel() comp := compressor.NewMock() stor := storage.NewMock() - mDb := database.NewMem() - mCache := cache.NewMem() + mDb := database.NewMem(database.DefaultMemConfig) + mCache := cache.NewMem(cache.DefaultMemConfig) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} @@ -679,7 +677,7 @@ func TestServiceDelete(t *testing.T) { t.Error(err) } heartbeatDel := make(chan interface{}) - serv := New(comp, stor, mDb, mCache, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) err = serv.CleanUp(ctx) if err != nil { t.Error(err) @@ -700,8 +698,8 @@ func TestServiceDelete(t *testing.T) { defer cancel() comp := compressor.NewMock() stor := storage.NewMock() - mDb := database.NewMem() - mCache := cache.NewMem() + mDb := database.NewMem(database.DefaultMemConfig) + mCache := cache.NewMem(cache.DefaultMemConfig) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} @@ -709,7 +707,7 @@ func TestServiceDelete(t *testing.T) { qDel := &QueueDel{newPQueue(0xEF3F, mCache)} qDel.Monitor(ctx) heartbeatDel := make(chan interface{}) - serv := New(comp, stor, mDb, mCache, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) gDel, ctxDel := errgroup.WithContext(ctx) serv.StartWorkingPoolDel(ctxDel, gDel) files := []model.File{Png(), Png()} @@ -729,8 +727,8 @@ func TestServiceDelete(t *testing.T) { defer cancel() comp := compressor.NewMock() stor := storage.NewMock() - mDb := database.NewMem() - mCache := cache.NewMem() + mDb := database.NewMem(database.DefaultMemConfig) + mCache := cache.NewMem(cache.DefaultMemConfig) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} @@ -738,7 +736,7 @@ func TestServiceDelete(t *testing.T) { qDel := &QueueDel{newPQueue(0xEF3F, mCache)} qDel.Monitor(ctx) heartbeatDel := make(chan interface{}) - serv := New(comp, stor, mDb, mCache, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) gDel, ctxDel := errgroup.WithContext(ctx) serv.StartWorkingPoolDel(ctxDel, gDel) files := []model.File{Png(), Png()} @@ -764,15 +762,15 @@ func TestServiceHealth(t *testing.T) { defer cancel() comp := compressor.NewMock() stor := storage.NewMock() - mDb := database.NewMem() - mCache := cache.NewMem() + mDb := database.NewMem(database.DefaultMemConfig) + mCache := cache.NewMem(cache.DefaultMemConfig) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(comp, stor, mDb, mCache, qCalc, qComp, qDel) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel) _, err := serv.Health(ctx) if err != nil { t.Error(err) diff --git a/domain/service/workerpool.go b/domain/service/workerpool.go index c761aac..2d010e7 100644 --- a/domain/service/workerpool.go +++ b/domain/service/workerpool.go @@ -12,7 +12,7 @@ import ( func (s *Service) StartWorkingPoolCalc(ctx context.Context, g *errgroup.Group) { go func() { - sem := make(chan struct{}, s.conf.numberOfWorkersCalc) + sem := make(chan struct{}, s.conf.NumberOfWorkersCalc) for { select { case sem <- struct{}{}: @@ -58,7 +58,7 @@ func (s *Service) StartWorkingPoolCalc(ctx context.Context, g *errgroup.Group) { e = err continue } - vect := linalg.PageRank(edgs, s.conf.accuracy) + vect := linalg.PageRank(edgs, s.conf.Accuracy) err = s.pers.UpdateRatings(ctx, album, vect) if err != nil { err = errors.Wrap(err) @@ -77,7 +77,7 @@ func (s *Service) StartWorkingPoolCalc(ctx context.Context, g *errgroup.Group) { func (s *Service) StartWorkingPoolComp(ctx context.Context, g *errgroup.Group) { go func() { - sem := make(chan struct{}, s.conf.numberOfWorkersComp) + sem := make(chan struct{}, s.conf.NumberOfWorkersComp) for { select { case sem <- struct{}{}: diff --git a/go.mod b/go.mod index 3ff8427..52d356a 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/cheggaaa/pb/v3 v3.0.8 github.com/dgraph-io/badger/v3 v3.2103.2 github.com/emirpasic/gods v1.12.0 + github.com/go-playground/validator v9.31.0+incompatible github.com/go-redis/redis/v8 v8.11.4 github.com/hashicorp/golang-lru v0.5.4 github.com/julienschmidt/httprouter v1.3.0 @@ -38,6 +39,8 @@ require ( github.com/dustin/go-humanize v1.0.0 // indirect github.com/fatih/color v1.12.0 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/go-playground/locales v0.12.1 // indirect + github.com/go-playground/universal-translator v0.16.0 // indirect github.com/go-stack/stack v1.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/glog v1.0.0 // indirect @@ -52,6 +55,7 @@ require ( github.com/klauspost/compress v1.13.6 // indirect github.com/klauspost/cpuid/v2 v2.0.9 // indirect github.com/kr/text v0.2.0 // indirect + github.com/leodido/go-urn v1.1.0 // indirect github.com/lib/pq v1.8.0 // indirect github.com/libdns/libdns v0.2.1 // indirect github.com/magiconair/properties v1.8.5 // indirect diff --git a/go.sum b/go.sum index e58be76..9e95ff6 100644 --- a/go.sum +++ b/go.sum @@ -162,8 +162,12 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc= github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= +github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= +github.com/go-playground/validator v9.31.0+incompatible h1:UA72EPEogEnq76ehGdEDp4Mit+3FDh548oRqwVgNsHA= +github.com/go-playground/validator v9.31.0+incompatible/go.mod h1:yrEkQXlcI+PugkyDjY2bRrL/UBU4f3rvrgkN3V8JEig= github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg= github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -333,6 +337,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 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.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/lib/pq v0.0.0-20180327071824-d34b9ff171c2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg= @@ -995,6 +1000,7 @@ gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLF gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/infrastructure/cache/cache.go b/infrastructure/cache/cache.go index 14b62e9..68b7d3f 100644 --- a/infrastructure/cache/cache.go +++ b/infrastructure/cache/cache.go @@ -1,21 +1,23 @@ package cache import ( + "context" + "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/pkg/log" ) -func New(s string) (domain.Cacher, error) { - switch s { +func New(ctx context.Context, conf CacheConfig) (domain.Cacher, error) { + switch conf.Cache { case "redis": log.Info("connecting to cache") - return NewRedis() + return NewRedis(ctx, conf.Redis) case "mem": - mem := NewMem() + mem := NewMem(conf.Mem) mem.Monitor() return mem, nil default: - mem := NewMem() + mem := NewMem(conf.Mem) mem.Monitor() return mem, nil } diff --git a/infrastructure/cache/cache_integration_test.go b/infrastructure/cache/cache_integration_test.go index cf151b1..e523e22 100644 --- a/infrastructure/cache/cache_integration_test.go +++ b/infrastructure/cache/cache_integration_test.go @@ -18,7 +18,9 @@ func TestMain(m *testing.M) { log.SetOutput(os.Stderr) log.SetLevel(log.CRITICAL) docker := dockertest.New() - docker.RunRedis() + host := &DefaultRedisConfig.Host + port := &DefaultRedisConfig.Port + docker.RunRedis(host, port) log.SetOutput(io.Discard) code := m.Run() docker.Purge() diff --git a/infrastructure/cache/config.go b/infrastructure/cache/config.go index 5c3e91b..b59a6b1 100644 --- a/infrastructure/cache/config.go +++ b/infrastructure/cache/config.go @@ -2,46 +2,47 @@ package cache import ( "time" - - "github.com/spf13/viper" ) -func newMemConfig() memConfig { - return memConfig{ - limiterRequestsPerSecond: viper.GetFloat64("middleware.limiter.requestsPerSecond"), - limiterBurst: viper.GetInt("middleware.limiter.burst"), - timeToLive: viper.GetDuration("cache.redis.timeToLive"), - cleanupInterval: viper.GetDuration("cache.redis.cleanupInterval"), - } +type CacheConfig struct { + Cache string `mapstructure:"CACHE" validate:"required"` + Mem MemConfig `mapstructure:",squash"` + Redis RedisConfig `mapstructure:",squash"` } -type memConfig struct { - limiterRequestsPerSecond float64 - limiterBurst int - timeToLive time.Duration - cleanupInterval time.Duration +type MemConfig struct { + CleanupInterval time.Duration `mapstructure:"CACHE_MEM_CLEANUP_INTERVAL" validate:"required"` + LimiterRequestsPerSecond float64 `mapstructure:"MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND" validate:"required"` + LimiterBurst int `mapstructure:"MIDDLEWARE_LIMITER_BURST" validate:"required"` + TimeToLive time.Duration `mapstructure:"CACHE_REDIS_TIME_TO_LIVE" validate:"required"` } -func newRedisConfig() redisConfig { - return redisConfig{ - host: viper.GetString("cache.redis.host"), - port: viper.GetString("cache.redis.port"), - times: viper.GetInt("cache.redis.retry.times"), - pause: viper.GetDuration("cache.redis.retry.pause"), - timeout: viper.GetDuration("cache.redis.retry.timeout"), - limiterRequestsPerMinute: viper.GetInt("middleware.limiter.requestsPerSecond"), - limiterBurst: viper.GetInt64("middleware.limiter.burst"), - timeToLive: viper.GetDuration("cache.redis.timeToLive"), - } +type RedisConfig struct { + Host string `mapstructure:"CACHE_REDIS_HOST" validate:"required"` + Port string `mapstructure:"CACHE_REDIS_PORT" validate:"required"` + RetryTimes int `mapstructure:"CACHE_REDIS_RETRY_TIMES" validate:"required"` + RetryPause time.Duration `mapstructure:"CACHE_REDIS_RETRY_PAUSE" validate:"required"` + Timeout time.Duration `mapstructure:"CACHE_REDIS_TIMEOUT" validate:"required"` + LimiterRequestsPerMinute int `mapstructure:"MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND" validate:"required"` + LimiterBurst int64 `mapstructure:"MIDDLEWARE_LIMITER_BURST" validate:"required"` + TimeToLive time.Duration `mapstructure:"CACHE_REDIS_TIME_TO_LIVE" validate:"required"` } -type redisConfig struct { - host string - port string - times int - pause time.Duration - timeout time.Duration - limiterRequestsPerMinute int - limiterBurst int64 - timeToLive time.Duration -} +var ( + DefaultMemConfig = MemConfig{ + CleanupInterval: 0, + LimiterRequestsPerSecond: 100, + LimiterBurst: 1, + TimeToLive: 0, + } + DefaultRedisConfig = RedisConfig{ + Host: "localhost", + Port: "6379", + RetryTimes: 4, + RetryPause: 5 * time.Second, + Timeout: 30 * time.Second, + LimiterRequestsPerMinute: 100, + LimiterBurst: 1, + TimeToLive: 1 * time.Second, + } +) diff --git a/infrastructure/cache/mem.go b/infrastructure/cache/mem.go index 2fc2af1..3511bd3 100644 --- a/infrastructure/cache/mem.go +++ b/infrastructure/cache/mem.go @@ -13,8 +13,7 @@ import ( "github.com/zitryss/aye-and-nay/pkg/errors" ) -func NewMem(opts ...options) *Mem { - conf := newMemConfig() +func NewMem(conf MemConfig, opts ...options) *Mem { m := &Mem{ conf: conf, syncVisitors: syncVisitors{visitors: map[uint64]*visitorTime{}}, @@ -44,7 +43,7 @@ func WithHeartbeatToken(ch chan<- interface{}) options { } type Mem struct { - conf memConfig + conf MemConfig syncVisitors syncQueues syncPQueues @@ -121,12 +120,12 @@ func (m *Mem) Monitor() { now := time.Now() m.syncVisitors.Lock() for k, v := range m.visitors { - if now.Sub(v.seen) >= m.conf.timeToLive { + if now.Sub(v.seen) >= m.conf.TimeToLive { delete(m.visitors, k) } } m.syncVisitors.Unlock() - time.Sleep(m.conf.cleanupInterval) + time.Sleep(m.conf.CleanupInterval) } }() go func() { @@ -137,12 +136,12 @@ func (m *Mem) Monitor() { now := time.Now() m.syncPairs.Lock() for k, v := range m.pairs { - if now.Sub(v.seen) >= m.conf.timeToLive { + if now.Sub(v.seen) >= m.conf.TimeToLive { delete(m.pairs, k) } } m.syncPairs.Unlock() - time.Sleep(m.conf.cleanupInterval) + time.Sleep(m.conf.CleanupInterval) if m.heartbeat.pair != nil { m.heartbeat.pair <- struct{}{} } @@ -156,12 +155,12 @@ func (m *Mem) Monitor() { now := time.Now() m.syncTokens.Lock() for k, v := range m.tokens { - if now.Sub(v.seen) >= m.conf.timeToLive { + if now.Sub(v.seen) >= m.conf.TimeToLive { delete(m.tokens, k) } } m.syncTokens.Unlock() - time.Sleep(m.conf.cleanupInterval) + time.Sleep(m.conf.CleanupInterval) if m.heartbeat.token != nil { m.heartbeat.token <- struct{}{} } @@ -174,7 +173,7 @@ func (m *Mem) Allow(_ context.Context, ip uint64) (bool, error) { defer m.syncVisitors.Unlock() v, ok := m.visitors[ip] if !ok { - l := rate.NewLimiter(rate.Limit(m.conf.limiterRequestsPerSecond), m.conf.limiterBurst) + l := rate.NewLimiter(rate.Limit(m.conf.LimiterRequestsPerSecond), m.conf.LimiterBurst) v = &visitorTime{limiter: l} m.visitors[ip] = v } diff --git a/infrastructure/cache/mem_test.go b/infrastructure/cache/mem_test.go index d35deab..49b16e0 100644 --- a/infrastructure/cache/mem_test.go +++ b/infrastructure/cache/mem_test.go @@ -8,14 +8,13 @@ import ( "time" "github.com/zitryss/aye-and-nay/domain/domain" - _ "github.com/zitryss/aye-and-nay/internal/config" . "github.com/zitryss/aye-and-nay/internal/testing" "github.com/zitryss/aye-and-nay/pkg/errors" ) func TestMemPair(t *testing.T) { t.Run("Positive", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) err := mem.Push(context.Background(), 0x23D2, [][2]uint64{{0x3E3D, 0xB399}}) if err != nil { t.Error(err) @@ -32,14 +31,14 @@ func TestMemPair(t *testing.T) { } }) t.Run("Negative1", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) _, _, err := mem.Pop(context.Background(), 0x73BF) if !errors.Is(err, domain.ErrPairNotFound) { t.Error(err) } }) t.Run("Negative2", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) err := mem.Push(context.Background(), 0x1AE9, [][2]uint64{{0x44DC, 0x721B}}) if err != nil { t.Error(err) @@ -55,13 +54,13 @@ func TestMemPair(t *testing.T) { }) t.Run("Negative3", func(t *testing.T) { heartbeatPair := make(chan interface{}) - mem := NewMem(WithHeartbeatPair(heartbeatPair)) + mem := NewMem(DefaultMemConfig, WithHeartbeatPair(heartbeatPair)) mem.Monitor() err := mem.Push(context.Background(), 0xF51A, [][2]uint64{{0x4BB0, 0x3A87}}) if err != nil { t.Error(err) } - time.Sleep(mem.conf.timeToLive) + time.Sleep(mem.conf.TimeToLive) CheckChannel(t, heartbeatPair) CheckChannel(t, heartbeatPair) _, _, err = mem.Pop(context.Background(), 0xF51A) @@ -73,7 +72,7 @@ func TestMemPair(t *testing.T) { func TestMemToken(t *testing.T) { t.Run("Positive", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) token := uint64(0xC2E7) album1 := uint64(0xB41C) image1 := uint64(0x52BD) @@ -93,7 +92,7 @@ func TestMemToken(t *testing.T) { } }) t.Run("Negative1", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) token := uint64(0x1C4A) album := uint64(0xF0EE) image := uint64(0x583C) @@ -107,7 +106,7 @@ func TestMemToken(t *testing.T) { } }) t.Run("Negative2", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) token := uint64(0xC4F8) _, _, err := mem.Get(context.Background(), token) if !errors.Is(err, domain.ErrTokenNotFound) { @@ -115,7 +114,7 @@ func TestMemToken(t *testing.T) { } }) t.Run("Negative3", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) token := uint64(0xEB96) album := uint64(0xC67F) image := uint64(0x7C45) @@ -141,7 +140,7 @@ func TestMemToken(t *testing.T) { } }) t.Run("Negative4", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) token := uint64(0xD3BF) err := mem.Del(context.Background(), token) if err != nil { @@ -150,7 +149,7 @@ func TestMemToken(t *testing.T) { }) t.Run("Negative5", func(t *testing.T) { heartbeatToken := make(chan interface{}) - mem := NewMem(WithHeartbeatToken(heartbeatToken)) + mem := NewMem(DefaultMemConfig, WithHeartbeatToken(heartbeatToken)) mem.Monitor() token := uint64(0xE0AF) album := uint64(0xCF1E) @@ -159,7 +158,7 @@ func TestMemToken(t *testing.T) { if err != nil { t.Error(err) } - time.Sleep(mem.conf.timeToLive) + time.Sleep(mem.conf.TimeToLive) CheckChannel(t, heartbeatToken) CheckChannel(t, heartbeatToken) _, _, err = mem.Get(context.Background(), token) diff --git a/infrastructure/cache/redis.go b/infrastructure/cache/redis.go index f1b4edd..fc76375 100644 --- a/infrastructure/cache/redis.go +++ b/infrastructure/cache/redis.go @@ -14,13 +14,12 @@ import ( "github.com/zitryss/aye-and-nay/pkg/retry" ) -func NewRedis() (*Redis, error) { - conf := newRedisConfig() - client := redisdb.NewClient(&redisdb.Options{Addr: conf.host + ":" + conf.port}) +func NewRedis(ctx context.Context, conf RedisConfig) (*Redis, error) { + client := redisdb.NewClient(&redisdb.Options{Addr: conf.Host + ":" + conf.Port}) r := &Redis{conf, client} - ctx, cancel := context.WithTimeout(context.Background(), conf.timeout) + ctx, cancel := context.WithTimeout(ctx, conf.Timeout) defer cancel() - err := retry.Do(conf.times, conf.pause, func() error { + err := retry.Do(conf.RetryTimes, conf.RetryPause, func() error { _, err := r.Health(ctx) if err != nil { return errors.Wrap(err) @@ -34,7 +33,7 @@ func NewRedis() (*Redis, error) { } type Redis struct { - conf redisConfig + conf RedisConfig client *redisdb.Client } @@ -52,11 +51,11 @@ func (r *Redis) Allow(ctx context.Context, ip uint64) (bool, error) { if err != nil { return false, errors.Wrap(err) } - if count >= r.conf.limiterRequestsPerMinute { + if count >= r.conf.LimiterRequestsPerMinute { return false, nil } pipe := r.client.Pipeline() - pipe.IncrBy(ctx, key, r.conf.limiterBurst) + pipe.IncrBy(ctx, key, r.conf.LimiterBurst) pipe.Expire(ctx, key, 59*time.Second) _, err = pipe.Exec(ctx) if err != nil { @@ -165,7 +164,7 @@ func (r *Redis) Push(ctx context.Context, album uint64, pairs [][2]uint64) error image1B64 := base64.FromUint64(images[1]) pipe.RPush(ctx, key, image0B64+":"+image1B64) } - pipe.Expire(ctx, key, r.conf.timeToLive) + pipe.Expire(ctx, key, r.conf.TimeToLive) _, err := pipe.Exec(ctx) if err != nil { return errors.Wrap(err) @@ -187,7 +186,7 @@ func (r *Redis) Pop(ctx context.Context, album uint64) (uint64, uint64, error) { if err != nil { return 0x0, 0x0, errors.Wrap(err) } - _ = r.client.Expire(ctx, key, r.conf.timeToLive) + _ = r.client.Expire(ctx, key, r.conf.TimeToLive) imagesB64 := strings.Split(val, ":") if len(imagesB64) != 2 { return 0x0, 0x0, errors.Wrap(domain.ErrUnknown) @@ -215,7 +214,7 @@ func (r *Redis) Set(ctx context.Context, token uint64, album uint64, image uint6 if n == 1 { return errors.Wrap(domain.ErrTokenAlreadyExists) } - err = r.client.Set(ctx, key, albumB64+":"+imageB64, r.conf.timeToLive).Err() + err = r.client.Set(ctx, key, albumB64+":"+imageB64, r.conf.TimeToLive).Err() if err != nil { return errors.Wrap(err) } @@ -265,7 +264,7 @@ func (r *Redis) Health(ctx context.Context) (bool, error) { return true, nil } -func (r *Redis) Close() error { +func (r *Redis) Close(_ context.Context) error { err := r.client.Close() if err != nil { return errors.Wrap(err) diff --git a/infrastructure/cache/redis_integration_test.go b/infrastructure/cache/redis_integration_test.go index 7c11e00..6146a7f 100644 --- a/infrastructure/cache/redis_integration_test.go +++ b/infrastructure/cache/redis_integration_test.go @@ -8,7 +8,6 @@ import ( "time" "github.com/zitryss/aye-and-nay/domain/domain" - _ "github.com/zitryss/aye-and-nay/internal/config" "github.com/zitryss/aye-and-nay/pkg/errors" ) @@ -17,11 +16,11 @@ func TestRedisAllow(t *testing.T) { if testing.Short() { t.Skip("short flag is set") } - redis, err := NewRedis() + redis, err := NewRedis(DefaultRedisConfig) if err != nil { t.Fatal(err) } - rpm := redis.conf.limiterRequestsPerMinute + rpm := redis.conf.LimiterRequestsPerMinute for j := 0; j < rpm; j++ { allowed, err := redis.Allow(context.Background(), 0xDEAD) if err != nil { @@ -43,11 +42,11 @@ func TestRedisAllow(t *testing.T) { } }) t.Run("Negative", func(t *testing.T) { - redis, err := NewRedis() + redis, err := NewRedis(DefaultRedisConfig) if err != nil { t.Fatal(err) } - rps := redis.conf.limiterRequestsPerMinute + rps := redis.conf.LimiterRequestsPerMinute for i := 0; i < rps; i++ { allowed, err := redis.Allow(context.Background(), 0xBEEF) if err != nil { @@ -68,7 +67,7 @@ func TestRedisAllow(t *testing.T) { } func TestRedisQueue(t *testing.T) { - redis, err := NewRedis() + redis, err := NewRedis(DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -162,7 +161,7 @@ func TestRedisQueue(t *testing.T) { } func TestRedisPQueue(t *testing.T) { - redis, err := NewRedis() + redis, err := NewRedis(DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -244,7 +243,7 @@ func TestRedisPQueue(t *testing.T) { func TestRedisPair(t *testing.T) { t.Run("Positive", func(t *testing.T) { - redis, err := NewRedis() + redis, err := NewRedis(DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -266,7 +265,7 @@ func TestRedisPair(t *testing.T) { } }) t.Run("Negative1", func(t *testing.T) { - redis, err := NewRedis() + redis, err := NewRedis(DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -276,7 +275,7 @@ func TestRedisPair(t *testing.T) { } }) t.Run("Negative2", func(t *testing.T) { - redis, err := NewRedis() + redis, err := NewRedis(DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -299,7 +298,7 @@ func TestRedisPair(t *testing.T) { func TestRedisToken(t *testing.T) { t.Run("Positive", func(t *testing.T) { - redis, err := NewRedis() + redis, err := NewRedis(DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -322,7 +321,7 @@ func TestRedisToken(t *testing.T) { } }) t.Run("Negative1", func(t *testing.T) { - redis, err := NewRedis() + redis, err := NewRedis(DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -339,7 +338,7 @@ func TestRedisToken(t *testing.T) { } }) t.Run("Negative2", func(t *testing.T) { - redis, err := NewRedis() + redis, err := NewRedis(DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -350,7 +349,7 @@ func TestRedisToken(t *testing.T) { } }) t.Run("Negative3", func(t *testing.T) { - redis, err := NewRedis() + redis, err := NewRedis(DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -379,7 +378,7 @@ func TestRedisToken(t *testing.T) { } }) t.Run("Negative4", func(t *testing.T) { - redis, err := NewRedis() + redis, err := NewRedis(DefaultRedisConfig) if err != nil { t.Fatal(err) } diff --git a/infrastructure/compressor/compressor.go b/infrastructure/compressor/compressor.go index 9ff55ff..9debdc7 100644 --- a/infrastructure/compressor/compressor.go +++ b/infrastructure/compressor/compressor.go @@ -7,20 +7,20 @@ import ( "github.com/zitryss/aye-and-nay/pkg/log" ) -func New(s string) (domain.Compresser, error) { - switch s { - case "imaginary": - log.Info("connecting to imaginary") - return NewImaginary() +func New(ctx context.Context, conf CompressorConfig) (domain.Compresser, error) { + switch conf.Compressor { case "shortpixel": log.Info("connecting to compressor") - sp := NewShortPixel() - err := sp.Ping(context.Background()) + sp := NewShortpixel(conf.Shortpixel) + err := sp.Ping(ctx) if err != nil { return nil, err } sp.Monitor() return sp, nil + case "imaginary": + log.Info("connecting to imaginary") + return NewImaginary(ctx, conf.Imaginary) case "mock": return NewMock(), nil default: diff --git a/infrastructure/compressor/compressor_integration_test.go b/infrastructure/compressor/compressor_integration_test.go index 03600e1..3b51fd4 100644 --- a/infrastructure/compressor/compressor_integration_test.go +++ b/infrastructure/compressor/compressor_integration_test.go @@ -18,7 +18,9 @@ func TestMain(m *testing.M) { log.SetOutput(os.Stderr) log.SetLevel(log.CRITICAL) docker := dockertest.New() - docker.RunImaginary() + host := &DefaultImaginaryConfig.Host + port := &DefaultImaginaryConfig.Port + docker.RunImaginary(host, port) log.SetOutput(io.Discard) code := m.Run() docker.Purge() diff --git a/infrastructure/compressor/config.go b/infrastructure/compressor/config.go index 851f5c3..cce2ae7 100644 --- a/infrastructure/compressor/config.go +++ b/infrastructure/compressor/config.go @@ -2,54 +2,59 @@ package compressor import ( "time" - - "github.com/spf13/viper" ) -func newImaginaryConfig() imaginaryConfig { - return imaginaryConfig{ - host: viper.GetString("compressor.imaginary.host"), - port: viper.GetString("compressor.imaginary.port"), - times: viper.GetInt("compressor.imaginary.retry.times"), - pause: viper.GetDuration("compressor.imaginary.retry.pause"), - timeout: viper.GetDuration("compressor.imaginary.retry.timeout"), - } +type CompressorConfig struct { + Compressor string `mapstructure:"COMPRESSOR" validate:"required"` + Shortpixel ShortpixelConfig `mapstructure:",squash"` + Imaginary ImaginaryConfig `mapstructure:",squash"` } -type imaginaryConfig struct { - host string - port string - times int - pause time.Duration - timeout time.Duration +type ShortpixelConfig struct { + Url string `mapstructure:"COMPRESSOR_SHORTPIXEL_URL" validate:"required"` + Url2 string `mapstructure:"COMPRESSOR_SHORTPIXEL_URL2" validate:"required"` + ApiKey string `mapstructure:"COMPRESSOR_SHORTPIXEL_API_KEY" validate:"required"` + RetryTimes int `mapstructure:"COMPRESSOR_SHORTPIXEL_RETRY_TIMES" validate:"required"` + RetryPause time.Duration `mapstructure:"COMPRESSOR_SHORTPIXEL_RETRY_PAUSE" validate:"required"` + Timeout time.Duration `mapstructure:"COMPRESSOR_SHORTPIXEL_TIMEOUT" validate:"required"` + Wait string `mapstructure:"COMPRESSOR_SHORTPIXEL_WAIT" validate:"required"` + UploadTimeout time.Duration `mapstructure:"COMPRESSOR_SHORTPIXEL_UPLOAD_TIMEOUT" validate:"required"` + DownloadTimeout time.Duration `mapstructure:"COMPRESSOR_SHORTPIXEL_DOWNLOAD_TIMEOUT" validate:"required"` + RepeatIn time.Duration `mapstructure:"COMPRESSOR_SHORTPIXEL_REPEAT_IN" validate:"required"` + RestartIn time.Duration `mapstructure:"COMPRESSOR_SHORTPIXEL_RESTART_IN" validate:"required"` } -func newShortPixelConfig() shortPixelConfig { - return shortPixelConfig{ - url: viper.GetString("compressor.shortpixel.url"), - url2: viper.GetString("compressor.shortpixel.url2"), - apiKey: viper.GetString("compressor.shortpixel.apiKey"), - times: viper.GetInt("compressor.shortpixel.retry.times"), - pause: viper.GetDuration("compressor.shortpixel.retry.pause"), - timeout: viper.GetDuration("compressor.shortpixel.retry.timeout"), - wait: viper.GetString("compressor.shortpixel.wait"), - uploadTimeout: viper.GetDuration("compressor.shortpixel.uploadTimeout"), - downloadTimeout: viper.GetDuration("compressor.shortpixel.downloadTimeout"), - repeatIn: viper.GetDuration("compressor.shortpixel.repeatIn"), - restartIn: viper.GetDuration("compressor.shortpixel.restartIn"), - } +type ImaginaryConfig struct { + Host string `mapstructure:"COMPRESSOR_IMAGINARY_HOST" validate:"required"` + Port string `mapstructure:"COMPRESSOR_IMAGINARY_PORT" validate:"required"` + RetryTimes int `mapstructure:"COMPRESSOR_IMAGINARY_RETRY_TIMES" validate:"required"` + RetryPause time.Duration `mapstructure:"COMPRESSOR_IMAGINARY_RETRY_PAUSE" validate:"required"` + Timeout time.Duration `mapstructure:"COMPRESSOR_IMAGINARY_TIMEOUT" validate:"required"` } -type shortPixelConfig struct { - url string - url2 string - apiKey string - times int - pause time.Duration - timeout time.Duration - wait string - uploadTimeout time.Duration - downloadTimeout time.Duration - repeatIn time.Duration - restartIn time.Duration +func (c CompressorConfig) IsMock() bool { + return c.Compressor == "mock" } + +var ( + DefaultShortpixelConfig = ShortpixelConfig{ + Url: "", + Url2: "", + ApiKey: "", + RetryTimes: 0, + RetryPause: 0, + Timeout: 0, + Wait: "", + UploadTimeout: 250 * time.Millisecond, + DownloadTimeout: 250 * time.Millisecond, + RepeatIn: 0, + RestartIn: 0, + } + DefaultImaginaryConfig = ImaginaryConfig{ + Host: "localhost", + Port: "9001", + RetryTimes: 4, + RetryPause: 5 * time.Second, + Timeout: 30 * time.Second, + } +) diff --git a/infrastructure/compressor/imaginary.go b/infrastructure/compressor/imaginary.go index e422b9e..3ab2212 100644 --- a/infrastructure/compressor/imaginary.go +++ b/infrastructure/compressor/imaginary.go @@ -13,12 +13,11 @@ import ( "github.com/zitryss/aye-and-nay/pkg/retry" ) -func NewImaginary() (*Imaginary, error) { - conf := newImaginaryConfig() +func NewImaginary(ctx context.Context, conf ImaginaryConfig) (*Imaginary, error) { im := &Imaginary{conf} - ctx, cancel := context.WithTimeout(context.Background(), conf.timeout) + ctx, cancel := context.WithTimeout(ctx, conf.Timeout) defer cancel() - err := retry.Do(conf.times, conf.pause, func() error { + err := retry.Do(conf.RetryTimes, conf.RetryPause, func() error { _, err := im.Health(ctx) if err != nil { return errors.Wrap(err) @@ -32,7 +31,7 @@ func NewImaginary() (*Imaginary, error) { } type Imaginary struct { - conf imaginaryConfig + conf ImaginaryConfig } func (im *Imaginary) Compress(ctx context.Context, f model.File) (model.File, error) { @@ -57,15 +56,15 @@ func (im *Imaginary) Compress(ctx context.Context, f model.File) (model.File, er if err != nil { return model.File{}, errors.Wrap(err) } - url := "http://" + im.conf.host + ":" + im.conf.port + "/convert?type=png&compression=9" + url := "http://" + im.conf.Host + ":" + im.conf.Port + "/convert?type=png&compression=9" req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, body) if err != nil { return model.File{}, errors.Wrap(err) } req.Header.Set("Content-Type", multi.FormDataContentType()) - c := http.Client{Timeout: im.conf.timeout} + c := http.Client{Timeout: im.conf.Timeout} resp := (*http.Response)(nil) - err = retry.Do(im.conf.times, im.conf.pause, func() error { + err = retry.Do(im.conf.RetryTimes, im.conf.RetryPause, func() error { resp, err = c.Do(req) if err != nil { return errors.Wrapf(domain.ErrThirdPartyUnavailable, "%s", err) @@ -107,13 +106,13 @@ func (im *Imaginary) Compress(ctx context.Context, f model.File) (model.File, er } func (im *Imaginary) Health(ctx context.Context) (bool, error) { - url := "http://" + im.conf.host + ":" + im.conf.port + "/health" + url := "http://" + im.conf.Host + ":" + im.conf.Port + "/health" body := io.Reader(nil) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, body) if err != nil { return false, errors.Wrapf(domain.ErrBadHealthCompressor, "%s", err) } - c := http.Client{Timeout: im.conf.timeout} + c := http.Client{Timeout: im.conf.Timeout} resp, err := c.Do(req) if err != nil { return false, errors.Wrapf(domain.ErrBadHealthCompressor, "%s", err) diff --git a/infrastructure/compressor/imaginary_integration_test.go b/infrastructure/compressor/imaginary_integration_test.go index b42870c..8e8e78a 100644 --- a/infrastructure/compressor/imaginary_integration_test.go +++ b/infrastructure/compressor/imaginary_integration_test.go @@ -9,8 +9,6 @@ import ( "testing" "github.com/zitryss/aye-and-nay/domain/model" - - _ "github.com/zitryss/aye-and-nay/internal/config" ) func TestImaginaryPositive(t *testing.T) { @@ -32,7 +30,7 @@ func TestImaginaryPositive(t *testing.T) { } for _, tt := range tests { t.Run("", func(t *testing.T) { - im, err := NewImaginary() + im, err := NewImaginary(DefaultImaginaryConfig) if err != nil { t.Fatal(err) } @@ -57,7 +55,7 @@ func TestImaginaryNegative(t *testing.T) { if testing.Short() { t.Skip("short flag is set") } - im, err := NewImaginary() + im, err := NewImaginary(DefaultImaginaryConfig) if err != nil { t.Fatal(err) } @@ -80,7 +78,7 @@ func TestImaginaryNegative(t *testing.T) { } func TestImaginaryHealth(t *testing.T) { - im, err := NewImaginary() + im, err := NewImaginary(DefaultImaginaryConfig) if err != nil { t.Fatal(err) } diff --git a/infrastructure/compressor/shortpixel.go b/infrastructure/compressor/shortpixel.go index 1d8f3bf..a424d13 100644 --- a/infrastructure/compressor/shortpixel.go +++ b/infrastructure/compressor/shortpixel.go @@ -17,8 +17,7 @@ import ( "github.com/zitryss/aye-and-nay/pkg/retry" ) -func NewShortPixel(opts ...options) *Shortpixel { - conf := newShortPixelConfig() +func NewShortpixel(conf ShortpixelConfig, opts ...options) *Shortpixel { sp := &Shortpixel{ conf: conf, ch: make(chan struct{}, 1), @@ -38,7 +37,7 @@ func WithHeartbeatRestart(ch chan<- interface{}) options { } type Shortpixel struct { - conf shortPixelConfig + conf ShortpixelConfig done uint32 ch chan struct{} heartbeat struct { @@ -47,7 +46,7 @@ type Shortpixel struct { } func (sp *Shortpixel) Ping(ctx context.Context) error { - ctx, cancel := context.WithTimeout(ctx, sp.conf.timeout) + ctx, cancel := context.WithTimeout(ctx, sp.conf.Timeout) defer cancel() _, err := sp.upload(ctx, Png()) if err != nil { @@ -63,7 +62,7 @@ func (sp *Shortpixel) Monitor() { if sp.heartbeat.restart != nil { sp.heartbeat.restart <- struct{}{} } - time.Sleep(sp.conf.restartIn) + time.Sleep(sp.conf.RestartIn) atomic.StoreUint32(&sp.done, 0) if sp.heartbeat.restart != nil { sp.heartbeat.restart <- struct{}{} @@ -115,7 +114,7 @@ func (sp *Shortpixel) upload(ctx context.Context, f model.File) (string, error) if err != nil { return "", errors.Wrap(err) } - _, err = io.WriteString(part, sp.conf.apiKey) + _, err = io.WriteString(part, sp.conf.ApiKey) if err != nil { return "", errors.Wrap(err) } @@ -131,7 +130,7 @@ func (sp *Shortpixel) upload(ctx context.Context, f model.File) (string, error) if err != nil { return "", errors.Wrap(err) } - _, err = io.WriteString(part, sp.conf.wait) + _, err = io.WriteString(part, sp.conf.Wait) if err != nil { return "", errors.Wrap(err) } @@ -163,14 +162,14 @@ func (sp *Shortpixel) upload(ctx context.Context, f model.File) (string, error) if err != nil { return "", errors.Wrap(err) } - c := http.Client{Timeout: sp.conf.uploadTimeout} - req, err := http.NewRequestWithContext(ctx, http.MethodPost, sp.conf.url, body) + c := http.Client{Timeout: sp.conf.UploadTimeout} + req, err := http.NewRequestWithContext(ctx, http.MethodPost, sp.conf.Url, body) if err != nil { return "", errors.Wrap(err) } req.Header.Set("Content-Type", multi.FormDataContentType()) resp := (*http.Response)(nil) - err = retry.Do(sp.conf.times, sp.conf.pause, func() error { + err = retry.Do(sp.conf.RetryTimes, sp.conf.RetryPause, func() error { resp, err = c.Do(req) if err != nil { return errors.Wrapf(domain.ErrThirdPartyUnavailable, "%s", err) @@ -238,7 +237,7 @@ func (sp *Shortpixel) upload(ctx context.Context, f model.File) (string, error) } func (sp *Shortpixel) repeat(ctx context.Context, src string) (string, error) { - time.Sleep(sp.conf.repeatIn) + time.Sleep(sp.conf.RepeatIn) body := pool.GetBuffer() defer pool.PutBuffer(body) request := struct { @@ -248,9 +247,9 @@ func (sp *Shortpixel) repeat(ctx context.Context, src string) (string, error) { Convertto string `json:"convertto"` Urllist []string `json:"urllist"` }{ - Key: sp.conf.apiKey, + Key: sp.conf.ApiKey, Lossy: "1", - Wait: sp.conf.wait, + Wait: sp.conf.Wait, Convertto: "png", Urllist: []string{src}, } @@ -258,13 +257,13 @@ func (sp *Shortpixel) repeat(ctx context.Context, src string) (string, error) { if err != nil { return "", errors.Wrap(err) } - c := http.Client{Timeout: sp.conf.uploadTimeout} - req, err := http.NewRequestWithContext(ctx, http.MethodPost, sp.conf.url2, body) + c := http.Client{Timeout: sp.conf.UploadTimeout} + req, err := http.NewRequestWithContext(ctx, http.MethodPost, sp.conf.Url2, body) if err != nil { return "", errors.Wrap(err) } resp := (*http.Response)(nil) - err = retry.Do(sp.conf.times, sp.conf.pause, func() error { + err = retry.Do(sp.conf.RetryTimes, sp.conf.RetryPause, func() error { resp, err = c.Do(req) if err != nil { return errors.Wrapf(domain.ErrThirdPartyUnavailable, "%s", err) @@ -324,14 +323,14 @@ func (sp *Shortpixel) repeat(ctx context.Context, src string) (string, error) { } func (sp *Shortpixel) download(ctx context.Context, src string) (model.File, error) { - c := http.Client{Timeout: sp.conf.downloadTimeout} + c := http.Client{Timeout: sp.conf.DownloadTimeout} body := io.Reader(nil) req, err := http.NewRequestWithContext(ctx, http.MethodGet, src, body) if err != nil { return model.File{}, errors.Wrap(err) } resp := (*http.Response)(nil) - err = retry.Do(sp.conf.times, sp.conf.pause, func() error { + err = retry.Do(sp.conf.RetryTimes, sp.conf.RetryPause, func() error { resp, err = c.Do(req) if err != nil { return errors.Wrapf(domain.ErrThirdPartyUnavailable, "%s", err) diff --git a/infrastructure/compressor/shortpixel_test.go b/infrastructure/compressor/shortpixel_test.go index b63b74a..9e9b057 100644 --- a/infrastructure/compressor/shortpixel_test.go +++ b/infrastructure/compressor/shortpixel_test.go @@ -11,10 +11,7 @@ import ( "testing" "time" - "github.com/spf13/viper" - "github.com/zitryss/aye-and-nay/domain/domain" - _ "github.com/zitryss/aye-and-nay/internal/config" . "github.com/zitryss/aye-and-nay/internal/testing" "github.com/zitryss/aye-and-nay/pkg/errors" ) @@ -42,7 +39,7 @@ type response []struct { LocalPath string `json:"LocalPath,omitempty"` } -func TestShortPixel(t *testing.T) { +func TestShortpixel(t *testing.T) { t.Run("Positive1", func(t *testing.T) { fn1 := func(w http.ResponseWriter, r *http.Request) { _, err := io.Copy(w, Png()) @@ -87,8 +84,9 @@ func TestShortPixel(t *testing.T) { } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() - viper.Set("compressor.shortpixel.url", mockserver2.URL) - sp := NewShortPixel() + conf := DefaultShortpixelConfig + conf.Url = mockserver2.URL + sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) if err != nil { t.Error(err) @@ -135,8 +133,9 @@ func TestShortPixel(t *testing.T) { } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() - viper.Set("compressor.shortpixel.url", mockserver2.URL) - sp := NewShortPixel() + conf := DefaultShortpixelConfig + conf.Url = mockserver2.URL + sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) if err != nil { t.Error(err) @@ -147,8 +146,9 @@ func TestShortPixel(t *testing.T) { } mockserver1 := httptest.NewServer(http.HandlerFunc(fn1)) mockserver1.Close() - viper.Set("compressor.shortpixel.url", mockserver1.URL) - sp := NewShortPixel() + conf := DefaultShortpixelConfig + conf.Url = mockserver1.URL + sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) if !errors.Is(err, domain.ErrThirdPartyUnavailable) { t.Error(err) @@ -194,31 +194,32 @@ func TestShortPixel(t *testing.T) { } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() - viper.Set("compressor.shortpixel.url", mockserver2.URL) - sp := NewShortPixel() + conf := DefaultShortpixelConfig + conf.Url = mockserver2.URL + sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) if !errors.Is(err, domain.ErrThirdPartyUnavailable) { t.Error(err) } }) t.Run("NegativeTimeout1", func(t *testing.T) { - d := viper.GetDuration("compressor.shortpixel.uploadTimeout") + viper.GetDuration("compressor.shortpixel.downloadTimeout") + conf := DefaultShortpixelConfig fn1 := func(w http.ResponseWriter, r *http.Request) { - time.Sleep(2 * d) + time.Sleep(2 * (conf.UploadTimeout + conf.DownloadTimeout)) } mockserver1 := httptest.NewServer(http.HandlerFunc(fn1)) defer mockserver1.Close() - viper.Set("compressor.shortpixel.url", mockserver1.URL) - sp := NewShortPixel() + conf.Url = mockserver1.URL + sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) if !errors.Is(err, domain.ErrThirdPartyUnavailable) { t.Error(err) } }) t.Run("NegativeTimeout2", func(t *testing.T) { - d := viper.GetDuration("compressor.shortpixel.uploadTimeout") + viper.GetDuration("compressor.shortpixel.downloadTimeout") + conf := DefaultShortpixelConfig fn1 := func(w http.ResponseWriter, r *http.Request) { - time.Sleep(2 * d) + time.Sleep(2 * (conf.UploadTimeout + conf.DownloadTimeout)) } mockserver1 := httptest.NewServer(http.HandlerFunc(fn1)) defer mockserver1.Close() @@ -257,8 +258,8 @@ func TestShortPixel(t *testing.T) { } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() - viper.Set("compressor.shortpixel.url", mockserver2.URL) - sp := NewShortPixel() + conf.Url = mockserver2.URL + sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) if !errors.Is(err, domain.ErrThirdPartyUnavailable) { t.Error(err) @@ -270,8 +271,9 @@ func TestShortPixel(t *testing.T) { } mockserver1 := httptest.NewServer(http.HandlerFunc(fn1)) defer mockserver1.Close() - viper.Set("compressor.shortpixel.url", mockserver1.URL) - sp := NewShortPixel() + conf := DefaultShortpixelConfig + conf.Url = mockserver1.URL + sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) if !errors.Is(err, domain.ErrThirdPartyUnavailable) { t.Error(err) @@ -318,8 +320,9 @@ func TestShortPixel(t *testing.T) { } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() - viper.Set("compressor.shortpixel.url", mockserver2.URL) - sp := NewShortPixel() + conf := DefaultShortpixelConfig + conf.Url = mockserver2.URL + sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) if !errors.Is(err, domain.ErrThirdPartyUnavailable) { t.Error(err) @@ -357,8 +360,9 @@ func TestShortPixel(t *testing.T) { } mockserver1 := httptest.NewServer(http.HandlerFunc(fn1)) defer mockserver1.Close() - viper.Set("compressor.shortpixel.url", mockserver1.URL) - sp := NewShortPixel() + conf := DefaultShortpixelConfig + conf.Url = mockserver1.URL + sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) if !errors.Is(err, domain.ErrThirdPartyUnavailable) { t.Error(err) @@ -384,8 +388,9 @@ func TestShortPixel(t *testing.T) { } mockserver1 := httptest.NewServer(http.HandlerFunc(fn1)) defer mockserver1.Close() - viper.Set("compressor.shortpixel.url", mockserver1.URL) - sp := NewShortPixel() + conf := DefaultShortpixelConfig + conf.Url = mockserver1.URL + sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) if !errors.Is(err, domain.ErrThirdPartyUnavailable) { t.Error(err) @@ -411,8 +416,9 @@ func TestShortPixel(t *testing.T) { } mockserver1 := httptest.NewServer(http.HandlerFunc(fn1)) defer mockserver1.Close() - viper.Set("compressor.shortpixel.url", mockserver1.URL) - sp := NewShortPixel() + conf := DefaultShortpixelConfig + conf.Url = mockserver1.URL + sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) if !errors.Is(err, domain.ErrNotImage) { t.Error(err) @@ -438,8 +444,9 @@ func TestShortPixel(t *testing.T) { } mockserver1 := httptest.NewServer(http.HandlerFunc(fn1)) defer mockserver1.Close() - viper.Set("compressor.shortpixel.url", mockserver1.URL) - sp := NewShortPixel() + conf := DefaultShortpixelConfig + conf.Url = mockserver1.URL + sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) if !errors.Is(err, domain.ErrNotImage) { t.Error(err) @@ -511,9 +518,10 @@ func TestShortPixel(t *testing.T) { } mockserver3 := httptest.NewServer(http.HandlerFunc(fn3)) defer mockserver3.Close() - viper.Set("compressor.shortpixel.url", mockserver3.URL) - viper.Set("compressor.shortpixel.url2", mockserver2.URL) - sp := NewShortPixel() + conf := DefaultShortpixelConfig + conf.Url = mockserver3.URL + conf.Url2 = mockserver2.URL + sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) if err != nil { t.Error(err) @@ -579,9 +587,10 @@ func TestShortPixel(t *testing.T) { } mockserver3 := httptest.NewServer(http.HandlerFunc(fn3)) defer mockserver3.Close() - viper.Set("compressor.shortpixel.url", mockserver3.URL) - viper.Set("compressor.shortpixel.url2", mockserver2.URL) - sp := NewShortPixel() + conf := DefaultShortpixelConfig + conf.Url = mockserver3.URL + conf.Url2 = mockserver2.URL + sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) if err != nil { t.Error(err) @@ -614,18 +623,19 @@ func TestShortPixel(t *testing.T) { } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() - viper.Set("compressor.shortpixel.url", mockserver2.URL) - viper.Set("compressor.shortpixel.url2", mockserver1.URL) - sp := NewShortPixel() + conf := DefaultShortpixelConfig + conf.Url = mockserver2.URL + conf.Url2 = mockserver1.URL + sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) if !errors.Is(err, domain.ErrThirdPartyUnavailable) { t.Error(err) } }) t.Run("NegativeRecoveryTimeout", func(t *testing.T) { - d := viper.GetDuration("compressor.shortpixel.uploadTimeout") + viper.GetDuration("compressor.shortpixel.downloadTimeout") + conf := DefaultShortpixelConfig fn1 := func(w http.ResponseWriter, r *http.Request) { - time.Sleep(2 * d) + time.Sleep(2 * (conf.UploadTimeout + conf.DownloadTimeout)) } mockserver1 := httptest.NewServer(http.HandlerFunc(fn1)) defer mockserver1.Close() @@ -651,9 +661,9 @@ func TestShortPixel(t *testing.T) { } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() - viper.Set("compressor.shortpixel.url", mockserver2.URL) - viper.Set("compressor.shortpixel.url2", mockserver1.URL) - sp := NewShortPixel() + conf.Url = mockserver2.URL + conf.Url2 = mockserver1.URL + sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) if !errors.Is(err, domain.ErrThirdPartyUnavailable) { t.Error(err) @@ -687,9 +697,10 @@ func TestShortPixel(t *testing.T) { } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() - viper.Set("compressor.shortpixel.url", mockserver2.URL) - viper.Set("compressor.shortpixel.url2", mockserver1.URL) - sp := NewShortPixel() + conf := DefaultShortpixelConfig + conf.Url = mockserver2.URL + conf.Url2 = mockserver1.URL + sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) if !errors.Is(err, domain.ErrThirdPartyUnavailable) { t.Error(err) @@ -749,9 +760,10 @@ func TestShortPixel(t *testing.T) { } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() - viper.Set("compressor.shortpixel.url", mockserver2.URL) - viper.Set("compressor.shortpixel.url2", mockserver1.URL) - sp := NewShortPixel() + conf := DefaultShortpixelConfig + conf.Url = mockserver2.URL + conf.Url2 = mockserver1.URL + sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) if !errors.Is(err, domain.ErrThirdPartyUnavailable) { t.Error(err) @@ -799,9 +811,10 @@ func TestShortPixel(t *testing.T) { } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() - viper.Set("compressor.shortpixel.url", mockserver2.URL) - viper.Set("compressor.shortpixel.url2", mockserver1.URL) - sp := NewShortPixel() + conf := DefaultShortpixelConfig + conf.Url = mockserver2.URL + conf.Url2 = mockserver1.URL + sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) if !errors.Is(err, domain.ErrThirdPartyUnavailable) { t.Error(err) @@ -852,9 +865,10 @@ func TestShortPixel(t *testing.T) { } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() - viper.Set("compressor.shortpixel.url", mockserver2.URL) - viper.Set("compressor.shortpixel.url2", mockserver1.URL) - sp := NewShortPixel() + conf := DefaultShortpixelConfig + conf.Url = mockserver2.URL + conf.Url2 = mockserver1.URL + sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) if !errors.Is(err, domain.ErrThirdPartyUnavailable) { t.Error(err) diff --git a/infrastructure/database/badger.go b/infrastructure/database/badger.go index 8d54c8d..856c7cf 100644 --- a/infrastructure/database/badger.go +++ b/infrastructure/database/badger.go @@ -18,26 +18,18 @@ import ( "github.com/zitryss/aye-and-nay/pkg/pool" ) -type mode bool - -const ( - disk mode = false - inMemory mode = true -) - -func NewBadger(mode mode) (*Badger, error) { +func NewBadger(conf BadgerConfig) (*Badger, error) { _ = runtime.GOMAXPROCS(128) - conf := newBadgerConfig() path := "./badger" - if mode == inMemory { + if conf.InMemory { path = "" } - opts := badger.DefaultOptions(path).WithCompression(options.None).WithLogger(nil).WithInMemory(bool(mode)) + opts := badger.DefaultOptions(path).WithCompression(options.None).WithLogger(nil).WithInMemory(conf.InMemory) db, err := badger.Open(opts) if err != nil { return nil, errors.Wrap(err) } - cache, err := lru.New(conf.lru) + cache, err := lru.New(conf.LRU) if err != nil { return &Badger{}, errors.Wrap(err) } @@ -45,7 +37,7 @@ func NewBadger(mode mode) (*Badger, error) { } type Badger struct { - conf badgerConfig + conf BadgerConfig db *badger.DB cache *lru.Cache } @@ -53,8 +45,8 @@ type Badger struct { func (b *Badger) Monitor() { go func() { for { - _ = b.db.RunValueLogGC(b.conf.gcRatio) - time.Sleep(b.conf.cleanupInterval) + _ = b.db.RunValueLogGC(b.conf.GcRatio) + time.Sleep(b.conf.CleanupInterval) } }() } @@ -68,7 +60,7 @@ func (b *Badger) SaveAlbum(_ context.Context, alb model.Album) error { albLru := make(albumLru, len(alb.Images)) for i := range alb.Images { img := &alb.Images[i] - img.Compressed = b.conf.compressed + img.Compressed = b.conf.Compressed edgs[img.Id] = make(map[uint64]int, len(alb.Images)) albLru[img.Id] = img.Src } @@ -349,7 +341,7 @@ func (b *Badger) Health(_ context.Context) (bool, error) { return true, nil } -func (b *Badger) Close() error { +func (b *Badger) Close(_ context.Context) error { err := b.db.Close() if err != nil { return errors.Wrap(err) diff --git a/infrastructure/database/badger_test.go b/infrastructure/database/badger_test.go index 88ff048..08694cd 100644 --- a/infrastructure/database/badger_test.go +++ b/infrastructure/database/badger_test.go @@ -11,14 +11,13 @@ import ( "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/model" - _ "github.com/zitryss/aye-and-nay/internal/config" . "github.com/zitryss/aye-and-nay/internal/testing" "github.com/zitryss/aye-and-nay/pkg/errors" ) func TestBadgerAlbum(t *testing.T) { t.Run("Positive", func(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } @@ -36,7 +35,7 @@ func TestBadgerAlbum(t *testing.T) { } }) t.Run("Negative1", func(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } @@ -52,7 +51,7 @@ func TestBadgerAlbum(t *testing.T) { } }) t.Run("Negative2", func(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } @@ -62,7 +61,7 @@ func TestBadgerAlbum(t *testing.T) { } }) t.Run("Negative3", func(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } @@ -75,7 +74,7 @@ func TestBadgerAlbum(t *testing.T) { func TestBadgerCount(t *testing.T) { t.Run("Positive", func(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } @@ -129,7 +128,7 @@ func TestBadgerCount(t *testing.T) { } }) t.Run("Negative1", func(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } @@ -155,7 +154,7 @@ func TestBadgerCount(t *testing.T) { } }) t.Run("Negative2", func(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } @@ -165,7 +164,7 @@ func TestBadgerCount(t *testing.T) { } }) t.Run("Negative3", func(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } @@ -175,7 +174,7 @@ func TestBadgerCount(t *testing.T) { } }) t.Run("Negative4", func(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } @@ -185,7 +184,7 @@ func TestBadgerCount(t *testing.T) { } }) t.Run("Negative5", func(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } @@ -203,7 +202,7 @@ func TestBadgerCount(t *testing.T) { func TestBadgerImage(t *testing.T) { t.Run("Positive", func(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } @@ -221,7 +220,7 @@ func TestBadgerImage(t *testing.T) { } }) t.Run("Negative1", func(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } @@ -231,7 +230,7 @@ func TestBadgerImage(t *testing.T) { } }) t.Run("Negative2", func(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } @@ -249,7 +248,7 @@ func TestBadgerImage(t *testing.T) { func TestBadgerVote(t *testing.T) { t.Run("Positive", func(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } @@ -275,7 +274,7 @@ func TestBadgerVote(t *testing.T) { } }) t.Run("Negative", func(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } @@ -288,7 +287,7 @@ func TestBadgerVote(t *testing.T) { func TestBadgerSort(t *testing.T) { t.Run("Positive", func(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } @@ -312,7 +311,7 @@ func TestBadgerSort(t *testing.T) { } }) t.Run("Negative", func(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } @@ -325,7 +324,7 @@ func TestBadgerSort(t *testing.T) { func TestBadgerRatings(t *testing.T) { t.Run("Positive", func(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } @@ -360,7 +359,7 @@ func TestBadgerRatings(t *testing.T) { } }) t.Run("Negative", func(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } @@ -384,7 +383,7 @@ func TestBadgerRatings(t *testing.T) { func TestBadgerDelete(t *testing.T) { t.Run("Positive1", func(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } @@ -421,7 +420,7 @@ func TestBadgerDelete(t *testing.T) { } }) t.Run("Positive2", func(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } @@ -448,7 +447,7 @@ func TestBadgerDelete(t *testing.T) { } }) t.Run("Negative", func(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } @@ -465,7 +464,7 @@ func TestBadgerDelete(t *testing.T) { } func TestBadgerLru(t *testing.T) { - badger, err := NewBadger(inMemory) + badger, err := NewBadger(DefaultBadgerConfig) if err != nil { t.Fatal(err) } diff --git a/infrastructure/database/config.go b/infrastructure/database/config.go index 4912af4..8d7043a 100644 --- a/infrastructure/database/config.go +++ b/infrastructure/database/config.go @@ -2,54 +2,55 @@ package database import ( "time" - - "github.com/spf13/viper" ) -func newMemConfig() memConfig { - return memConfig{ - compressed: viper.GetString("compressor.use") == "mock", - } +type DatabaseConfig struct { + Database string `mapstructure:"DATABASE" validate:"required"` + Mem MemConfig `mapstructure:",squash"` + Mongo MongoConfig `mapstructure:",squash"` + Badger BadgerConfig `mapstructure:",squash"` } -type memConfig struct { - compressed bool +type MemConfig struct { + Compressed bool } -func newMongoConfig() mongoConfig { - return mongoConfig{ - host: viper.GetString("database.mongo.host"), - port: viper.GetString("database.mongo.port"), - times: viper.GetInt("database.mongo.retry.times"), - pause: viper.GetDuration("database.mongo.retry.pause"), - timeout: viper.GetDuration("database.mongo.retry.timeout"), - compressed: viper.GetString("compressor.use") == "mock", - lru: viper.GetInt("database.mongo.lru"), - } +type MongoConfig struct { + Host string `mapstructure:"DATABASE_MONGO_HOST" validate:"required"` + Port string `mapstructure:"DATABASE_MONGO_PORT" validate:"required"` + RetryTimes int `mapstructure:"DATABASE_MONGO_RETRY_TIMES" validate:"required"` + RetryPause time.Duration `mapstructure:"DATABASE_MONGO_RETRY_PAUSE" validate:"required"` + Timeout time.Duration `mapstructure:"DATABASE_MONGO_TIMEOUT" validate:"required"` + LRU int `mapstructure:"DATABASE_MONGO_LRU" validate:"required"` + Compressed bool } -type mongoConfig struct { - host string - port string - times int - pause time.Duration - timeout time.Duration - compressed bool - lru int +type BadgerConfig struct { + InMemory bool `mapstructure:"DATABASE_BADGER_IN_MEMORY"` + GcRatio float64 `mapstructure:"DATABASE_BADGER_GC_RATIO" validate:"required"` + CleanupInterval time.Duration `mapstructure:"DATABASE_BADGER_CLEANUP_INTERVAL" validate:"required"` + LRU int `mapstructure:"DATABASE_BADGER_LRU" validate:"required"` + Compressed bool } -func newBadgerConfig() badgerConfig { - return badgerConfig{ - gcRatio: viper.GetFloat64("database.badger.gcRatio"), - cleanupInterval: viper.GetDuration("database.badger.cleanupInterval"), - compressed: viper.GetString("compressor.use") == "mock", - lru: viper.GetInt("database.badger.lru"), +var ( + DefaultMemConfig = MemConfig{ + Compressed: false, } -} - -type badgerConfig struct { - gcRatio float64 - cleanupInterval time.Duration - compressed bool - lru int -} + DefaultMongoConfig = MongoConfig{ + Host: "localhost", + Port: "27017", + RetryTimes: 4, + RetryPause: 5 * time.Second, + Timeout: 30 * time.Second, + LRU: 1, + Compressed: false, + } + DefaultBadgerConfig = BadgerConfig{ + InMemory: true, + GcRatio: 0, + CleanupInterval: 0, + LRU: 1, + Compressed: false, + } +) diff --git a/infrastructure/database/database.go b/infrastructure/database/database.go index 67b21fe..bbda2c4 100644 --- a/infrastructure/database/database.go +++ b/infrastructure/database/database.go @@ -1,25 +1,27 @@ package database import ( + "context" + "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/pkg/log" ) -func New(s string) (domain.Databaser, error) { - switch s { +func New(ctx context.Context, conf DatabaseConfig) (domain.Databaser, error) { + switch conf.Database { case "mongo": log.Info("connecting to database") - return NewMongo() + return NewMongo(ctx, conf.Mongo) case "badger": log.Info("connecting to embedded database") - b, err := NewBadger(disk) + b, err := NewBadger(conf.Badger) if err != nil { return nil, err } return b, nil case "mem": - return NewMem(), nil + return NewMem(conf.Mem), nil default: - return NewMem(), nil + return NewMem(conf.Mem), nil } } diff --git a/infrastructure/database/database_integration_test.go b/infrastructure/database/database_integration_test.go index e6de19a..a635197 100644 --- a/infrastructure/database/database_integration_test.go +++ b/infrastructure/database/database_integration_test.go @@ -18,7 +18,9 @@ func TestMain(m *testing.M) { log.SetOutput(os.Stderr) log.SetLevel(log.CRITICAL) docker := dockertest.New() - docker.RunMongo() + host := &DefaultMongoConfig.Host + port := &DefaultMongoConfig.Port + docker.RunMongo(host, port) log.SetOutput(io.Discard) code := m.Run() docker.Purge() diff --git a/infrastructure/database/mem.go b/infrastructure/database/mem.go index 12f23d3..719371a 100644 --- a/infrastructure/database/mem.go +++ b/infrastructure/database/mem.go @@ -10,8 +10,7 @@ import ( "github.com/zitryss/aye-and-nay/pkg/errors" ) -func NewMem() *Mem { - conf := newMemConfig() +func NewMem(conf MemConfig) *Mem { return &Mem{ conf: conf, syncAlbums: syncAlbums{albums: map[uint64]model.Album{}}, @@ -19,7 +18,7 @@ func NewMem() *Mem { } type Mem struct { - conf memConfig + conf MemConfig syncAlbums } @@ -38,7 +37,7 @@ func (m *Mem) SaveAlbum(_ context.Context, alb model.Album) error { edgs := make(map[uint64]map[uint64]int, len(alb.Images)) for i := range alb.Images { img := &alb.Images[i] - img.Compressed = m.conf.compressed + img.Compressed = m.conf.Compressed edgs[img.Id] = make(map[uint64]int, len(alb.Images)) } alb.Edges = edgs diff --git a/infrastructure/database/mem_test.go b/infrastructure/database/mem_test.go index 2907700..0df8ef2 100644 --- a/infrastructure/database/mem_test.go +++ b/infrastructure/database/mem_test.go @@ -11,14 +11,13 @@ import ( "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/model" - _ "github.com/zitryss/aye-and-nay/internal/config" . "github.com/zitryss/aye-and-nay/internal/testing" "github.com/zitryss/aye-and-nay/pkg/errors" ) func TestMemAlbum(t *testing.T) { t.Run("Positive", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) alb := AlbumEmptyFactory(0x6CC4) err := mem.SaveAlbum(context.Background(), alb) if err != nil { @@ -33,7 +32,7 @@ func TestMemAlbum(t *testing.T) { } }) t.Run("Negative1", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) alb := AlbumFullFactory(0xA566) err := mem.SaveAlbum(context.Background(), alb) if err != nil { @@ -46,14 +45,14 @@ func TestMemAlbum(t *testing.T) { } }) t.Run("Negative2", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) _, err := mem.GetImagesIds(context.Background(), 0xA9B4) if !errors.Is(err, domain.ErrAlbumNotFound) { t.Error(err) } }) t.Run("Negative3", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) _, err := mem.GetEdges(context.Background(), 0x3F1E) if !errors.Is(err, domain.ErrAlbumNotFound) { t.Error(err) @@ -63,7 +62,7 @@ func TestMemAlbum(t *testing.T) { func TestMemCount(t *testing.T) { t.Run("Positive", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) alb := AlbumEmptyFactory(0x746C) err := mem.SaveAlbum(context.Background(), alb) if err != nil { @@ -114,7 +113,7 @@ func TestMemCount(t *testing.T) { } }) t.Run("Negative1", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) alb := AlbumEmptyFactory(0x99DF) err := mem.SaveAlbum(context.Background(), alb) if err != nil { @@ -137,28 +136,28 @@ func TestMemCount(t *testing.T) { } }) t.Run("Negative2", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) _, err := mem.CountImages(context.Background(), 0xF256) if !errors.Is(err, domain.ErrAlbumNotFound) { t.Error(err) } }) t.Run("Negative3", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) _, err := mem.CountImagesCompressed(context.Background(), 0xC52A) if !errors.Is(err, domain.ErrAlbumNotFound) { t.Error(err) } }) t.Run("Negative4", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) err := mem.UpdateCompressionStatus(context.Background(), 0xF73E, 0x3E3D) if !errors.Is(err, domain.ErrAlbumNotFound) { t.Error(err) } }) t.Run("Negative5", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) alb := AlbumEmptyFactory(0xDF75) err := mem.SaveAlbum(context.Background(), alb) if err != nil { @@ -173,7 +172,7 @@ func TestMemCount(t *testing.T) { func TestMemImage(t *testing.T) { t.Run("Positive", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) alb := AlbumEmptyFactory(0xB0C4) err := mem.SaveAlbum(context.Background(), alb) if err != nil { @@ -188,14 +187,14 @@ func TestMemImage(t *testing.T) { } }) t.Run("Negative1", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) _, err := mem.GetImageSrc(context.Background(), 0x12EE, 0x51DE) if !errors.Is(err, domain.ErrAlbumNotFound) { t.Error(err) } }) t.Run("Negative2", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) alb := AlbumEmptyFactory(0xD585) err := mem.SaveAlbum(context.Background(), alb) if err != nil { @@ -210,7 +209,7 @@ func TestMemImage(t *testing.T) { func TestMemVote(t *testing.T) { t.Run("Positive", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) alb := AlbumFullFactory(0x4D76) err := mem.SaveAlbum(context.Background(), alb) if err != nil { @@ -233,7 +232,7 @@ func TestMemVote(t *testing.T) { } }) t.Run("Negative", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) err := mem.SaveVote(context.Background(), 0x1FAD, 0x84E6, 0x308E) if !errors.Is(err, domain.ErrAlbumNotFound) { t.Error(err) @@ -243,7 +242,7 @@ func TestMemVote(t *testing.T) { func TestMemSort(t *testing.T) { t.Run("Positive", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) alb := AlbumFullFactory(0x5A96) err := mem.SaveAlbum(context.Background(), alb) if err != nil { @@ -264,7 +263,7 @@ func TestMemSort(t *testing.T) { } }) t.Run("Negative", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) _, err := mem.GetImagesOrdered(context.Background(), 0x66BE) if !errors.Is(err, domain.ErrAlbumNotFound) { t.Error(err) @@ -274,7 +273,7 @@ func TestMemSort(t *testing.T) { func TestMemRatings(t *testing.T) { t.Run("Positive", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) alb := AlbumFullFactory(0x4E54) err := mem.SaveAlbum(context.Background(), alb) if err != nil { @@ -306,7 +305,7 @@ func TestMemRatings(t *testing.T) { } }) t.Run("Negative", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) img1 := model.Image{Id: 0x3E3D, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/PT4AAAAAAAA", Rating: 0.54412788} img2 := model.Image{Id: 0xB399, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/mbMAAAAAAAA", Rating: 0.32537162} img3 := model.Image{Id: 0xDA2A, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/KtoAAAAAAAA", Rating: 0.43185491} @@ -327,7 +326,7 @@ func TestMemRatings(t *testing.T) { func TestMemDelete(t *testing.T) { t.Run("Positive1", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) alb := AlbumEmptyFactory(0x748C) _, err := mem.CountImages(context.Background(), 0x748C) if !errors.Is(err, domain.ErrAlbumNotFound) { @@ -361,7 +360,7 @@ func TestMemDelete(t *testing.T) { } }) t.Run("Positive2", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) alb := AlbumEmptyFactory(0x7B43) alb.Expires = time.Now().Add(-1 * time.Hour) err := mem.SaveAlbum(context.Background(), alb) @@ -385,7 +384,7 @@ func TestMemDelete(t *testing.T) { } }) t.Run("Negative", func(t *testing.T) { - mem := NewMem() + mem := NewMem(DefaultMemConfig) alb := AlbumEmptyFactory(0x608C) err := mem.SaveAlbum(context.Background(), alb) if err != nil { diff --git a/infrastructure/database/mongo.go b/infrastructure/database/mongo.go index cc5413f..9b32d51 100644 --- a/infrastructure/database/mongo.go +++ b/infrastructure/database/mongo.go @@ -35,11 +35,10 @@ type edgeDao struct { Weight int } -func NewMongo() (*Mongo, error) { - conf := newMongoConfig() - ctx, cancel := context.WithTimeout(context.Background(), conf.timeout) +func NewMongo(ctx context.Context, conf MongoConfig) (*Mongo, error) { + ctx, cancel := context.WithTimeout(ctx, conf.Timeout) defer cancel() - opts := optionsdb.Client().ApplyURI("mongodb://" + conf.host + ":" + conf.port) + opts := optionsdb.Client().ApplyURI("mongodb://" + conf.Host + ":" + conf.Port) client, err := mongodb.Connect(ctx, opts) if err != nil { return &Mongo{}, errors.Wrap(err) @@ -47,12 +46,12 @@ func NewMongo() (*Mongo, error) { db := client.Database("aye-and-nay") images := db.Collection("images") edges := db.Collection("edges") - cache, err := lru.New(conf.lru) + cache, err := lru.New(conf.LRU) if err != nil { return &Mongo{}, errors.Wrap(err) } m := &Mongo{conf, client, db, images, edges, cache} - err = retry.Do(conf.times, conf.pause, func() error { + err = retry.Do(conf.RetryTimes, conf.RetryPause, func() error { _, err := m.Health(ctx) if err != nil { return errors.Wrap(err) @@ -66,7 +65,7 @@ func NewMongo() (*Mongo, error) { } type Mongo struct { - conf mongoConfig + conf MongoConfig client *mongodb.Client db *mongodb.Database images *mongodb.Collection @@ -86,7 +85,7 @@ func (m *Mongo) SaveAlbum(ctx context.Context, alb model.Album) error { imgsDao := make([]interface{}, 0, len(alb.Images)) albLru := make(albumLru, len(alb.Images)) for _, img := range alb.Images { - imgDao := imageDao{int64(alb.Id), int64(img.Id), img.Src, img.Rating, m.conf.compressed, alb.Expires} + imgDao := imageDao{int64(alb.Id), int64(img.Id), img.Src, img.Rating, m.conf.Compressed, alb.Expires} imgsDao = append(imgsDao, imgDao) albLru[img.Id] = img.Src } @@ -350,8 +349,8 @@ func (m *Mongo) Health(ctx context.Context) (bool, error) { return true, err } -func (m *Mongo) Close() error { - ctx, cancel := context.WithTimeout(context.Background(), m.conf.timeout) +func (m *Mongo) Close(ctx context.Context) error { + ctx, cancel := context.WithTimeout(ctx, m.conf.Timeout) defer cancel() err := m.client.Disconnect(ctx) if err != nil { diff --git a/infrastructure/database/mongo_integration_test.go b/infrastructure/database/mongo_integration_test.go index b757411..b7b26f3 100644 --- a/infrastructure/database/mongo_integration_test.go +++ b/infrastructure/database/mongo_integration_test.go @@ -11,14 +11,13 @@ import ( "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/model" - _ "github.com/zitryss/aye-and-nay/internal/config" . "github.com/zitryss/aye-and-nay/internal/testing" "github.com/zitryss/aye-and-nay/pkg/errors" ) func TestMongoAlbum(t *testing.T) { t.Run("Positive", func(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -36,7 +35,7 @@ func TestMongoAlbum(t *testing.T) { } }) t.Run("Negative1", func(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -52,7 +51,7 @@ func TestMongoAlbum(t *testing.T) { } }) t.Run("Negative2", func(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -62,7 +61,7 @@ func TestMongoAlbum(t *testing.T) { } }) t.Run("Negative3", func(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -75,7 +74,7 @@ func TestMongoAlbum(t *testing.T) { func TestMongoCount(t *testing.T) { t.Run("Positive", func(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -129,7 +128,7 @@ func TestMongoCount(t *testing.T) { } }) t.Run("Negative1", func(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -155,7 +154,7 @@ func TestMongoCount(t *testing.T) { } }) t.Run("Negative2", func(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -165,7 +164,7 @@ func TestMongoCount(t *testing.T) { } }) t.Run("Negative3", func(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -175,7 +174,7 @@ func TestMongoCount(t *testing.T) { } }) t.Run("Negative4", func(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -185,7 +184,7 @@ func TestMongoCount(t *testing.T) { } }) t.Run("Negative5", func(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -203,7 +202,7 @@ func TestMongoCount(t *testing.T) { func TestMongoImage(t *testing.T) { t.Run("Positive", func(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -221,7 +220,7 @@ func TestMongoImage(t *testing.T) { } }) t.Run("Negative1", func(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -231,7 +230,7 @@ func TestMongoImage(t *testing.T) { } }) t.Run("Negative2", func(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -249,7 +248,7 @@ func TestMongoImage(t *testing.T) { func TestMongoVote(t *testing.T) { t.Run("Positive", func(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -275,7 +274,7 @@ func TestMongoVote(t *testing.T) { } }) t.Run("Negative", func(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -288,7 +287,7 @@ func TestMongoVote(t *testing.T) { func TestMongoSort(t *testing.T) { t.Run("Positive", func(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -312,7 +311,7 @@ func TestMongoSort(t *testing.T) { } }) t.Run("Negative", func(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -325,7 +324,7 @@ func TestMongoSort(t *testing.T) { func TestMongoRatings(t *testing.T) { t.Run("Positive", func(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -360,7 +359,7 @@ func TestMongoRatings(t *testing.T) { } }) t.Run("Negative", func(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -384,7 +383,7 @@ func TestMongoRatings(t *testing.T) { func TestMongoDelete(t *testing.T) { t.Run("Positive1", func(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -421,7 +420,7 @@ func TestMongoDelete(t *testing.T) { } }) t.Run("Positive2", func(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -451,7 +450,7 @@ func TestMongoDelete(t *testing.T) { }) }) t.Run("Negative", func(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -468,7 +467,7 @@ func TestMongoDelete(t *testing.T) { } func TestMongoLru(t *testing.T) { - mongo, err := NewMongo() + mongo, err := NewMongo(DefaultMongoConfig) if err != nil { t.Fatal(err) } diff --git a/infrastructure/storage/config.go b/infrastructure/storage/config.go index c0f6d45..6418149 100644 --- a/infrastructure/storage/config.go +++ b/infrastructure/storage/config.go @@ -2,36 +2,39 @@ package storage import ( "time" - - "github.com/spf13/viper" ) -func newMinioConfig() minioConfig { - return minioConfig{ - host: viper.GetString("storage.minio.host"), - port: viper.GetString("storage.minio.port"), - accessKey: viper.GetString("storage.minio.accessKey"), - secretKey: viper.GetString("storage.minio.secretKey"), - token: viper.GetString("storage.minio.token"), - secure: viper.GetBool("storage.minio.secure"), - times: viper.GetInt("storage.minio.retry.times"), - pause: viper.GetDuration("storage.minio.retry.pause"), - timeout: viper.GetDuration("storage.minio.retry.timeout"), - location: viper.GetString("storage.minio.location"), - prefix: viper.GetString("storage.minio.prefix"), - } +type StorageConfig struct { + Storage string `mapstructure:"STORAGE" validate:"required"` + Minio MinioConfig `mapstructure:",squash"` } -type minioConfig struct { - host string - port string - accessKey string - secretKey string - token string - secure bool - times int - pause time.Duration - timeout time.Duration - location string - prefix string +type MinioConfig struct { + Host string `mapstructure:"STORAGE_MINIO_HOST" validate:"required"` + Port string `mapstructure:"STORAGE_MINIO_PORT" validate:"required"` + AccessKey string `mapstructure:"STORAGE_MINIO_ACCESS_KEY" validate:"required"` + SecretKey string `mapstructure:"STORAGE_MINIO_SECRET_KEY" validate:"required"` + Token string `mapstructure:"STORAGE_MINIO_TOKEN"` + Secure bool `mapstructure:"STORAGE_MINIO_SECURE"` + RetryTimes int `mapstructure:"STORAGE_MINIO_RETRY_TIMES" validate:"required"` + RetryPause time.Duration `mapstructure:"STORAGE_MINIO_RETRY_PAUSE" validate:"required"` + Timeout time.Duration `mapstructure:"STORAGE_MINIO_TIMEOUT" validate:"required"` + Location string `mapstructure:"STORAGE_MINIO_LOCATION" validate:"required"` + Prefix string `mapstructure:"STORAGE_MINIO_PREFIX"` } + +var ( + DefaultMinioConfig = MinioConfig{ + Host: "localhost", + Port: "9000", + AccessKey: "12345678", + SecretKey: "qwertyui", + Token: "", + Secure: false, + RetryTimes: 4, + RetryPause: 5 * time.Second, + Timeout: 30 * time.Second, + Location: "eu-central-1", + Prefix: "", + } +) diff --git a/infrastructure/storage/minio.go b/infrastructure/storage/minio.go index e4ed851..951e110 100644 --- a/infrastructure/storage/minio.go +++ b/infrastructure/storage/minio.go @@ -16,19 +16,18 @@ import ( "github.com/zitryss/aye-and-nay/pkg/retry" ) -func NewMinio() (*Minio, error) { - conf := newMinioConfig() - client, err := minios3.New(conf.host+":"+conf.port, &minios3.Options{ - Creds: credentials.NewStaticV4(conf.accessKey, conf.secretKey, conf.token), - Secure: conf.secure, +func NewMinio(ctx context.Context, conf MinioConfig) (*Minio, error) { + client, err := minios3.New(conf.Host+":"+conf.Port, &minios3.Options{ + Creds: credentials.NewStaticV4(conf.AccessKey, conf.SecretKey, conf.Token), + Secure: conf.Secure, }) if err != nil { return &Minio{}, errors.Wrap(err) } m := &Minio{conf, client} - ctx, cancel := context.WithTimeout(context.Background(), conf.timeout) + ctx, cancel := context.WithTimeout(ctx, conf.Timeout) defer cancel() - err = retry.Do(conf.times, conf.pause, func() error { + err = retry.Do(conf.RetryTimes, conf.RetryPause, func() error { _, err := m.Health(ctx) if err != nil { return errors.Wrap(err) @@ -43,7 +42,7 @@ func NewMinio() (*Minio, error) { return &Minio{}, errors.Wrap(err) } if !found { - err = client.MakeBucket(ctx, "aye-and-nay", minios3.MakeBucketOptions{Region: conf.location}) + err = client.MakeBucket(ctx, "aye-and-nay", minios3.MakeBucketOptions{Region: conf.Location}) if err != nil { return &Minio{}, errors.Wrap(err) } @@ -57,7 +56,7 @@ func NewMinio() (*Minio, error) { } type Minio struct { - conf minioConfig + conf MinioConfig client *minios3.Client } @@ -70,7 +69,7 @@ func (m *Minio) Put(ctx context.Context, album uint64, image uint64, f model.Fil if err != nil { return "", errors.Wrap(err) } - src := m.conf.prefix + "/aye-and-nay/" + filename + src := m.conf.Prefix + "/aye-and-nay/" + filename return src, nil } @@ -111,13 +110,13 @@ func (m *Minio) Remove(ctx context.Context, album uint64, image uint64) error { } func (m *Minio) Health(ctx context.Context) (bool, error) { - url := "http://" + m.conf.host + ":" + m.conf.port + "/minio/health/live" + url := "http://" + m.conf.Host + ":" + m.conf.Port + "/minio/health/live" body := io.Reader(nil) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, body) if err != nil { return false, errors.Wrapf(domain.ErrBadHealthStorage, "%s", err) } - c := http.Client{Timeout: m.conf.timeout} + c := http.Client{Timeout: m.conf.Timeout} resp, err := c.Do(req) if err != nil { return false, errors.Wrapf(domain.ErrBadHealthStorage, "%s", err) @@ -134,13 +133,13 @@ func (m *Minio) Health(ctx context.Context) (bool, error) { if resp.StatusCode < 200 || resp.StatusCode > 299 { return false, errors.Wrapf(domain.ErrBadHealthStorage, "%s", "no connection to minio") } - url = "http://" + m.conf.host + ":" + m.conf.port + "/minio/health/ready" + url = "http://" + m.conf.Host + ":" + m.conf.Port + "/minio/health/ready" body = io.Reader(nil) req, err = http.NewRequestWithContext(ctx, http.MethodGet, url, body) if err != nil { return false, errors.Wrapf(domain.ErrBadHealthStorage, "%s", err) } - c = http.Client{Timeout: m.conf.timeout} + c = http.Client{Timeout: m.conf.Timeout} resp, err = c.Do(req) if err != nil { return false, errors.Wrapf(domain.ErrBadHealthStorage, "%s", err) diff --git a/infrastructure/storage/minio_integration_test.go b/infrastructure/storage/minio_integration_test.go index 3b2955c..2faf55f 100644 --- a/infrastructure/storage/minio_integration_test.go +++ b/infrastructure/storage/minio_integration_test.go @@ -8,14 +8,13 @@ import ( minios3 "github.com/minio/minio-go/v7" - _ "github.com/zitryss/aye-and-nay/internal/config" . "github.com/zitryss/aye-and-nay/internal/testing" "github.com/zitryss/aye-and-nay/pkg/errors" ) func TestMinio(t *testing.T) { t.Run("", func(t *testing.T) { - minio, err := NewMinio() + minio, err := NewMinio(DefaultMinioConfig) if err != nil { t.Fatal(err) } @@ -55,7 +54,7 @@ func TestMinio(t *testing.T) { } }) t.Run("", func(t *testing.T) { - minio, err := NewMinio() + minio, err := NewMinio(DefaultMinioConfig) if err != nil { t.Fatal(err) } @@ -88,7 +87,7 @@ func TestMinio(t *testing.T) { } func TestMinioHealth(t *testing.T) { - minio, err := NewMinio() + minio, err := NewMinio(DefaultMinioConfig) if err != nil { t.Fatal(err) } diff --git a/infrastructure/storage/storage.go b/infrastructure/storage/storage.go index 8f91f3b..d867b72 100644 --- a/infrastructure/storage/storage.go +++ b/infrastructure/storage/storage.go @@ -1,15 +1,17 @@ package storage import ( + "context" + "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/pkg/log" ) -func New(s string) (domain.Storager, error) { - switch s { +func New(ctx context.Context, conf StorageConfig) (domain.Storager, error) { + switch conf.Storage { case "minio": log.Info("connecting to storage") - return NewMinio() + return NewMinio(ctx, conf.Minio) case "mock": return NewMock(), nil default: diff --git a/infrastructure/storage/storage_integration_test.go b/infrastructure/storage/storage_integration_test.go index 5e8c62a..68b8831 100644 --- a/infrastructure/storage/storage_integration_test.go +++ b/infrastructure/storage/storage_integration_test.go @@ -18,7 +18,11 @@ func TestMain(m *testing.M) { log.SetOutput(os.Stderr) log.SetLevel(log.CRITICAL) docker := dockertest.New() - docker.RunMinio() + host := &DefaultMinioConfig.Host + port := &DefaultMinioConfig.Port + accessKey := DefaultMinioConfig.AccessKey + secretKey := DefaultMinioConfig.SecretKey + docker.RunMinio(host, port, accessKey, secretKey) log.SetOutput(io.Discard) code := m.Run() docker.Purge() diff --git a/internal/config/config.go b/internal/config/config.go index 311ae79..bcba1fd 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1,49 +1,95 @@ package config import ( + "reflect" + "strings" + + "github.com/fsnotify/fsnotify" + "github.com/go-playground/validator" "github.com/spf13/viper" - "github.com/zitryss/aye-and-nay/pkg/unit" + "github.com/zitryss/aye-and-nay/delivery/http" + "github.com/zitryss/aye-and-nay/domain/service" + "github.com/zitryss/aye-and-nay/infrastructure/cache" + "github.com/zitryss/aye-and-nay/infrastructure/compressor" + "github.com/zitryss/aye-and-nay/infrastructure/database" + "github.com/zitryss/aye-and-nay/infrastructure/storage" + "github.com/zitryss/aye-and-nay/pkg/errors" ) -func init() { - viper.Set("middleware.limiter.requestsPerSecond", 100) - viper.Set("middleware.limiter.burst", 1) - viper.Set("controller.maxNumberOfFiles", 3) - viper.Set("controller.maxFileSize", 512*unit.KB) - viper.Set("service.numberOfWorkersCalc", 2) - viper.Set("service.tempLinks", true) - viper.Set("service.numberOfWorkersComp", 2) - viper.Set("service.accuracy", 0.625) - viper.Set("cache.redis.host", "localhost") - viper.Set("cache.redis.port", 6379) - viper.Set("cache.redis.retry.times", 4) - viper.Set("cache.redis.retry.pause", "5s") - viper.Set("cache.redis.retry.timeout", "30s") - viper.Set("cache.redis.timeToLive", "1s") - viper.Set("compressor.use", "notamock") - viper.Set("compressor.imaginary.host", "localhost") - viper.Set("compressor.imaginary.port", 9001) - viper.Set("compressor.imaginary.retry.times", 4) - viper.Set("compressor.imaginary.retry.pause", "5s") - viper.Set("compressor.imaginary.retry.timeout", "30s") - viper.Set("compressor.shortpixel.uploadTimeout", "250ms") - viper.Set("compressor.shortpixel.downloadTimeout", "250ms") - viper.Set("database.mongo.host", "localhost") - viper.Set("database.mongo.port", 27017) - viper.Set("database.mongo.retry.times", 4) - viper.Set("database.mongo.retry.pause", "5s") - viper.Set("database.mongo.retry.timeout", "30s") - viper.Set("database.mongo.lru", 1) - viper.Set("database.badger.lru", 1) - viper.Set("storage.minio.host", "localhost") - viper.Set("storage.minio.port", 9000) - viper.Set("storage.minio.accessKey", "12345678") - viper.Set("storage.minio.secretKey", "qwertyui") - viper.Set("storage.minio.token", "") - viper.Set("storage.minio.secure", false) - viper.Set("storage.minio.retry.times", 4) - viper.Set("storage.minio.retry.pause", "5s") - viper.Set("storage.minio.retry.timeout", "30s") - viper.Set("storage.minio.location", "eu-central-1") +func New(path string) (Config, error) { + viper.Reset() + conf := Config{} + err := readConfig(path, &conf) + if err != nil { + return Config{}, errors.Wrap(err) + } + fillGaps(&conf) + err = validator.New().Struct(conf) + if err != nil { + return Config{}, errors.Wrap(err) + } + return conf, nil +} + +func OnChange(run func()) { + viper.OnConfigChange(func(_ fsnotify.Event) { + run() + }) + viper.WatchConfig() +} + +type Config struct { + App AppConfig `mapstructure:",squash"` + Server http.ServerConfig `mapstructure:",squash"` + Middleware http.MiddlewareConfig `mapstructure:",squash"` + Service service.ServiceConfig `mapstructure:",squash"` + Cache cache.CacheConfig `mapstructure:",squash"` + Compressor compressor.CompressorConfig `mapstructure:",squash"` + Database database.DatabaseConfig `mapstructure:",squash"` + Storage storage.StorageConfig `mapstructure:",squash"` +} + +type AppConfig struct { + Name string `mapstructure:"APP_NAME" validate:"required"` + Ballast int64 `mapstructure:"APP_BALLAST"` + Log string `mapstructure:"APP_LOG" validate:"required"` +} + +func readConfig(path string, conf *Config) error { + viper.SetConfigFile(path) + viper.AutomaticEnv() + _ = viper.ReadInConfig() + if len(viper.AllSettings()) == 0 { + bindEnv(reflect.TypeOf(*conf)) + } + if len(viper.AllSettings()) == 0 { + return errors.Wrap(errors.New("no configuration is provided")) + } + err := viper.Unmarshal(conf) + if err != nil { + return errors.Wrap(err) + } + return nil +} + +func bindEnv(t reflect.Type) { + if t.Kind() != reflect.Struct { + return + } + for _, field := range reflect.VisibleFields(t) { + bindEnv(field.Type) + tag := field.Tag.Get("mapstructure") + if field.IsExported() && tag != "" && tag != ",squash" { + _ = viper.BindEnv(strings.ToLower(tag), tag) + } + } +} + +func fillGaps(conf *Config) { + if conf.Compressor.IsMock() { + conf.Database.Mem.Compressed = true + conf.Database.Mongo.Compressed = true + conf.Database.Badger.Compressed = true + } } diff --git a/internal/dockertest/dockertest.go b/internal/dockertest/dockertest.go index eb52ac2..2f78ab6 100644 --- a/internal/dockertest/dockertest.go +++ b/internal/dockertest/dockertest.go @@ -5,7 +5,6 @@ import ( "os" "github.com/ory/dockertest/v3" - "github.com/spf13/viper" "github.com/zitryss/aye-and-nay/pkg/env" "github.com/zitryss/aye-and-nay/pkg/errors" @@ -40,58 +39,56 @@ type docker struct { resources []*dockertest.Resource } -func (d *docker) RunRedis() { +func (d *docker) RunRedis(host *string, hPort *string) { repository := "redis" tag := "6-alpine" env := []string(nil) cmd := []string(nil) - port := "6379/tcp" + cPort := "6379/tcp" conf := func(port string) { - viper.Set("cache.redis.host", d.host) - viper.Set("cache.redis.port", port) + *host = d.host + *hPort = port } - d.run(repository, tag, env, cmd, port, conf) + d.run(repository, tag, env, cmd, cPort, conf) } -func (d *docker) RunImaginary() { +func (d *docker) RunImaginary(host *string, hPort *string) { repository := "h2non/imaginary" tag := "1" env := []string(nil) cmd := []string(nil) - port := "9000/tcp" + cPort := "9000/tcp" conf := func(port string) { - viper.Set("compressor.imaginary.host", d.host) - viper.Set("compressor.imaginary.port", port) + *host = d.host + *hPort = port } - d.run(repository, tag, env, cmd, port, conf) + d.run(repository, tag, env, cmd, cPort, conf) } -func (d *docker) RunMongo() { +func (d *docker) RunMongo(host *string, hPort *string) { repository := "mongo" tag := "5" env := []string(nil) cmd := []string(nil) - port := "27017/tcp" + cPort := "27017/tcp" conf := func(port string) { - viper.Set("database.mongo.host", d.host) - viper.Set("database.mongo.port", port) + *host = d.host + *hPort = port } - d.run(repository, tag, env, cmd, port, conf) + d.run(repository, tag, env, cmd, cPort, conf) } -func (d *docker) RunMinio() { +func (d *docker) RunMinio(host *string, hPort *string, accessKey string, secretKey string) { repository := "minio/minio" tag := "RELEASE.2021-11-24T23-19-33Z" - accessKey := viper.GetString("storage.minio.accessKey") - secretKey := viper.GetString("storage.minio.secretKey") env := []string{"MINIO_ACCESS_KEY=" + accessKey, "MINIO_SECRET_KEY=" + secretKey} cmd := []string{"server", "/data"} - port := "9000/tcp" + cPort := "9000/tcp" conf := func(port string) { - viper.Set("storage.minio.host", d.host) - viper.Set("storage.minio.port", port) + *host = d.host + *hPort = port } - d.run(repository, tag, env, cmd, port, conf) + d.run(repository, tag, env, cmd, cPort, conf) } func (d *docker) run(repository string, tag string, env []string, cmd []string, containerPort string, conf func(string)) { diff --git a/main.go b/main.go index 13e2da6..2732e4b 100644 --- a/main.go +++ b/main.go @@ -8,7 +8,6 @@ import ( "os/signal" "syscall" - "github.com/spf13/viper" "golang.org/x/sync/errgroup" "github.com/zitryss/aye-and-nay/delivery/http" @@ -17,6 +16,7 @@ import ( "github.com/zitryss/aye-and-nay/infrastructure/compressor" "github.com/zitryss/aye-and-nay/infrastructure/database" "github.com/zitryss/aye-and-nay/infrastructure/storage" + "github.com/zitryss/aye-and-nay/internal/config" "github.com/zitryss/aye-and-nay/pkg/errors" "github.com/zitryss/aye-and-nay/pkg/log" ) @@ -26,148 +26,171 @@ var ( ) func main() { - conf := "" - flag.StringVar(&conf, "config", "./config.yml", "relative filepath to a config file") + path := "" + flag.StringVar(&path, "config", "./config.env", "filepath to a config file") flag.Parse() - viper.SetConfigFile(conf) - err := viper.ReadInConfig() - if err != nil { - _, _ = fmt.Fprintln(os.Stderr, "critical:", err) - os.Exit(1) - } - ballast = make([]byte, viper.GetInt64("app.ballast")) + reload := true + for reload { + reload = false - p := viper.GetString("app.name") - l := viper.GetString("app.log") - log.SetOutput(os.Stderr) - log.SetPrefix(p) - log.SetLevel(l) - log.Info("logging initialized") + ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) - ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) - defer stop() + conf, err := config.New(path) + if err != nil { + _, _ = fmt.Fprintln(os.Stderr, "critical:", err) + reload = true + stop() + continue + } - cach, err := cache.New(viper.GetString("cache.use")) - if err != nil { - log.Critical(err) - os.Exit(1) - } + config.OnChange(func() { + reload = true + stop() + }) - comp, err := compressor.New(viper.GetString("compressor.use")) - if err != nil { - log.Critical(err) - os.Exit(1) - } + ballast = make([]byte, conf.App.Ballast) - data, err := database.New(viper.GetString("database.use")) - if err != nil { - log.Critical(err) - os.Exit(1) - } + log.SetOutput(os.Stderr) + log.SetPrefix(conf.App.Name) + log.SetLevel(conf.App.Log) + log.Info("logging initialized:", "log level:", conf.App.Log) - stor, err := storage.New(viper.GetString("storage.use")) - if err != nil { - log.Critical(err) - os.Exit(1) - } + cach, err := cache.New(ctx, conf.Cache) + if err != nil { + log.Critical(err) + reload = true + stop() + continue + } - qCalc := service.NewQueueCalc(cach) - qCalc.Monitor(ctx) + comp, err := compressor.New(ctx, conf.Compressor) + if err != nil { + log.Critical(err) + reload = true + stop() + continue + } - qComp := &service.QueueComp{} - if viper.GetString("compressor.use") != "mock" { - qComp = service.NewQueueComp(cach) - qComp.Monitor(ctx) - } + data, err := database.New(ctx, conf.Database) + if err != nil { + log.Critical(err) + reload = true + stop() + continue + } - qDel := service.NewQueueDel(cach) - qDel.Monitor(ctx) + stor, err := storage.New(ctx, conf.Storage) + if err != nil { + log.Critical(err) + reload = true + stop() + continue + } - serv := service.New(comp, stor, data, cach, qCalc, qComp, qDel) - err = serv.CleanUp(ctx) - if err != nil { - log.Critical(err) - os.Exit(1) - } + qCalc := service.NewQueueCalc(cach) + qCalc.Monitor(ctx) - gCalc, ctxCalc := errgroup.WithContext(ctx) - log.Info("starting calculation worker pool") - serv.StartWorkingPoolCalc(ctxCalc, gCalc) + qComp := &service.QueueComp{} + if conf.Compressor.IsMock() { + qComp = service.NewQueueComp(cach) + qComp.Monitor(ctx) + } - gComp := (*errgroup.Group)(nil) - ctxComp := context.Context(nil) - if viper.GetString("compressor.use") != "mock" { - gComp, ctxComp = errgroup.WithContext(ctx) - log.Info("starting compression worker pool") - serv.StartWorkingPoolComp(ctxComp, gComp) - } + qDel := service.NewQueueDel(cach) + qDel.Monitor(ctx) - gDel, ctxDel := errgroup.WithContext(ctx) - log.Info("starting deletion worker pool") - serv.StartWorkingPoolDel(ctxDel, gDel) + serv := service.New(conf.Service, comp, stor, data, cach, qCalc, qComp, qDel) + err = serv.CleanUp(ctx) + if err != nil { + log.Critical(err) + reload = true + stop() + continue + } - middle := http.NewMiddleware(cach) - srvWait := make(chan error, 1) - srv, err := http.NewServer(middle.Chain, serv, srvWait) - if err != nil { - log.Critical(err) - os.Exit(1) - } - srv.Monitor(ctx) - log.Info("starting web server") - err = srv.Start() + gCalc, ctxCalc := errgroup.WithContext(ctx) + log.Info("starting calculation worker pool") + serv.StartWorkingPoolCalc(ctxCalc, gCalc) - log.Info("stopping web server") - if err != nil && !errors.Is(err, http.ErrServerClosed) { - log.Error(err) - } - err = <-srvWait - if err != nil { - log.Error(err) - } + gComp := (*errgroup.Group)(nil) + ctxComp := context.Context(nil) + if conf.Compressor.IsMock() { + gComp, ctxComp = errgroup.WithContext(ctx) + log.Info("starting compression worker pool") + serv.StartWorkingPoolComp(ctxComp, gComp) + } - log.Info("stopping deletion worker pool") - err = gDel.Wait() - if err != nil { - log.Error(err) - } + gDel, ctxDel := errgroup.WithContext(ctx) + log.Info("starting deletion worker pool") + serv.StartWorkingPoolDel(ctxDel, gDel) - if viper.GetString("compressor.use") != "mock" { - log.Info("stopping compression worker pool") - err = gComp.Wait() + middle := http.NewMiddleware(conf.Middleware, cach) + srvWait := make(chan error, 1) + srv, err := http.NewServer(conf.Server, middle.Chain, serv, srvWait) if err != nil { - log.Error(err) + log.Critical(err) + reload = true + stop() + continue } - } + srv.Monitor(ctx) + log.Info("starting web server") + err = srv.Start() - log.Info("stopping calculation worker pool") - err = gCalc.Wait() - if err != nil { - log.Error(err) - } - - r, ok := cach.(*cache.Redis) - if ok { - err = r.Close() + log.Info("stopping web server") + if err != nil && !errors.Is(err, http.ErrServerClosed) { + log.Error(err) + } + err = <-srvWait if err != nil { log.Error(err) } - } - m, ok := data.(*database.Mongo) - if ok { - err = m.Close() + log.Info("stopping deletion worker pool") + err = gDel.Wait() if err != nil { log.Error(err) } - } - b, ok := data.(*database.Badger) - if ok { - err = b.Close() + if conf.Compressor.IsMock() { + log.Info("stopping compression worker pool") + err = gComp.Wait() + if err != nil { + log.Error(err) + } + } + + log.Info("stopping calculation worker pool") + err = gCalc.Wait() if err != nil { log.Error(err) } + + r, ok := cach.(*cache.Redis) + if ok { + err = r.Close(ctx) + if err != nil { + log.Error(err) + } + } + + m, ok := data.(*database.Mongo) + if ok { + err = m.Close(ctx) + if err != nil { + log.Error(err) + } + } + + b, ok := data.(*database.Badger) + if ok { + err = b.Close(ctx) + if err != nil { + log.Error(err) + } + } + + stop() } } From 6fa9fa2b40c0a19467f4fd683430465b0dfe3347 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Mon, 10 Jan 2022 11:33:25 +0100 Subject: [PATCH 23/92] Correct tests --- delivery/http/controller.go | 8 +- delivery/http/error.go | 4 +- delivery/http/middleware_test.go | 6 +- domain/service/queue_integration_test.go | 2 +- domain/service/service_integration_test.go | 134 +++++++++--------- .../cache/redis_integration_test.go | 24 ++-- .../compressor/imaginary_integration_test.go | 6 +- .../database/mongo_integration_test.go | 46 +++--- .../storage/minio_integration_test.go | 6 +- 9 files changed, 118 insertions(+), 118 deletions(-) diff --git a/delivery/http/controller.go b/delivery/http/controller.go index 85bce44..510bc2e 100644 --- a/delivery/http/controller.go +++ b/delivery/http/controller.go @@ -125,7 +125,7 @@ func (c *controller) handleAlbum() httprouter.Handle { return resp, nil } output := func(ctx context.Context, w http.ResponseWriter, resp albumResponse) error { - w.Header().Set(http.CanonicalHeaderKey("Content-Type"), "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(201) err := json.NewEncoder(w).Encode(resp) if err != nil { @@ -173,7 +173,7 @@ func (c *controller) handleReady() httprouter.Handle { return resp, nil } output := func(ctx context.Context, w http.ResponseWriter, resp readyResponse) error { - w.Header().Set(http.CanonicalHeaderKey("Content-Type"), "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json; charset=utf-8") err := json.NewEncoder(w).Encode(resp) if err != nil { return errors.Wrap(err) @@ -225,7 +225,7 @@ func (c *controller) handlePair() httprouter.Handle { return resp, nil } output := func(ctx context.Context, w http.ResponseWriter, resp pairResponse) error { - w.Header().Set(http.CanonicalHeaderKey("Content-Type"), "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json; charset=utf-8") err := json.NewEncoder(w).Encode(resp) if err != nil { return errors.Wrap(err) @@ -379,7 +379,7 @@ func (c *controller) handleTop() httprouter.Handle { return resp, nil } output := func(ctx context.Context, w http.ResponseWriter, resp topResponse) error { - w.Header().Set(http.CanonicalHeaderKey("Content-Type"), "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json; charset=utf-8") err := json.NewEncoder(w).Encode(resp) if err != nil { return errors.Wrap(err) diff --git a/delivery/http/error.go b/delivery/http/error.go index 768c52e..95d26af 100644 --- a/delivery/http/error.go +++ b/delivery/http/error.go @@ -40,8 +40,8 @@ func handleError(w http.ResponseWriter, err error) { func handleOuterError(w http.ResponseWriter, err error) { resp := errorResponse{} defer func() { - w.Header().Set(http.CanonicalHeaderKey("Content-Type"), "application/json; charset=utf-8") - w.Header().Set(http.CanonicalHeaderKey("X-Content-Type-Options"), "nosniff") + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("X-Content-Type-Options", "nosniff") w.WriteHeader(resp.Error.statusCode) _ = json.NewEncoder(w).Encode(resp) }() diff --git a/delivery/http/middleware_test.go b/delivery/http/middleware_test.go index 6149e40..69ee4c8 100644 --- a/delivery/http/middleware_test.go +++ b/delivery/http/middleware_test.go @@ -27,7 +27,7 @@ func (l limiterMockNeg) Allow(_ context.Context, _ uint64) (bool, error) { func TestMiddlewareRecover(t *testing.T) { t.Run("Positive", func(t *testing.T) { fn := func(w http.ResponseWriter, r *http.Request) { - w.Header().Set(http.CanonicalHeaderKey("Content-Type"), "text/plain; charset=utf-8") + w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.WriteHeader(418) _, _ = io.WriteString(w, "I'm a teapot") } @@ -60,7 +60,7 @@ func TestMiddlewareRecover(t *testing.T) { func TestMiddlewareLimit(t *testing.T) { t.Run("Positive", func(t *testing.T) { fn := func(w http.ResponseWriter, r *http.Request) { - w.Header().Set(http.CanonicalHeaderKey("Content-Type"), "text/plain; charset=utf-8") + w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.WriteHeader(418) _, _ = io.WriteString(w, "I'm a teapot") } @@ -76,7 +76,7 @@ func TestMiddlewareLimit(t *testing.T) { }) t.Run("Negative", func(t *testing.T) { fn := func(w http.ResponseWriter, r *http.Request) { - w.Header().Set(http.CanonicalHeaderKey("Content-Type"), "text/plain; charset=utf-8") + w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.WriteHeader(418) _, _ = io.WriteString(w, "I'm a teapot") } diff --git a/domain/service/queue_integration_test.go b/domain/service/queue_integration_test.go index a55ae47..d268375 100644 --- a/domain/service/queue_integration_test.go +++ b/domain/service/queue_integration_test.go @@ -11,7 +11,7 @@ import ( ) func TestPQueueIntegration(t *testing.T) { - redis, err := cache.NewRedis(cache.DefaultRedisConfig) + redis, err := cache.NewRedis(context.Background(), cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } diff --git a/domain/service/service_integration_test.go b/domain/service/service_integration_test.go index 017a3e3..a3e426d 100644 --- a/domain/service/service_integration_test.go +++ b/domain/service/service_integration_test.go @@ -65,19 +65,19 @@ func TestServiceIntegrationAlbum(t *testing.T) { }() ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) + imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio(storage.DefaultMinioConfig) + minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo(database.DefaultMongoConfig) + mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis(cache.DefaultRedisConfig) + redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -126,15 +126,15 @@ func TestServiceIntegrationAlbum(t *testing.T) { heartbeatRestart := make(chan interface{}) comp := compressor.NewShortpixel(compressor.DefaultShortpixelConfig, compressor.WithHeartbeatRestart(heartbeatRestart)) comp.Monitor() - minio, err := storage.NewMinio(storage.DefaultMinioConfig) + minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo(database.DefaultMongoConfig) + mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis(cache.DefaultRedisConfig) + redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -236,19 +236,19 @@ func TestServiceIntegrationPair(t *testing.T) { } ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) + imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio(storage.DefaultMinioConfig) + minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo(database.DefaultMongoConfig) + mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis(cache.DefaultRedisConfig) + redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -325,19 +325,19 @@ func TestServiceIntegrationPair(t *testing.T) { } ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) + imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio(storage.DefaultMinioConfig) + minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo(database.DefaultMongoConfig) + mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis(cache.DefaultRedisConfig) + redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -407,19 +407,19 @@ func TestServiceIntegrationPair(t *testing.T) { t.Run("Negative", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) + imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio(storage.DefaultMinioConfig) + minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo(database.DefaultMongoConfig) + mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis(cache.DefaultRedisConfig) + redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -450,19 +450,19 @@ func TestServiceIntegrationImage(t *testing.T) { } ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) + imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio(storage.DefaultMinioConfig) + minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo(database.DefaultMongoConfig) + mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis(cache.DefaultRedisConfig) + redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -500,19 +500,19 @@ func TestServiceIntegrationImage(t *testing.T) { t.Run("Negative", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) + imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio(storage.DefaultMinioConfig) + minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo(database.DefaultMongoConfig) + mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis(cache.DefaultRedisConfig) + redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -543,19 +543,19 @@ func TestServiceIntegrationVote(t *testing.T) { } ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) + imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio(storage.DefaultMinioConfig) + minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo(database.DefaultMongoConfig) + mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis(cache.DefaultRedisConfig) + redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -592,19 +592,19 @@ func TestServiceIntegrationVote(t *testing.T) { } ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) + imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio(storage.DefaultMinioConfig) + minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo(database.DefaultMongoConfig) + mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis(cache.DefaultRedisConfig) + redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -643,19 +643,19 @@ func TestServiceIntegrationVote(t *testing.T) { } ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) + imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio(storage.DefaultMinioConfig) + minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo(database.DefaultMongoConfig) + mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis(cache.DefaultRedisConfig) + redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -692,19 +692,19 @@ func TestServiceIntegrationVote(t *testing.T) { } ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) + imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio(storage.DefaultMinioConfig) + minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo(database.DefaultMongoConfig) + mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis(cache.DefaultRedisConfig) + redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -744,19 +744,19 @@ func TestServiceIntegrationTop(t *testing.T) { } ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) + imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio(storage.DefaultMinioConfig) + minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo(database.DefaultMongoConfig) + mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis(cache.DefaultRedisConfig) + redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -807,19 +807,19 @@ func TestServiceIntegrationTop(t *testing.T) { t.Run("Negative", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) + imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio(storage.DefaultMinioConfig) + minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo(database.DefaultMongoConfig) + mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis(cache.DefaultRedisConfig) + redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -841,19 +841,19 @@ func TestServiceIntegrationDelete(t *testing.T) { t.Run("Positive1", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) + imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio(storage.DefaultMinioConfig) + minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo(database.DefaultMongoConfig) + mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis(cache.DefaultRedisConfig) + redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -899,19 +899,19 @@ func TestServiceIntegrationDelete(t *testing.T) { t.Run("Positive2", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) + imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio(storage.DefaultMinioConfig) + minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo(database.DefaultMongoConfig) + mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis(cache.DefaultRedisConfig) + redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -940,19 +940,19 @@ func TestServiceIntegrationDelete(t *testing.T) { t.Run("Negative", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) + imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio(storage.DefaultMinioConfig) + minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo(database.DefaultMongoConfig) + mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis(cache.DefaultRedisConfig) + redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -987,19 +987,19 @@ func TestServiceIntegrationDelete(t *testing.T) { func TestServiceIntegrationHealth(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - imaginary, err := compressor.NewImaginary(compressor.DefaultImaginaryConfig) + imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) if err != nil { t.Fatal(err) } - minio, err := storage.NewMinio(storage.DefaultMinioConfig) + minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) if err != nil { t.Fatal(err) } - mongo, err := database.NewMongo(database.DefaultMongoConfig) + mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) if err != nil { t.Fatal(err) } - redis, err := cache.NewRedis(cache.DefaultRedisConfig) + redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) if err != nil { t.Fatal(err) } diff --git a/infrastructure/cache/redis_integration_test.go b/infrastructure/cache/redis_integration_test.go index 6146a7f..6ef1ca4 100644 --- a/infrastructure/cache/redis_integration_test.go +++ b/infrastructure/cache/redis_integration_test.go @@ -16,7 +16,7 @@ func TestRedisAllow(t *testing.T) { if testing.Short() { t.Skip("short flag is set") } - redis, err := NewRedis(DefaultRedisConfig) + redis, err := NewRedis(context.Background(), DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -42,7 +42,7 @@ func TestRedisAllow(t *testing.T) { } }) t.Run("Negative", func(t *testing.T) { - redis, err := NewRedis(DefaultRedisConfig) + redis, err := NewRedis(context.Background(), DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -67,7 +67,7 @@ func TestRedisAllow(t *testing.T) { } func TestRedisQueue(t *testing.T) { - redis, err := NewRedis(DefaultRedisConfig) + redis, err := NewRedis(context.Background(), DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -161,7 +161,7 @@ func TestRedisQueue(t *testing.T) { } func TestRedisPQueue(t *testing.T) { - redis, err := NewRedis(DefaultRedisConfig) + redis, err := NewRedis(context.Background(), DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -243,7 +243,7 @@ func TestRedisPQueue(t *testing.T) { func TestRedisPair(t *testing.T) { t.Run("Positive", func(t *testing.T) { - redis, err := NewRedis(DefaultRedisConfig) + redis, err := NewRedis(context.Background(), DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -265,7 +265,7 @@ func TestRedisPair(t *testing.T) { } }) t.Run("Negative1", func(t *testing.T) { - redis, err := NewRedis(DefaultRedisConfig) + redis, err := NewRedis(context.Background(), DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -275,7 +275,7 @@ func TestRedisPair(t *testing.T) { } }) t.Run("Negative2", func(t *testing.T) { - redis, err := NewRedis(DefaultRedisConfig) + redis, err := NewRedis(context.Background(), DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -298,7 +298,7 @@ func TestRedisPair(t *testing.T) { func TestRedisToken(t *testing.T) { t.Run("Positive", func(t *testing.T) { - redis, err := NewRedis(DefaultRedisConfig) + redis, err := NewRedis(context.Background(), DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -321,7 +321,7 @@ func TestRedisToken(t *testing.T) { } }) t.Run("Negative1", func(t *testing.T) { - redis, err := NewRedis(DefaultRedisConfig) + redis, err := NewRedis(context.Background(), DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -338,7 +338,7 @@ func TestRedisToken(t *testing.T) { } }) t.Run("Negative2", func(t *testing.T) { - redis, err := NewRedis(DefaultRedisConfig) + redis, err := NewRedis(context.Background(), DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -349,7 +349,7 @@ func TestRedisToken(t *testing.T) { } }) t.Run("Negative3", func(t *testing.T) { - redis, err := NewRedis(DefaultRedisConfig) + redis, err := NewRedis(context.Background(), DefaultRedisConfig) if err != nil { t.Fatal(err) } @@ -378,7 +378,7 @@ func TestRedisToken(t *testing.T) { } }) t.Run("Negative4", func(t *testing.T) { - redis, err := NewRedis(DefaultRedisConfig) + redis, err := NewRedis(context.Background(), DefaultRedisConfig) if err != nil { t.Fatal(err) } diff --git a/infrastructure/compressor/imaginary_integration_test.go b/infrastructure/compressor/imaginary_integration_test.go index 8e8e78a..558bfab 100644 --- a/infrastructure/compressor/imaginary_integration_test.go +++ b/infrastructure/compressor/imaginary_integration_test.go @@ -30,7 +30,7 @@ func TestImaginaryPositive(t *testing.T) { } for _, tt := range tests { t.Run("", func(t *testing.T) { - im, err := NewImaginary(DefaultImaginaryConfig) + im, err := NewImaginary(context.Background(), DefaultImaginaryConfig) if err != nil { t.Fatal(err) } @@ -55,7 +55,7 @@ func TestImaginaryNegative(t *testing.T) { if testing.Short() { t.Skip("short flag is set") } - im, err := NewImaginary(DefaultImaginaryConfig) + im, err := NewImaginary(context.Background(), DefaultImaginaryConfig) if err != nil { t.Fatal(err) } @@ -78,7 +78,7 @@ func TestImaginaryNegative(t *testing.T) { } func TestImaginaryHealth(t *testing.T) { - im, err := NewImaginary(DefaultImaginaryConfig) + im, err := NewImaginary(context.Background(), DefaultImaginaryConfig) if err != nil { t.Fatal(err) } diff --git a/infrastructure/database/mongo_integration_test.go b/infrastructure/database/mongo_integration_test.go index b7b26f3..0642dc3 100644 --- a/infrastructure/database/mongo_integration_test.go +++ b/infrastructure/database/mongo_integration_test.go @@ -17,7 +17,7 @@ import ( func TestMongoAlbum(t *testing.T) { t.Run("Positive", func(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -35,7 +35,7 @@ func TestMongoAlbum(t *testing.T) { } }) t.Run("Negative1", func(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -51,7 +51,7 @@ func TestMongoAlbum(t *testing.T) { } }) t.Run("Negative2", func(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -61,7 +61,7 @@ func TestMongoAlbum(t *testing.T) { } }) t.Run("Negative3", func(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -74,7 +74,7 @@ func TestMongoAlbum(t *testing.T) { func TestMongoCount(t *testing.T) { t.Run("Positive", func(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -128,7 +128,7 @@ func TestMongoCount(t *testing.T) { } }) t.Run("Negative1", func(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -154,7 +154,7 @@ func TestMongoCount(t *testing.T) { } }) t.Run("Negative2", func(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -164,7 +164,7 @@ func TestMongoCount(t *testing.T) { } }) t.Run("Negative3", func(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -174,7 +174,7 @@ func TestMongoCount(t *testing.T) { } }) t.Run("Negative4", func(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -184,7 +184,7 @@ func TestMongoCount(t *testing.T) { } }) t.Run("Negative5", func(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -202,7 +202,7 @@ func TestMongoCount(t *testing.T) { func TestMongoImage(t *testing.T) { t.Run("Positive", func(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -220,7 +220,7 @@ func TestMongoImage(t *testing.T) { } }) t.Run("Negative1", func(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -230,7 +230,7 @@ func TestMongoImage(t *testing.T) { } }) t.Run("Negative2", func(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -248,7 +248,7 @@ func TestMongoImage(t *testing.T) { func TestMongoVote(t *testing.T) { t.Run("Positive", func(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -274,7 +274,7 @@ func TestMongoVote(t *testing.T) { } }) t.Run("Negative", func(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -287,7 +287,7 @@ func TestMongoVote(t *testing.T) { func TestMongoSort(t *testing.T) { t.Run("Positive", func(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -311,7 +311,7 @@ func TestMongoSort(t *testing.T) { } }) t.Run("Negative", func(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -324,7 +324,7 @@ func TestMongoSort(t *testing.T) { func TestMongoRatings(t *testing.T) { t.Run("Positive", func(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -359,7 +359,7 @@ func TestMongoRatings(t *testing.T) { } }) t.Run("Negative", func(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -383,7 +383,7 @@ func TestMongoRatings(t *testing.T) { func TestMongoDelete(t *testing.T) { t.Run("Positive1", func(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -420,7 +420,7 @@ func TestMongoDelete(t *testing.T) { } }) t.Run("Positive2", func(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -450,7 +450,7 @@ func TestMongoDelete(t *testing.T) { }) }) t.Run("Negative", func(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } @@ -467,7 +467,7 @@ func TestMongoDelete(t *testing.T) { } func TestMongoLru(t *testing.T) { - mongo, err := NewMongo(DefaultMongoConfig) + mongo, err := NewMongo(context.Background(), DefaultMongoConfig) if err != nil { t.Fatal(err) } diff --git a/infrastructure/storage/minio_integration_test.go b/infrastructure/storage/minio_integration_test.go index 2faf55f..59b8579 100644 --- a/infrastructure/storage/minio_integration_test.go +++ b/infrastructure/storage/minio_integration_test.go @@ -14,7 +14,7 @@ import ( func TestMinio(t *testing.T) { t.Run("", func(t *testing.T) { - minio, err := NewMinio(DefaultMinioConfig) + minio, err := NewMinio(context.Background(), DefaultMinioConfig) if err != nil { t.Fatal(err) } @@ -54,7 +54,7 @@ func TestMinio(t *testing.T) { } }) t.Run("", func(t *testing.T) { - minio, err := NewMinio(DefaultMinioConfig) + minio, err := NewMinio(context.Background(), DefaultMinioConfig) if err != nil { t.Fatal(err) } @@ -87,7 +87,7 @@ func TestMinio(t *testing.T) { } func TestMinioHealth(t *testing.T) { - minio, err := NewMinio(DefaultMinioConfig) + minio, err := NewMinio(context.Background(), DefaultMinioConfig) if err != nil { t.Fatal(err) } From 8fc4c6339e99ec243375359a9bfff269d24af7da Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Mon, 10 Jan 2022 18:29:34 +0100 Subject: [PATCH 24/92] Fix redis rate limiting --- build/config-dev.env | 2 +- build/config-embed.env | 2 +- build/config-prod.env | 2 +- config.env | 2 +- go.mod | 1 + go.sum | 2 ++ infrastructure/cache/config.go | 4 +-- infrastructure/cache/redis.go | 33 ++++++------------- .../cache/redis_integration_test.go | 6 ++-- 9 files changed, 22 insertions(+), 32 deletions(-) diff --git a/build/config-dev.env b/build/config-dev.env index 3673281..250f002 100644 --- a/build/config-dev.env +++ b/build/config-dev.env @@ -15,7 +15,7 @@ SERVER_SHUTDOWN_TIMEOUT=10s # MIDDLEWARE MIDDLEWARE_CORS_ALLOW_ORIGIN=* -MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=10000 # per minute in case of redis cache +MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=10000 MIDDLEWARE_LIMITER_BURST=10 # CONTROLLER diff --git a/build/config-embed.env b/build/config-embed.env index 973c253..7d8a30a 100644 --- a/build/config-embed.env +++ b/build/config-embed.env @@ -15,7 +15,7 @@ SERVER_SHUTDOWN_TIMEOUT=10s # MIDDLEWARE MIDDLEWARE_CORS_ALLOW_ORIGIN=* -MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=10000 # per minute in case of redis cache +MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=10000 MIDDLEWARE_LIMITER_BURST=10 # CONTROLLER diff --git a/build/config-prod.env b/build/config-prod.env index b0aa3ed..ef7f388 100644 --- a/build/config-prod.env +++ b/build/config-prod.env @@ -15,7 +15,7 @@ SERVER_SHUTDOWN_TIMEOUT=10s # MIDDLEWARE MIDDLEWARE_CORS_ALLOW_ORIGIN=* -MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=10000 # per minute in case of redis cache +MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=10000 MIDDLEWARE_LIMITER_BURST=10 # CONTROLLER diff --git a/config.env b/config.env index 47bf888..2c80f55 100644 --- a/config.env +++ b/config.env @@ -15,7 +15,7 @@ SERVER_SHUTDOWN_TIMEOUT=10s # MIDDLEWARE MIDDLEWARE_CORS_ALLOW_ORIGIN=* -MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=10000 # per minute in case of redis cache +MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=10000 MIDDLEWARE_LIMITER_BURST=10 # CONTROLLER diff --git a/go.mod b/go.mod index 52d356a..2afb466 100644 --- a/go.mod +++ b/go.mod @@ -41,6 +41,7 @@ require ( github.com/fsnotify/fsnotify v1.5.1 // indirect github.com/go-playground/locales v0.12.1 // indirect github.com/go-playground/universal-translator v0.16.0 // indirect + github.com/go-redis/redis_rate/v9 v9.1.2 // indirect github.com/go-stack/stack v1.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/glog v1.0.0 // indirect diff --git a/go.sum b/go.sum index 9e95ff6..e93481a 100644 --- a/go.sum +++ b/go.sum @@ -170,6 +170,8 @@ github.com/go-playground/validator v9.31.0+incompatible h1:UA72EPEogEnq76ehGdEDp github.com/go-playground/validator v9.31.0+incompatible/go.mod h1:yrEkQXlcI+PugkyDjY2bRrL/UBU4f3rvrgkN3V8JEig= github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg= github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w= +github.com/go-redis/redis_rate/v9 v9.1.2 h1:H0l5VzoAtOE6ydd38j8MCq3ABlGLnvvbA1xDSVVCHgQ= +github.com/go-redis/redis_rate/v9 v9.1.2/go.mod h1:oam2de2apSgRG8aJzwJddXbNu91Iyz1m8IKJE2vpvlQ= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= diff --git a/infrastructure/cache/config.go b/infrastructure/cache/config.go index b59a6b1..8086cff 100644 --- a/infrastructure/cache/config.go +++ b/infrastructure/cache/config.go @@ -23,7 +23,7 @@ type RedisConfig struct { RetryTimes int `mapstructure:"CACHE_REDIS_RETRY_TIMES" validate:"required"` RetryPause time.Duration `mapstructure:"CACHE_REDIS_RETRY_PAUSE" validate:"required"` Timeout time.Duration `mapstructure:"CACHE_REDIS_TIMEOUT" validate:"required"` - LimiterRequestsPerMinute int `mapstructure:"MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND" validate:"required"` + LimiterRequestsPerSecond int `mapstructure:"MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND" validate:"required"` LimiterBurst int64 `mapstructure:"MIDDLEWARE_LIMITER_BURST" validate:"required"` TimeToLive time.Duration `mapstructure:"CACHE_REDIS_TIME_TO_LIVE" validate:"required"` } @@ -41,7 +41,7 @@ var ( RetryTimes: 4, RetryPause: 5 * time.Second, Timeout: 30 * time.Second, - LimiterRequestsPerMinute: 100, + LimiterRequestsPerSecond: 100, LimiterBurst: 1, TimeToLive: 1 * time.Second, } diff --git a/infrastructure/cache/redis.go b/infrastructure/cache/redis.go index fc76375..c07e030 100644 --- a/infrastructure/cache/redis.go +++ b/infrastructure/cache/redis.go @@ -2,11 +2,11 @@ package cache import ( "context" - "strconv" "strings" "time" redisdb "github.com/go-redis/redis/v8" + "github.com/go-redis/redis_rate/v9" "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/pkg/base64" @@ -16,7 +16,7 @@ import ( func NewRedis(ctx context.Context, conf RedisConfig) (*Redis, error) { client := redisdb.NewClient(&redisdb.Options{Addr: conf.Host + ":" + conf.Port}) - r := &Redis{conf, client} + r := &Redis{conf: conf, client: client} ctx, cancel := context.WithTimeout(ctx, conf.Timeout) defer cancel() err := retry.Do(conf.RetryTimes, conf.RetryPause, func() error { @@ -29,39 +29,26 @@ func NewRedis(ctx context.Context, conf RedisConfig) (*Redis, error) { if err != nil { return &Redis{}, errors.Wrap(err) } + r.limiter = redis_rate.NewLimiter(client) + r.limit = redis_rate.PerSecond(conf.LimiterRequestsPerSecond) return r, nil } type Redis struct { - conf RedisConfig - client *redisdb.Client + conf RedisConfig + client *redisdb.Client + limiter *redis_rate.Limiter + limit redis_rate.Limit } func (r *Redis) Allow(ctx context.Context, ip uint64) (bool, error) { ipB64 := base64.FromUint64(ip) key := "ip:" + ipB64 - value, err := r.client.Get(ctx, key).Result() - if err != nil && !errors.Is(err, redisdb.Nil) { - return false, errors.Wrap(err) - } - if errors.Is(err, redisdb.Nil) { - value = "-1" - } - count, err := strconv.Atoi(value) - if err != nil { - return false, errors.Wrap(err) - } - if count >= r.conf.LimiterRequestsPerMinute { - return false, nil - } - pipe := r.client.Pipeline() - pipe.IncrBy(ctx, key, r.conf.LimiterBurst) - pipe.Expire(ctx, key, 59*time.Second) - _, err = pipe.Exec(ctx) + res, err := r.limiter.Allow(ctx, key, r.limit) if err != nil { return false, errors.Wrap(err) } - return true, nil + return res.Allowed > 0, nil } func (r *Redis) Add(ctx context.Context, queue uint64, album uint64) error { diff --git a/infrastructure/cache/redis_integration_test.go b/infrastructure/cache/redis_integration_test.go index 6ef1ca4..a829933 100644 --- a/infrastructure/cache/redis_integration_test.go +++ b/infrastructure/cache/redis_integration_test.go @@ -20,7 +20,7 @@ func TestRedisAllow(t *testing.T) { if err != nil { t.Fatal(err) } - rpm := redis.conf.LimiterRequestsPerMinute + rpm := redis.conf.LimiterRequestsPerSecond for j := 0; j < rpm; j++ { allowed, err := redis.Allow(context.Background(), 0xDEAD) if err != nil { @@ -30,7 +30,7 @@ func TestRedisAllow(t *testing.T) { t.Error("!allowed") } } - time.Sleep(60 * time.Second) + time.Sleep(1 * time.Second) for j := 0; j < rpm; j++ { allowed, err := redis.Allow(context.Background(), 0xDEAD) if err != nil { @@ -46,7 +46,7 @@ func TestRedisAllow(t *testing.T) { if err != nil { t.Fatal(err) } - rps := redis.conf.LimiterRequestsPerMinute + rps := redis.conf.LimiterRequestsPerSecond for i := 0; i < rps; i++ { allowed, err := redis.Allow(context.Background(), 0xBEEF) if err != nil { From d3039fc8e28c4df77608e11411b7980656c3c8f4 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Mon, 10 Jan 2022 18:50:33 +0100 Subject: [PATCH 25/92] Assign IP addresss correctly --- delivery/http/middleware.go | 12 +++++-- delivery/http/middleware_test.go | 57 ++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/delivery/http/middleware.go b/delivery/http/middleware.go index c3efb8b..76982c8 100644 --- a/delivery/http/middleware.go +++ b/delivery/http/middleware.go @@ -4,6 +4,7 @@ import ( "hash/fnv" "io" "net/http" + "strings" "github.com/rs/cors" @@ -56,9 +57,8 @@ func (m *Middleware) limit(h http.Handler) http.Handler { return handleHttpError( func(w http.ResponseWriter, r *http.Request) error { ctx := r.Context() - ip := r.RemoteAddr hash := fnv.New64a() - _, err := io.WriteString(hash, ip) + _, err := io.WriteString(hash, ip(r)) if err != nil { return errors.Wrap(err) } @@ -74,3 +74,11 @@ func (m *Middleware) limit(h http.Handler) http.Handler { }, ) } + +func ip(r *http.Request) string { + xff := r.Header.Get("X-Forwarded-For") + if xff != "" { + return strings.Split(xff, ", ")[0] + } + return strings.Split(r.RemoteAddr, ":")[0] +} diff --git a/delivery/http/middleware_test.go b/delivery/http/middleware_test.go index 69ee4c8..7b4dd20 100644 --- a/delivery/http/middleware_test.go +++ b/delivery/http/middleware_test.go @@ -91,3 +91,60 @@ func TestMiddlewareLimit(t *testing.T) { CheckBody(t, w, `{"error":{"code":0,"msg":"too many requests"}}`+"\n") }) } + +func TestIP(t *testing.T) { + type args struct { + xff string + remoteAddr string + } + tests := []struct { + args args + want string + }{ + { + args: args{ + xff: "203.0.113.195", + remoteAddr: "192.168.1.2:65530", + }, + want: "203.0.113.195", + }, + { + args: args{ + xff: "203.0.113.195, 70.41.3.18, 150.172.238.178", + remoteAddr: "192.168.1.2:65530", + }, + want: "203.0.113.195", + }, + { + args: args{ + xff: "2001:db8:85a3:8d3:1319:8a2e:370:7348", + remoteAddr: "192.168.1.2:65530", + }, + want: "2001:db8:85a3:8d3:1319:8a2e:370:7348", + }, + { + args: args{ + xff: "", + remoteAddr: "192.168.1.2:65530", + }, + want: "192.168.1.2", + }, + { + args: args{ + xff: "", + remoteAddr: "", + }, + want: "", + }, + } + for _, tt := range tests { + r := httptest.NewRequest(http.MethodGet, "/api/health/", http.NoBody) + r.Header.Set("X-Forwarded-For", tt.args.xff) + r.RemoteAddr = tt.args.remoteAddr + t.Run("", func(t *testing.T) { + if got := ip(r); got != tt.want { + t.Errorf("ip() = %v, want %v", got, tt.want) + } + }) + } +} From 7f4a5f7cc05ce15be700000726fe2977468eca18 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Tue, 11 Jan 2022 18:13:52 +0100 Subject: [PATCH 26/92] Watch config files --- build/config-dev.env | 12 +++-- build/config-embed.env | 12 +++-- build/config-prod.env | 12 +++-- config.env | 12 +++-- go.mod | 1 + go.sum | 2 + infrastructure/cache/config.go | 2 +- infrastructure/cache/redis.go | 4 +- infrastructure/compressor/config.go | 2 +- infrastructure/database/config.go | 2 +- infrastructure/storage/config.go | 2 +- internal/config/config.go | 81 +++++++++++++++++++++-------- main.go | 10 ++-- 13 files changed, 108 insertions(+), 46 deletions(-) diff --git a/build/config-dev.env b/build/config-dev.env index 250f002..382a728 100644 --- a/build/config-dev.env +++ b/build/config-dev.env @@ -1,3 +1,7 @@ +# CONFIG +CONFIG_RELOAD=true +CONFIG_RELOAD_INTERVAL=1s + # APP APP_NAME=config-dev APP_BALLAST=0 @@ -29,7 +33,7 @@ SERVICE_NUMBER_OF_WORKERS_COMP=8 SERVICE_ACCURACY=0.625 # CACHE: [mem, redis] -CACHE=redis +APP_CACHE=redis CACHE_MEM_CLEANUP_INTERVAL=15m CACHE_REDIS_HOST=localhost CACHE_REDIS_PORT=6379 @@ -39,7 +43,7 @@ CACHE_REDIS_TIMEOUT=30s CACHE_REDIS_TIME_TO_LIVE=15m # COMPRESSOR: [mock, shortpixel, imaginary] -COMPRESSOR=imaginary +APP_COMPRESSOR=imaginary COMPRESSOR_SHORTPIXEL_URL=https://api.shortpixel.com/v2/post-reducer.php COMPRESSOR_SHORTPIXEL_URL2=https://api.shortpixel.com/v2/reducer.php COMPRESSOR_SHORTPIXEL_API_KEY=abcdefghijklmnopqrst @@ -58,7 +62,7 @@ COMPRESSOR_IMAGINARY_RETRY_PAUSE=5s COMPRESSOR_IMAGINARY_TIMEOUT=30s # DATABASE: [mem, mongo, badger] -DATABASE=mongo +APP_DATABASE=mongo DATABASE_MONGO_HOST=localhost DATABASE_MONGO_PORT=27017 DATABASE_MONGO_RETRY_TIMES=4 @@ -71,7 +75,7 @@ DATABASE_BADGER_CLEANUP_INTERVAL=5m DATABASE_BADGER_LRU=100 # STORAGE: [mock, minio] -STORAGE=minio +APP_STORAGE=minio STORAGE_MINIO_HOST=localhost STORAGE_MINIO_PORT=9000 STORAGE_MINIO_ACCESS_KEY=12345678 diff --git a/build/config-embed.env b/build/config-embed.env index 7d8a30a..544bcd5 100644 --- a/build/config-embed.env +++ b/build/config-embed.env @@ -1,3 +1,7 @@ +# CONFIG +CONFIG_RELOAD=true +CONFIG_RELOAD_INTERVAL=1s + # APP APP_NAME=config-embed APP_BALLAST=0 @@ -29,7 +33,7 @@ SERVICE_NUMBER_OF_WORKERS_COMP=8 SERVICE_ACCURACY=0.625 # CACHE: [mem, redis] -CACHE=mem +APP_CACHE=mem CACHE_MEM_CLEANUP_INTERVAL=15m CACHE_REDIS_HOST=localhost CACHE_REDIS_PORT=6379 @@ -39,7 +43,7 @@ CACHE_REDIS_TIMEOUT=30s CACHE_REDIS_TIME_TO_LIVE=15m # COMPRESSOR: [mock, shortpixel, imaginary] -COMPRESSOR=mock +APP_COMPRESSOR=mock COMPRESSOR_SHORTPIXEL_URL=https://api.shortpixel.com/v2/post-reducer.php COMPRESSOR_SHORTPIXEL_URL2=https://api.shortpixel.com/v2/reducer.php COMPRESSOR_SHORTPIXEL_API_KEY=abcdefghijklmnopqrst @@ -58,7 +62,7 @@ COMPRESSOR_IMAGINARY_RETRY_PAUSE=5s COMPRESSOR_IMAGINARY_TIMEOUT=30s # DATABASE: [mem, mongo, badger] -DATABASE=badger +APP_DATABASE=badger DATABASE_MONGO_HOST=localhost DATABASE_MONGO_PORT=27017 DATABASE_MONGO_RETRY_TIMES=4 @@ -71,7 +75,7 @@ DATABASE_BADGER_CLEANUP_INTERVAL=5m DATABASE_BADGER_LRU=100 # STORAGE: [mock, minio] -STORAGE=minio +APP_STORAGE=minio STORAGE_MINIO_HOST=embed-minio STORAGE_MINIO_PORT=9000 STORAGE_MINIO_ACCESS_KEY=12345678 diff --git a/build/config-prod.env b/build/config-prod.env index ef7f388..e0adb85 100644 --- a/build/config-prod.env +++ b/build/config-prod.env @@ -1,3 +1,7 @@ +# CONFIG +CONFIG_RELOAD=true +CONFIG_RELOAD_INTERVAL=1s + # APP APP_NAME=config-prod APP_BALLAST=0 @@ -29,7 +33,7 @@ SERVICE_NUMBER_OF_WORKERS_COMP=8 SERVICE_ACCURACY=0.625 # CACHE: [mem, redis] -CACHE=redis +APP_CACHE=redis CACHE_MEM_CLEANUP_INTERVAL=15m CACHE_REDIS_HOST=prod-redis CACHE_REDIS_PORT=6379 @@ -39,7 +43,7 @@ CACHE_REDIS_TIMEOUT=30s CACHE_REDIS_TIME_TO_LIVE=15m # COMPRESSOR: [mock, shortpixel, imaginary] -COMPRESSOR=imaginary +APP_COMPRESSOR=imaginary COMPRESSOR_SHORTPIXEL_URL=https://api.shortpixel.com/v2/post-reducer.php COMPRESSOR_SHORTPIXEL_URL2=https://api.shortpixel.com/v2/reducer.php COMPRESSOR_SHORTPIXEL_API_KEY=abcdefghijklmnopqrst @@ -58,7 +62,7 @@ COMPRESSOR_IMAGINARY_RETRY_PAUSE=5s COMPRESSOR_IMAGINARY_TIMEOUT=30s # DATABASE: [mem, mongo, badger] -DATABASE=mongo +APP_DATABASE=mongo DATABASE_MONGO_HOST=prod-mongo DATABASE_MONGO_PORT=27017 DATABASE_MONGO_RETRY_TIMES=4 @@ -71,7 +75,7 @@ DATABASE_BADGER_CLEANUP_INTERVAL=5m DATABASE_BADGER_LRU=100 # STORAGE: [mock, minio] -STORAGE=minio +APP_STORAGE=minio STORAGE_MINIO_HOST=prod-minio STORAGE_MINIO_PORT=9000 STORAGE_MINIO_ACCESS_KEY=12345678 diff --git a/config.env b/config.env index 2c80f55..2996538 100644 --- a/config.env +++ b/config.env @@ -1,3 +1,7 @@ +# CONFIG +CONFIG_RELOAD=true +CONFIG_RELOAD_INTERVAL=1s + # APP APP_NAME=config APP_BALLAST=0 @@ -29,7 +33,7 @@ SERVICE_NUMBER_OF_WORKERS_COMP=8 SERVICE_ACCURACY=0.625 # CACHE: [mem, redis] -CACHE=mem +APP_CACHE=mem CACHE_MEM_CLEANUP_INTERVAL=15m CACHE_REDIS_HOST=localhost CACHE_REDIS_PORT=6379 @@ -39,7 +43,7 @@ CACHE_REDIS_TIMEOUT=30s CACHE_REDIS_TIME_TO_LIVE=15m # COMPRESSOR: [mock, shortpixel, imaginary] -COMPRESSOR=mock +APP_COMPRESSOR=mock COMPRESSOR_SHORTPIXEL_URL=https://api.shortpixel.com/v2/post-reducer.php COMPRESSOR_SHORTPIXEL_URL2=https://api.shortpixel.com/v2/reducer.php COMPRESSOR_SHORTPIXEL_API_KEY=abcdefghijklmnopqrst @@ -58,7 +62,7 @@ COMPRESSOR_IMAGINARY_RETRY_PAUSE=5s COMPRESSOR_IMAGINARY_TIMEOUT=30s # DATABASE: [mem, mongo, badger] -DATABASE=mem +APP_DATABASE=mem DATABASE_MONGO_HOST=localhost DATABASE_MONGO_PORT=27017 DATABASE_MONGO_RETRY_TIMES=4 @@ -71,7 +75,7 @@ DATABASE_BADGER_CLEANUP_INTERVAL=5m DATABASE_BADGER_LRU=100 # STORAGE: [mock, minio] -STORAGE=mock +APP_STORAGE=mock STORAGE_MINIO_HOST=localhost STORAGE_MINIO_PORT=9000 STORAGE_MINIO_ACCESS_KEY=12345678 diff --git a/go.mod b/go.mod index 2afb466..1290509 100644 --- a/go.mod +++ b/go.mod @@ -78,6 +78,7 @@ require ( github.com/opencontainers/runc v1.0.0-rc95 // indirect github.com/pelletier/go-toml v1.9.4 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/radovskyb/watcher v1.0.7 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/rs/xid v1.3.0 // indirect github.com/sirupsen/logrus v1.8.1 // indirect diff --git a/go.sum b/go.sum index e93481a..696386d 100644 --- a/go.sum +++ b/go.sum @@ -453,6 +453,8 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/radovskyb/watcher v1.0.7 h1:AYePLih6dpmS32vlHfhCeli8127LzkIgwJGcwwe8tUE= +github.com/radovskyb/watcher v1.0.7/go.mod h1:78okwvY5wPdzcb1UYnip1pvrZNIVEIh/Cm+ZuvsUYIg= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= diff --git a/infrastructure/cache/config.go b/infrastructure/cache/config.go index 8086cff..f747c03 100644 --- a/infrastructure/cache/config.go +++ b/infrastructure/cache/config.go @@ -5,7 +5,7 @@ import ( ) type CacheConfig struct { - Cache string `mapstructure:"CACHE" validate:"required"` + Cache string `mapstructure:"APP_CACHE" validate:"required"` Mem MemConfig `mapstructure:",squash"` Redis RedisConfig `mapstructure:",squash"` } diff --git a/infrastructure/cache/redis.go b/infrastructure/cache/redis.go index c07e030..a096d35 100644 --- a/infrastructure/cache/redis.go +++ b/infrastructure/cache/redis.go @@ -16,7 +16,9 @@ import ( func NewRedis(ctx context.Context, conf RedisConfig) (*Redis, error) { client := redisdb.NewClient(&redisdb.Options{Addr: conf.Host + ":" + conf.Port}) - r := &Redis{conf: conf, client: client} + r := &Redis{} + r.conf = conf + r.client = client ctx, cancel := context.WithTimeout(ctx, conf.Timeout) defer cancel() err := retry.Do(conf.RetryTimes, conf.RetryPause, func() error { diff --git a/infrastructure/compressor/config.go b/infrastructure/compressor/config.go index cce2ae7..4826dfa 100644 --- a/infrastructure/compressor/config.go +++ b/infrastructure/compressor/config.go @@ -5,7 +5,7 @@ import ( ) type CompressorConfig struct { - Compressor string `mapstructure:"COMPRESSOR" validate:"required"` + Compressor string `mapstructure:"APP_COMPRESSOR" validate:"required"` Shortpixel ShortpixelConfig `mapstructure:",squash"` Imaginary ImaginaryConfig `mapstructure:",squash"` } diff --git a/infrastructure/database/config.go b/infrastructure/database/config.go index 8d7043a..1f5924b 100644 --- a/infrastructure/database/config.go +++ b/infrastructure/database/config.go @@ -5,7 +5,7 @@ import ( ) type DatabaseConfig struct { - Database string `mapstructure:"DATABASE" validate:"required"` + Database string `mapstructure:"APP_DATABASE" validate:"required"` Mem MemConfig `mapstructure:",squash"` Mongo MongoConfig `mapstructure:",squash"` Badger BadgerConfig `mapstructure:",squash"` diff --git a/infrastructure/storage/config.go b/infrastructure/storage/config.go index 6418149..2ca2150 100644 --- a/infrastructure/storage/config.go +++ b/infrastructure/storage/config.go @@ -5,7 +5,7 @@ import ( ) type StorageConfig struct { - Storage string `mapstructure:"STORAGE" validate:"required"` + Storage string `mapstructure:"APP_STORAGE" validate:"required"` Minio MinioConfig `mapstructure:",squash"` } diff --git a/internal/config/config.go b/internal/config/config.go index bcba1fd..6934d14 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1,11 +1,13 @@ package config import ( + "context" "reflect" "strings" + "time" - "github.com/fsnotify/fsnotify" "github.com/go-playground/validator" + "github.com/radovskyb/watcher" "github.com/spf13/viper" "github.com/zitryss/aye-and-nay/delivery/http" @@ -15,11 +17,13 @@ import ( "github.com/zitryss/aye-and-nay/infrastructure/database" "github.com/zitryss/aye-and-nay/infrastructure/storage" "github.com/zitryss/aye-and-nay/pkg/errors" + "github.com/zitryss/aye-and-nay/pkg/log" ) func New(path string) (Config, error) { viper.Reset() conf := Config{} + conf.path = path err := readConfig(path, &conf) if err != nil { return Config{}, errors.Wrap(err) @@ -32,41 +36,73 @@ func New(path string) (Config, error) { return conf, nil } -func OnChange(run func()) { - viper.OnConfigChange(func(_ fsnotify.Event) { - run() - }) - viper.WatchConfig() -} - type Config struct { - App AppConfig `mapstructure:",squash"` - Server http.ServerConfig `mapstructure:",squash"` - Middleware http.MiddlewareConfig `mapstructure:",squash"` - Service service.ServiceConfig `mapstructure:",squash"` - Cache cache.CacheConfig `mapstructure:",squash"` - Compressor compressor.CompressorConfig `mapstructure:",squash"` - Database database.DatabaseConfig `mapstructure:",squash"` - Storage storage.StorageConfig `mapstructure:",squash"` + path string + Reload bool `mapstructure:"CONFIG_RELOAD"` + ReloadInterval time.Duration `mapstructure:"CONFIG_RELOAD_INTERVAL" validate:"required"` + App AppConfig `mapstructure:",squash"` + Server http.ServerConfig `mapstructure:",squash"` + Middleware http.MiddlewareConfig `mapstructure:",squash"` + Service service.ServiceConfig `mapstructure:",squash"` + Cache cache.CacheConfig `mapstructure:",squash"` + Compressor compressor.CompressorConfig `mapstructure:",squash"` + Database database.DatabaseConfig `mapstructure:",squash"` + Storage storage.StorageConfig `mapstructure:",squash"` } type AppConfig struct { - Name string `mapstructure:"APP_NAME" validate:"required"` + Name string `mapstructure:"APP_NAME" validate:"required"` Ballast int64 `mapstructure:"APP_BALLAST"` - Log string `mapstructure:"APP_LOG" validate:"required"` + Log string `mapstructure:"APP_LOG" validate:"required"` +} + +func (c *Config) OnChange(ctx context.Context, fn func()) { + w := watcher.New() + w.SetMaxEvents(1) + w.FilterOps(watcher.Write) + err := w.Add(c.path) + if err != nil { + log.Error(errors.Wrap(err)) + } + go func() { + for { + select { + case event := <-w.Event: + log.Debugf("watcher: event: %s\n", event) + fn() + case err := <-w.Error: + log.Error(errors.Wrap(err)) + case <-w.Closed: + return + case <-ctx.Done(): + w.Wait() + w.Close() + return + } + } + }() + go func() { + err := w.Start(c.ReloadInterval) + if err != nil { + log.Error(errors.Wrap(err)) + } + }() } func readConfig(path string, conf *Config) error { viper.SetConfigFile(path) viper.AutomaticEnv() - _ = viper.ReadInConfig() + err := viper.ReadInConfig() + if err != nil { + log.Error(errors.Wrap(err)) + } if len(viper.AllSettings()) == 0 { bindEnv(reflect.TypeOf(*conf)) } if len(viper.AllSettings()) == 0 { return errors.Wrap(errors.New("no configuration is provided")) } - err := viper.Unmarshal(conf) + err = viper.Unmarshal(conf) if err != nil { return errors.Wrap(err) } @@ -81,7 +117,10 @@ func bindEnv(t reflect.Type) { bindEnv(field.Type) tag := field.Tag.Get("mapstructure") if field.IsExported() && tag != "" && tag != ",squash" { - _ = viper.BindEnv(strings.ToLower(tag), tag) + err := viper.BindEnv(strings.ToLower(tag), tag) + if err != nil { + log.Error(errors.Wrap(err)) + } } } } diff --git a/main.go b/main.go index 2732e4b..39188b5 100644 --- a/main.go +++ b/main.go @@ -44,10 +44,12 @@ func main() { continue } - config.OnChange(func() { - reload = true - stop() - }) + if conf.Reload { + conf.OnChange(ctx, func() { + reload = true + stop() + }) + } ballast = make([]byte, conf.App.Ballast) From 7a1dc042a8ff831bcbd2316a4ef5865079f53559 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sat, 15 Jan 2022 00:26:55 +0100 Subject: [PATCH 27/92] Clean up logs --- internal/config/config.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index 6934d14..a1ef131 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -67,8 +67,7 @@ func (c *Config) OnChange(ctx context.Context, fn func()) { go func() { for { select { - case event := <-w.Event: - log.Debugf("watcher: event: %s\n", event) + case <-w.Event: fn() case err := <-w.Error: log.Error(errors.Wrap(err)) From 68f7e08ee96072a5369bb65e26eac16afb7be69b Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sat, 15 Jan 2022 00:37:02 +0100 Subject: [PATCH 28/92] Remove files from coverage report --- codecov.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/codecov.yml b/codecov.yml index a8fb609..698c3eb 100644 --- a/codecov.yml +++ b/codecov.yml @@ -8,5 +8,8 @@ ignore: - "main.go" - "tools.go" - "cmd/loadtest/main.go" + - "cmd/healthcheck/main.go" - "delivery/http/requests_easyjson.go" - "delivery/http/responses_easyjson.go" + - "internal/**/*" + - "pkg/log/level_string.go" From f22aba70139cf8bf6821d2ae276bfcb9756e1b47 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sat, 15 Jan 2022 00:48:28 +0100 Subject: [PATCH 29/92] Return always a protective header --- delivery/http/error.go | 1 - delivery/http/middleware.go | 11 ++++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/delivery/http/error.go b/delivery/http/error.go index 95d26af..a65136a 100644 --- a/delivery/http/error.go +++ b/delivery/http/error.go @@ -41,7 +41,6 @@ func handleOuterError(w http.ResponseWriter, err error) { resp := errorResponse{} defer func() { w.Header().Set("Content-Type", "application/json; charset=utf-8") - w.Header().Set("X-Content-Type-Options", "nosniff") w.WriteHeader(resp.Error.statusCode) _ = json.NewEncoder(w).Encode(resp) }() diff --git a/delivery/http/middleware.go b/delivery/http/middleware.go index 76982c8..016380b 100644 --- a/delivery/http/middleware.go +++ b/delivery/http/middleware.go @@ -29,7 +29,7 @@ func (m *Middleware) Chain(h http.Handler) http.Handler { AllowedOrigins: []string{m.conf.CorsAllowOrigin}, AllowedMethods: []string{http.MethodGet, http.MethodPost, http.MethodPatch}, }) - return c.Handler(m.recover(m.limit(h))) + return m.recover(m.limit(c.Handler(m.headers(h)))) } func (m *Middleware) recover(h http.Handler) http.Handler { @@ -75,6 +75,15 @@ func (m *Middleware) limit(h http.Handler) http.Handler { ) } +func (m *Middleware) headers(h http.Handler) http.Handler { + return http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + h.ServeHTTP(w, r) + w.Header().Set("X-Content-Type-Options", "nosniff") + }, + ) +} + func ip(r *http.Request) string { xff := r.Header.Get("X-Forwarded-For") if xff != "" { From 6e4384ad4bf01dc5bbb99a0900bb27868f7a4cd5 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sun, 16 Jan 2022 00:37:42 +0100 Subject: [PATCH 30/92] Adjust config files --- delivery/http/config.go | 11 +++++++++++ infrastructure/cache/config.go | 8 ++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/delivery/http/config.go b/delivery/http/config.go index 55862fb..ec753c3 100644 --- a/delivery/http/config.go +++ b/delivery/http/config.go @@ -28,6 +28,17 @@ type ControllerConfig struct { } var ( + DefaultServerConfig = ServerConfig{ + Domain: "", + Host: "localhost", + Port: "8001", + H2C: false, + ReadTimeout: 5 * time.Second, + WriteTimeout: 10 * time.Second, + IdleTimeout: 10 * time.Second, + ShutdownTimeout: 1 * time.Second, + Controller: DefaultControllerConfig, + } DefaultMiddlewareConfig = MiddlewareConfig{ CorsAllowOrigin: "", } diff --git a/infrastructure/cache/config.go b/infrastructure/cache/config.go index f747c03..8605a19 100644 --- a/infrastructure/cache/config.go +++ b/infrastructure/cache/config.go @@ -31,8 +31,8 @@ type RedisConfig struct { var ( DefaultMemConfig = MemConfig{ CleanupInterval: 0, - LimiterRequestsPerSecond: 100, - LimiterBurst: 1, + LimiterRequestsPerSecond: 10000, + LimiterBurst: 100, TimeToLive: 0, } DefaultRedisConfig = RedisConfig{ @@ -41,8 +41,8 @@ var ( RetryTimes: 4, RetryPause: 5 * time.Second, Timeout: 30 * time.Second, - LimiterRequestsPerSecond: 100, - LimiterBurst: 1, + LimiterRequestsPerSecond: 10000, + LimiterBurst: 100, TimeToLive: 1 * time.Second, } ) From 1df2e5e40d90dc79e920bbf6d5256f1bbe236529 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Fri, 21 Jan 2022 11:40:20 +0100 Subject: [PATCH 31/92] Update loadtest tool --- build/config-dev.env | 4 +- build/config-embed.env | 4 +- build/config-prod.env | 4 +- cmd/healthcheck/main.go | 33 +-- cmd/loadtest/loadtest.go | 147 ++++++++++++++ cmd/loadtest/main.go | 351 ++++++++------------------------ config.env | 4 +- delivery/http/server_test.go | 73 +++++++ domain/service/service.go | 4 +- infrastructure/cache/config.go | 8 +- internal/client/client.go | 356 +++++++++++++++++++++++++++++++++ internal/client/transport.go | 42 ++++ 12 files changed, 720 insertions(+), 310 deletions(-) create mode 100644 cmd/loadtest/loadtest.go create mode 100644 delivery/http/server_test.go create mode 100644 internal/client/client.go create mode 100644 internal/client/transport.go diff --git a/build/config-dev.env b/build/config-dev.env index 382a728..264be8e 100644 --- a/build/config-dev.env +++ b/build/config-dev.env @@ -19,8 +19,8 @@ SERVER_SHUTDOWN_TIMEOUT=10s # MIDDLEWARE MIDDLEWARE_CORS_ALLOW_ORIGIN=* -MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=10000 -MIDDLEWARE_LIMITER_BURST=10 +MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=30000 +MIDDLEWARE_LIMITER_BURST=300 # CONTROLLER CONTROLLER_MAX_NUMBER_OF_FILES=100 diff --git a/build/config-embed.env b/build/config-embed.env index 544bcd5..9b89ecf 100644 --- a/build/config-embed.env +++ b/build/config-embed.env @@ -19,8 +19,8 @@ SERVER_SHUTDOWN_TIMEOUT=10s # MIDDLEWARE MIDDLEWARE_CORS_ALLOW_ORIGIN=* -MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=10000 -MIDDLEWARE_LIMITER_BURST=10 +MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=30000 +MIDDLEWARE_LIMITER_BURST=300 # CONTROLLER CONTROLLER_MAX_NUMBER_OF_FILES=100 diff --git a/build/config-prod.env b/build/config-prod.env index e0adb85..a4b1f38 100644 --- a/build/config-prod.env +++ b/build/config-prod.env @@ -19,8 +19,8 @@ SERVER_SHUTDOWN_TIMEOUT=10s # MIDDLEWARE MIDDLEWARE_CORS_ALLOW_ORIGIN=* -MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=10000 -MIDDLEWARE_LIMITER_BURST=10 +MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=30000 +MIDDLEWARE_LIMITER_BURST=300 # CONTROLLER CONTROLLER_MAX_NUMBER_OF_FILES=100 diff --git a/cmd/healthcheck/main.go b/cmd/healthcheck/main.go index 274292a..3ba825a 100644 --- a/cmd/healthcheck/main.go +++ b/cmd/healthcheck/main.go @@ -2,42 +2,27 @@ package main import ( "flag" - "io" - "net/http" "os" - "github.com/spf13/viper" + "github.com/zitryss/aye-and-nay/internal/client" + "github.com/zitryss/aye-and-nay/internal/config" ) func main() { - conf := "" - flag.StringVar(&conf, "config", "./config.env", "relative filepath to a config file") + path := "" + flag.StringVar(&path, "config", "./config.env", "filepath to a config file") flag.Parse() - viper.SetConfigFile(conf) - err := viper.ReadInConfig() + conf, err := config.New(path) if err != nil { os.Exit(1) } - port := viper.GetString("server_port") - req, err := http.NewRequest(http.MethodGet, "http://localhost:"+port+"/api/health/", http.NoBody) + api := "http://localhost:" + conf.Server.Port + timeout := conf.Server.WriteTimeout + c, err := client.New(api, timeout) if err != nil { os.Exit(1) } - resp, err := http.DefaultClient.Do(req) - if err != nil { - os.Exit(1) - } - if resp.StatusCode != 200 { - _, _ = io.Copy(io.Discard, resp.Body) - _ = resp.Body.Close() - os.Exit(1) - } - _, err = io.Copy(io.Discard, resp.Body) - if err != nil { - _ = resp.Body.Close() - os.Exit(1) - } - err = resp.Body.Close() + err = c.Health() if err != nil { os.Exit(1) } diff --git a/cmd/loadtest/loadtest.go b/cmd/loadtest/loadtest.go new file mode 100644 index 0000000..fa4f004 --- /dev/null +++ b/cmd/loadtest/loadtest.go @@ -0,0 +1,147 @@ +package main + +import ( + "net/http" + "strings" + + "github.com/zitryss/aye-and-nay/internal/client" + "github.com/zitryss/aye-and-nay/pkg/errors" + "github.com/zitryss/aye-and-nay/pkg/log" +) + +type loadtest struct { + client *client.Client + err error +} + +func (l *loadtest) albumApi() string { + if l.err != nil { + return "" + } + album, err := l.client.Album() + if err != nil { + l.err = errors.Wrap(err) + log.Error(l.err) + return "" + } + return album +} + +func (l *loadtest) readyApi(album string) { + if l.err != nil { + return + } + err := l.client.Ready(album) + if err != nil { + l.err = errors.Wrap(err) + log.Error(l.err) + return + } +} + +func (l *loadtest) pairApi(album string) client.Pair { + if l.err != nil { + return client.Pair{} + } + pairs, err := l.client.Pair(album) + if err != nil { + l.err = errors.Wrap(err) + log.Error(l.err) + return client.Pair{} + } + return pairs +} + +func (l *loadtest) voteApi(album string, token1 string, token2 string) { + if l.err != nil { + return + } + err := l.client.Vote(album, token1, token2) + if err != nil { + l.err = errors.Wrap(err) + log.Error(l.err) + return + } +} + +func (l *loadtest) topApi(album string) []string { + if l.err != nil { + return nil + } + src, err := l.client.Top(album) + if err != nil { + l.err = errors.Wrap(err) + log.Error(l.err) + return nil + } + return src +} + +func (l *loadtest) healthApi() { + if l.err != nil { + return + } + err := l.client.Health() + if err != nil { + l.err = errors.Wrap(err) + log.Error(l.err) + return + } +} + +func (l *loadtest) albumHtml() { + l.html("/index.html") +} + +func (l *loadtest) pairHtml() { + l.html("/pair.html") +} + +func (l *loadtest) topHtml() { + l.html("/top.html") +} + +func (l *loadtest) html(page string) { + if l.err != nil { + return + } + if htmlAddress == "" { + return + } + err := l.client.Do(http.MethodGet, htmlAddress+page, http.NoBody) + if err != nil { + l.err = errors.Wrap(err) + log.Error(l.err) + return + } +} + +func (l *loadtest) pairMinio(src1 string, src2 string) { + l.minio(src1) + l.minio(src2) +} + +func (l *loadtest) topMinio(src []string) { + for _, s := range src { + l.minio(s) + } +} + +func (l *loadtest) minio(src string) { + if l.err != nil { + return + } + address := minioAddress + if strings.HasPrefix(src, "/api/images/") { + address = apiAddress + } + if minioAddress == "" && address == "" { + return + } + err := l.client.Do(http.MethodGet, address+src, http.NoBody) + if err != nil { + l.err = errors.Wrap(err) + log.Error(l.err) + return + } +} diff --git a/cmd/loadtest/main.go b/cmd/loadtest/main.go index e7c87b4..27e7d3f 100644 --- a/cmd/loadtest/main.go +++ b/cmd/loadtest/main.go @@ -1,306 +1,113 @@ -// The purpose of this tool is to provide a realistic load on the -// system. It creates "n" albums (default 2), each contains 20 images. -// In total, it sends n x 94 requests. package main import ( - "bytes" - "crypto/tls" - "encoding/json" + "context" "flag" "fmt" - "io" - "mime/multipart" - "net/http" "os" - "strings" + "os/signal" + "sync" + "syscall" "time" - "github.com/cheggaaa/pb/v3" - - "github.com/zitryss/aye-and-nay/pkg/debug" + "github.com/zitryss/aye-and-nay/internal/client" + "github.com/zitryss/aye-and-nay/pkg/log" ) var ( - n int - apiAddress string - minioAddress string - htmlAddress string + duration time.Duration connections int + timeout time.Duration testdata string + apiAddress string + htmlAddress string + minioAddress string verbose bool - b []byte - sep string ) func main() { - flag.IntVar(&n, "n", 2, "#albums") - flag.StringVar(&apiAddress, "api-address", "https://localhost", "") - flag.StringVar(&minioAddress, "minio-address", "https://localhost", "") - flag.StringVar(&htmlAddress, "html-address", "https://localhost", "") + flag.DurationVar(&duration, "duration", 10*time.Second, "in seconds") flag.IntVar(&connections, "connections", 2, "") + flag.DurationVar(&timeout, "timeout", 5*time.Second, "in seconds") flag.StringVar(&testdata, "testdata", "./testdata", "") + flag.StringVar(&apiAddress, "api-address", "https://localhost", "") + flag.StringVar(&htmlAddress, "html-address", "https://localhost", "") + flag.StringVar(&minioAddress, "minio-address", "https://localhost", "") flag.BoolVar(&verbose, "verbose", true, "") flag.Parse() - http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} - - bar := pb.StartNew(n * 94) - if !verbose { - bar.SetWriter(io.Discard) + if verbose { + log.SetOutput(os.Stderr) + log.SetLevel(log.ERROR) } - readFiles() + ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) + wg := sync.WaitGroup{} + wg.Add(2) - sem := make(chan struct{}, connections) - for i := 0; i < n; i++ { - sem <- struct{}{} - go func() { - defer func() { <-sem }() - albumHtml() - album := albumApi() - bar.Increment() - readyApi(album) - bar.Increment() - for j := 0; j < 4; j++ { - pairHtml() - for k := 0; k < 11; k++ { - src1, token1, src2, token2 := pairApi(album) - bar.Increment() - pairMinio(src1, src2) - voteApi(album, token1, token2) - bar.Increment() - } - topHtml() - src := topApi(album) - bar.Increment() - topMinio(src) + c, err := client.New(apiAddress, timeout*time.Second, client.WithFiles(testdata), client.WithTimes(5)) + if err != nil { + log.Critical(err) + os.Exit(1) + } + + go func() { + defer wg.Done() + passed1sAgo := 0 + for { + select { + case <-ctx.Done(): + return + case <-time.After(1 * time.Second): + passed, failed := c.Stats() + fmt.Printf("%d rps, ", passed-passed1sAgo) + fmt.Printf("%d passed (%.2f%%), ", passed, float64(passed)/float64(passed+failed)*100) + fmt.Printf("%d failed (%.2f%%)\n", failed, float64(failed)/float64(passed+failed)*100) + passed1sAgo = passed } - healthApi() - }() - } - for i := 0; i < connections; i++ { - sem <- struct{}{} - } - - bar.Finish() - fmt.Println(time.Since(bar.StartTime())) - fmt.Println(float64(n*94)/time.Since(bar.StartTime()).Seconds(), "rps") -} - -func readFiles() { - body := bytes.Buffer{} - multi := multipart.NewWriter(&body) - for i := 0; i < 4; i++ { - for _, filename := range []string{"alan.jpg", "john.bmp", "dennis.png", "tim.gif", "big.jpg"} { - part, err := multi.CreateFormFile("images", filename) - debug.Check(err) - b, err := os.ReadFile(testdata + "/" + filename) - debug.Check(err) - _, err = part.Write(b) - debug.Check(err) } - } - err := multi.WriteField("duration", "1h") - debug.Check(err) - err = multi.Close() - debug.Check(err) - - b = body.Bytes() - sep = multi.FormDataContentType() -} - -func albumHtml() { - html("/index.html") -} - -func albumApi() string { - body := bytes.NewReader(b) - req, err := http.NewRequest(http.MethodPost, apiAddress+"/api/albums/", body) - debug.Check(err) - req.Header.Set("Content-Type", sep) - - resp, err := http.DefaultClient.Do(req) - debug.Check(err) - debug.Assert(resp.StatusCode == 201) - - type result struct { - Album struct { - Id string - } - } - - res := result{} - err = json.NewDecoder(resp.Body).Decode(&res) - debug.Check(err) - err = resp.Body.Close() - debug.Check(err) - - return res.Album.Id -} - -func readyApi(album string) { - req, err := http.NewRequest(http.MethodGet, apiAddress+"/api/albums/"+album+"/ready/", http.NoBody) - debug.Check(err) - - resp, err := http.DefaultClient.Do(req) - debug.Check(err) - debug.Assert(resp.StatusCode == 200) - - type result struct { - Album struct { - Progress float64 - } - } - - res := result{} - err = json.NewDecoder(resp.Body).Decode(&res) - debug.Check(err) - err = resp.Body.Close() - debug.Check(err) -} - -func pairHtml() { - html("/pair.html") -} - -func pairApi(album string) (string, string, string, string) { - req, err := http.NewRequest(http.MethodGet, apiAddress+"/api/albums/"+album+"/pair/", http.NoBody) - debug.Check(err) - - resp, err := http.DefaultClient.Do(req) - debug.Check(err) - debug.Assert(resp.StatusCode == 200) - - type result struct { - Album struct { - Img1 struct { - Token string - Src string - } - Img2 struct { - Token string - Src string + }() + + go func() { + defer wg.Done() + start := time.Now() + sem := make(chan struct{}, connections) + for time.Since(start) < duration*time.Second { + select { + case sem <- struct{}{}: + case <-ctx.Done(): + return } + go func() { + defer func() { <-sem }() + l := loadtest{client: c} + l.albumHtml() + album := l.albumApi() + l.readyApi(album) + for j := 0; j < 5; j++ { + l.pairHtml() + for k := 0; k < 10; k++ { + pairs := l.pairApi(album) + l.pairMinio(pairs.One.Src, pairs.Two.Src) + l.voteApi(album, pairs.One.Token, pairs.Two.Token) + } + l.topHtml() + src := l.topApi(album) + l.topMinio(src) + } + l.healthApi() + }() } - } - - res := result{} - err = json.NewDecoder(resp.Body).Decode(&res) - debug.Check(err) - err = resp.Body.Close() - debug.Check(err) - - return res.Album.Img1.Src, res.Album.Img1.Token, res.Album.Img2.Src, res.Album.Img2.Token -} - -func pairMinio(src1 string, src2 string) { - minio(src1) - minio(src2) -} - -func voteApi(album string, token1 string, token2 string) { - body := strings.NewReader("{\"album\":{\"imgFrom\":{\"token\":\"" + token1 + "\"},\"imgTo\":{\"token\":\"" + token2 + "\"}}}") - req, err := http.NewRequest(http.MethodPatch, apiAddress+"/api/albums/"+album+"/vote/", body) - debug.Check(err) - req.Header.Set("Content-Type", "application/json; charset=utf-8") - - resp, err := http.DefaultClient.Do(req) - debug.Check(err) - debug.Assert(resp.StatusCode == 200) - _, err = io.Copy(io.Discard, resp.Body) - debug.Check(err) - err = resp.Body.Close() - debug.Check(err) -} - -func topHtml() { - html("/top.html") -} - -func topApi(album string) []string { - req, err := http.NewRequest(http.MethodGet, apiAddress+"/api/albums/"+album+"/top/", http.NoBody) - debug.Check(err) - - resp, err := http.DefaultClient.Do(req) - debug.Check(err) - debug.Assert(resp.StatusCode == 200) - - type image struct { - Src string - Rating float64 - } - type result struct { - Album struct { - Images []image + for i := 0; i < connections; i++ { + sem <- struct{}{} } - } - - res := result{} - err = json.NewDecoder(resp.Body).Decode(&res) - debug.Check(err) - err = resp.Body.Close() - debug.Check(err) + stop() + }() - src := []string(nil) - for _, image := range res.Album.Images { - src = append(src, image.Src) - } - return src -} + wg.Wait() -func topMinio(src []string) { - for _, s := range src { - minio(s) - } -} - -func healthApi() { - req, err := http.NewRequest(http.MethodGet, apiAddress+"/api/health/", http.NoBody) - debug.Check(err) - resp, err := http.DefaultClient.Do(req) - debug.Check(err) - debug.Assert(resp.StatusCode == 200) - _, err = io.Copy(io.Discard, resp.Body) - debug.Check(err) - err = resp.Body.Close() - debug.Check(err) -} - -func html(page string) { - if htmlAddress == "" { - return - } - req, err := http.NewRequest(http.MethodGet, htmlAddress+page, http.NoBody) - if err != nil { - return - } - resp, err := http.DefaultClient.Do(req) - if err != nil { - return - } - debug.Assert(resp.StatusCode == 200) - _, _ = io.Copy(io.Discard, resp.Body) - _ = resp.Body.Close() -} - -func minio(src string) { - address := minioAddress - if strings.HasPrefix(src, "/api/images/") { - address = apiAddress - } - if minioAddress == "" && address == "" { - return - } - req, err := http.NewRequest(http.MethodGet, address+src, http.NoBody) - if err != nil { - return - } - resp, err := http.DefaultClient.Do(req) - if err != nil { - return + _, failed := c.Stats() + if failed > 0 { + os.Exit(1) } - debug.Assert(resp.StatusCode == 200) - _, _ = io.Copy(io.Discard, resp.Body) - _ = resp.Body.Close() } diff --git a/config.env b/config.env index 2996538..36eed06 100644 --- a/config.env +++ b/config.env @@ -19,8 +19,8 @@ SERVER_SHUTDOWN_TIMEOUT=10s # MIDDLEWARE MIDDLEWARE_CORS_ALLOW_ORIGIN=* -MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=10000 -MIDDLEWARE_LIMITER_BURST=10 +MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=30000 +MIDDLEWARE_LIMITER_BURST=300 # CONTROLLER CONTROLLER_MAX_NUMBER_OF_FILES=100 diff --git a/delivery/http/server_test.go b/delivery/http/server_test.go new file mode 100644 index 0000000..6370246 --- /dev/null +++ b/delivery/http/server_test.go @@ -0,0 +1,73 @@ +package http + +import ( + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/zitryss/aye-and-nay/domain/service" + "github.com/zitryss/aye-and-nay/infrastructure/cache" + "github.com/zitryss/aye-and-nay/infrastructure/compressor" + "github.com/zitryss/aye-and-nay/infrastructure/database" + "github.com/zitryss/aye-and-nay/infrastructure/storage" + "github.com/zitryss/aye-and-nay/internal/client" +) + +func TestServer(t *testing.T) { + comp := compressor.NewMock() + stor := storage.NewMock() + data := database.NewMem(database.DefaultMemConfig) + cach := cache.NewMem(cache.DefaultMemConfig) + qCalc := &service.QueueCalc{} + qComp := &service.QueueComp{} + qDel := &service.QueueDel{} + serv := service.New(service.DefaultServiceConfig, comp, stor, data, cach, qCalc, qComp, qDel) + + middle := NewMiddleware(DefaultMiddlewareConfig, cach) + srvWait := make(chan error, 1) + srv, err := NewServer(DefaultServerConfig, middle.Chain, serv, srvWait) + if err != nil { + t.Fatal(err) + } + + mockserver := httptest.NewServer(srv.srv.Handler) + defer mockserver.Close() + c, err := client.New(mockserver.URL, 5*time.Second, client.WithFiles("../../testdata"), client.WithTimes(1)) + if err != nil { + t.Fatal(err) + } + + album, err := c.Album() + if err != nil { + t.Error(err) + } + err = c.Ready(album) + if err != nil { + t.Error(err) + } + p, err := c.Pair(album) + if err != nil { + t.Error(err) + } + err = c.Do(http.MethodGet, mockserver.URL+p.One.Src, http.NoBody) + if err != nil { + t.Error(err) + } + err = c.Do(http.MethodGet, mockserver.URL+p.Two.Src, http.NoBody) + if err != nil { + t.Error(err) + } + err = c.Vote(album, p.One.Token, p.Two.Token) + if err != nil { + t.Error(err) + } + _, err = c.Top(album) + if err != nil { + t.Error(err) + } + err = c.Health() + if err != nil { + t.Error(err) + } +} diff --git a/domain/service/service.go b/domain/service/service.go index f900602..d916f39 100644 --- a/domain/service/service.go +++ b/domain/service/service.go @@ -215,7 +215,7 @@ func (s *Service) Pair(ctx context.Context, album uint64) (model.Image, model.Im return model.Image{}, model.Image{}, errors.Wrap(err) } token1B64 := base64.FromUint64(token1) - src1 = "/api/images/" + token1B64 + src1 = "/api/images/" + token1B64 + "/" token2, err = s.rand.id() if err != nil { return model.Image{}, model.Image{}, errors.Wrap(err) @@ -225,7 +225,7 @@ func (s *Service) Pair(ctx context.Context, album uint64) (model.Image, model.Im return model.Image{}, model.Image{}, errors.Wrap(err) } token2B64 := base64.FromUint64(token2) - src2 = "/api/images/" + token2B64 + src2 = "/api/images/" + token2B64 + "/" } else { src1, err = s.pers.GetImageSrc(ctx, album, image1) if err != nil { diff --git a/infrastructure/cache/config.go b/infrastructure/cache/config.go index 8605a19..9edf4ac 100644 --- a/infrastructure/cache/config.go +++ b/infrastructure/cache/config.go @@ -31,8 +31,8 @@ type RedisConfig struct { var ( DefaultMemConfig = MemConfig{ CleanupInterval: 0, - LimiterRequestsPerSecond: 10000, - LimiterBurst: 100, + LimiterRequestsPerSecond: 30000, + LimiterBurst: 300, TimeToLive: 0, } DefaultRedisConfig = RedisConfig{ @@ -41,8 +41,8 @@ var ( RetryTimes: 4, RetryPause: 5 * time.Second, Timeout: 30 * time.Second, - LimiterRequestsPerSecond: 10000, - LimiterBurst: 100, + LimiterRequestsPerSecond: 30000, + LimiterBurst: 300, TimeToLive: 1 * time.Second, } ) diff --git a/internal/client/client.go b/internal/client/client.go new file mode 100644 index 0000000..6f93529 --- /dev/null +++ b/internal/client/client.go @@ -0,0 +1,356 @@ +package client + +import ( + "bytes" + "crypto/tls" + "encoding/json" + "io" + "mime/multipart" + "net" + "net/http" + "os" + "strconv" + "strings" + "sync" + "time" + + "github.com/zitryss/aye-and-nay/pkg/errors" +) + +func New(apiAddress string, timeout time.Duration, opts ...options) (*Client, error) { + c := Client{} + httpTransport := &http.Transport{ + Proxy: http.ProxyFromEnvironment, + ForceAttemptHTTP2: true, + MaxIdleConns: 100, + DialContext: (&net.Dialer{ + KeepAlive: 30 * time.Second, + Timeout: 30 * time.Second, + }).DialContext, + TLSHandshakeTimeout: 10 * time.Second, + IdleConnTimeout: 90 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + } + transport := newTransport(httpTransport, &c.m, &c.passed, &c.failed) + httpClient := &http.Client{ + Jar: nil, + Timeout: timeout, + Transport: transport, + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + } + c.client = httpClient + c.apiAddress = apiAddress + for _, opt := range opts { + opt(&c) + } + if c.testdata != "" { + err := c.readFiles() + if err != nil { + return &Client{}, errors.Wrap(err) + } + } + return &c, nil +} + +type options func(*Client) + +func WithFiles(testdata string) options { + return func(c *Client) { + c.testdata = testdata + } +} + +func WithTimes(times int) options { + return func(c *Client) { + c.times = times + } +} + +type Client struct { + client *http.Client + testdata string + apiAddress string + times int + b []byte + sep string + m sync.Mutex + passed int + failed int +} + +func (c *Client) readFiles() error { + body := bytes.Buffer{} + multi := multipart.NewWriter(&body) + for i := 0; i < c.times; i++ { + for _, filename := range []string{"alan.jpg", "john.bmp", "dennis.png"} { + part, err := multi.CreateFormFile("images", filename) + if err != nil { + return errors.Wrap(err) + } + b, err := os.ReadFile(c.testdata + "/" + filename) + if err != nil { + return errors.Wrap(err) + } + _, err = part.Write(b) + if err != nil { + return errors.Wrap(err) + } + } + } + err := multi.WriteField("duration", "1h") + if err != nil { + return errors.Wrap(err) + } + err = multi.Close() + if err != nil { + return errors.Wrap(err) + } + c.b = body.Bytes() + c.sep = multi.FormDataContentType() + return nil +} + +func (c *Client) Album() (string, error) { + body := bytes.NewReader(c.b) + req, err := http.NewRequest(http.MethodPost, c.apiAddress+"/api/albums/", body) + if err != nil { + return "", errors.Wrap(err) + } + req.Header.Set("Content-Type", c.sep) + + resp, err := c.client.Do(req) + if err != nil { + return "", errors.Wrap(err) + } + defer func() { + _, _ = io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + }() + if resp.StatusCode/100 != 2 { + return "", errors.Wrap(errors.New("response status code: expected = 2xx, actual = " + strconv.Itoa(resp.StatusCode))) + } + + type result struct { + Album struct { + Id string + } + } + + res := result{} + err = json.NewDecoder(resp.Body).Decode(&res) + if err != nil { + return "", errors.Wrap(err) + } + + return res.Album.Id, nil +} + +func (c *Client) Ready(album string) error { + req, err := http.NewRequest(http.MethodGet, c.apiAddress+"/api/albums/"+album+"/ready/", http.NoBody) + if err != nil { + return errors.Wrap(err) + } + + resp, err := c.client.Do(req) + if err != nil { + return errors.Wrap(err) + } + defer func() { + _, _ = io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + }() + if resp.StatusCode/100 != 2 { + return errors.Wrap(errors.New("response status code: expected = 2xx, actual = " + strconv.Itoa(resp.StatusCode))) + } + + type result struct { + Album struct { + Progress float64 + } + } + + res := result{} + err = json.NewDecoder(resp.Body).Decode(&res) + if err != nil { + return errors.Wrap(err) + } + + return nil +} + +type Pair struct { + One elem + Two elem +} + +type elem struct { + Token string + Src string +} + +func (c *Client) Pair(album string) (Pair, error) { + req, err := http.NewRequest(http.MethodGet, c.apiAddress+"/api/albums/"+album+"/pair/", http.NoBody) + if err != nil { + return Pair{}, errors.Wrap(err) + } + + resp, err := c.client.Do(req) + if err != nil { + return Pair{}, errors.Wrap(err) + } + defer func() { + _, _ = io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + }() + if resp.StatusCode/100 != 2 { + return Pair{}, errors.Wrap(errors.New("response status code: expected = 2xx, actual = " + strconv.Itoa(resp.StatusCode))) + } + + type result struct { + Album struct { + Img1 struct { + Token string + Src string + } + Img2 struct { + Token string + Src string + } + } + } + + res := result{} + err = json.NewDecoder(resp.Body).Decode(&res) + if err != nil { + return Pair{}, errors.Wrap(err) + } + + p := Pair{ + One: elem{ + Token: res.Album.Img1.Token, + Src: res.Album.Img1.Src, + }, + Two: elem{ + Token: res.Album.Img2.Token, + Src: res.Album.Img2.Src, + }, + } + return p, nil +} + +func (c *Client) Vote(album string, token1 string, token2 string) error { + body := strings.NewReader("{\"album\":{\"imgFrom\":{\"token\":\"" + token1 + "\"},\"imgTo\":{\"token\":\"" + token2 + "\"}}}") + req, err := http.NewRequest(http.MethodPatch, c.apiAddress+"/api/albums/"+album+"/vote/", body) + if err != nil { + return errors.Wrap(err) + } + req.Header.Set("Content-Type", "application/json; charset=utf-8") + + resp, err := c.client.Do(req) + if err != nil { + return errors.Wrap(err) + } + defer func() { + _, _ = io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + }() + if resp.StatusCode/100 != 2 { + return errors.Wrap(errors.New("response status code: expected = 2xx, actual = " + strconv.Itoa(resp.StatusCode))) + } + + return nil +} + +func (c *Client) Top(album string) ([]string, error) { + req, err := http.NewRequest(http.MethodGet, c.apiAddress+"/api/albums/"+album+"/top/", http.NoBody) + if err != nil { + return nil, errors.Wrap(err) + } + + resp, err := c.client.Do(req) + if err != nil { + return nil, errors.Wrap(err) + } + defer func() { + _, _ = io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + }() + if resp.StatusCode/100 != 2 { + return nil, errors.Wrap(errors.New("response status code: expected = 2xx, actual = " + strconv.Itoa(resp.StatusCode))) + } + + type image struct { + Src string + Rating float64 + } + type result struct { + Album struct { + Images []image + } + } + + res := result{} + err = json.NewDecoder(resp.Body).Decode(&res) + if err != nil { + return nil, errors.Wrap(err) + } + + src := []string(nil) + for _, image := range res.Album.Images { + src = append(src, image.Src) + } + return src, nil +} + +func (c *Client) Health() error { + req, err := http.NewRequest(http.MethodGet, c.apiAddress+"/api/health/", http.NoBody) + if err != nil { + return errors.Wrap(err) + } + resp, err := c.client.Do(req) + if err != nil { + return errors.Wrap(err) + } + defer func() { + _, _ = io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + }() + if resp.StatusCode/100 != 2 { + return errors.Wrap(errors.New("response status code: expected = 2xx, actual = " + strconv.Itoa(resp.StatusCode))) + } + return nil +} + +func (c *Client) Do(method string, url string, body io.ReadCloser) error { + req, err := http.NewRequest(method, url, body) + if err != nil { + return errors.Wrap(err) + } + resp, err := c.client.Do(req) + if err != nil { + return errors.Wrap(err) + } + defer func() { + _, _ = io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + }() + if resp.StatusCode/100 != 2 { + return errors.Wrap(errors.New("response status code: expected = 2xx, actual = " + strconv.Itoa(resp.StatusCode))) + } + return nil +} + +func (c *Client) Stats() (int, int) { + p := 0 + f := 0 + c.m.Lock() + p = c.passed + f = c.failed + c.m.Unlock() + return p, f +} diff --git a/internal/client/transport.go b/internal/client/transport.go new file mode 100644 index 0000000..176b709 --- /dev/null +++ b/internal/client/transport.go @@ -0,0 +1,42 @@ +package client + +import ( + "net/http" + "sync" +) + +func newTransport(roundTrip http.RoundTripper, m *sync.Mutex, passed *int, failed *int) *transport { + t := transport{} + t.original = roundTrip + t.m = m + t.passed = passed + t.failed = failed + return &t +} + +type transport struct { + original http.RoundTripper + m *sync.Mutex + passed *int + failed *int +} + +func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) { + resp, err := t.original.RoundTrip(req) + if err != nil { + t.m.Lock() + *t.failed++ + t.m.Unlock() + return resp, err + } + if resp.StatusCode/100 != 2 { + t.m.Lock() + *t.failed++ + t.m.Unlock() + return resp, err + } + t.m.Lock() + *t.passed++ + t.m.Unlock() + return resp, err +} From 621b6847ab2ed306a083f3225423d8267028fc21 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sun, 23 Jan 2022 00:39:06 +0100 Subject: [PATCH 32/92] Change api name --- build/swagger.yml | 10 +++++----- cmd/loadtest/loadtest.go | 4 ++-- cmd/loadtest/main.go | 2 +- delivery/http/controller.go | 16 ++++++++-------- delivery/http/controller_test.go | 6 +++--- delivery/http/requests.go | 2 +- delivery/http/responses.go | 2 +- delivery/http/router.go | 2 +- delivery/http/server_test.go | 2 +- domain/service/service_integration_test.go | 12 ++++++------ domain/service/service_test.go | 12 ++++++------ go.mod | 11 ++--------- go.sum | 18 ------------------ infrastructure/storage/minio.go | 14 +++++++------- .../storage/minio_integration_test.go | 6 +++--- internal/client/client.go | 4 ++-- 16 files changed, 49 insertions(+), 74 deletions(-) diff --git a/build/swagger.yml b/build/swagger.yml index a34ae97..f276288 100644 --- a/build/swagger.yml +++ b/build/swagger.yml @@ -26,7 +26,7 @@ paths: $ref: '#/components/responses/InternalServerError' '503': $ref: '#/components/responses/ServiceUnavailable' - /api/albums/{album}/ready/: + /api/albums/{album}/status/: get: description: > Second request in a sequence (optional). It informs about @@ -37,7 +37,7 @@ paths: - $ref: '#/components/parameters/albumParam' responses: '200': - $ref: '#/components/responses/ReadyResponse' + $ref: '#/components/responses/StatusResponse' '500': $ref: '#/components/responses/InternalServerError' '503': @@ -138,7 +138,7 @@ components: properties: id: $ref: '#/components/schemas/Id' - ReadyResponse: + StatusResponse: type: object properties: album: @@ -243,12 +243,12 @@ components: application/json: schema: $ref: '#/components/schemas/AlbumResponse' - ReadyResponse: + StatusResponse: description: OK content: application/json: schema: - $ref: '#/components/schemas/ReadyResponse' + $ref: '#/components/schemas/StatusResponse' PairResponse: description: OK content: diff --git a/cmd/loadtest/loadtest.go b/cmd/loadtest/loadtest.go index fa4f004..2e1c080 100644 --- a/cmd/loadtest/loadtest.go +++ b/cmd/loadtest/loadtest.go @@ -27,11 +27,11 @@ func (l *loadtest) albumApi() string { return album } -func (l *loadtest) readyApi(album string) { +func (l *loadtest) statusApi(album string) { if l.err != nil { return } - err := l.client.Ready(album) + err := l.client.Status(album) if err != nil { l.err = errors.Wrap(err) log.Error(l.err) diff --git a/cmd/loadtest/main.go b/cmd/loadtest/main.go index 27e7d3f..6ba53e5 100644 --- a/cmd/loadtest/main.go +++ b/cmd/loadtest/main.go @@ -83,7 +83,7 @@ func main() { l := loadtest{client: c} l.albumHtml() album := l.albumApi() - l.readyApi(album) + l.statusApi(album) for j := 0; j < 5; j++ { l.pairHtml() for k := 0; k < 10; k++ { diff --git a/delivery/http/controller.go b/delivery/http/controller.go index 510bc2e..b5b1c3d 100644 --- a/delivery/http/controller.go +++ b/delivery/http/controller.go @@ -152,27 +152,27 @@ func (c *controller) handleAlbum() httprouter.Handle { ) } -func (c *controller) handleReady() httprouter.Handle { - input := func(r *http.Request, ps httprouter.Params) (context.Context, readyRequest, error) { +func (c *controller) handleStatus() httprouter.Handle { + input := func(r *http.Request, ps httprouter.Params) (context.Context, statusRequest, error) { ctx := r.Context() - req := readyRequest{} + req := statusRequest{} req.album.id = ps.ByName("album") return ctx, req, nil } - process := func(ctx context.Context, req readyRequest) (readyResponse, error) { + process := func(ctx context.Context, req statusRequest) (statusResponse, error) { album, err := base64.ToUint64(req.album.id) if err != nil { - return readyResponse{}, errors.Wrap(err) + return statusResponse{}, errors.Wrap(err) } p, err := c.serv.Progress(ctx, album) if err != nil { - return readyResponse{}, errors.Wrap(err) + return statusResponse{}, errors.Wrap(err) } - resp := readyResponse{} + resp := statusResponse{} resp.Album.Progress = p return resp, nil } - output := func(ctx context.Context, w http.ResponseWriter, resp readyResponse) error { + output := func(ctx context.Context, w http.ResponseWriter, resp statusResponse) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") err := json.NewEncoder(w).Encode(resp) if err != nil { diff --git a/delivery/http/controller_test.go b/delivery/http/controller_test.go index 3f8b954..f11ba13 100644 --- a/delivery/http/controller_test.go +++ b/delivery/http/controller_test.go @@ -364,7 +364,7 @@ func TestControllerHandleAlbum(t *testing.T) { } } -func TestControllerHandleReady(t *testing.T) { +func TestControllerHandleStatus(t *testing.T) { type give struct { err error } @@ -532,9 +532,9 @@ func TestControllerHandleReady(t *testing.T) { t.Run("", func(t *testing.T) { serv := service.NewMock(tt.give.err) contr := newController(DefaultControllerConfig, serv) - fn := contr.handleReady() + fn := contr.handleStatus() w := httptest.NewRecorder() - r := httptest.NewRequest(http.MethodGet, "/api/albums/rRsAAAAAAAA/ready", http.NoBody) + r := httptest.NewRequest(http.MethodGet, "/api/albums/rRsAAAAAAAA/status", http.NoBody) ps := httprouter.Params{httprouter.Param{Key: "album", Value: "rRsAAAAAAAA"}} fn(w, r, ps) CheckStatusCode(t, w, tt.want.code) diff --git a/delivery/http/requests.go b/delivery/http/requests.go index 85b95e5..9a948b4 100644 --- a/delivery/http/requests.go +++ b/delivery/http/requests.go @@ -15,7 +15,7 @@ type albumRequest struct { dur time.Duration } -type readyRequest struct { +type statusRequest struct { album struct { id string } diff --git a/delivery/http/responses.go b/delivery/http/responses.go index 38a8d2c..8baa1cb 100644 --- a/delivery/http/responses.go +++ b/delivery/http/responses.go @@ -14,7 +14,7 @@ type albumResponse struct { } //easyjson:json -type readyResponse struct { +type statusResponse struct { Album struct { Progress float64 `json:"progress"` } `json:"album"` diff --git a/delivery/http/router.go b/delivery/http/router.go index e1f2486..655685f 100644 --- a/delivery/http/router.go +++ b/delivery/http/router.go @@ -9,7 +9,7 @@ import ( func newRouter(contr controller) http.Handler { router := httprouter.New() router.POST("/api/albums/", contr.handleAlbum()) - router.GET("/api/albums/:album/ready/", contr.handleReady()) + router.GET("/api/albums/:album/status/", contr.handleStatus()) router.GET("/api/albums/:album/pair/", contr.handlePair()) router.GET("/api/images/:token/", contr.handleImage()) router.PATCH("/api/albums/:album/vote/", contr.handleVote()) diff --git a/delivery/http/server_test.go b/delivery/http/server_test.go index 6370246..e800ff3 100644 --- a/delivery/http/server_test.go +++ b/delivery/http/server_test.go @@ -42,7 +42,7 @@ func TestServer(t *testing.T) { if err != nil { t.Error(err) } - err = c.Ready(album) + err = c.Status(album) if err != nil { t.Error(err) } diff --git a/domain/service/service_integration_test.go b/domain/service/service_integration_test.go index a3e426d..2604166 100644 --- a/domain/service/service_integration_test.go +++ b/domain/service/service_integration_test.go @@ -268,8 +268,8 @@ func TestServiceIntegrationPair(t *testing.T) { if err != nil { t.Error(err) } - img1 := model.Image{Id: 0x3BC7, Token: 0x3BC9, Src: "/api/images/yTsAAAAAAAA"} - img2 := model.Image{Id: 0x3BC8, Token: 0x3BCA, Src: "/api/images/yjsAAAAAAAA"} + img1 := model.Image{Id: 0x3BC7, Token: 0x3BC9, Src: "/api/images/yTsAAAAAAAA/"} + img2 := model.Image{Id: 0x3BC8, Token: 0x3BCA, Src: "/api/images/yjsAAAAAAAA/"} imgs1 := []model.Image{img1, img2} if reflect.DeepEqual(img7, img8) { t.Error("img7 == img8") @@ -284,8 +284,8 @@ func TestServiceIntegrationPair(t *testing.T) { if err != nil { t.Error(err) } - img3 := model.Image{Id: 0x3BC8, Token: 0x3BCB, Src: "/api/images/yzsAAAAAAAA"} - img4 := model.Image{Id: 0x3BC7, Token: 0x3BCC, Src: "/api/images/zDsAAAAAAAA"} + img3 := model.Image{Id: 0x3BC8, Token: 0x3BCB, Src: "/api/images/yzsAAAAAAAA/"} + img4 := model.Image{Id: 0x3BC7, Token: 0x3BCC, Src: "/api/images/zDsAAAAAAAA/"} imgs2 := []model.Image{img3, img4} if reflect.DeepEqual(img9, img10) { t.Error("img9 == img10") @@ -300,8 +300,8 @@ func TestServiceIntegrationPair(t *testing.T) { if err != nil { t.Error(err) } - img5 := model.Image{Id: 0x3BC7, Token: 0x3BCD, Src: "/api/images/zTsAAAAAAAA"} - img6 := model.Image{Id: 0x3BC8, Token: 0x3BCE, Src: "/api/images/zjsAAAAAAAA"} + img5 := model.Image{Id: 0x3BC7, Token: 0x3BCD, Src: "/api/images/zTsAAAAAAAA/"} + img6 := model.Image{Id: 0x3BC8, Token: 0x3BCE, Src: "/api/images/zjsAAAAAAAA/"} imgs3 := []model.Image{img5, img6} if reflect.DeepEqual(img11, img12) { t.Error("img11 == img12") diff --git a/domain/service/service_test.go b/domain/service/service_test.go index 778793e..8acde0d 100644 --- a/domain/service/service_test.go +++ b/domain/service/service_test.go @@ -201,8 +201,8 @@ func TestServicePair(t *testing.T) { if err != nil { t.Error(err) } - img1 := model.Image{Id: 0x3BC7, Token: 0x3BC9, Src: "/api/images/yTsAAAAAAAA"} - img2 := model.Image{Id: 0x3BC8, Token: 0x3BCA, Src: "/api/images/yjsAAAAAAAA"} + img1 := model.Image{Id: 0x3BC7, Token: 0x3BC9, Src: "/api/images/yTsAAAAAAAA/"} + img2 := model.Image{Id: 0x3BC8, Token: 0x3BCA, Src: "/api/images/yjsAAAAAAAA/"} imgs1 := []model.Image{img1, img2} if reflect.DeepEqual(img7, img8) { t.Error("img7 == img8") @@ -217,8 +217,8 @@ func TestServicePair(t *testing.T) { if err != nil { t.Error(err) } - img3 := model.Image{Id: 0x3BC8, Token: 0x3BCB, Src: "/api/images/yzsAAAAAAAA"} - img4 := model.Image{Id: 0x3BC7, Token: 0x3BCC, Src: "/api/images/zDsAAAAAAAA"} + img3 := model.Image{Id: 0x3BC8, Token: 0x3BCB, Src: "/api/images/yzsAAAAAAAA/"} + img4 := model.Image{Id: 0x3BC7, Token: 0x3BCC, Src: "/api/images/zDsAAAAAAAA/"} imgs2 := []model.Image{img3, img4} if reflect.DeepEqual(img9, img10) { t.Error("img9 == img10") @@ -233,8 +233,8 @@ func TestServicePair(t *testing.T) { if err != nil { t.Error(err) } - img5 := model.Image{Id: 0x3BC7, Token: 0x3BCD, Src: "/api/images/zTsAAAAAAAA"} - img6 := model.Image{Id: 0x3BC8, Token: 0x3BCE, Src: "/api/images/zjsAAAAAAAA"} + img5 := model.Image{Id: 0x3BC7, Token: 0x3BCD, Src: "/api/images/zTsAAAAAAAA/"} + img6 := model.Image{Id: 0x3BC8, Token: 0x3BCE, Src: "/api/images/zjsAAAAAAAA/"} imgs3 := []model.Image{img5, img6} if reflect.DeepEqual(img11, img12) { t.Error("img11 == img12") diff --git a/go.mod b/go.mod index 1290509..0799cee 100644 --- a/go.mod +++ b/go.mod @@ -4,16 +4,17 @@ go 1.17 require ( github.com/caddyserver/certmagic v0.15.2 - github.com/cheggaaa/pb/v3 v3.0.8 github.com/dgraph-io/badger/v3 v3.2103.2 github.com/emirpasic/gods v1.12.0 github.com/go-playground/validator v9.31.0+incompatible github.com/go-redis/redis/v8 v8.11.4 + github.com/go-redis/redis_rate/v9 v9.1.2 github.com/hashicorp/golang-lru v0.5.4 github.com/julienschmidt/httprouter v1.3.0 github.com/mailru/easyjson v0.7.7 github.com/minio/minio-go/v7 v7.0.16 github.com/ory/dockertest/v3 v3.6.5 + github.com/radovskyb/watcher v1.0.7 github.com/rs/cors v1.8.0 github.com/spf13/viper v1.9.0 go.mongodb.org/mongo-driver v1.8.0 @@ -27,7 +28,6 @@ require ( github.com/Azure/go-ansiterm v0.0.0-20210608035416-43c61cb656b4 // indirect github.com/Microsoft/go-winio v0.5.0 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect - github.com/VividCortex/ewma v1.2.0 // indirect github.com/cenkalti/backoff/v4 v4.1.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect @@ -37,11 +37,9 @@ require ( github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.4.0 // indirect github.com/dustin/go-humanize v1.0.0 // indirect - github.com/fatih/color v1.12.0 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect github.com/go-playground/locales v0.12.1 // indirect github.com/go-playground/universal-translator v0.16.0 // indirect - github.com/go-redis/redis_rate/v9 v9.1.2 // indirect github.com/go-stack/stack v1.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/glog v1.0.0 // indirect @@ -60,9 +58,6 @@ require ( github.com/lib/pq v1.8.0 // indirect github.com/libdns/libdns v0.2.1 // indirect github.com/magiconair/properties v1.8.5 // indirect - github.com/mattn/go-colorable v0.1.8 // indirect - github.com/mattn/go-isatty v0.0.13 // indirect - github.com/mattn/go-runewidth v0.0.13 // indirect github.com/mholt/acmez v1.0.1 // indirect github.com/miekg/dns v1.1.43 // indirect github.com/minio/md5-simd v1.1.2 // indirect @@ -78,8 +73,6 @@ require ( github.com/opencontainers/runc v1.0.0-rc95 // indirect github.com/pelletier/go-toml v1.9.4 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/radovskyb/watcher v1.0.7 // indirect - github.com/rivo/uniseg v0.2.0 // indirect github.com/rs/xid v1.3.0 // indirect github.com/sirupsen/logrus v1.8.1 // indirect github.com/spf13/afero v1.6.0 // indirect diff --git a/go.sum b/go.sum index 696386d..0189211 100644 --- a/go.sum +++ b/go.sum @@ -55,9 +55,6 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEV github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= -github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= -github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= @@ -83,8 +80,6 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= -github.com/cheggaaa/pb/v3 v3.0.8 h1:bC8oemdChbke2FHIIGy9mn4DPJ2caZYQnfbRqwmdCoA= -github.com/cheggaaa/pb/v3 v3.0.8/go.mod h1:UICbiLec/XO6Hw6k+BHEtHeQFzzBH4i2/qk/ow1EJTA= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -145,9 +140,6 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc= -github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -354,19 +346,12 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= -github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mholt/acmez v1.0.1 h1:J7uquHOKEmo71UDnVApy1sSLA0oF/r+NtVrNzMKKA9I= github.com/mholt/acmez v1.0.1/go.mod h1:8qnn8QA/Ewx8E3ZSsmscqsIjhhpxuy9vqdgbX2ceceM= @@ -455,9 +440,6 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/radovskyb/watcher v1.0.7 h1:AYePLih6dpmS32vlHfhCeli8127LzkIgwJGcwwe8tUE= github.com/radovskyb/watcher v1.0.7/go.mod h1:78okwvY5wPdzcb1UYnip1pvrZNIVEIh/Cm+ZuvsUYIg= -github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= diff --git a/infrastructure/storage/minio.go b/infrastructure/storage/minio.go index 951e110..1d2496e 100644 --- a/infrastructure/storage/minio.go +++ b/infrastructure/storage/minio.go @@ -5,7 +5,7 @@ import ( "io" "net/http" - minios3 "github.com/minio/minio-go/v7" + minioS3 "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" "github.com/zitryss/aye-and-nay/domain/domain" @@ -17,7 +17,7 @@ import ( ) func NewMinio(ctx context.Context, conf MinioConfig) (*Minio, error) { - client, err := minios3.New(conf.Host+":"+conf.Port, &minios3.Options{ + client, err := minioS3.New(conf.Host+":"+conf.Port, &minioS3.Options{ Creds: credentials.NewStaticV4(conf.AccessKey, conf.SecretKey, conf.Token), Secure: conf.Secure, }) @@ -42,7 +42,7 @@ func NewMinio(ctx context.Context, conf MinioConfig) (*Minio, error) { return &Minio{}, errors.Wrap(err) } if !found { - err = client.MakeBucket(ctx, "aye-and-nay", minios3.MakeBucketOptions{Region: conf.Location}) + err = client.MakeBucket(ctx, "aye-and-nay", minioS3.MakeBucketOptions{Region: conf.Location}) if err != nil { return &Minio{}, errors.Wrap(err) } @@ -57,7 +57,7 @@ func NewMinio(ctx context.Context, conf MinioConfig) (*Minio, error) { type Minio struct { conf MinioConfig - client *minios3.Client + client *minioS3.Client } func (m *Minio) Put(ctx context.Context, album uint64, image uint64, f model.File) (string, error) { @@ -65,7 +65,7 @@ func (m *Minio) Put(ctx context.Context, album uint64, image uint64, f model.Fil albumB64 := base64.FromUint64(album) imageB64 := base64.FromUint64(image) filename := "albums/" + albumB64 + "/images/" + imageB64 - _, err := m.client.PutObject(ctx, "aye-and-nay", filename, f.Reader, f.Size, minios3.PutObjectOptions{}) + _, err := m.client.PutObject(ctx, "aye-and-nay", filename, f.Reader, f.Size, minioS3.PutObjectOptions{}) if err != nil { return "", errors.Wrap(err) } @@ -77,7 +77,7 @@ func (m *Minio) Get(ctx context.Context, album uint64, image uint64) (model.File albumB64 := base64.FromUint64(album) imageB64 := base64.FromUint64(image) filename := "albums/" + albumB64 + "/images/" + imageB64 - obj, err := m.client.GetObject(ctx, "aye-and-nay", filename, minios3.GetObjectOptions{}) + obj, err := m.client.GetObject(ctx, "aye-and-nay", filename, minioS3.GetObjectOptions{}) if err != nil { return model.File{}, errors.Wrap(err) } @@ -102,7 +102,7 @@ func (m *Minio) Remove(ctx context.Context, album uint64, image uint64) error { albumB64 := base64.FromUint64(album) imageB64 := base64.FromUint64(image) filename := "albums/" + albumB64 + "/images/" + imageB64 - err := m.client.RemoveObject(ctx, "aye-and-nay", filename, minios3.RemoveObjectOptions{}) + err := m.client.RemoveObject(ctx, "aye-and-nay", filename, minioS3.RemoveObjectOptions{}) if err != nil { return errors.Wrap(err) } diff --git a/infrastructure/storage/minio_integration_test.go b/infrastructure/storage/minio_integration_test.go index 59b8579..c88f770 100644 --- a/infrastructure/storage/minio_integration_test.go +++ b/infrastructure/storage/minio_integration_test.go @@ -6,7 +6,7 @@ import ( "context" "testing" - minios3 "github.com/minio/minio-go/v7" + minioS3 "github.com/minio/minio-go/v7" . "github.com/zitryss/aye-and-nay/internal/testing" "github.com/zitryss/aye-and-nay/pkg/errors" @@ -19,7 +19,7 @@ func TestMinio(t *testing.T) { t.Fatal(err) } f, err := minio.Get(context.Background(), 0x70D8, 0xD5C7) - e := (*minios3.ErrorResponse)(nil) + e := (*minioS3.ErrorResponse)(nil) if errors.As(err, &e) { t.Error(err) } @@ -45,7 +45,7 @@ func TestMinio(t *testing.T) { t.Error(err) } f, err = minio.Get(context.Background(), 0x70D8, 0xD5C7) - e = (*minios3.ErrorResponse)(nil) + e = (*minioS3.ErrorResponse)(nil) if errors.As(err, &e) { t.Error(err) } diff --git a/internal/client/client.go b/internal/client/client.go index 6f93529..d8468e5 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -150,8 +150,8 @@ func (c *Client) Album() (string, error) { return res.Album.Id, nil } -func (c *Client) Ready(album string) error { - req, err := http.NewRequest(http.MethodGet, c.apiAddress+"/api/albums/"+album+"/ready/", http.NoBody) +func (c *Client) Status(album string) error { + req, err := http.NewRequest(http.MethodGet, c.apiAddress+"/api/albums/"+album+"/status/", http.NoBody) if err != nil { return errors.Wrap(err) } From 637fdba45efd8f596ce60bc30c2be5c3ae97d854 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sun, 23 Jan 2022 00:43:30 +0100 Subject: [PATCH 33/92] Change JSON response --- delivery/http/controller.go | 2 +- delivery/http/controller_test.go | 2 +- delivery/http/responses.go | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/delivery/http/controller.go b/delivery/http/controller.go index b5b1c3d..84fdc42 100644 --- a/delivery/http/controller.go +++ b/delivery/http/controller.go @@ -169,7 +169,7 @@ func (c *controller) handleStatus() httprouter.Handle { return statusResponse{}, errors.Wrap(err) } resp := statusResponse{} - resp.Album.Progress = p + resp.Album.Compression.Progress = p return resp, nil } output := func(ctx context.Context, w http.ResponseWriter, resp statusResponse) error { diff --git a/delivery/http/controller_test.go b/delivery/http/controller_test.go index f11ba13..961853f 100644 --- a/delivery/http/controller_test.go +++ b/delivery/http/controller_test.go @@ -384,7 +384,7 @@ func TestControllerHandleStatus(t *testing.T) { want: want{ code: 200, typ: "application/json; charset=utf-8", - body: `{"album":{"progress":1}}` + "\n", + body: `{"album":{"compression":{"progress":1}}}` + "\n", }, }, { diff --git a/delivery/http/responses.go b/delivery/http/responses.go index 8baa1cb..4a427c9 100644 --- a/delivery/http/responses.go +++ b/delivery/http/responses.go @@ -16,7 +16,9 @@ type albumResponse struct { //easyjson:json type statusResponse struct { Album struct { - Progress float64 `json:"progress"` + Compression struct { + Progress float64 `json:"progress"` + } `json:"compression"` } `json:"album"` } From a19a91a700f41dce2c6676f3150133e3e323259d Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sun, 23 Jan 2022 01:00:14 +0100 Subject: [PATCH 34/92] Check interfaces --- domain/service/mock.go | 5 +++++ domain/service/service.go | 4 ++++ infrastructure/cache/mem.go | 4 ++++ infrastructure/cache/redis.go | 4 ++++ infrastructure/compressor/imaginary.go | 4 ++++ infrastructure/compressor/mock.go | 5 +++++ infrastructure/compressor/shortpixel.go | 4 ++++ infrastructure/database/badger.go | 4 ++++ infrastructure/database/mem.go | 4 ++++ infrastructure/database/mongo.go | 4 ++++ infrastructure/storage/minio.go | 4 ++++ infrastructure/storage/mock.go | 5 +++++ 12 files changed, 51 insertions(+) diff --git a/domain/service/mock.go b/domain/service/mock.go index cb45f4d..47a2199 100644 --- a/domain/service/mock.go +++ b/domain/service/mock.go @@ -5,12 +5,17 @@ import ( "io" "time" + "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/model" . "github.com/zitryss/aye-and-nay/internal/testing" "github.com/zitryss/aye-and-nay/pkg/errors" "github.com/zitryss/aye-and-nay/pkg/pool" ) +var ( + _ domain.Servicer = (*Mock)(nil) +) + func NewMock(err error) *Mock { return &Mock{err} } diff --git a/domain/service/service.go b/domain/service/service.go index d916f39..7e8acb6 100644 --- a/domain/service/service.go +++ b/domain/service/service.go @@ -12,6 +12,10 @@ import ( myrand "github.com/zitryss/aye-and-nay/pkg/rand" ) +var ( + _ domain.Servicer = (*Service)(nil) +) + func New( conf ServiceConfig, comp domain.Compresser, diff --git a/infrastructure/cache/mem.go b/infrastructure/cache/mem.go index 3511bd3..fe3e4e0 100644 --- a/infrastructure/cache/mem.go +++ b/infrastructure/cache/mem.go @@ -13,6 +13,10 @@ import ( "github.com/zitryss/aye-and-nay/pkg/errors" ) +var ( + _ domain.Cacher = (*Mem)(nil) +) + func NewMem(conf MemConfig, opts ...options) *Mem { m := &Mem{ conf: conf, diff --git a/infrastructure/cache/redis.go b/infrastructure/cache/redis.go index a096d35..c025efc 100644 --- a/infrastructure/cache/redis.go +++ b/infrastructure/cache/redis.go @@ -14,6 +14,10 @@ import ( "github.com/zitryss/aye-and-nay/pkg/retry" ) +var ( + _ domain.Cacher = (*Redis)(nil) +) + func NewRedis(ctx context.Context, conf RedisConfig) (*Redis, error) { client := redisdb.NewClient(&redisdb.Options{Addr: conf.Host + ":" + conf.Port}) r := &Redis{} diff --git a/infrastructure/compressor/imaginary.go b/infrastructure/compressor/imaginary.go index 3ab2212..372f175 100644 --- a/infrastructure/compressor/imaginary.go +++ b/infrastructure/compressor/imaginary.go @@ -13,6 +13,10 @@ import ( "github.com/zitryss/aye-and-nay/pkg/retry" ) +var ( + _ domain.Compresser = (*Imaginary)(nil) +) + func NewImaginary(ctx context.Context, conf ImaginaryConfig) (*Imaginary, error) { im := &Imaginary{conf} ctx, cancel := context.WithTimeout(ctx, conf.Timeout) diff --git a/infrastructure/compressor/mock.go b/infrastructure/compressor/mock.go index 2d888ea..22fd410 100644 --- a/infrastructure/compressor/mock.go +++ b/infrastructure/compressor/mock.go @@ -4,11 +4,16 @@ import ( "context" "io" + "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/model" "github.com/zitryss/aye-and-nay/pkg/errors" "github.com/zitryss/aye-and-nay/pkg/pool" ) +var ( + _ domain.Compresser = (*Mock)(nil) +) + func NewMock() *Mock { return &Mock{} } diff --git a/infrastructure/compressor/shortpixel.go b/infrastructure/compressor/shortpixel.go index a424d13..2fdcfb9 100644 --- a/infrastructure/compressor/shortpixel.go +++ b/infrastructure/compressor/shortpixel.go @@ -17,6 +17,10 @@ import ( "github.com/zitryss/aye-and-nay/pkg/retry" ) +var ( + _ domain.Compresser = (*Shortpixel)(nil) +) + func NewShortpixel(conf ShortpixelConfig, opts ...options) *Shortpixel { sp := &Shortpixel{ conf: conf, diff --git a/infrastructure/database/badger.go b/infrastructure/database/badger.go index 856c7cf..ff71440 100644 --- a/infrastructure/database/badger.go +++ b/infrastructure/database/badger.go @@ -18,6 +18,10 @@ import ( "github.com/zitryss/aye-and-nay/pkg/pool" ) +var ( + _ domain.Databaser = (*Badger)(nil) +) + func NewBadger(conf BadgerConfig) (*Badger, error) { _ = runtime.GOMAXPROCS(128) path := "./badger" diff --git a/infrastructure/database/mem.go b/infrastructure/database/mem.go index 719371a..4398c37 100644 --- a/infrastructure/database/mem.go +++ b/infrastructure/database/mem.go @@ -10,6 +10,10 @@ import ( "github.com/zitryss/aye-and-nay/pkg/errors" ) +var ( + _ domain.Databaser = (*Mem)(nil) +) + func NewMem(conf MemConfig) *Mem { return &Mem{ conf: conf, diff --git a/infrastructure/database/mongo.go b/infrastructure/database/mongo.go index 9b32d51..47851b8 100644 --- a/infrastructure/database/mongo.go +++ b/infrastructure/database/mongo.go @@ -17,6 +17,10 @@ import ( "github.com/zitryss/aye-and-nay/pkg/retry" ) +var ( + _ domain.Databaser = (*Mongo)(nil) +) + type albumLru map[uint64]string type imageDao struct { diff --git a/infrastructure/storage/minio.go b/infrastructure/storage/minio.go index 1d2496e..7f12e4f 100644 --- a/infrastructure/storage/minio.go +++ b/infrastructure/storage/minio.go @@ -16,6 +16,10 @@ import ( "github.com/zitryss/aye-and-nay/pkg/retry" ) +var ( + _ domain.Storager = (*Minio)(nil) +) + func NewMinio(ctx context.Context, conf MinioConfig) (*Minio, error) { client, err := minioS3.New(conf.Host+":"+conf.Port, &minioS3.Options{ Creds: credentials.NewStaticV4(conf.AccessKey, conf.SecretKey, conf.Token), diff --git a/infrastructure/storage/mock.go b/infrastructure/storage/mock.go index d0e7ed2..bceeba6 100644 --- a/infrastructure/storage/mock.go +++ b/infrastructure/storage/mock.go @@ -4,6 +4,7 @@ import ( "context" "io" + "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/model" . "github.com/zitryss/aye-and-nay/internal/testing" "github.com/zitryss/aye-and-nay/pkg/base64" @@ -11,6 +12,10 @@ import ( "github.com/zitryss/aye-and-nay/pkg/pool" ) +var ( + _ domain.Storager = (*Mock)(nil) +) + func NewMock() *Mock { return &Mock{} } From 3fb5c4fc17ccc4c2f1d70ad0c749d6ef81632692 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sun, 23 Jan 2022 01:04:36 +0100 Subject: [PATCH 35/92] Stop rerouting requests --- delivery/http/router.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/delivery/http/router.go b/delivery/http/router.go index 655685f..84794d5 100644 --- a/delivery/http/router.go +++ b/delivery/http/router.go @@ -8,12 +8,19 @@ import ( func newRouter(contr controller) http.Handler { router := httprouter.New() + // router.POST("/api/albums", contr.handleAlbum()) router.POST("/api/albums/", contr.handleAlbum()) + // router.GET("/api/albums/:album/status", contr.handleStatus()) router.GET("/api/albums/:album/status/", contr.handleStatus()) + // router.GET("/api/albums/:album/pair", contr.handlePair()) router.GET("/api/albums/:album/pair/", contr.handlePair()) + // router.GET("/api/images/:token", contr.handleImage()) router.GET("/api/images/:token/", contr.handleImage()) + // router.PATCH("/api/albums/:album/vote", contr.handleVote()) router.PATCH("/api/albums/:album/vote/", contr.handleVote()) + // router.GET("/api/albums/:album/top", contr.handleTop()) router.GET("/api/albums/:album/top/", contr.handleTop()) + // router.GET("/api/health", contr.handleHealth()) router.GET("/api/health/", contr.handleHealth()) return router } From 29213fceb12da3b6f8fa8c1d4bbc74280a545148 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Tue, 25 Jan 2022 17:38:59 +0100 Subject: [PATCH 36/92] Set unlimited ulimit --- main.go | 6 ++++++ ulimit.go | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 ulimit.go diff --git a/main.go b/main.go index 39188b5..237f27a 100644 --- a/main.go +++ b/main.go @@ -30,6 +30,12 @@ func main() { flag.StringVar(&path, "config", "./config.env", "filepath to a config file") flag.Parse() + err := setUlimit() + if err != nil { + log.Critical(err) + os.Exit(1) + } + reload := true for reload { reload = false diff --git a/ulimit.go b/ulimit.go new file mode 100644 index 0000000..f8d62eb --- /dev/null +++ b/ulimit.go @@ -0,0 +1,21 @@ +//go:build !windows + +package main + +import ( + "syscall" +) + +func setUlimit() error { + rLimit := syscall.Rlimit{} + err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit) + if err != nil { + return err + } + rLimit.Cur = rLimit.Max + err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit) + if err != nil { + return err + } + return nil +} From ed643dfc35f52d6ca78a4def1bdb7b98cde296c1 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Tue, 25 Jan 2022 22:25:45 +0100 Subject: [PATCH 37/92] Make checks consistent --- infrastructure/compressor/imaginary.go | 4 ++-- infrastructure/compressor/shortpixel.go | 6 +++--- infrastructure/storage/minio.go | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/infrastructure/compressor/imaginary.go b/infrastructure/compressor/imaginary.go index 372f175..eb6639d 100644 --- a/infrastructure/compressor/imaginary.go +++ b/infrastructure/compressor/imaginary.go @@ -78,7 +78,7 @@ func (im *Imaginary) Compress(ctx context.Context, f model.File) (model.File, er _ = resp.Body.Close() return errors.Wrap(domain.ErrUnsupportedMediaType) } - if resp.StatusCode < 200 || resp.StatusCode > 299 { + if resp.StatusCode/100 != 2 { _, _ = io.Copy(io.Discard, resp.Body) _ = resp.Body.Close() return errors.Wrapf(domain.ErrThirdPartyUnavailable, "status code %d", resp.StatusCode) @@ -130,7 +130,7 @@ func (im *Imaginary) Health(ctx context.Context) (bool, error) { if err != nil { return false, errors.Wrapf(domain.ErrBadHealthCompressor, "%s", err) } - if resp.StatusCode < 200 || resp.StatusCode > 299 { + if resp.StatusCode/100 != 2 { return false, errors.Wrapf(domain.ErrBadHealthCompressor, "%s", "no connection to imaginary") } return true, nil diff --git a/infrastructure/compressor/shortpixel.go b/infrastructure/compressor/shortpixel.go index 2fdcfb9..df3095a 100644 --- a/infrastructure/compressor/shortpixel.go +++ b/infrastructure/compressor/shortpixel.go @@ -178,7 +178,7 @@ func (sp *Shortpixel) upload(ctx context.Context, f model.File) (string, error) if err != nil { return errors.Wrapf(domain.ErrThirdPartyUnavailable, "%s", err) } - if resp.StatusCode < 200 || resp.StatusCode > 299 { + if resp.StatusCode/100 != 2 { _, _ = io.Copy(io.Discard, resp.Body) _ = resp.Body.Close() return errors.Wrapf(domain.ErrThirdPartyUnavailable, "status code %d", resp.StatusCode) @@ -272,7 +272,7 @@ func (sp *Shortpixel) repeat(ctx context.Context, src string) (string, error) { if err != nil { return errors.Wrapf(domain.ErrThirdPartyUnavailable, "%s", err) } - if resp.StatusCode < 200 || resp.StatusCode > 299 { + if resp.StatusCode/100 != 2 { _, _ = io.Copy(io.Discard, resp.Body) _ = resp.Body.Close() return errors.Wrapf(domain.ErrThirdPartyUnavailable, "status code %d", resp.StatusCode) @@ -339,7 +339,7 @@ func (sp *Shortpixel) download(ctx context.Context, src string) (model.File, err if err != nil { return errors.Wrapf(domain.ErrThirdPartyUnavailable, "%s", err) } - if resp.StatusCode < 200 || resp.StatusCode > 299 { + if resp.StatusCode/100 != 2 { _, _ = io.Copy(io.Discard, resp.Body) _ = resp.Body.Close() return errors.Wrapf(domain.ErrThirdPartyUnavailable, "status code %d", resp.StatusCode) diff --git a/infrastructure/storage/minio.go b/infrastructure/storage/minio.go index 7f12e4f..54a7144 100644 --- a/infrastructure/storage/minio.go +++ b/infrastructure/storage/minio.go @@ -134,7 +134,7 @@ func (m *Minio) Health(ctx context.Context) (bool, error) { if err != nil { return false, errors.Wrapf(domain.ErrBadHealthStorage, "%s", err) } - if resp.StatusCode < 200 || resp.StatusCode > 299 { + if resp.StatusCode/100 != 2 { return false, errors.Wrapf(domain.ErrBadHealthStorage, "%s", "no connection to minio") } url = "http://" + m.conf.Host + ":" + m.conf.Port + "/minio/health/ready" @@ -157,7 +157,7 @@ func (m *Minio) Health(ctx context.Context) (bool, error) { if err != nil { return false, errors.Wrapf(domain.ErrBadHealthStorage, "%s", err) } - if resp.StatusCode < 200 || resp.StatusCode > 299 { + if resp.StatusCode/100 != 2 { return false, errors.Wrapf(domain.ErrBadHealthStorage, "%s", "minio is not ready") } _, err = m.client.ListBuckets(ctx) From dac1c80cadec09b360468c6f71aee31a4e441c69 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Wed, 26 Jan 2022 23:00:37 +0100 Subject: [PATCH 38/92] Use init function for unlimit --- main.go | 6 ------ ulimit.go | 11 +++++++++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/main.go b/main.go index 237f27a..39188b5 100644 --- a/main.go +++ b/main.go @@ -30,12 +30,6 @@ func main() { flag.StringVar(&path, "config", "./config.env", "filepath to a config file") flag.Parse() - err := setUlimit() - if err != nil { - log.Critical(err) - os.Exit(1) - } - reload := true for reload { reload = false diff --git a/ulimit.go b/ulimit.go index f8d62eb..5728b18 100644 --- a/ulimit.go +++ b/ulimit.go @@ -3,9 +3,20 @@ package main import ( + "os" "syscall" + + "github.com/zitryss/aye-and-nay/pkg/log" ) +func init() { + err := setUlimit() + if err != nil { + log.Critical(err) + os.Exit(1) + } +} + func setUlimit() error { rLimit := syscall.Rlimit{} err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit) From 9efb3616a25d533a6d21009303766e7ae085dede Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sat, 29 Jan 2022 14:14:06 +0100 Subject: [PATCH 39/92] Replace manual checks with asserts --- delivery/http/controller_test.go | 63 +- delivery/http/middleware_test.go | 30 +- delivery/http/server_test.go | 43 +- domain/service/queue_integration_test.go | 43 +- domain/service/queue_test.go | 50 +- domain/service/service_integration_test.go | 674 +++++------------- domain/service/service_test.go | 405 +++-------- go.mod | 4 + infrastructure/cache/config.go | 4 +- infrastructure/cache/mem_test.go | 111 +-- .../cache/redis_integration_test.go | 349 +++------ .../compressor/imaginary_integration_test.go | 49 +- infrastructure/compressor/shortpixel_test.go | 187 ++--- infrastructure/database/badger_test.go | 378 +++------- infrastructure/database/mem_test.go | 268 ++----- .../database/mongo_integration_test.go | 381 +++------- .../storage/minio_integration_test.go | 87 +-- internal/testing/testing.go | 137 ++-- pkg/errors/errors_test.go | 7 +- pkg/linalg/linalg_test.go | 6 +- pkg/log/log_test.go | 10 +- pkg/retry/retry_test.go | 27 +- 22 files changed, 924 insertions(+), 2389 deletions(-) diff --git a/delivery/http/controller_test.go b/delivery/http/controller_test.go index 961853f..1b16d99 100644 --- a/delivery/http/controller_test.go +++ b/delivery/http/controller_test.go @@ -14,6 +14,7 @@ import ( "testing" "github.com/julienschmidt/httprouter" + "github.com/stretchr/testify/assert" "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/service" @@ -332,34 +333,24 @@ func TestControllerHandleAlbum(t *testing.T) { multi := multipart.NewWriter(&body) for _, filename := range tt.give.filenames { part, err := multi.CreateFormFile("images", filename) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) b, err := os.ReadFile("../../testdata/" + filename) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) _, err = part.Write(b) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } if tt.give.durationOn { err := multi.WriteField("duration", tt.give.duration) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } err := multi.Close() - if err != nil { - t.Error(err) - } + assert.NoError(t, err) r := httptest.NewRequest(http.MethodPost, "/api/albums/", &body) r.Header.Set("Content-Type", multi.FormDataContentType()) fn(w, r, nil) - CheckStatusCode(t, w, tt.want.code) - CheckContentType(t, w, tt.want.typ) - CheckBody(t, w, tt.want.body) + AssertStatusCode(t, w, tt.want.code) + AssertContentType(t, w, tt.want.typ) + AssertBody(t, w, tt.want.body) }) } } @@ -537,9 +528,9 @@ func TestControllerHandleStatus(t *testing.T) { r := httptest.NewRequest(http.MethodGet, "/api/albums/rRsAAAAAAAA/status", http.NoBody) ps := httprouter.Params{httprouter.Param{Key: "album", Value: "rRsAAAAAAAA"}} fn(w, r, ps) - CheckStatusCode(t, w, tt.want.code) - CheckContentType(t, w, tt.want.typ) - CheckBody(t, w, tt.want.body) + AssertStatusCode(t, w, tt.want.code) + AssertContentType(t, w, tt.want.typ) + AssertBody(t, w, tt.want.body) }) } } @@ -717,9 +708,9 @@ func TestControllerHandlePair(t *testing.T) { r := httptest.NewRequest(http.MethodGet, "/api/albums/nkUAAAAAAAA/", http.NoBody) ps := httprouter.Params{httprouter.Param{Key: "album", Value: "nkUAAAAAAAA"}} fn(w, r, ps) - CheckStatusCode(t, w, tt.want.code) - CheckContentType(t, w, tt.want.typ) - CheckBody(t, w, tt.want.body) + AssertStatusCode(t, w, tt.want.code) + AssertContentType(t, w, tt.want.typ) + AssertBody(t, w, tt.want.body) }) } } @@ -898,9 +889,9 @@ func TestControllerHandleImage(t *testing.T) { r := httptest.NewRequest(http.MethodGet, "/api/images/8v7AAAAAAAA/", http.NoBody) ps := httprouter.Params{httprouter.Param{Key: "token", Value: "8v7AAAAAAAA"}} fn(w, r, ps) - CheckStatusCode(t, w, tt.want.code) - CheckContentType(t, w, tt.want.typ) - CheckBody(t, w, tt.want.body) + AssertStatusCode(t, w, tt.want.code) + AssertContentType(t, w, tt.want.typ) + AssertBody(t, w, tt.want.body) }) } } @@ -1080,9 +1071,9 @@ func TestControllerHandleVote(t *testing.T) { r.Header.Set("Content-Type", "application/json; charset=utf-8") ps := httprouter.Params{httprouter.Param{Key: "album", Value: "fIIAAAAAAAA"}} fn(w, r, ps) - CheckStatusCode(t, w, tt.want.code) - CheckContentType(t, w, tt.want.typ) - CheckBody(t, w, tt.want.body) + AssertStatusCode(t, w, tt.want.code) + AssertContentType(t, w, tt.want.typ) + AssertBody(t, w, tt.want.body) }) } } @@ -1260,9 +1251,9 @@ func TestControllerHandleTop(t *testing.T) { r := httptest.NewRequest(http.MethodGet, "/api/albums/byYAAAAAAAA/top/", http.NoBody) ps := httprouter.Params{httprouter.Param{Key: "album", Value: "byYAAAAAAAA"}} fn(w, r, ps) - CheckStatusCode(t, w, tt.want.code) - CheckContentType(t, w, tt.want.typ) - CheckBody(t, w, tt.want.body) + AssertStatusCode(t, w, tt.want.code) + AssertContentType(t, w, tt.want.typ) + AssertBody(t, w, tt.want.body) }) } } @@ -1340,9 +1331,9 @@ func TestControllerHandleHealth(t *testing.T) { r := httptest.NewRequest(http.MethodGet, "/api/health/", http.NoBody) ps := httprouter.Params{} fn(w, r, ps) - CheckStatusCode(t, w, tt.want.code) - CheckContentType(t, w, tt.want.typ) - CheckBody(t, w, tt.want.body) + AssertStatusCode(t, w, tt.want.code) + AssertContentType(t, w, tt.want.typ) + AssertBody(t, w, tt.want.body) }) } } diff --git a/delivery/http/middleware_test.go b/delivery/http/middleware_test.go index 7b4dd20..7132afd 100644 --- a/delivery/http/middleware_test.go +++ b/delivery/http/middleware_test.go @@ -9,6 +9,8 @@ import ( "net/http/httptest" "testing" + "github.com/stretchr/testify/assert" + . "github.com/zitryss/aye-and-nay/internal/testing" ) @@ -37,9 +39,9 @@ func TestMiddlewareRecover(t *testing.T) { w := httptest.NewRecorder() r := httptest.NewRequest(http.MethodGet, "/", http.NoBody) handler.ServeHTTP(w, r) - CheckStatusCode(t, w, 418) - CheckContentType(t, w, "text/plain; charset=utf-8") - CheckBody(t, w, `I'm a teapot`) + AssertStatusCode(t, w, 418) + AssertContentType(t, w, "text/plain; charset=utf-8") + AssertBody(t, w, `I'm a teapot`) }) t.Run("Negative", func(t *testing.T) { fn := func(w http.ResponseWriter, r *http.Request) { @@ -51,9 +53,9 @@ func TestMiddlewareRecover(t *testing.T) { w := httptest.NewRecorder() r := httptest.NewRequest(http.MethodGet, "/", http.NoBody) handler.ServeHTTP(w, r) - CheckStatusCode(t, w, 500) - CheckContentType(t, w, "application/json; charset=utf-8") - CheckBody(t, w, `{"error":{"code":17,"msg":"internal server error"}}`+"\n") + AssertStatusCode(t, w, 500) + AssertContentType(t, w, "application/json; charset=utf-8") + AssertBody(t, w, `{"error":{"code":17,"msg":"internal server error"}}`+"\n") }) } @@ -70,9 +72,9 @@ func TestMiddlewareLimit(t *testing.T) { w := httptest.NewRecorder() r := httptest.NewRequest(http.MethodGet, "/", http.NoBody) handler.ServeHTTP(w, r) - CheckStatusCode(t, w, 418) - CheckContentType(t, w, "text/plain; charset=utf-8") - CheckBody(t, w, `I'm a teapot`) + AssertStatusCode(t, w, 418) + AssertContentType(t, w, "text/plain; charset=utf-8") + AssertBody(t, w, `I'm a teapot`) }) t.Run("Negative", func(t *testing.T) { fn := func(w http.ResponseWriter, r *http.Request) { @@ -86,9 +88,9 @@ func TestMiddlewareLimit(t *testing.T) { w := httptest.NewRecorder() r := httptest.NewRequest(http.MethodGet, "/", http.NoBody) handler.ServeHTTP(w, r) - CheckStatusCode(t, w, 429) - CheckContentType(t, w, "application/json; charset=utf-8") - CheckBody(t, w, `{"error":{"code":0,"msg":"too many requests"}}`+"\n") + AssertStatusCode(t, w, 429) + AssertContentType(t, w, "application/json; charset=utf-8") + AssertBody(t, w, `{"error":{"code":0,"msg":"too many requests"}}`+"\n") }) } @@ -142,9 +144,7 @@ func TestIP(t *testing.T) { r.Header.Set("X-Forwarded-For", tt.args.xff) r.RemoteAddr = tt.args.remoteAddr t.Run("", func(t *testing.T) { - if got := ip(r); got != tt.want { - t.Errorf("ip() = %v, want %v", got, tt.want) - } + assert.Equal(t, tt.want, ip(r)) }) } } diff --git a/delivery/http/server_test.go b/delivery/http/server_test.go index e800ff3..07b62e0 100644 --- a/delivery/http/server_test.go +++ b/delivery/http/server_test.go @@ -6,6 +6,9 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/zitryss/aye-and-nay/domain/service" "github.com/zitryss/aye-and-nay/infrastructure/cache" "github.com/zitryss/aye-and-nay/infrastructure/compressor" @@ -27,47 +30,27 @@ func TestServer(t *testing.T) { middle := NewMiddleware(DefaultMiddlewareConfig, cach) srvWait := make(chan error, 1) srv, err := NewServer(DefaultServerConfig, middle.Chain, serv, srvWait) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) mockserver := httptest.NewServer(srv.srv.Handler) defer mockserver.Close() c, err := client.New(mockserver.URL, 5*time.Second, client.WithFiles("../../testdata"), client.WithTimes(1)) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) album, err := c.Album() - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = c.Status(album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) p, err := c.Pair(album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = c.Do(http.MethodGet, mockserver.URL+p.One.Src, http.NoBody) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = c.Do(http.MethodGet, mockserver.URL+p.Two.Src, http.NoBody) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = c.Vote(album, p.One.Token, p.Two.Token) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) _, err = c.Top(album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = c.Health() - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } diff --git a/domain/service/queue_integration_test.go b/domain/service/queue_integration_test.go index d268375..bbed00e 100644 --- a/domain/service/queue_integration_test.go +++ b/domain/service/queue_integration_test.go @@ -7,14 +7,15 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/zitryss/aye-and-nay/infrastructure/cache" ) func TestPQueueIntegration(t *testing.T) { redis, err := cache.NewRedis(context.Background(), cache.DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) pq := newPQueue(0xFE28, redis) ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -22,39 +23,21 @@ func TestPQueueIntegration(t *testing.T) { go func() { time.Sleep(100 * time.Millisecond) err := pq.add(ctx, 0x85D5, time.Now().Add(400*time.Millisecond)) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) time.Sleep(100 * time.Millisecond) err = pq.add(ctx, 0x89C1, time.Now().Add(200*time.Millisecond)) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) time.Sleep(100 * time.Millisecond) err = pq.add(ctx, 0x97D3, time.Now().Add(400*time.Millisecond)) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) }() album, err := pq.poll(ctx) - if err != nil { - t.Error(err) - } - if album != 0x89C1 { - t.Error("album != 0x89C1") - } + assert.NoError(t, err) + assert.Equal(t, uint64(0x89C1), album) album, err = pq.poll(ctx) - if err != nil { - t.Error(err) - } - if album != 0x85D5 { - t.Error("album != 0x85D5") - } + assert.NoError(t, err) + assert.Equal(t, uint64(0x85D5), album) album, err = pq.poll(ctx) - if err != nil { - t.Error(err) - } - if album != 0x97D3 { - t.Error("album != 0x97D3") - } + assert.NoError(t, err) + assert.Equal(t, uint64(0x97D3), album) } diff --git a/domain/service/queue_test.go b/domain/service/queue_test.go index df29b57..54b6381 100644 --- a/domain/service/queue_test.go +++ b/domain/service/queue_test.go @@ -7,6 +7,8 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/zitryss/aye-and-nay/infrastructure/cache" ) @@ -19,54 +21,30 @@ func TestPQueue(t *testing.T) { go func() { time.Sleep(100 * time.Millisecond) err := pq.add(ctx, 0x85D5, time.Now().Add(400*time.Millisecond)) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) time.Sleep(100 * time.Millisecond) err = pq.add(ctx, 0x89C1, time.Now().Add(200*time.Millisecond)) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) time.Sleep(100 * time.Millisecond) err = pq.add(ctx, 0x97D3, time.Now().Add(400*time.Millisecond)) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) }() start := time.Now() album, err := pq.poll(ctx) d := time.Since(start) - if err != nil { - t.Error(err) - } - if album != 0x89C1 { - t.Error("album != 0x89C1") - } - if !(380*time.Millisecond < d && d < 420*time.Millisecond) { - t.Error("!(380*time.Millisecond < d && d < 420*time.Millisecond)") - } + assert.NoError(t, err) + assert.Equal(t, uint64(0x89C1), album) + assert.True(t, 380*time.Millisecond < d && d < 420*time.Millisecond) start = time.Now() album, err = pq.poll(ctx) d = time.Since(start) - if err != nil { - t.Error(err) - } - if album != 0x85D5 { - t.Error("album != 0x85D5") - } - if !(80*time.Millisecond < d && d < 120*time.Millisecond) { - t.Error("!(80*time.Millisecond < d && d < 120*time.Millisecond)") - } + assert.NoError(t, err) + assert.Equal(t, uint64(0x85D5), album) + assert.True(t, 80*time.Millisecond < d && d < 120*time.Millisecond) start = time.Now() album, err = pq.poll(ctx) d = time.Since(start) - if err != nil { - t.Error(err) - } - if album != 0x97D3 { - t.Error("album != 0x97D3") - } - if !(180*time.Millisecond < d && d < 220*time.Millisecond) { - t.Error("!(180*time.Millisecond < d && d < 220*time.Millisecond)") - } + assert.NoError(t, err) + assert.Equal(t, uint64(0x97D3), album) + assert.True(t, 180*time.Millisecond < d && d < 220*time.Millisecond) } diff --git a/domain/service/service_integration_test.go b/domain/service/service_integration_test.go index 2604166..9903302 100644 --- a/domain/service/service_integration_test.go +++ b/domain/service/service_integration_test.go @@ -6,10 +6,11 @@ import ( "context" "io" "os" - "reflect" "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "golang.org/x/sync/errgroup" "github.com/zitryss/aye-and-nay/domain/domain" @@ -21,7 +22,6 @@ import ( "github.com/zitryss/aye-and-nay/internal/dockertest" . "github.com/zitryss/aye-and-nay/internal/testing" "github.com/zitryss/aye-and-nay/pkg/env" - "github.com/zitryss/aye-and-nay/pkg/errors" "github.com/zitryss/aye-and-nay/pkg/log" ) @@ -66,21 +66,13 @@ func TestServiceIntegrationAlbum(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{newQueue(0xB273, redis)} @@ -93,25 +85,15 @@ func TestServiceIntegrationAlbum(t *testing.T) { serv.StartWorkingPoolComp(ctxComp, gComp) files := []model.File{Png(), Png()} _, err = serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } - v := CheckChannel(t, heartbeatComp) + assert.NoError(t, err) + v := AssertChannel(t, heartbeatComp) p, ok := v.(float64) - if !ok { - t.Error("v.(type) != float64") - } - if !EqualFloat(p, 0.5) { - t.Error("p != 0.5") - } - v = CheckChannel(t, heartbeatComp) + assert.True(t, ok) + assert.InDelta(t, 0.5, p, TOLERANCE) + v = AssertChannel(t, heartbeatComp) p, ok = v.(float64) - if !ok { - t.Error("v.(type) != float64") - } - if !EqualFloat(p, 1) { - t.Error("p != 1") - } + assert.True(t, ok) + assert.InDelta(t, 1, p, TOLERANCE) }) t.Run("Negative", func(t *testing.T) { fn1 := func() func() (uint64, error) { @@ -127,17 +109,11 @@ func TestServiceIntegrationAlbum(t *testing.T) { comp := compressor.NewShortpixel(compressor.DefaultShortpixelConfig, compressor.WithHeartbeatRestart(heartbeatRestart)) comp.Monitor() minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{newQueue(0x88AB, redis)} @@ -150,76 +126,44 @@ func TestServiceIntegrationAlbum(t *testing.T) { serv.StartWorkingPoolComp(ctxComp, gComp) files := []model.File{Png(), Png()} _, err = serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } - v := CheckChannel(t, heartbeatComp) - _ = CheckChannel(t, heartbeatComp) + assert.NoError(t, err) + v := AssertChannel(t, heartbeatComp) + _ = AssertChannel(t, heartbeatComp) err, ok := v.(error) - if !ok { - t.Error("v.(type) != error") - } - if !errors.Is(err, domain.ErrThirdPartyUnavailable) { - t.Error(err) - } + assert.True(t, ok) + assert.ErrorIs(t, err, domain.ErrThirdPartyUnavailable) files = []model.File{Png(), Png()} _, err = serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } - v = CheckChannel(t, heartbeatComp) + assert.NoError(t, err) + v = AssertChannel(t, heartbeatComp) p, ok := v.(float64) - if !ok { - t.Error("v.(type) != float64") - } - if !EqualFloat(p, 0.5) { - t.Error("p != 0.5") - } - v = CheckChannel(t, heartbeatComp) + assert.True(t, ok) + assert.InDelta(t, 0.5, p, TOLERANCE) + v = AssertChannel(t, heartbeatComp) p, ok = v.(float64) - if !ok { - t.Error("v.(type) != float64") - } - if !EqualFloat(p, 1) { - t.Error("p != 1") - } - CheckChannel(t, heartbeatRestart) - CheckChannel(t, heartbeatRestart) + assert.True(t, ok) + assert.InDelta(t, 1, p, TOLERANCE) + AssertChannel(t, heartbeatRestart) + AssertChannel(t, heartbeatRestart) files = []model.File{Png(), Png()} _, err = serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } - v = CheckChannel(t, heartbeatComp) - _ = CheckChannel(t, heartbeatComp) + assert.NoError(t, err) + v = AssertChannel(t, heartbeatComp) + _ = AssertChannel(t, heartbeatComp) err, ok = v.(error) - if !ok { - t.Error("v.(type) != error") - } - if !errors.Is(err, domain.ErrThirdPartyUnavailable) { - t.Error(err) - } + assert.True(t, ok) + assert.ErrorIs(t, err, domain.ErrThirdPartyUnavailable) files = []model.File{Png(), Png()} _, err = serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } - v = CheckChannel(t, heartbeatComp) + assert.NoError(t, err) + v = AssertChannel(t, heartbeatComp) p, ok = v.(float64) - if !ok { - t.Error("v.(type) != float64") - } - if !EqualFloat(p, 0.5) { - t.Error("p != 0.5") - } - v = CheckChannel(t, heartbeatComp) + assert.True(t, ok) + assert.InDelta(t, 0.5, p, TOLERANCE) + v = AssertChannel(t, heartbeatComp) p, ok = v.(float64) - if !ok { - t.Error("v.(type) != float64") - } - if !EqualFloat(p, 1) { - t.Error("p != 1") - } + assert.True(t, ok) + assert.InDelta(t, 1, p, TOLERANCE) }) } @@ -232,26 +176,17 @@ func TestServiceIntegrationPair(t *testing.T) { return 0x3BC5 + i, nil } }() - fn2 := func(n int, swap func(i int, j int)) { - } + fn2 := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} @@ -261,57 +196,31 @@ func TestServiceIntegrationPair(t *testing.T) { serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img7, img8, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img1 := model.Image{Id: 0x3BC7, Token: 0x3BC9, Src: "/api/images/yTsAAAAAAAA/"} img2 := model.Image{Id: 0x3BC8, Token: 0x3BCA, Src: "/api/images/yjsAAAAAAAA/"} imgs1 := []model.Image{img1, img2} - if reflect.DeepEqual(img7, img8) { - t.Error("img7 == img8") - } - if !IsIn(img7, imgs1) { - t.Error("img7 is not in imgs") - } - if !IsIn(img8, imgs1) { - t.Error("img8 is not in imgs") - } + assert.NotEqual(t, img7, img8) + AssertContains(t, imgs1, img7) + AssertContains(t, imgs1, img8) img9, img10, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img3 := model.Image{Id: 0x3BC8, Token: 0x3BCB, Src: "/api/images/yzsAAAAAAAA/"} img4 := model.Image{Id: 0x3BC7, Token: 0x3BCC, Src: "/api/images/zDsAAAAAAAA/"} imgs2 := []model.Image{img3, img4} - if reflect.DeepEqual(img9, img10) { - t.Error("img9 == img10") - } - if !IsIn(img9, imgs2) { - t.Error("img9 is not in imgs") - } - if !IsIn(img10, imgs2) { - t.Error("img10 is not in imgs") - } + assert.NotEqual(t, img9, img10) + AssertContains(t, imgs2, img9) + AssertContains(t, imgs2, img10) img11, img12, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img5 := model.Image{Id: 0x3BC7, Token: 0x3BCD, Src: "/api/images/zTsAAAAAAAA/"} img6 := model.Image{Id: 0x3BC8, Token: 0x3BCE, Src: "/api/images/zjsAAAAAAAA/"} imgs3 := []model.Image{img5, img6} - if reflect.DeepEqual(img11, img12) { - t.Error("img11 == img12") - } - if !IsIn(img11, imgs3) { - t.Error("img11 is not in imgs") - } - if !IsIn(img12, imgs3) { - t.Error("img12 is not in imgs") - } + assert.NotEqual(t, img11, img12) + AssertContains(t, imgs3, img11) + AssertContains(t, imgs3, img12) }) t.Run("Positive2", func(t *testing.T) { fn1 := func() func() (uint64, error) { @@ -321,26 +230,17 @@ func TestServiceIntegrationPair(t *testing.T) { return 0xFAFD + i, nil } }() - fn2 := func(n int, swap func(i int, j int)) { - } + fn2 := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} @@ -352,77 +252,43 @@ func TestServiceIntegrationPair(t *testing.T) { serv := New(conf, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img7, img8, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img1 := model.Image{Id: 0xFAFF, Token: 0xFAFF, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/__oAAAAAAAA"} img2 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} imgs1 := []model.Image{img1, img2} - if reflect.DeepEqual(img7, img8) { - t.Error("img7 == img8") - } - if !IsIn(img7, imgs1) { - t.Error("img7 is not in imgs") - } - if !IsIn(img8, imgs1) { - t.Error("img8 is not in imgs") - } + assert.NotEqual(t, img7, img8) + AssertContains(t, imgs1, img7) + AssertContains(t, imgs1, img8) img9, img10, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img3 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} img4 := model.Image{Id: 0xFAFF, Token: 0xFAFF, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/__oAAAAAAAA"} imgs2 := []model.Image{img3, img4} - if reflect.DeepEqual(img9, img10) { - t.Error("img9 == img10") - } - if !IsIn(img9, imgs2) { - t.Error("img9 is not in imgs") - } - if !IsIn(img10, imgs2) { - t.Error("img10 is not in imgs") - } + assert.NotEqual(t, img9, img10) + AssertContains(t, imgs2, img9) + AssertContains(t, imgs2, img10) img11, img12, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img5 := model.Image{Id: 0xFAFF, Token: 0xFAFF, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/__oAAAAAAAA"} img6 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} imgs3 := []model.Image{img5, img6} - if reflect.DeepEqual(img11, img12) { - t.Error("img11 == img12") - } - if !IsIn(img11, imgs3) { - t.Error("img11 is not in imgs") - } - if !IsIn(img12, imgs3) { - t.Error("img12 is not in imgs") - } + assert.NotEqual(t, img11, img12) + AssertContains(t, imgs3, img11) + AssertContains(t, imgs3, img12) }) t.Run("Negative", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} @@ -431,9 +297,7 @@ func TestServiceIntegrationPair(t *testing.T) { qDel.Monitor(ctx) serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel) _, _, err = serv.Pair(ctx, 0xEB46) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } @@ -446,26 +310,17 @@ func TestServiceIntegrationImage(t *testing.T) { return 0xA83F + i, nil } }() - fn2 := func(n int, swap func(i int, j int)) { - } + fn2 := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} @@ -475,47 +330,27 @@ func TestServiceIntegrationImage(t *testing.T) { serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img1, img2, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) f, err := serv.Image(ctx, img1.Token) - if err != nil { - t.Error(err) - } - if f.Reader == nil { - t.Error("f.Reader == nil") - } + assert.NoError(t, err) + assert.NotNil(t, f.Reader) f, err = serv.Image(ctx, img2.Token) - if err != nil { - t.Error(err) - } - if f.Reader == nil { - t.Error("f.Reader == nil") - } + assert.NoError(t, err) + assert.NotNil(t, f.Reader) }) t.Run("Negative", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} @@ -524,9 +359,7 @@ func TestServiceIntegrationImage(t *testing.T) { qDel.Monitor(ctx) serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel) _, err = serv.Image(ctx, 0xE283) - if !errors.Is(err, domain.ErrTokenNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) } @@ -539,26 +372,17 @@ func TestServiceIntegrationVote(t *testing.T) { return 0xC389 + i, nil } }() - fn2 := func(n int, swap func(i int, j int)) { - } + fn2 := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} @@ -568,17 +392,11 @@ func TestServiceIntegrationVote(t *testing.T) { serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img1, img2, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = serv.Vote(ctx, album, img1.Token, img2.Token) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) }) t.Run("Positive2", func(t *testing.T) { fn1 := func() func() (uint64, error) { @@ -588,26 +406,17 @@ func TestServiceIntegrationVote(t *testing.T) { return 0x1E58 + i, nil } }() - fn2 := func(n int, swap func(i int, j int)) { - } + fn2 := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} @@ -619,17 +428,11 @@ func TestServiceIntegrationVote(t *testing.T) { serv := New(conf, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img1, img2, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = serv.Vote(ctx, album, img1.Token, img2.Token) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) }) t.Run("Negative1", func(t *testing.T) { fn1 := func() func() (uint64, error) { @@ -639,26 +442,17 @@ func TestServiceIntegrationVote(t *testing.T) { return 0xE24F + i, nil } }() - fn2 := func(n int, swap func(i int, j int)) { - } + fn2 := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} @@ -668,17 +462,11 @@ func TestServiceIntegrationVote(t *testing.T) { serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img1, img2, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = serv.Vote(ctx, 0x12E6, img1.Token, img2.Token) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative2", func(t *testing.T) { fn1 := func() func() (uint64, error) { @@ -688,26 +476,17 @@ func TestServiceIntegrationVote(t *testing.T) { return 0xBC43 + i, nil } }() - fn2 := func(n int, swap func(i int, j int)) { - } + fn2 := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} @@ -717,17 +496,11 @@ func TestServiceIntegrationVote(t *testing.T) { serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) _, _, err = serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = serv.Vote(ctx, album, 0x1CC1, 0xF83C) - if !errors.Is(err, domain.ErrTokenNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) } @@ -740,26 +513,17 @@ func TestServiceIntegrationTop(t *testing.T) { return 0x4DB8 + i, nil } }() - fn2 := func(n int, swap func(i int, j int)) { - } + fn2 := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) qCalc := &QueueCalc{newQueue(0x1A01, redis)} qCalc.Monitor(ctx) qComp := &QueueComp{} @@ -772,57 +536,35 @@ func TestServiceIntegrationTop(t *testing.T) { serv.StartWorkingPoolCalc(ctxCalc, gCalc) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img1, img2, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = serv.Vote(ctx, album, img1.Token, img2.Token) - if err != nil { - t.Error(err) - } - CheckChannel(t, heartbeatCalc) + assert.NoError(t, err) + AssertChannel(t, heartbeatCalc) img3, img4, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = serv.Vote(ctx, album, img3.Token, img4.Token) - if err != nil { - t.Error(err) - } - CheckChannel(t, heartbeatCalc) + assert.NoError(t, err) + AssertChannel(t, heartbeatCalc) imgs1, err := serv.Top(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img5 := model.Image{Id: 0x4DBA, Src: "/aye-and-nay/albums/uU0AAAAAAAA/images/uk0AAAAAAAA", Rating: 0.5, Compressed: false} img6 := model.Image{Id: 0x4DBB, Src: "/aye-and-nay/albums/uU0AAAAAAAA/images/u00AAAAAAAA", Rating: 0.5, Compressed: false} imgs2 := []model.Image{img5, img6} - if !reflect.DeepEqual(imgs1, imgs2) { - t.Error("imgs1 != imgs2") - } + assert.Equal(t, imgs2, imgs1) }) t.Run("Negative", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} @@ -831,9 +573,7 @@ func TestServiceIntegrationTop(t *testing.T) { qDel.Monitor(ctx) serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel) _, err = serv.Top(ctx, 0x83CD) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } @@ -842,21 +582,13 @@ func TestServiceIntegrationDelete(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} @@ -866,31 +598,21 @@ func TestServiceIntegrationDelete(t *testing.T) { alb1 := AlbumEmptyFactory(0x101F) alb1.Expires = time.Now().Add(-1 * time.Hour) err = mongo.SaveAlbum(ctx, alb1) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) alb2 := AlbumEmptyFactory(0xFFBB) alb2.Expires = time.Now().Add(1 * time.Hour) err = mongo.SaveAlbum(ctx, alb2) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) heartbeatDel := make(chan interface{}) serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) err = serv.CleanUp(ctx) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) gDel, ctxDel := errgroup.WithContext(ctx) serv.StartWorkingPoolDel(ctxDel, gDel) - v := CheckChannel(t, heartbeatDel) + v := AssertChannel(t, heartbeatDel) album, ok := v.(uint64) - if !ok { - t.Error("v.(type) != uint64") - } - if album != 0x101F { - t.Error("album != 0x101F") - } + assert.True(t, ok) + assert.Equal(t, uint64(0x101F), album) t.Cleanup(func() { _ = mongo.DeleteAlbum(context.Background(), 0x101F) _ = mongo.DeleteAlbum(context.Background(), 0xFFBB) @@ -900,21 +622,13 @@ func TestServiceIntegrationDelete(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} @@ -928,34 +642,22 @@ func TestServiceIntegrationDelete(t *testing.T) { files := []model.File{Png(), Png()} dur := 100 * time.Millisecond album, err := serv.Album(ctx, files, dur) - if err != nil { - t.Error(err) - } - CheckChannel(t, heartbeatDel) + assert.NoError(t, err) + AssertChannel(t, heartbeatDel) _, err = serv.Top(ctx, album) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} @@ -969,18 +671,10 @@ func TestServiceIntegrationDelete(t *testing.T) { files := []model.File{Png(), Png()} dur := 0 * time.Second album, err := serv.Album(ctx, files, dur) - if err != nil { - t.Error(err) - } - select { - case <-heartbeatDel: - t.Error("<-heartbeatDel") - case <-time.After(1 * time.Second): - } + assert.NoError(t, err) + AssertNotChannel(t, heartbeatDel) _, err = serv.Top(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) }) } @@ -988,21 +682,13 @@ func TestServiceIntegrationHealth(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) qCalc := &QueueCalc{} qCalc.Monitor(ctx) qComp := &QueueComp{} @@ -1011,7 +697,5 @@ func TestServiceIntegrationHealth(t *testing.T) { qDel.Monitor(ctx) serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel) _, err = serv.Health(ctx) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } diff --git a/domain/service/service_test.go b/domain/service/service_test.go index 8acde0d..19da214 100644 --- a/domain/service/service_test.go +++ b/domain/service/service_test.go @@ -4,10 +4,10 @@ package service import ( "context" - "reflect" "testing" "time" + "github.com/stretchr/testify/assert" "golang.org/x/sync/errgroup" "github.com/zitryss/aye-and-nay/domain/domain" @@ -17,7 +17,6 @@ import ( "github.com/zitryss/aye-and-nay/infrastructure/database" "github.com/zitryss/aye-and-nay/infrastructure/storage" . "github.com/zitryss/aye-and-nay/internal/testing" - "github.com/zitryss/aye-and-nay/pkg/errors" ) func TestServiceAlbum(t *testing.T) { @@ -47,25 +46,15 @@ func TestServiceAlbum(t *testing.T) { serv.StartWorkingPoolComp(ctxComp, gComp) files := []model.File{Png(), Png()} _, err := serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } - v := CheckChannel(t, heartbeatComp) + assert.NoError(t, err) + v := AssertChannel(t, heartbeatComp) p, ok := v.(float64) - if !ok { - t.Error("v.(type) != float64") - } - if !EqualFloat(p, 0.5) { - t.Error("p != 0.5") - } - v = CheckChannel(t, heartbeatComp) + assert.True(t, ok) + assert.InDelta(t, 0.5, p, TOLERANCE) + v = AssertChannel(t, heartbeatComp) p, ok = v.(float64) - if !ok { - t.Error("v.(type) != float64") - } - if !EqualFloat(p, 1) { - t.Error("p != 1") - } + assert.True(t, ok) + assert.InDelta(t, 1, p, TOLERANCE) }) t.Run("Negative", func(t *testing.T) { fn1 := func() func() (uint64, error) { @@ -95,76 +84,44 @@ func TestServiceAlbum(t *testing.T) { serv.StartWorkingPoolComp(ctxComp, gComp) files := []model.File{Png(), Png()} _, err := serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } - v := CheckChannel(t, heartbeatComp) - _ = CheckChannel(t, heartbeatComp) + assert.NoError(t, err) + v := AssertChannel(t, heartbeatComp) + _ = AssertChannel(t, heartbeatComp) err, ok := v.(error) - if !ok { - t.Error("v.(type) != error") - } - if !errors.Is(err, domain.ErrThirdPartyUnavailable) { - t.Error(err) - } + assert.True(t, ok) + assert.ErrorIs(t, err, domain.ErrThirdPartyUnavailable) files = []model.File{Png(), Png()} _, err = serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } - v = CheckChannel(t, heartbeatComp) + assert.NoError(t, err) + v = AssertChannel(t, heartbeatComp) p, ok := v.(float64) - if !ok { - t.Error("v.(type) != float64") - } - if !EqualFloat(p, 0.5) { - t.Error("p != 0.5") - } - v = CheckChannel(t, heartbeatComp) + assert.True(t, ok) + assert.InDelta(t, 0.5, p, TOLERANCE) + v = AssertChannel(t, heartbeatComp) p, ok = v.(float64) - if !ok { - t.Error("v.(type) != float64") - } - if !EqualFloat(p, 1) { - t.Error("p != 1") - } - CheckChannel(t, heartbeatRestart) - CheckChannel(t, heartbeatRestart) + assert.True(t, ok) + assert.InDelta(t, 1, p, TOLERANCE) + AssertChannel(t, heartbeatRestart) + AssertChannel(t, heartbeatRestart) files = []model.File{Png(), Png()} _, err = serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } - v = CheckChannel(t, heartbeatComp) - _ = CheckChannel(t, heartbeatComp) + assert.NoError(t, err) + v = AssertChannel(t, heartbeatComp) + _ = AssertChannel(t, heartbeatComp) err, ok = v.(error) - if !ok { - t.Error("v.(type) != error") - } - if !errors.Is(err, domain.ErrThirdPartyUnavailable) { - t.Error(err) - } + assert.True(t, ok) + assert.ErrorIs(t, err, domain.ErrThirdPartyUnavailable) files = []model.File{Png(), Png()} _, err = serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } - v = CheckChannel(t, heartbeatComp) + assert.NoError(t, err) + v = AssertChannel(t, heartbeatComp) p, ok = v.(float64) - if !ok { - t.Error("v.(type) != float64") - } - if !EqualFloat(p, 0.5) { - t.Error("p != 0.5") - } - v = CheckChannel(t, heartbeatComp) + assert.True(t, ok) + assert.InDelta(t, 0.5, p, TOLERANCE) + v = AssertChannel(t, heartbeatComp) p, ok = v.(float64) - if !ok { - t.Error("v.(type) != float64") - } - if !EqualFloat(p, 1) { - t.Error("p != 1") - } + assert.True(t, ok) + assert.InDelta(t, 1, p, TOLERANCE) }) } @@ -177,8 +134,7 @@ func TestServicePair(t *testing.T) { return 0x3BC5 + i, nil } }() - fn2 := func(n int, swap func(i int, j int)) { - } + fn2 := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() comp := compressor.NewMock() @@ -194,57 +150,31 @@ func TestServicePair(t *testing.T) { serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img7, img8, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img1 := model.Image{Id: 0x3BC7, Token: 0x3BC9, Src: "/api/images/yTsAAAAAAAA/"} img2 := model.Image{Id: 0x3BC8, Token: 0x3BCA, Src: "/api/images/yjsAAAAAAAA/"} imgs1 := []model.Image{img1, img2} - if reflect.DeepEqual(img7, img8) { - t.Error("img7 == img8") - } - if !IsIn(img7, imgs1) { - t.Error("img7 is not in imgs") - } - if !IsIn(img8, imgs1) { - t.Error("img8 is not in imgs") - } + assert.NotEqual(t, img7, img8) + AssertContains(t, imgs1, img7) + AssertContains(t, imgs1, img8) img9, img10, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img3 := model.Image{Id: 0x3BC8, Token: 0x3BCB, Src: "/api/images/yzsAAAAAAAA/"} img4 := model.Image{Id: 0x3BC7, Token: 0x3BCC, Src: "/api/images/zDsAAAAAAAA/"} imgs2 := []model.Image{img3, img4} - if reflect.DeepEqual(img9, img10) { - t.Error("img9 == img10") - } - if !IsIn(img9, imgs2) { - t.Error("img9 is not in imgs") - } - if !IsIn(img10, imgs2) { - t.Error("img10 is not in imgs") - } + assert.NotEqual(t, img9, img10) + AssertContains(t, imgs2, img9) + AssertContains(t, imgs2, img10) img11, img12, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img5 := model.Image{Id: 0x3BC7, Token: 0x3BCD, Src: "/api/images/zTsAAAAAAAA/"} img6 := model.Image{Id: 0x3BC8, Token: 0x3BCE, Src: "/api/images/zjsAAAAAAAA/"} imgs3 := []model.Image{img5, img6} - if reflect.DeepEqual(img11, img12) { - t.Error("img11 == img12") - } - if !IsIn(img11, imgs3) { - t.Error("img11 is not in imgs") - } - if !IsIn(img12, imgs3) { - t.Error("img12 is not in imgs") - } + assert.NotEqual(t, img11, img12) + AssertContains(t, imgs3, img11) + AssertContains(t, imgs3, img12) }) t.Run("Positive2", func(t *testing.T) { fn1 := func() func() (uint64, error) { @@ -254,8 +184,7 @@ func TestServicePair(t *testing.T) { return 0xFAFD + i, nil } }() - fn2 := func(n int, swap func(i int, j int)) { - } + fn2 := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() comp := compressor.NewMock() @@ -273,57 +202,31 @@ func TestServicePair(t *testing.T) { serv := New(conf, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img7, img8, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img1 := model.Image{Id: 0xFAFF, Token: 0xFAFF, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/__oAAAAAAAA"} img2 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} imgs1 := []model.Image{img1, img2} - if reflect.DeepEqual(img7, img8) { - t.Error("img7 == img8") - } - if !IsIn(img7, imgs1) { - t.Error("img7 is not in imgs") - } - if !IsIn(img8, imgs1) { - t.Error("img8 is not in imgs") - } + assert.NotEqual(t, img7, img8) + AssertContains(t, imgs1, img7) + AssertContains(t, imgs1, img8) img9, img10, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img3 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} img4 := model.Image{Id: 0xFAFF, Token: 0xFAFF, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/__oAAAAAAAA"} imgs2 := []model.Image{img3, img4} - if reflect.DeepEqual(img9, img10) { - t.Error("img9 == img10") - } - if !IsIn(img9, imgs2) { - t.Error("img9 is not in imgs") - } - if !IsIn(img10, imgs2) { - t.Error("img10 is not in imgs") - } + assert.NotEqual(t, img9, img10) + AssertContains(t, imgs2, img9) + AssertContains(t, imgs2, img10) img11, img12, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img5 := model.Image{Id: 0xFAFF, Token: 0xFAFF, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/__oAAAAAAAA"} img6 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} imgs3 := []model.Image{img5, img6} - if reflect.DeepEqual(img11, img12) { - t.Error("img11 == img12") - } - if !IsIn(img11, imgs3) { - t.Error("img11 is not in imgs") - } - if !IsIn(img12, imgs3) { - t.Error("img12 is not in imgs") - } + assert.NotEqual(t, img11, img12) + AssertContains(t, imgs3, img11) + AssertContains(t, imgs3, img12) }) t.Run("Negative", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) @@ -340,9 +243,7 @@ func TestServicePair(t *testing.T) { qDel.Monitor(ctx) serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel) _, _, err := serv.Pair(ctx, 0xEB46) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } @@ -355,8 +256,7 @@ func TestServiceImage(t *testing.T) { return 0xA83F + i, nil } }() - fn2 := func(n int, swap func(i int, j int)) { - } + fn2 := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() comp := compressor.NewMock() @@ -372,27 +272,15 @@ func TestServiceImage(t *testing.T) { serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img1, img2, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) f, err := serv.Image(ctx, img1.Token) - if err != nil { - t.Error(err) - } - if f.Reader == nil { - t.Error("f.Reader == nil") - } + assert.NoError(t, err) + assert.NotNil(t, f.Reader) f, err = serv.Image(ctx, img2.Token) - if err != nil { - t.Error(err) - } - if f.Reader == nil { - t.Error("f.Reader == nil") - } + assert.NoError(t, err) + assert.NotNil(t, f.Reader) }) t.Run("Negative", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) @@ -409,9 +297,7 @@ func TestServiceImage(t *testing.T) { qDel.Monitor(ctx) serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel) _, err := serv.Image(ctx, 0xE283) - if !errors.Is(err, domain.ErrTokenNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) } @@ -424,8 +310,7 @@ func TestServiceVote(t *testing.T) { return 0xC389 + i, nil } }() - fn2 := func(n int, swap func(i int, j int)) { - } + fn2 := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() comp := compressor.NewMock() @@ -441,17 +326,11 @@ func TestServiceVote(t *testing.T) { serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img1, img2, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = serv.Vote(ctx, album, img1.Token, img2.Token) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) }) t.Run("Positive2", func(t *testing.T) { fn1 := func() func() (uint64, error) { @@ -461,8 +340,7 @@ func TestServiceVote(t *testing.T) { return 0x1E58 + i, nil } }() - fn2 := func(n int, swap func(i int, j int)) { - } + fn2 := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() comp := compressor.NewMock() @@ -480,17 +358,11 @@ func TestServiceVote(t *testing.T) { serv := New(conf, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img1, img2, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = serv.Vote(ctx, album, img1.Token, img2.Token) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) }) t.Run("Negative1", func(t *testing.T) { fn1 := func() func() (uint64, error) { @@ -500,8 +372,7 @@ func TestServiceVote(t *testing.T) { return 0xE24F + i, nil } }() - fn2 := func(n int, swap func(i int, j int)) { - } + fn2 := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() comp := compressor.NewMock() @@ -517,17 +388,11 @@ func TestServiceVote(t *testing.T) { serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img1, img2, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = serv.Vote(ctx, 0x12E6, img1.Token, img2.Token) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative2", func(t *testing.T) { fn1 := func() func() (uint64, error) { @@ -537,8 +402,7 @@ func TestServiceVote(t *testing.T) { return 0xBC43 + i, nil } }() - fn2 := func(n int, swap func(i int, j int)) { - } + fn2 := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() comp := compressor.NewMock() @@ -554,17 +418,11 @@ func TestServiceVote(t *testing.T) { serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) _, _, err = serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = serv.Vote(ctx, album, 0x1CC1, 0xF83C) - if !errors.Is(err, domain.ErrTokenNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) } @@ -577,8 +435,7 @@ func TestServiceTop(t *testing.T) { return 0x4DB8 + i, nil } }() - fn2 := func(n int, swap func(i int, j int)) { - } + fn2 := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() comp := compressor.NewMock() @@ -597,37 +454,23 @@ func TestServiceTop(t *testing.T) { serv.StartWorkingPoolCalc(ctxCalc, gCalc) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img1, img2, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = serv.Vote(ctx, album, img1.Token, img2.Token) - if err != nil { - t.Error(err) - } - CheckChannel(t, heartbeatCalc) + assert.NoError(t, err) + AssertChannel(t, heartbeatCalc) img3, img4, err := serv.Pair(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = serv.Vote(ctx, album, img3.Token, img4.Token) - if err != nil { - t.Error(err) - } - CheckChannel(t, heartbeatCalc) + assert.NoError(t, err) + AssertChannel(t, heartbeatCalc) imgs1, err := serv.Top(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img5 := model.Image{Id: 0x4DBA, Src: "/aye-and-nay/albums/uU0AAAAAAAA/images/uk0AAAAAAAA", Rating: 0.5, Compressed: false} img6 := model.Image{Id: 0x4DBB, Src: "/aye-and-nay/albums/uU0AAAAAAAA/images/u00AAAAAAAA", Rating: 0.5, Compressed: false} imgs2 := []model.Image{img5, img6} - if !reflect.DeepEqual(imgs1, imgs2) { - t.Error("imgs1 != imgs2") - } + assert.Equal(t, imgs2, imgs1) }) t.Run("Negative", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) @@ -644,9 +487,7 @@ func TestServiceTop(t *testing.T) { qDel.Monitor(ctx) serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel) _, err := serv.Top(ctx, 0x83CD) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } @@ -667,31 +508,21 @@ func TestServiceDelete(t *testing.T) { alb1 := AlbumEmptyFactory(0x101F) alb1.Expires = time.Now().Add(-1 * time.Hour) err := mDb.SaveAlbum(ctx, alb1) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) alb2 := AlbumEmptyFactory(0xFFBB) alb2.Expires = time.Now().Add(1 * time.Hour) err = mDb.SaveAlbum(ctx, alb2) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) heartbeatDel := make(chan interface{}) serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) err = serv.CleanUp(ctx) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) gDel, ctxDel := errgroup.WithContext(ctx) serv.StartWorkingPoolDel(ctxDel, gDel) - v := CheckChannel(t, heartbeatDel) + v := AssertChannel(t, heartbeatDel) album, ok := v.(uint64) - if !ok { - t.Error("v.(type) != uint64") - } - if album != 0x101F { - t.Error("album != 0x101F") - } + assert.True(t, ok) + assert.Equal(t, uint64(0x101F), album) }) t.Run("Positive2", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) @@ -713,14 +544,10 @@ func TestServiceDelete(t *testing.T) { files := []model.File{Png(), Png()} dur := 100 * time.Millisecond album, err := serv.Album(ctx, files, dur) - if err != nil { - t.Error(err) - } - CheckChannel(t, heartbeatDel) + assert.NoError(t, err) + AssertChannel(t, heartbeatDel) _, err = serv.Top(ctx, album) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) @@ -742,18 +569,10 @@ func TestServiceDelete(t *testing.T) { files := []model.File{Png(), Png()} dur := 0 * time.Second album, err := serv.Album(ctx, files, dur) - if err != nil { - t.Error(err) - } - select { - case <-heartbeatDel: - t.Error("<-heartbeatDel") - case <-time.After(1 * time.Second): - } + assert.NoError(t, err) + AssertNotChannel(t, heartbeatDel) _, err = serv.Top(ctx, album) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) }) } @@ -772,7 +591,5 @@ func TestServiceHealth(t *testing.T) { qDel.Monitor(ctx) serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel) _, err := serv.Health(ctx) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } diff --git a/go.mod b/go.mod index 0799cee..b05b4fb 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( github.com/radovskyb/watcher v1.0.7 github.com/rs/cors v1.8.0 github.com/spf13/viper v1.9.0 + github.com/stretchr/testify v1.7.0 go.mongodb.org/mongo-driver v1.8.0 golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c golang.org/x/sync v0.0.0-20210220032951-036812b2e83c @@ -32,6 +33,7 @@ require ( github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/containerd/continuity v0.1.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgraph-io/ristretto v0.1.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/docker/go-connections v0.4.0 // indirect @@ -73,6 +75,7 @@ require ( github.com/opencontainers/runc v1.0.0-rc95 // indirect github.com/pelletier/go-toml v1.9.4 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rs/xid v1.3.0 // indirect github.com/sirupsen/logrus v1.8.1 // indirect github.com/spf13/afero v1.6.0 // indirect @@ -98,4 +101,5 @@ require ( gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect gopkg.in/ini.v1 v1.66.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) diff --git a/infrastructure/cache/config.go b/infrastructure/cache/config.go index 9edf4ac..20543b7 100644 --- a/infrastructure/cache/config.go +++ b/infrastructure/cache/config.go @@ -41,8 +41,8 @@ var ( RetryTimes: 4, RetryPause: 5 * time.Second, Timeout: 30 * time.Second, - LimiterRequestsPerSecond: 30000, - LimiterBurst: 300, + LimiterRequestsPerSecond: 100, + LimiterBurst: 10, TimeToLive: 1 * time.Second, } ) diff --git a/infrastructure/cache/mem_test.go b/infrastructure/cache/mem_test.go index 49b16e0..d09dfd4 100644 --- a/infrastructure/cache/mem_test.go +++ b/infrastructure/cache/mem_test.go @@ -7,66 +7,47 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/zitryss/aye-and-nay/domain/domain" . "github.com/zitryss/aye-and-nay/internal/testing" - "github.com/zitryss/aye-and-nay/pkg/errors" ) func TestMemPair(t *testing.T) { t.Run("Positive", func(t *testing.T) { mem := NewMem(DefaultMemConfig) err := mem.Push(context.Background(), 0x23D2, [][2]uint64{{0x3E3D, 0xB399}}) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) image1, image2, err := mem.Pop(context.Background(), 0x23D2) - if err != nil { - t.Error(err) - } - if image1 != 0x3E3D { - t.Error("image1 != 0x3E3D") - } - if image2 != 0xB399 { - t.Error("image2 != 0xB399") - } + assert.NoError(t, err) + assert.Equal(t, uint64(0x3E3D), image1) + assert.Equal(t, uint64(0xB399), image2) }) t.Run("Negative1", func(t *testing.T) { mem := NewMem(DefaultMemConfig) _, _, err := mem.Pop(context.Background(), 0x73BF) - if !errors.Is(err, domain.ErrPairNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrPairNotFound) }) t.Run("Negative2", func(t *testing.T) { mem := NewMem(DefaultMemConfig) err := mem.Push(context.Background(), 0x1AE9, [][2]uint64{{0x44DC, 0x721B}}) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) _, _, err = mem.Pop(context.Background(), 0x1AE9) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) _, _, err = mem.Pop(context.Background(), 0x1AE9) - if !errors.Is(err, domain.ErrPairNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrPairNotFound) }) t.Run("Negative3", func(t *testing.T) { heartbeatPair := make(chan interface{}) mem := NewMem(DefaultMemConfig, WithHeartbeatPair(heartbeatPair)) mem.Monitor() err := mem.Push(context.Background(), 0xF51A, [][2]uint64{{0x4BB0, 0x3A87}}) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) time.Sleep(mem.conf.TimeToLive) - CheckChannel(t, heartbeatPair) - CheckChannel(t, heartbeatPair) + AssertChannel(t, heartbeatPair) + AssertChannel(t, heartbeatPair) _, _, err = mem.Pop(context.Background(), 0xF51A) - if !errors.Is(err, domain.ErrPairNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrPairNotFound) }) } @@ -77,19 +58,11 @@ func TestMemToken(t *testing.T) { album1 := uint64(0xB41C) image1 := uint64(0x52BD) err := mem.Set(context.Background(), token, album1, image1) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) album2, image2, err := mem.Get(context.Background(), token) - if err != nil { - t.Error(err) - } - if album1 != album2 { - t.Error("album1 != album2") - } - if image1 != image2 { - t.Error("image1 != image2") - } + assert.NoError(t, err) + assert.Equal(t, album1, album2) + assert.Equal(t, image1, image2) }) t.Run("Negative1", func(t *testing.T) { mem := NewMem(DefaultMemConfig) @@ -97,21 +70,15 @@ func TestMemToken(t *testing.T) { album := uint64(0xF0EE) image := uint64(0x583C) err := mem.Set(context.Background(), token, album, image) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = mem.Set(context.Background(), token, album, image) - if !errors.Is(err, domain.ErrTokenAlreadyExists) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrTokenAlreadyExists) }) t.Run("Negative2", func(t *testing.T) { mem := NewMem(DefaultMemConfig) token := uint64(0xC4F8) _, _, err := mem.Get(context.Background(), token) - if !errors.Is(err, domain.ErrTokenNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) t.Run("Negative3", func(t *testing.T) { mem := NewMem(DefaultMemConfig) @@ -119,33 +86,21 @@ func TestMemToken(t *testing.T) { album := uint64(0xC67F) image := uint64(0x7C45) err := mem.Set(context.Background(), token, album, image) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) _, _, err = mem.Get(context.Background(), token) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = mem.Del(context.Background(), token) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = mem.Del(context.Background(), token) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) _, _, err = mem.Get(context.Background(), token) - if !errors.Is(err, domain.ErrTokenNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) t.Run("Negative4", func(t *testing.T) { mem := NewMem(DefaultMemConfig) token := uint64(0xD3BF) err := mem.Del(context.Background(), token) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) }) t.Run("Negative5", func(t *testing.T) { heartbeatToken := make(chan interface{}) @@ -155,15 +110,11 @@ func TestMemToken(t *testing.T) { album := uint64(0xCF1E) image := uint64(0xDD0A) err := mem.Set(context.Background(), token, album, image) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) time.Sleep(mem.conf.TimeToLive) - CheckChannel(t, heartbeatToken) - CheckChannel(t, heartbeatToken) + AssertChannel(t, heartbeatToken) + AssertChannel(t, heartbeatToken) _, _, err = mem.Get(context.Background(), token) - if !errors.Is(err, domain.ErrTokenNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) } diff --git a/infrastructure/cache/redis_integration_test.go b/infrastructure/cache/redis_integration_test.go index a829933..4f1d2ad 100644 --- a/infrastructure/cache/redis_integration_test.go +++ b/infrastructure/cache/redis_integration_test.go @@ -7,8 +7,10 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/zitryss/aye-and-nay/domain/domain" - "github.com/zitryss/aye-and-nay/pkg/errors" ) func TestRedisAllow(t *testing.T) { @@ -17,375 +19,204 @@ func TestRedisAllow(t *testing.T) { t.Skip("short flag is set") } redis, err := NewRedis(context.Background(), DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) rpm := redis.conf.LimiterRequestsPerSecond for j := 0; j < rpm; j++ { allowed, err := redis.Allow(context.Background(), 0xDEAD) - if err != nil { - t.Error(err) - } - if !allowed { - t.Error("!allowed") - } + assert.NoError(t, err) + assert.True(t, allowed) } time.Sleep(1 * time.Second) for j := 0; j < rpm; j++ { allowed, err := redis.Allow(context.Background(), 0xDEAD) - if err != nil { - t.Error(err) - } - if !allowed { - t.Error("!allowed") - } + assert.NoError(t, err) + assert.True(t, allowed) } }) t.Run("Negative", func(t *testing.T) { + t.Skip("flaky test") redis, err := NewRedis(context.Background(), DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) rps := redis.conf.LimiterRequestsPerSecond for i := 0; i < rps; i++ { allowed, err := redis.Allow(context.Background(), 0xBEEF) - if err != nil { - t.Error(err) - } - if !allowed { - t.Error("!allowed") - } + assert.NoError(t, err) + assert.True(t, allowed) } allowed, err := redis.Allow(context.Background(), 0xBEEF) - if err != nil { - t.Error(err) - } - if allowed { - t.Error("allowed") - } + assert.NoError(t, err) + assert.False(t, allowed) }) } func TestRedisQueue(t *testing.T) { redis, err := NewRedis(context.Background(), DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) n, err := redis.Size(context.Background(), 0x5D6D) - if err != nil { - t.Error(err) - } - if n != 0 { - t.Error("n != 0") - } + assert.NoError(t, err) + assert.Equal(t, 0, n) err = redis.Add(context.Background(), 0x5D6D, 0x1ED1) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = redis.Add(context.Background(), 0x5D6D, 0x1ED1) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = redis.Add(context.Background(), 0x5D6D, 0xF612) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = redis.Add(context.Background(), 0x5D6D, 0x1A83) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = redis.Add(context.Background(), 0x5D6D, 0xF612) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) n, err = redis.Size(context.Background(), 0x5D6D) - if err != nil { - t.Error(err) - } - if n != 3 { - t.Error("n != 3") - } + assert.NoError(t, err) + assert.Equal(t, 3, n) album, err := redis.Poll(context.Background(), 0x5D6D) - if err != nil { - t.Error(err) - } - if album != 0x1ED1 { - t.Error("album != 0x1ED1") - } + assert.NoError(t, err) + assert.Equal(t, uint64(0x1ED1), album) n, err = redis.Size(context.Background(), 0x5D6D) - if err != nil { - t.Error(err) - } - if n != 2 { - t.Error("n != 2") - } + assert.NoError(t, err) + assert.Equal(t, 2, n) album, err = redis.Poll(context.Background(), 0x5D6D) - if err != nil { - t.Error(err) - } - if album != 0xF612 { - t.Error("album != 0xF612") - } + assert.NoError(t, err) + assert.Equal(t, uint64(0xF612), album) album, err = redis.Poll(context.Background(), 0x5D6D) - if err != nil { - t.Error(err) - } - if album != 0x1A83 { - t.Error("album != 0x1A83") - } + assert.NoError(t, err) + assert.Equal(t, uint64(0x1A83), album) n, err = redis.Size(context.Background(), 0x5D6D) - if err != nil { - t.Error(err) - } - if n != 0 { - t.Error("n != 0") - } + assert.NoError(t, err) + assert.Equal(t, 0, n) album, err = redis.Poll(context.Background(), 0x5D6D) - if err == nil { - t.Error(err) - } - if album != 0x0 { - t.Error("album != \"0x0\"") - } + assert.Error(t, err) + assert.Equal(t, uint64(0x0), album) n, err = redis.Size(context.Background(), 0x5D6D) - if err != nil { - t.Error(err) - } - if n != 0 { - t.Error("n != 0") - } + assert.NoError(t, err) + assert.Equal(t, 0, n) _, err = redis.Poll(context.Background(), 0x5D6D) - if !errors.Is(err, domain.ErrUnknown) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrUnknown) } func TestRedisPQueue(t *testing.T) { redis, err := NewRedis(context.Background(), DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) n, err := redis.PSize(context.Background(), 0x7D31) - if err != nil { - t.Error(err) - } - if n != 0 { - t.Error("n != 0") - } + assert.NoError(t, err) + assert.Equal(t, 0, n) err = redis.PAdd(context.Background(), 0x7D31, 0xE976, time.Unix(904867200, 0)) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = redis.PAdd(context.Background(), 0x7D31, 0xEC0E, time.Unix(1075852800, 0)) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = redis.PAdd(context.Background(), 0x7D31, 0x4CAF, time.Unix(681436800, 0)) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) n, err = redis.PSize(context.Background(), 0x7D31) - if err != nil { - t.Error(err) - } - if n != 3 { - t.Error("n != 3") - } + assert.NoError(t, err) + assert.Equal(t, 3, n) album, expires, err := redis.PPoll(context.Background(), 0x7D31) - if err != nil { - t.Error(err) - } - if album != 0x4CAF { - t.Error("album != 0x4CAF") - } - if !expires.Equal(time.Unix(681436800, 0)) { - t.Error("!expires.Equal(time.Unix(681436800, 0))") - } + assert.NoError(t, err) + assert.Equal(t, uint64(0x4CAF), album) + assert.True(t, expires.Equal(time.Unix(681436800, 0))) n, err = redis.PSize(context.Background(), 0x7D31) - if err != nil { - t.Error(err) - } - if n != 2 { - t.Error("n != 2") - } + assert.NoError(t, err) + assert.Equal(t, 2, n) album, expires, err = redis.PPoll(context.Background(), 0x7D31) - if err != nil { - t.Error(err) - } - if album != 0xE976 { - t.Error("album != 0xE976") - } - if !expires.Equal(time.Unix(904867200, 0)) { - t.Error("!expires.Equal(time.Unix(904867200, 0))") - } + assert.NoError(t, err) + assert.Equal(t, uint64(0xE976), album) + assert.True(t, expires.Equal(time.Unix(904867200, 0))) album, expires, err = redis.PPoll(context.Background(), 0x7D31) - if err != nil { - t.Error(err) - } - if album != 0xEC0E { - t.Error("album != 0xEC0E") - } - if !expires.Equal(time.Unix(1075852800, 0)) { - t.Error("!expires.Equal(time.Unix(1075852800, 0))") - } + assert.NoError(t, err) + assert.Equal(t, uint64(0xEC0E), album) + assert.True(t, expires.Equal(time.Unix(1075852800, 0))) n, err = redis.PSize(context.Background(), 0x7D31) - if err != nil { - t.Error(err) - } - if n != 0 { - t.Error("n != 0") - } + assert.NoError(t, err) + assert.Equal(t, 0, n) _, _, err = redis.PPoll(context.Background(), 0x7D31) - if !errors.Is(err, domain.ErrUnknown) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrUnknown) } func TestRedisPair(t *testing.T) { t.Run("Positive", func(t *testing.T) { redis, err := NewRedis(context.Background(), DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) image1 := uint64(0x3E3D) image2 := uint64(0xB399) err = redis.Push(context.Background(), 0x23D2, [][2]uint64{{image1, image2}}) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) image3, image4, err := redis.Pop(context.Background(), 0x23D2) - if err != nil { - t.Error(err) - } - if image1 != image3 { - t.Error("image1 != image3") - } - if image2 != image4 { - t.Error("image2 != image4") - } + assert.NoError(t, err) + assert.Equal(t, image1, image3) + assert.Equal(t, image2, image4) }) t.Run("Negative1", func(t *testing.T) { redis, err := NewRedis(context.Background(), DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) _, _, err = redis.Pop(context.Background(), 0x73BF) - if !errors.Is(err, domain.ErrPairNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrPairNotFound) }) t.Run("Negative2", func(t *testing.T) { redis, err := NewRedis(context.Background(), DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) image1 := uint64(0x44DC) image2 := uint64(0x721B) err = redis.Push(context.Background(), 0x1AE9, [][2]uint64{{image1, image2}}) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) _, _, err = redis.Pop(context.Background(), 0x1AE9) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) _, _, err = redis.Pop(context.Background(), 0x1AE9) - if !errors.Is(err, domain.ErrPairNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrPairNotFound) }) } func TestRedisToken(t *testing.T) { t.Run("Positive", func(t *testing.T) { redis, err := NewRedis(context.Background(), DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) token := uint64(0xC2E7) album1 := uint64(0xB41C) image1 := uint64(0x52BD) err = redis.Set(context.Background(), token, album1, image1) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) album2, image2, err := redis.Get(context.Background(), token) - if err != nil { - t.Error(err) - } - if album1 != album2 { - t.Error("album1 != album2") - } - if image1 != image2 { - t.Error("image1 != image2") - } + assert.NoError(t, err) + assert.Equal(t, album1, album2) + assert.Equal(t, image1, image2) }) t.Run("Negative1", func(t *testing.T) { redis, err := NewRedis(context.Background(), DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) token := uint64(0x1C4A) album := uint64(0xF0EE) image := uint64(0x583C) err = redis.Set(context.Background(), token, album, image) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = redis.Set(context.Background(), token, album, image) - if !errors.Is(err, domain.ErrTokenAlreadyExists) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrTokenAlreadyExists) }) t.Run("Negative2", func(t *testing.T) { redis, err := NewRedis(context.Background(), DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) token := uint64(0xC4F8) _, _, err = redis.Get(context.Background(), token) - if !errors.Is(err, domain.ErrTokenNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) t.Run("Negative3", func(t *testing.T) { redis, err := NewRedis(context.Background(), DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) token := uint64(0xEB96) album := uint64(0xC67F) image := uint64(0x7C45) err = redis.Set(context.Background(), token, album, image) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) _, _, err = redis.Get(context.Background(), token) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = redis.Del(context.Background(), token) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = redis.Del(context.Background(), token) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) _, _, err = redis.Get(context.Background(), token) - if !errors.Is(err, domain.ErrTokenNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) t.Run("Negative4", func(t *testing.T) { redis, err := NewRedis(context.Background(), DefaultRedisConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) token := uint64(0xD3BF) err = redis.Del(context.Background(), token) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) }) } diff --git a/infrastructure/compressor/imaginary_integration_test.go b/infrastructure/compressor/imaginary_integration_test.go index 558bfab..3e1ef3f 100644 --- a/infrastructure/compressor/imaginary_integration_test.go +++ b/infrastructure/compressor/imaginary_integration_test.go @@ -8,6 +8,9 @@ import ( "os" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/zitryss/aye-and-nay/domain/model" ) @@ -31,22 +34,13 @@ func TestImaginaryPositive(t *testing.T) { for _, tt := range tests { t.Run("", func(t *testing.T) { im, err := NewImaginary(context.Background(), DefaultImaginaryConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) b, err := os.ReadFile("../../testdata/" + tt.filename) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) buf := bytes.NewBuffer(b) - f := model.File{ - Reader: buf, - Size: int64(buf.Len()), - } + f := model.File{Reader: buf, Size: int64(buf.Len())} _, err = im.Compress(context.Background(), f) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) }) } } @@ -56,34 +50,19 @@ func TestImaginaryNegative(t *testing.T) { t.Skip("short flag is set") } im, err := NewImaginary(context.Background(), DefaultImaginaryConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) b, err := os.ReadFile("../../testdata/john.bmp") - if err != nil { - t.Error(err) - } + assert.NoError(t, err) buf := bytes.NewBuffer(b) - f1 := model.File{ - Reader: buf, - Size: int64(buf.Len()), - } + f1 := model.File{Reader: buf, Size: int64(buf.Len())} f2, err := im.Compress(context.Background(), f1) - if err != nil { - t.Error(err) - } - if f1.Size != f2.Size { - t.Error("f1.Size != f2.Size") - } + assert.NoError(t, err) + assert.Equal(t, f1.Size, f2.Size) } func TestImaginaryHealth(t *testing.T) { im, err := NewImaginary(context.Background(), DefaultImaginaryConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) _, err = im.Health(context.Background()) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } diff --git a/infrastructure/compressor/shortpixel_test.go b/infrastructure/compressor/shortpixel_test.go index 9e9b057..ed077e1 100644 --- a/infrastructure/compressor/shortpixel_test.go +++ b/infrastructure/compressor/shortpixel_test.go @@ -11,9 +11,10 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/zitryss/aye-and-nay/domain/domain" . "github.com/zitryss/aye-and-nay/internal/testing" - "github.com/zitryss/aye-and-nay/pkg/errors" ) type response []struct { @@ -43,9 +44,7 @@ func TestShortpixel(t *testing.T) { t.Run("Positive1", func(t *testing.T) { fn1 := func(w http.ResponseWriter, r *http.Request) { _, err := io.Copy(w, Png()) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver1 := httptest.NewServer(http.HandlerFunc(fn1)) defer mockserver1.Close() @@ -78,9 +77,7 @@ func TestShortpixel(t *testing.T) { }, } err := json.NewEncoder(w).Encode(resp) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() @@ -88,16 +85,12 @@ func TestShortpixel(t *testing.T) { conf.Url = mockserver2.URL sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) }) t.Run("Positive2", func(t *testing.T) { fn1 := func(w http.ResponseWriter, r *http.Request) { _, err := io.Copy(w, Png()) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver1 := httptest.NewServer(http.HandlerFunc(fn1)) defer mockserver1.Close() @@ -127,9 +120,7 @@ func TestShortpixel(t *testing.T) { } ]` _, err := io.WriteString(w, resp) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() @@ -137,9 +128,7 @@ func TestShortpixel(t *testing.T) { conf.Url = mockserver2.URL sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) }) t.Run("NegativeInvalidUrl1", func(t *testing.T) { fn1 := func(w http.ResponseWriter, r *http.Request) { @@ -150,9 +139,7 @@ func TestShortpixel(t *testing.T) { conf.Url = mockserver1.URL sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) - if !errors.Is(err, domain.ErrThirdPartyUnavailable) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrThirdPartyUnavailable) }) t.Run("NegativeInvalidUrl2", func(t *testing.T) { fn1 := func(w http.ResponseWriter, r *http.Request) { @@ -188,9 +175,7 @@ func TestShortpixel(t *testing.T) { }, } err := json.NewEncoder(w).Encode(resp) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() @@ -198,9 +183,7 @@ func TestShortpixel(t *testing.T) { conf.Url = mockserver2.URL sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) - if !errors.Is(err, domain.ErrThirdPartyUnavailable) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrThirdPartyUnavailable) }) t.Run("NegativeTimeout1", func(t *testing.T) { conf := DefaultShortpixelConfig @@ -212,9 +195,7 @@ func TestShortpixel(t *testing.T) { conf.Url = mockserver1.URL sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) - if !errors.Is(err, domain.ErrThirdPartyUnavailable) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrThirdPartyUnavailable) }) t.Run("NegativeTimeout2", func(t *testing.T) { conf := DefaultShortpixelConfig @@ -252,18 +233,14 @@ func TestShortpixel(t *testing.T) { }, } err := json.NewEncoder(w).Encode(resp) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() conf.Url = mockserver2.URL sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) - if !errors.Is(err, domain.ErrThirdPartyUnavailable) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrThirdPartyUnavailable) }) t.Run("NegativeErrorHttpCode1", func(t *testing.T) { fn1 := func(w http.ResponseWriter, r *http.Request) { @@ -275,9 +252,7 @@ func TestShortpixel(t *testing.T) { conf.Url = mockserver1.URL sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) - if !errors.Is(err, domain.ErrThirdPartyUnavailable) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrThirdPartyUnavailable) }) t.Run("NegativeErrorHttpCode2", func(t *testing.T) { fn1 := func(w http.ResponseWriter, r *http.Request) { @@ -314,9 +289,7 @@ func TestShortpixel(t *testing.T) { }, } err := json.NewEncoder(w).Encode(resp) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() @@ -324,9 +297,7 @@ func TestShortpixel(t *testing.T) { conf.Url = mockserver2.URL sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) - if !errors.Is(err, domain.ErrThirdPartyUnavailable) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrThirdPartyUnavailable) }) t.Run("NegativeInvalidJson", func(t *testing.T) { fn1 := func(w http.ResponseWriter, r *http.Request) { @@ -354,9 +325,7 @@ func TestShortpixel(t *testing.T) { } ` _, err := io.WriteString(w, resp) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver1 := httptest.NewServer(http.HandlerFunc(fn1)) defer mockserver1.Close() @@ -364,9 +333,7 @@ func TestShortpixel(t *testing.T) { conf.Url = mockserver1.URL sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) - if !errors.Is(err, domain.ErrThirdPartyUnavailable) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrThirdPartyUnavailable) }) t.Run("NegativeErrorStatusCode1", func(t *testing.T) { fn1 := func(w http.ResponseWriter, r *http.Request) { @@ -382,9 +349,7 @@ func TestShortpixel(t *testing.T) { }, } err := json.NewEncoder(w).Encode(resp[0]) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver1 := httptest.NewServer(http.HandlerFunc(fn1)) defer mockserver1.Close() @@ -392,9 +357,7 @@ func TestShortpixel(t *testing.T) { conf.Url = mockserver1.URL sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) - if !errors.Is(err, domain.ErrThirdPartyUnavailable) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrThirdPartyUnavailable) }) t.Run("NegativeErrorStatusCode2", func(t *testing.T) { fn1 := func(w http.ResponseWriter, r *http.Request) { @@ -410,9 +373,7 @@ func TestShortpixel(t *testing.T) { }, } err := json.NewEncoder(w).Encode(resp[0]) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver1 := httptest.NewServer(http.HandlerFunc(fn1)) defer mockserver1.Close() @@ -420,9 +381,7 @@ func TestShortpixel(t *testing.T) { conf.Url = mockserver1.URL sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) - if !errors.Is(err, domain.ErrNotImage) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrNotImage) }) t.Run("NegativeErrorStatusCode3", func(t *testing.T) { fn1 := func(w http.ResponseWriter, r *http.Request) { @@ -438,9 +397,7 @@ func TestShortpixel(t *testing.T) { }, } err := json.NewEncoder(w).Encode(resp[0]) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver1 := httptest.NewServer(http.HandlerFunc(fn1)) defer mockserver1.Close() @@ -448,16 +405,12 @@ func TestShortpixel(t *testing.T) { conf.Url = mockserver1.URL sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) - if !errors.Is(err, domain.ErrNotImage) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrNotImage) }) t.Run("PositiveRecovery1", func(t *testing.T) { fn1 := func(w http.ResponseWriter, r *http.Request) { _, err := io.Copy(w, Png()) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver1 := httptest.NewServer(http.HandlerFunc(fn1)) defer mockserver1.Close() @@ -490,9 +443,7 @@ func TestShortpixel(t *testing.T) { }, } err := json.NewEncoder(w).Encode(resp) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() @@ -512,9 +463,7 @@ func TestShortpixel(t *testing.T) { }, } err := json.NewEncoder(w).Encode(resp) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver3 := httptest.NewServer(http.HandlerFunc(fn3)) defer mockserver3.Close() @@ -523,16 +472,12 @@ func TestShortpixel(t *testing.T) { conf.Url2 = mockserver2.URL sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) }) t.Run("PositiveRecovery2", func(t *testing.T) { fn1 := func(w http.ResponseWriter, r *http.Request) { _, err := io.Copy(w, Png()) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver1 := httptest.NewServer(http.HandlerFunc(fn1)) defer mockserver1.Close() @@ -562,9 +507,7 @@ func TestShortpixel(t *testing.T) { } ]` _, err := io.WriteString(w, resp) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() @@ -581,9 +524,7 @@ func TestShortpixel(t *testing.T) { } ]` _, err := io.WriteString(w, resp) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver3 := httptest.NewServer(http.HandlerFunc(fn3)) defer mockserver3.Close() @@ -592,9 +533,7 @@ func TestShortpixel(t *testing.T) { conf.Url2 = mockserver2.URL sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) }) t.Run("NegativeRecoveryInvalidUrl", func(t *testing.T) { fn1 := func(w http.ResponseWriter, r *http.Request) { @@ -617,9 +556,7 @@ func TestShortpixel(t *testing.T) { }, } err := json.NewEncoder(w).Encode(resp) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() @@ -628,9 +565,7 @@ func TestShortpixel(t *testing.T) { conf.Url2 = mockserver1.URL sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) - if !errors.Is(err, domain.ErrThirdPartyUnavailable) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrThirdPartyUnavailable) }) t.Run("NegativeRecoveryTimeout", func(t *testing.T) { conf := DefaultShortpixelConfig @@ -655,9 +590,7 @@ func TestShortpixel(t *testing.T) { }, } err := json.NewEncoder(w).Encode(resp) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() @@ -665,9 +598,7 @@ func TestShortpixel(t *testing.T) { conf.Url2 = mockserver1.URL sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) - if !errors.Is(err, domain.ErrThirdPartyUnavailable) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrThirdPartyUnavailable) }) t.Run("NegativeRecoveryErrorHttpCode", func(t *testing.T) { fn1 := func(w http.ResponseWriter, r *http.Request) { @@ -691,9 +622,7 @@ func TestShortpixel(t *testing.T) { }, } err := json.NewEncoder(w).Encode(resp) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() @@ -702,9 +631,7 @@ func TestShortpixel(t *testing.T) { conf.Url2 = mockserver1.URL sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) - if !errors.Is(err, domain.ErrThirdPartyUnavailable) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrThirdPartyUnavailable) }) t.Run("NegativeRecoveryInvalidJson", func(t *testing.T) { fn1 := func(w http.ResponseWriter, r *http.Request) { @@ -732,9 +659,7 @@ func TestShortpixel(t *testing.T) { } ` _, err := io.WriteString(w, resp) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver1 := httptest.NewServer(http.HandlerFunc(fn1)) defer mockserver1.Close() @@ -754,9 +679,7 @@ func TestShortpixel(t *testing.T) { }, } err := json.NewEncoder(w).Encode(resp) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() @@ -765,9 +688,7 @@ func TestShortpixel(t *testing.T) { conf.Url2 = mockserver1.URL sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) - if !errors.Is(err, domain.ErrThirdPartyUnavailable) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrThirdPartyUnavailable) }) t.Run("NegativeRecoveryErrorStatusCode", func(t *testing.T) { fn1 := func(w http.ResponseWriter, r *http.Request) { @@ -783,9 +704,7 @@ func TestShortpixel(t *testing.T) { }, } err := json.NewEncoder(w).Encode(resp[0]) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver1 := httptest.NewServer(http.HandlerFunc(fn1)) defer mockserver1.Close() @@ -805,9 +724,7 @@ func TestShortpixel(t *testing.T) { }, } err := json.NewEncoder(w).Encode(resp) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() @@ -816,9 +733,7 @@ func TestShortpixel(t *testing.T) { conf.Url2 = mockserver1.URL sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) - if !errors.Is(err, domain.ErrThirdPartyUnavailable) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrThirdPartyUnavailable) }) t.Run("NegativeRecoveryProcessingStatusCode", func(t *testing.T) { fn1 := func(w http.ResponseWriter, r *http.Request) { @@ -837,9 +752,7 @@ func TestShortpixel(t *testing.T) { }, } err := json.NewEncoder(w).Encode(resp[0]) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver1 := httptest.NewServer(http.HandlerFunc(fn1)) defer mockserver1.Close() @@ -859,9 +772,7 @@ func TestShortpixel(t *testing.T) { }, } err := json.NewEncoder(w).Encode(resp) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } mockserver2 := httptest.NewServer(http.HandlerFunc(fn2)) defer mockserver2.Close() @@ -870,8 +781,6 @@ func TestShortpixel(t *testing.T) { conf.Url2 = mockserver1.URL sp := NewShortpixel(conf) _, err := sp.Compress(context.Background(), Png()) - if !errors.Is(err, domain.ErrThirdPartyUnavailable) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrThirdPartyUnavailable) }) } diff --git a/infrastructure/database/badger_test.go b/infrastructure/database/badger_test.go index 08694cd..ac68b47 100644 --- a/infrastructure/database/badger_test.go +++ b/infrastructure/database/badger_test.go @@ -4,335 +4,206 @@ package database import ( "context" - "reflect" "sort" "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/model" . "github.com/zitryss/aye-and-nay/internal/testing" - "github.com/zitryss/aye-and-nay/pkg/errors" ) func TestBadgerAlbum(t *testing.T) { t.Run("Positive", func(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumEmptyFactory(0x6CC4) err = badger.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) edgs, err := badger.GetEdges(context.Background(), 0x6CC4) - if err != nil { - t.Error(err) - } - if !reflect.DeepEqual(edgs, alb.Edges) { - t.Error("edgs != alb.GetEdges") - } + assert.NoError(t, err) + assert.Equal(t, alb.Edges, edgs) }) t.Run("Negative1", func(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumFullFactory(0xA566) err = badger.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) alb = AlbumFullFactory(0xA566) err = badger.SaveAlbum(context.Background(), alb) - if !errors.Is(err, domain.ErrAlbumAlreadyExists) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumAlreadyExists) }) t.Run("Negative2", func(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) _, err = badger.GetImagesIds(context.Background(), 0xA9B4) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative3", func(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) _, err = badger.GetEdges(context.Background(), 0x3F1E) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestBadgerCount(t *testing.T) { t.Run("Positive", func(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumEmptyFactory(0x746C) err = badger.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) n, err := badger.CountImages(context.Background(), 0x746C) - if err != nil { - t.Error(err) - } - if n != 5 { - t.Error("n != 5") - } + assert.NoError(t, err) + assert.Equal(t, 5, n) n, err = badger.CountImagesCompressed(context.Background(), 0x746C) - if err != nil { - t.Error(err) - } - if n != 0 { - t.Error("n != 0") - } + assert.NoError(t, err) + assert.Equal(t, 0, n) err = badger.UpdateCompressionStatus(context.Background(), 0x746C, 0x3E3D) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) n, err = badger.CountImages(context.Background(), 0x746C) - if err != nil { - t.Error(err) - } - if n != 5 { - t.Error("n != 5") - } + assert.NoError(t, err) + assert.Equal(t, 5, n) n, err = badger.CountImagesCompressed(context.Background(), 0x746C) - if err != nil { - t.Error(err) - } - if n != 1 { - t.Error("n != 1") - } + assert.NoError(t, err) + assert.Equal(t, 1, n) err = badger.UpdateCompressionStatus(context.Background(), 0x746C, 0xB399) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) n, err = badger.CountImagesCompressed(context.Background(), 0x746C) - if err != nil { - t.Error(err) - } - if n != 2 { - t.Error("n != 2") - } + assert.NoError(t, err) + assert.Equal(t, 2, n) }) t.Run("Negative1", func(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumEmptyFactory(0x99DF) err = badger.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = badger.UpdateCompressionStatus(context.Background(), 0x99DF, 0x3E3D) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = badger.UpdateCompressionStatus(context.Background(), 0x99DF, 0x3E3D) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) n, err := badger.CountImagesCompressed(context.Background(), 0x99DF) - if err != nil { - t.Error(err) - } - if n != 1 { - t.Error("n != 1") - } + assert.NoError(t, err) + assert.Equal(t, 1, n) }) t.Run("Negative2", func(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) _, err = badger.CountImages(context.Background(), 0xF256) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative3", func(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) _, err = badger.CountImagesCompressed(context.Background(), 0xC52A) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative4", func(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) err = badger.UpdateCompressionStatus(context.Background(), 0xF73E, 0x3E3D) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative5", func(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumEmptyFactory(0xDF75) err = badger.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = badger.UpdateCompressionStatus(context.Background(), 0xDF75, 0xE7A4) - if !errors.Is(err, domain.ErrImageNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrImageNotFound) }) } func TestBadgerImage(t *testing.T) { t.Run("Positive", func(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumEmptyFactory(0xB0C4) err = badger.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) src, err := badger.GetImageSrc(context.Background(), 0xB0C4, 0x51DE) - if err != nil { - t.Error(err) - } - if src != "/aye-and-nay/albums/xLAAAAAAAAA/images/3lEAAAAAAAA" { - t.Error("src != \"/aye-and-nay/albums/xLAAAAAAAAA/images/3lEAAAAAAAA\"") - } + assert.NoError(t, err) + assert.Equal(t, "/aye-and-nay/albums/xLAAAAAAAAA/images/3lEAAAAAAAA", src) }) t.Run("Negative1", func(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) _, err = badger.GetImageSrc(context.Background(), 0x12EE, 0x51DE) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative2", func(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumEmptyFactory(0xD585) err = badger.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) _, err = badger.GetImageSrc(context.Background(), 0xD585, 0xDA30) - if !errors.Is(err, domain.ErrImageNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrImageNotFound) }) } func TestBadgerVote(t *testing.T) { t.Run("Positive", func(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumFullFactory(0x4D76) err = badger.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = badger.SaveVote(context.Background(), 0x4D76, 0xDA2A, 0xDA52) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = badger.SaveVote(context.Background(), 0x4D76, 0xDA2A, 0xDA52) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) edgs, err := badger.GetEdges(context.Background(), 0x4D76) - if err != nil { - t.Error(err) - } - if edgs[0xDA2A][0xDA52] != 2 { - t.Error("edgs[imageFrom][imageTo] != 2") - } + assert.NoError(t, err) + assert.Equal(t, 2, edgs[0xDA2A][0xDA52]) }) t.Run("Negative", func(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) err = badger.SaveVote(context.Background(), 0x1FAD, 0x84E6, 0x308E) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestBadgerSort(t *testing.T) { t.Run("Positive", func(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumFullFactory(0x5A96) err = badger.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) imgs1, err := badger.GetImagesOrdered(context.Background(), 0x5A96) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img1 := model.Image{Id: 0x51DE, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/3lEAAAAAAAA", Rating: 0.77920413} img2 := model.Image{Id: 0x3E3D, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/PT4AAAAAAAA", Rating: 0.48954984} img3 := model.Image{Id: 0xDA2A, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/KtoAAAAAAAA", Rating: 0.41218211} img4 := model.Image{Id: 0xB399, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/mbMAAAAAAAA", Rating: 0.19186324} img5 := model.Image{Id: 0xDA52, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/UtoAAAAAAAA", Rating: 0.13278389} imgs2 := []model.Image{img1, img2, img3, img4, img5} - if !reflect.DeepEqual(imgs1, imgs2) { - t.Error("imgs1 != imgs2") - } + assert.Equal(t, imgs2, imgs1) }) t.Run("Negative", func(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) _, err = badger.GetImagesOrdered(context.Background(), 0x66BE) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestBadgerRatings(t *testing.T) { t.Run("Positive", func(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumFullFactory(0x4E54) err = badger.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img1 := model.Image{Id: 0x3E3D, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/PT4AAAAAAAA", Rating: 0.54412788} img2 := model.Image{Id: 0xB399, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/mbMAAAAAAAA", Rating: 0.32537162} img3 := model.Image{Id: 0xDA2A, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/KtoAAAAAAAA", Rating: 0.43185491} @@ -346,23 +217,15 @@ func TestBadgerRatings(t *testing.T) { vector[img4.Id] = img4.Rating vector[img5.Id] = img5.Rating err = badger.UpdateRatings(context.Background(), 0x4E54, vector) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) imgs2, err := badger.GetImagesOrdered(context.Background(), 0x4E54) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) sort.Slice(imgs1, func(i, j int) bool { return imgs1[i].Rating > imgs1[j].Rating }) - if !reflect.DeepEqual(imgs1, imgs2) { - t.Error("imgs1 != imgs2") - } + assert.Equal(t, imgs1, imgs2) }) t.Run("Negative", func(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) img1 := model.Image{Id: 0x3E3D, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/PT4AAAAAAAA", Rating: 0.54412788} img2 := model.Image{Id: 0xB399, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/mbMAAAAAAAA", Rating: 0.32537162} img3 := model.Image{Id: 0xDA2A, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/KtoAAAAAAAA", Rating: 0.43185491} @@ -375,114 +238,67 @@ func TestBadgerRatings(t *testing.T) { vector[img4.Id] = img4.Rating vector[img5.Id] = img5.Rating err = badger.UpdateRatings(context.Background(), 0xA293, vector) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestBadgerDelete(t *testing.T) { t.Run("Positive1", func(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumEmptyFactory(0x748C) _, err = badger.CountImages(context.Background(), 0x748C) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) err = badger.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) n, err := badger.CountImages(context.Background(), 0x748C) - if err != nil { - t.Error(err) - } - if n != 5 { - t.Error("n != 5") - } + assert.NoError(t, err) + assert.Equal(t, 5, n) albums, err := badger.AlbumsToBeDeleted(context.Background()) - if err != nil { - t.Error(err) - } - if albums != nil { - t.Error("albums != nil") - } + assert.NoError(t, err) + assert.Len(t, albums, 0) err = badger.DeleteAlbum(context.Background(), 0x748C) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) _, err = badger.CountImages(context.Background(), 0x748C) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Positive2", func(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumEmptyFactory(0x7B43) alb.Expires = time.Now().Add(-1 * time.Hour) err = badger.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) albums, err := badger.AlbumsToBeDeleted(context.Background()) - if err != nil { - t.Error(err) - } - if !(len(albums) == 1 && albums[0].Id == alb.Id && !albums[0].Expires.IsZero()) { - t.Error("!(len(albums) == 1 && albums[0].Id == alb.Id && !albums[0].Expires.IsZero())") - } + assert.NoError(t, err) + assert.True(t, len(albums) == 1 && albums[0].Id == alb.Id && !albums[0].Expires.IsZero()) err = badger.DeleteAlbum(context.Background(), 0x7B43) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) _, err = badger.CountImages(context.Background(), 0x7B43) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) + t.Cleanup(func() { _ = badger.DeleteAlbum(context.Background(), 0x7B43) }) }) t.Run("Negative", func(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumEmptyFactory(0x608C) err = badger.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = badger.DeleteAlbum(context.Background(), 0xB7FF) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestBadgerLru(t *testing.T) { badger, err := NewBadger(DefaultBadgerConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb1 := AlbumEmptyFactory(0x36FC) err = badger.SaveAlbum(context.Background(), alb1) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) alb2 := AlbumEmptyFactory(0xB020) err = badger.SaveAlbum(context.Background(), alb2) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) edgs, err := badger.GetEdges(context.Background(), 0x36FC) - if err != nil { - t.Error(err) - } - if !reflect.DeepEqual(edgs, alb1.Edges) { - t.Error("edgs != alb1.GetEdges") - } + assert.NoError(t, err) + assert.Equal(t, alb1.Edges, edgs) } diff --git a/infrastructure/database/mem_test.go b/infrastructure/database/mem_test.go index 0df8ef2..2db6ff9 100644 --- a/infrastructure/database/mem_test.go +++ b/infrastructure/database/mem_test.go @@ -4,15 +4,15 @@ package database import ( "context" - "reflect" "sort" "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/model" . "github.com/zitryss/aye-and-nay/internal/testing" - "github.com/zitryss/aye-and-nay/pkg/errors" ) func TestMemAlbum(t *testing.T) { @@ -20,43 +20,29 @@ func TestMemAlbum(t *testing.T) { mem := NewMem(DefaultMemConfig) alb := AlbumEmptyFactory(0x6CC4) err := mem.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) edgs, err := mem.GetEdges(context.Background(), 0x6CC4) - if err != nil { - t.Error(err) - } - if !reflect.DeepEqual(edgs, alb.Edges) { - t.Error("edgs != alb.GetEdges") - } + assert.NoError(t, err) + assert.Equal(t, alb.Edges, edgs) }) t.Run("Negative1", func(t *testing.T) { mem := NewMem(DefaultMemConfig) alb := AlbumFullFactory(0xA566) err := mem.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) alb = AlbumFullFactory(0xA566) err = mem.SaveAlbum(context.Background(), alb) - if !errors.Is(err, domain.ErrAlbumAlreadyExists) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumAlreadyExists) }) t.Run("Negative2", func(t *testing.T) { mem := NewMem(DefaultMemConfig) _, err := mem.GetImagesIds(context.Background(), 0xA9B4) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative3", func(t *testing.T) { mem := NewMem(DefaultMemConfig) _, err := mem.GetEdges(context.Background(), 0x3F1E) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } @@ -65,108 +51,62 @@ func TestMemCount(t *testing.T) { mem := NewMem(DefaultMemConfig) alb := AlbumEmptyFactory(0x746C) err := mem.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) n, err := mem.CountImages(context.Background(), 0x746C) - if err != nil { - t.Error(err) - } - if n != 5 { - t.Error("n != 5") - } + assert.NoError(t, err) + assert.Equal(t, 5, n) n, err = mem.CountImagesCompressed(context.Background(), 0x746C) - if err != nil { - t.Error(err) - } - if n != 0 { - t.Error("n != 0") - } + assert.NoError(t, err) + assert.Equal(t, 0, n) err = mem.UpdateCompressionStatus(context.Background(), 0x746C, 0x3E3D) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) n, err = mem.CountImages(context.Background(), 0x746C) - if err != nil { - t.Error(err) - } - if n != 5 { - t.Error("n != 5") - } + assert.NoError(t, err) + assert.Equal(t, 5, n) n, err = mem.CountImagesCompressed(context.Background(), 0x746C) - if err != nil { - t.Error(err) - } - if n != 1 { - t.Error("n != 1") - } + assert.NoError(t, err) + assert.Equal(t, 1, n) err = mem.UpdateCompressionStatus(context.Background(), 0x746C, 0xB399) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) n, err = mem.CountImagesCompressed(context.Background(), 0x746C) - if err != nil { - t.Error(err) - } - if n != 2 { - t.Error("n != 2") - } + assert.NoError(t, err) + assert.Equal(t, 2, n) }) t.Run("Negative1", func(t *testing.T) { mem := NewMem(DefaultMemConfig) alb := AlbumEmptyFactory(0x99DF) err := mem.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = mem.UpdateCompressionStatus(context.Background(), 0x99DF, 0x3E3D) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = mem.UpdateCompressionStatus(context.Background(), 0x99DF, 0x3E3D) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) n, err := mem.CountImagesCompressed(context.Background(), 0x99DF) - if err != nil { - t.Error(err) - } - if n != 1 { - t.Error("n != 1") - } + assert.NoError(t, err) + assert.Equal(t, 1, n) }) t.Run("Negative2", func(t *testing.T) { mem := NewMem(DefaultMemConfig) _, err := mem.CountImages(context.Background(), 0xF256) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative3", func(t *testing.T) { mem := NewMem(DefaultMemConfig) _, err := mem.CountImagesCompressed(context.Background(), 0xC52A) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative4", func(t *testing.T) { mem := NewMem(DefaultMemConfig) err := mem.UpdateCompressionStatus(context.Background(), 0xF73E, 0x3E3D) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative5", func(t *testing.T) { mem := NewMem(DefaultMemConfig) alb := AlbumEmptyFactory(0xDF75) err := mem.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = mem.UpdateCompressionStatus(context.Background(), 0xDF75, 0xE7A4) - if !errors.Is(err, domain.ErrImageNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrImageNotFound) }) } @@ -175,35 +115,23 @@ func TestMemImage(t *testing.T) { mem := NewMem(DefaultMemConfig) alb := AlbumEmptyFactory(0xB0C4) err := mem.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) src, err := mem.GetImageSrc(context.Background(), 0xB0C4, 0x51DE) - if err != nil { - t.Error(err) - } - if src != "/aye-and-nay/albums/xLAAAAAAAAA/images/3lEAAAAAAAA" { - t.Error("src != \"/aye-and-nay/albums/xLAAAAAAAAA/images/3lEAAAAAAAA\"") - } + assert.NoError(t, err) + assert.Equal(t, "/aye-and-nay/albums/xLAAAAAAAAA/images/3lEAAAAAAAA", src) }) t.Run("Negative1", func(t *testing.T) { mem := NewMem(DefaultMemConfig) _, err := mem.GetImageSrc(context.Background(), 0x12EE, 0x51DE) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative2", func(t *testing.T) { mem := NewMem(DefaultMemConfig) alb := AlbumEmptyFactory(0xD585) err := mem.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) _, err = mem.GetImageSrc(context.Background(), 0xD585, 0xDA30) - if !errors.Is(err, domain.ErrImageNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrImageNotFound) }) } @@ -212,31 +140,19 @@ func TestMemVote(t *testing.T) { mem := NewMem(DefaultMemConfig) alb := AlbumFullFactory(0x4D76) err := mem.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = mem.SaveVote(context.Background(), 0x4D76, 0xDA2A, 0xDA52) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = mem.SaveVote(context.Background(), 0x4D76, 0xDA2A, 0xDA52) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) edgs, err := mem.GetEdges(context.Background(), 0x4D76) - if err != nil { - t.Error(err) - } - if edgs[0xDA2A][0xDA52] != 2 { - t.Error("edgs[imageFrom][imageTo] != 2") - } + assert.NoError(t, err) + assert.Equal(t, 2, edgs[0xDA2A][0xDA52]) }) t.Run("Negative", func(t *testing.T) { mem := NewMem(DefaultMemConfig) err := mem.SaveVote(context.Background(), 0x1FAD, 0x84E6, 0x308E) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } @@ -245,29 +161,21 @@ func TestMemSort(t *testing.T) { mem := NewMem(DefaultMemConfig) alb := AlbumFullFactory(0x5A96) err := mem.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) imgs1, err := mem.GetImagesOrdered(context.Background(), 0x5A96) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img1 := model.Image{Id: 0x51DE, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/3lEAAAAAAAA", Rating: 0.77920413} img2 := model.Image{Id: 0x3E3D, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/PT4AAAAAAAA", Rating: 0.48954984} img3 := model.Image{Id: 0xDA2A, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/KtoAAAAAAAA", Rating: 0.41218211} img4 := model.Image{Id: 0xB399, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/mbMAAAAAAAA", Rating: 0.19186324} img5 := model.Image{Id: 0xDA52, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/UtoAAAAAAAA", Rating: 0.13278389} imgs2 := []model.Image{img1, img2, img3, img4, img5} - if !reflect.DeepEqual(imgs1, imgs2) { - t.Error("imgs1 != imgs2") - } + assert.Equal(t, imgs2, imgs1) }) t.Run("Negative", func(t *testing.T) { mem := NewMem(DefaultMemConfig) _, err := mem.GetImagesOrdered(context.Background(), 0x66BE) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } @@ -276,9 +184,7 @@ func TestMemRatings(t *testing.T) { mem := NewMem(DefaultMemConfig) alb := AlbumFullFactory(0x4E54) err := mem.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img1 := model.Image{Id: 0x3E3D, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/PT4AAAAAAAA", Rating: 0.54412788} img2 := model.Image{Id: 0xB399, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/mbMAAAAAAAA", Rating: 0.32537162} img3 := model.Image{Id: 0xDA2A, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/KtoAAAAAAAA", Rating: 0.43185491} @@ -292,17 +198,11 @@ func TestMemRatings(t *testing.T) { vector[img4.Id] = img4.Rating vector[img5.Id] = img5.Rating err = mem.UpdateRatings(context.Background(), 0x4E54, vector) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) imgs2, err := mem.GetImagesOrdered(context.Background(), 0x4E54) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) sort.Slice(imgs1, func(i, j int) bool { return imgs1[i].Rating > imgs1[j].Rating }) - if !reflect.DeepEqual(imgs1, imgs2) { - t.Error("imgs1 != imgs2") - } + assert.Equal(t, imgs1, imgs2) }) t.Run("Negative", func(t *testing.T) { mem := NewMem(DefaultMemConfig) @@ -318,9 +218,7 @@ func TestMemRatings(t *testing.T) { vector[img4.Id] = img4.Rating vector[img5.Id] = img5.Rating err := mem.UpdateRatings(context.Background(), 0xA293, vector) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } @@ -329,70 +227,40 @@ func TestMemDelete(t *testing.T) { mem := NewMem(DefaultMemConfig) alb := AlbumEmptyFactory(0x748C) _, err := mem.CountImages(context.Background(), 0x748C) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) err = mem.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) n, err := mem.CountImages(context.Background(), 0x748C) - if err != nil { - t.Error(err) - } - if n != 5 { - t.Error("n != 5") - } + assert.NoError(t, err) + assert.Equal(t, 5, n) albums, err := mem.AlbumsToBeDeleted(context.Background()) - if err != nil { - t.Error(err) - } - if albums != nil { - t.Error("albums != nil") - } + assert.NoError(t, err) + assert.Len(t, albums, 0) err = mem.DeleteAlbum(context.Background(), 0x748C) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) _, err = mem.CountImages(context.Background(), 0x748C) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Positive2", func(t *testing.T) { mem := NewMem(DefaultMemConfig) alb := AlbumEmptyFactory(0x7B43) alb.Expires = time.Now().Add(-1 * time.Hour) err := mem.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) albums, err := mem.AlbumsToBeDeleted(context.Background()) - if err != nil { - t.Error(err) - } - if !(len(albums) == 1 && albums[0].Id == alb.Id && !albums[0].Expires.IsZero()) { - t.Error("!(len(albums) == 1 && albums[0].Id == alb.Id && !albums[0].Expires.IsZero())") - } + assert.NoError(t, err) + assert.True(t, len(albums) == 1 && albums[0].Id == alb.Id && !albums[0].Expires.IsZero()) err = mem.DeleteAlbum(context.Background(), 0x7B43) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) _, err = mem.CountImages(context.Background(), 0x7B43) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative", func(t *testing.T) { mem := NewMem(DefaultMemConfig) alb := AlbumEmptyFactory(0x608C) err := mem.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = mem.DeleteAlbum(context.Background(), 0xB7FF) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } diff --git a/infrastructure/database/mongo_integration_test.go b/infrastructure/database/mongo_integration_test.go index 0642dc3..6f8db10 100644 --- a/infrastructure/database/mongo_integration_test.go +++ b/infrastructure/database/mongo_integration_test.go @@ -4,335 +4,206 @@ package database import ( "context" - "reflect" "sort" "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/model" . "github.com/zitryss/aye-and-nay/internal/testing" - "github.com/zitryss/aye-and-nay/pkg/errors" ) func TestMongoAlbum(t *testing.T) { t.Run("Positive", func(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumEmptyFactory(0x6CC4) err = mongo.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) edgs, err := mongo.GetEdges(context.Background(), 0x6CC4) - if err != nil { - t.Error(err) - } - if !reflect.DeepEqual(edgs, alb.Edges) { - t.Error("edgs != alb.GetEdges") - } + assert.NoError(t, err) + assert.Equal(t, alb.Edges, edgs) }) t.Run("Negative1", func(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumFullFactory(0xA566) err = mongo.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) alb = AlbumFullFactory(0xA566) err = mongo.SaveAlbum(context.Background(), alb) - if !errors.Is(err, domain.ErrAlbumAlreadyExists) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumAlreadyExists) }) t.Run("Negative2", func(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) _, err = mongo.GetImagesIds(context.Background(), 0xA9B4) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative3", func(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) _, err = mongo.GetEdges(context.Background(), 0x3F1E) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestMongoCount(t *testing.T) { t.Run("Positive", func(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumEmptyFactory(0x746C) err = mongo.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) n, err := mongo.CountImages(context.Background(), 0x746C) - if err != nil { - t.Error(err) - } - if n != 5 { - t.Error("n != 5") - } + assert.NoError(t, err) + assert.Equal(t, 5, n) n, err = mongo.CountImagesCompressed(context.Background(), 0x746C) - if err != nil { - t.Error(err) - } - if n != 0 { - t.Error("n != 0") - } + assert.NoError(t, err) + assert.Equal(t, 0, n) err = mongo.UpdateCompressionStatus(context.Background(), 0x746C, 0x3E3D) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) n, err = mongo.CountImages(context.Background(), 0x746C) - if err != nil { - t.Error(err) - } - if n != 5 { - t.Error("n != 5") - } + assert.NoError(t, err) + assert.Equal(t, 5, n) n, err = mongo.CountImagesCompressed(context.Background(), 0x746C) - if err != nil { - t.Error(err) - } - if n != 1 { - t.Error("n != 1") - } + assert.NoError(t, err) + assert.Equal(t, 1, n) err = mongo.UpdateCompressionStatus(context.Background(), 0x746C, 0xB399) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) n, err = mongo.CountImagesCompressed(context.Background(), 0x746C) - if err != nil { - t.Error(err) - } - if n != 2 { - t.Error("n != 2") - } + assert.NoError(t, err) + assert.Equal(t, 2, n) }) t.Run("Negative1", func(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumEmptyFactory(0x99DF) err = mongo.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = mongo.UpdateCompressionStatus(context.Background(), 0x99DF, 0x3E3D) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = mongo.UpdateCompressionStatus(context.Background(), 0x99DF, 0x3E3D) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) n, err := mongo.CountImagesCompressed(context.Background(), 0x99DF) - if err != nil { - t.Error(err) - } - if n != 1 { - t.Error("n != 1") - } + assert.NoError(t, err) + assert.Equal(t, 1, n) }) t.Run("Negative2", func(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) _, err = mongo.CountImages(context.Background(), 0xF256) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative3", func(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) _, err = mongo.CountImagesCompressed(context.Background(), 0xC52A) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative4", func(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) err = mongo.UpdateCompressionStatus(context.Background(), 0xF73E, 0x3E3D) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative5", func(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumEmptyFactory(0xDF75) err = mongo.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = mongo.UpdateCompressionStatus(context.Background(), 0xDF75, 0xE7A4) - if !errors.Is(err, domain.ErrImageNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrImageNotFound) }) } func TestMongoImage(t *testing.T) { t.Run("Positive", func(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumEmptyFactory(0xB0C4) err = mongo.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) src, err := mongo.GetImageSrc(context.Background(), 0xB0C4, 0x51DE) - if err != nil { - t.Error(err) - } - if src != "/aye-and-nay/albums/xLAAAAAAAAA/images/3lEAAAAAAAA" { - t.Error("src != \"/aye-and-nay/albums/xLAAAAAAAAA/images/3lEAAAAAAAA\"") - } + assert.NoError(t, err) + assert.Equal(t, "/aye-and-nay/albums/xLAAAAAAAAA/images/3lEAAAAAAAA", src) }) t.Run("Negative1", func(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) _, err = mongo.GetImageSrc(context.Background(), 0x12EE, 0x51DE) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative2", func(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumEmptyFactory(0xD585) err = mongo.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) _, err = mongo.GetImageSrc(context.Background(), 0xD585, 0xDA30) - if !errors.Is(err, domain.ErrImageNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrImageNotFound) }) } func TestMongoVote(t *testing.T) { t.Run("Positive", func(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumFullFactory(0x4D76) err = mongo.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = mongo.SaveVote(context.Background(), 0x4D76, 0xDA2A, 0xDA52) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = mongo.SaveVote(context.Background(), 0x4D76, 0xDA2A, 0xDA52) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) edgs, err := mongo.GetEdges(context.Background(), 0x4D76) - if err != nil { - t.Error(err) - } - if edgs[0xDA2A][0xDA52] != 2 { - t.Error("edgs[imageFrom][imageTo] != 2") - } + assert.NoError(t, err) + assert.Equal(t, 2, edgs[0xDA2A][0xDA52]) }) t.Run("Negative", func(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) err = mongo.SaveVote(context.Background(), 0x1FAD, 0x84E6, 0x308E) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestMongoSort(t *testing.T) { t.Run("Positive", func(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumFullFactory(0x5A96) err = mongo.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) imgs1, err := mongo.GetImagesOrdered(context.Background(), 0x5A96) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img1 := model.Image{Id: 0x51DE, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/3lEAAAAAAAA", Rating: 0.77920413} img2 := model.Image{Id: 0x3E3D, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/PT4AAAAAAAA", Rating: 0.48954984} img3 := model.Image{Id: 0xDA2A, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/KtoAAAAAAAA", Rating: 0.41218211} img4 := model.Image{Id: 0xB399, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/mbMAAAAAAAA", Rating: 0.19186324} img5 := model.Image{Id: 0xDA52, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/UtoAAAAAAAA", Rating: 0.13278389} imgs2 := []model.Image{img1, img2, img3, img4, img5} - if !reflect.DeepEqual(imgs1, imgs2) { - t.Error("imgs1 != imgs2") - } + assert.Equal(t, imgs2, imgs1) }) t.Run("Negative", func(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) _, err = mongo.GetImagesOrdered(context.Background(), 0x66BE) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestMongoRatings(t *testing.T) { t.Run("Positive", func(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumFullFactory(0x4E54) err = mongo.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) img1 := model.Image{Id: 0x3E3D, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/PT4AAAAAAAA", Rating: 0.54412788} img2 := model.Image{Id: 0xB399, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/mbMAAAAAAAA", Rating: 0.32537162} img3 := model.Image{Id: 0xDA2A, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/KtoAAAAAAAA", Rating: 0.43185491} @@ -346,23 +217,15 @@ func TestMongoRatings(t *testing.T) { vector[img4.Id] = img4.Rating vector[img5.Id] = img5.Rating err = mongo.UpdateRatings(context.Background(), 0x4E54, vector) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) imgs2, err := mongo.GetImagesOrdered(context.Background(), 0x4E54) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) sort.Slice(imgs1, func(i, j int) bool { return imgs1[i].Rating > imgs1[j].Rating }) - if !reflect.DeepEqual(imgs1, imgs2) { - t.Error("imgs1 != imgs2") - } + assert.Equal(t, imgs1, imgs2) }) t.Run("Negative", func(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) img1 := model.Image{Id: 0x3E3D, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/PT4AAAAAAAA", Rating: 0.54412788} img2 := model.Image{Id: 0xB399, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/mbMAAAAAAAA", Rating: 0.32537162} img3 := model.Image{Id: 0xDA2A, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/KtoAAAAAAAA", Rating: 0.43185491} @@ -375,117 +238,67 @@ func TestMongoRatings(t *testing.T) { vector[img4.Id] = img4.Rating vector[img5.Id] = img5.Rating err = mongo.UpdateRatings(context.Background(), 0xA293, vector) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestMongoDelete(t *testing.T) { t.Run("Positive1", func(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumEmptyFactory(0x748C) _, err = mongo.CountImages(context.Background(), 0x748C) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) err = mongo.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) n, err := mongo.CountImages(context.Background(), 0x748C) - if err != nil { - t.Error(err) - } - if n != 5 { - t.Error("n != 5") - } + assert.NoError(t, err) + assert.Equal(t, 5, n) albums, err := mongo.AlbumsToBeDeleted(context.Background()) - if err != nil { - t.Error(err) - } - if len(albums) != 0 { - t.Error("len(albums) != 0") - } + assert.NoError(t, err) + assert.Len(t, albums, 0) err = mongo.DeleteAlbum(context.Background(), 0x748C) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) _, err = mongo.CountImages(context.Background(), 0x748C) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Positive2", func(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumEmptyFactory(0x7B43) alb.Expires = time.Now().Add(-1 * time.Hour) err = mongo.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) albums, err := mongo.AlbumsToBeDeleted(context.Background()) - if err != nil { - t.Error(err) - } - if !(len(albums) == 1 && albums[0].Id == alb.Id && !albums[0].Expires.IsZero()) { - t.Error("!(len(albums) == 1 && albums[0].Id == alb.Id && !albums[0].Expires.IsZero())") - } + assert.NoError(t, err) + assert.True(t, len(albums) == 1 && albums[0].Id == alb.Id && !albums[0].Expires.IsZero()) err = mongo.DeleteAlbum(context.Background(), 0x7B43) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) _, err = mongo.CountImages(context.Background(), 0x7B43) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } - t.Cleanup(func() { - _ = mongo.DeleteAlbum(context.Background(), 0x7B43) - }) + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) + t.Cleanup(func() { _ = mongo.DeleteAlbum(context.Background(), 0x7B43) }) }) t.Run("Negative", func(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb := AlbumEmptyFactory(0x608C) err = mongo.SaveAlbum(context.Background(), alb) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) err = mongo.DeleteAlbum(context.Background(), 0xB7FF) - if !errors.Is(err, domain.ErrAlbumNotFound) { - t.Error(err) - } + assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestMongoLru(t *testing.T) { mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) alb1 := AlbumEmptyFactory(0x36FC) err = mongo.SaveAlbum(context.Background(), alb1) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) alb2 := AlbumEmptyFactory(0xB020) err = mongo.SaveAlbum(context.Background(), alb2) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) edgs, err := mongo.GetEdges(context.Background(), 0x36FC) - if err != nil { - t.Error(err) - } - if !reflect.DeepEqual(edgs, alb1.Edges) { - t.Error("edgs != alb1.GetEdges") - } + assert.NoError(t, err) + assert.Equal(t, alb1.Edges, edgs) } diff --git a/infrastructure/storage/minio_integration_test.go b/infrastructure/storage/minio_integration_test.go index c88f770..f05a1a3 100644 --- a/infrastructure/storage/minio_integration_test.go +++ b/infrastructure/storage/minio_integration_test.go @@ -7,92 +7,53 @@ import ( "testing" minioS3 "github.com/minio/minio-go/v7" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" . "github.com/zitryss/aye-and-nay/internal/testing" - "github.com/zitryss/aye-and-nay/pkg/errors" ) func TestMinio(t *testing.T) { t.Run("", func(t *testing.T) { minio, err := NewMinio(context.Background(), DefaultMinioConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) f, err := minio.Get(context.Background(), 0x70D8, 0xD5C7) - e := (*minioS3.ErrorResponse)(nil) - if errors.As(err, &e) { - t.Error(err) - } - if f.Reader != nil { - t.Error("f.Reader != nil") - } + e := minioS3.ErrorResponse{} + assert.ErrorAs(t, err, &e) + assert.Nil(t, f.Reader) src, err := minio.Put(context.Background(), 0x70D8, 0xD5C7, Png()) - if err != nil { - t.Error(err) - } - if src != "/aye-and-nay/albums/2HAAAAAAAAA/images/x9UAAAAAAAA" { - t.Error("src != \"/aye-and-nay/albums/2HAAAAAAAAA/images/x9UAAAAAAAA\"") - } + assert.NoError(t, err) + assert.Equal(t, "/aye-and-nay/albums/2HAAAAAAAAA/images/x9UAAAAAAAA", src) f, err = minio.Get(context.Background(), 0x70D8, 0xD5C7) - if err != nil { - t.Error(err) - } - if !EqualFile(f, Png()) { - t.Error("!EqualFile(f, Png())") - } + assert.NoError(t, err) + AssertEqualFile(t, f, Png()) err = minio.Remove(context.Background(), 0x70D8, 0xD5C7) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) f, err = minio.Get(context.Background(), 0x70D8, 0xD5C7) - e = (*minioS3.ErrorResponse)(nil) - if errors.As(err, &e) { - t.Error(err) - } - if f.Reader != nil { - t.Error("f.Reader != nil") - } + e = minioS3.ErrorResponse{} + assert.ErrorAs(t, err, &e) + assert.Nil(t, f.Reader) }) t.Run("", func(t *testing.T) { minio, err := NewMinio(context.Background(), DefaultMinioConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) src, err := minio.Put(context.Background(), 0x872D, 0x882D, Png()) - if err != nil { - t.Error(err) - } - if src != "/aye-and-nay/albums/LYcAAAAAAAA/images/LYgAAAAAAAA" { - t.Error("src != \"/aye-and-nay/albums/LYcAAAAAAAA/images/LYgAAAAAAAA\"") - } + assert.NoError(t, err) + assert.Equal(t, "/aye-and-nay/albums/LYcAAAAAAAA/images/LYgAAAAAAAA", src) f, err := minio.Get(context.Background(), 0x872D, 0x882D) - if err != nil { - t.Error(err) - } - if !EqualFile(f, Png()) { - t.Error("!EqualFile(f, Png())") - } + assert.NoError(t, err) + AssertEqualFile(t, f, Png()) err = minio.Remove(context.Background(), 0x872D, 0x882D) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) src, err = minio.Put(context.Background(), 0x872D, 0x882D, Png()) - if err != nil { - t.Error(err) - } - if src != "/aye-and-nay/albums/LYcAAAAAAAA/images/LYgAAAAAAAA" { - t.Error("src != \"/aye-and-nay/albums/LYcAAAAAAAA/images/LYgAAAAAAAA\"") - } + assert.NoError(t, err) + assert.Equal(t, "/aye-and-nay/albums/LYcAAAAAAAA/images/LYgAAAAAAAA", src) }) } func TestMinioHealth(t *testing.T) { minio, err := NewMinio(context.Background(), DefaultMinioConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) _, err = minio.Health(context.Background()) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) } diff --git a/internal/testing/testing.go b/internal/testing/testing.go index 16b9b53..6efd1e6 100644 --- a/internal/testing/testing.go +++ b/internal/testing/testing.go @@ -3,18 +3,19 @@ package testing import ( "bytes" _ "embed" - "math" "net/http/httptest" "reflect" "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/zitryss/aye-and-nay/domain/model" "github.com/zitryss/aye-and-nay/pkg/base64" ) const ( - tolerance = 0.000000000000001 + TOLERANCE = 0.000000000000001 ) var ( @@ -22,51 +23,9 @@ var ( png []byte ) -func CheckStatusCode(t *testing.T, w *httptest.ResponseRecorder, code int) { - t.Helper() - got := w.Code - want := code - if got != want { - t.Errorf("Status Code = %v; want %v", got, want) - } -} - -func CheckContentType(t *testing.T, w *httptest.ResponseRecorder, content string) { - t.Helper() - got := w.Result().Header.Get("Content-Type") - want := content - if got != want { - t.Errorf("Content-Type = %v; want %v", got, want) - } -} - -func CheckBody(t *testing.T, w *httptest.ResponseRecorder, body string) { - t.Helper() - got := w.Body.String() - want := body - if got != want { - t.Errorf("Body = %v; want %v", got, want) - } -} - -func CheckChannel(t *testing.T, heartbeat <-chan interface{}) interface{} { - t.Helper() - v := interface{}(nil) - select { - case v = <-heartbeat: - case <-time.After(1 * time.Second): - t.Fatal("<-time.After(1 * time.Second)") - } - return v -} - -func IsIn(image model.Image, imgs []model.Image) bool { - for _, img := range imgs { - if reflect.DeepEqual(image, img) { - return true - } - } - return false +func Png() model.File { + buf := bytes.NewBuffer(png) + return model.File{Reader: buf, Size: int64(buf.Len())} } func AlbumEmptyFactory(id uint64) model.Album { @@ -108,48 +67,70 @@ func AlbumFullFactory(id uint64) model.Album { return alb } -func EqualMap(x, y map[uint64]float64) bool { - if len(x) != len(y) { - return false +func AssertStatusCode(t *testing.T, w *httptest.ResponseRecorder, code int) { + t.Helper() + got := w.Code + want := code + if got != want { + t.Errorf("Status Code = %v; want %v", got, want) } - for xk, xv := range x { - yv, ok := y[xk] - if !ok { - return false - } - if !EqualFloat(xv, yv) { - return false - } +} + +func AssertContentType(t *testing.T, w *httptest.ResponseRecorder, content string) { + t.Helper() + got := w.Result().Header.Get("Content-Type") + want := content + if got != want { + t.Errorf("Content-Type = %v; want %v", got, want) } - return true } -func EqualFloat(x, y float64) bool { - diff := math.Abs(x - y) - if diff > tolerance { - return false +func AssertBody(t *testing.T, w *httptest.ResponseRecorder, body string) { + t.Helper() + got := w.Body.String() + want := body + if got != want { + t.Errorf("Body = %v; want %v", got, want) } - return true } -func Png() model.File { - buf := bytes.NewBuffer(png) - return model.File{Reader: buf, Size: int64(buf.Len())} +func AssertChannel(t *testing.T, heartbeat <-chan interface{}) interface{} { + t.Helper() + v := interface{}(nil) + select { + case v = <-heartbeat: + case <-time.After(1 * time.Second): + t.Error("<-time.After(1 * time.Second)") + } + return v } -func EqualFile(x, y model.File) bool { +func AssertNotChannel(t *testing.T, heartbeat <-chan interface{}) { + t.Helper() + select { + case <-heartbeat: + t.Error("<-heartbeatDel") + case <-time.After(1 * time.Second): + } +} + +func AssertContains(t *testing.T, imgs []model.Image, image model.Image) { + t.Helper() + for _, img := range imgs { + if reflect.DeepEqual(image, img) { + return + } + } + t.Errorf("%#v does not contain %#v", imgs, image) +} + +func AssertEqualFile(t *testing.T, x, y model.File) { + t.Helper() bx := make([]byte, x.Size) _, err := x.Read(bx) - if err != nil { - return false - } + assert.NoError(t, err) by := make([]byte, y.Size) _, err = y.Read(by) - if err != nil { - return false - } - if !reflect.DeepEqual(bx, by) { - return false - } - return true + assert.NoError(t, err) + assert.Equal(t, bx, by) } diff --git a/pkg/errors/errors_test.go b/pkg/errors/errors_test.go index c4c5806..f42fc44 100644 --- a/pkg/errors/errors_test.go +++ b/pkg/errors/errors_test.go @@ -4,9 +4,10 @@ package errors_test import ( "fmt" - "reflect" "testing" + "github.com/stretchr/testify/assert" + "github.com/zitryss/aye-and-nay/pkg/errors" ) @@ -59,9 +60,7 @@ func TestCause(t *testing.T) { for _, tt := range tests { t.Run("", func(t *testing.T) { got := errors.Cause(tt.give) - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("Cause(%v) = %v, want %v", tt.give, got, tt.want) - } + assert.Equal(t, tt.want, got) }) } } diff --git a/pkg/linalg/linalg_test.go b/pkg/linalg/linalg_test.go index a929683..eb91f0c 100644 --- a/pkg/linalg/linalg_test.go +++ b/pkg/linalg/linalg_test.go @@ -7,6 +7,8 @@ import ( "math/rand" "testing" + "github.com/stretchr/testify/assert" + . "github.com/zitryss/aye-and-nay/internal/testing" "github.com/zitryss/aye-and-nay/pkg/linalg" ) @@ -35,9 +37,7 @@ func TestPageRank(t *testing.T) { want[0xFB26] = 0.11761540730647063 want[0xF523] = 0.07719901505201851 want[0xFC63] = 0.055433125751816706 - if !EqualMap(got, want) { - t.Error("!equalMap(got, want)") - } + assert.InDeltaMapValues(t, want, got, TOLERANCE) } func BenchmarkPageRank(b *testing.B) { diff --git a/pkg/log/log_test.go b/pkg/log/log_test.go index da02832..40412b0 100644 --- a/pkg/log/log_test.go +++ b/pkg/log/log_test.go @@ -6,6 +6,8 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/zitryss/aye-and-nay/pkg/log" ) @@ -63,9 +65,7 @@ func TestLogLevelPositive(t *testing.T) { log.Critical("message7") log.Criticalf("message8: %s %s", "ju", "iv") got := w.String() - if got != tt.want { - t.Errorf("level = %v; got %v; want %v", tt.level, got, tt.want) - } + assert.Equal(t, tt.want, got) }) } } @@ -105,9 +105,7 @@ func TestLogLevelNegative(t *testing.T) { log.Critical("message7") log.Criticalf("message8: %s %s", "ju", "iv") got := w.String() - if got != tt.want { - t.Errorf("level = %v; got %v; want %v", log.DEBUG, got, tt.want) - } + assert.Equal(t, tt.want, got) }) } } diff --git a/pkg/retry/retry_test.go b/pkg/retry/retry_test.go index b43fd84..66c47f9 100644 --- a/pkg/retry/retry_test.go +++ b/pkg/retry/retry_test.go @@ -3,10 +3,11 @@ package retry_test import ( - "reflect" "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/zitryss/aye-and-nay/pkg/errors" "github.com/zitryss/aye-and-nay/pkg/retry" ) @@ -61,12 +62,8 @@ func TestDo1(t *testing.T) { time.Sleep(tt.busy) return nil }) - if !reflect.DeepEqual(err, tt.err) { - t.Errorf("Do() err = %v, want = %v", err, tt.err) - } - if c != tt.calls { - t.Errorf("Do() calls = %v, want = %v", c, tt.calls) - } + assert.Equal(t, tt.err, err) + assert.Equal(t, tt.calls, c) }) } } @@ -121,12 +118,8 @@ func TestDo2(t *testing.T) { time.Sleep(tt.busy) return errors.New("no luck") }) - if !reflect.DeepEqual(err, tt.err) { - t.Errorf("Do() err = %v, want = %v", err, tt.err) - } - if c != tt.calls { - t.Errorf("Do() calls = %v, want = %v", c, tt.calls) - } + assert.Equal(t, tt.err, err) + assert.Equal(t, tt.calls, c) }) } } @@ -184,12 +177,8 @@ func TestDo3(t *testing.T) { } return nil }) - if !reflect.DeepEqual(err, tt.err) { - t.Errorf("Do() err = %v, want = %v", err, tt.err) - } - if c != tt.calls { - t.Errorf("Do() calls = %v, want = %v", c, tt.calls) - } + assert.Equal(t, tt.err, err) + assert.Equal(t, tt.calls, c) }) } } From 0dc3a5691b765b70d6bdb8993f7e422bdbf1bad0 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sun, 30 Jan 2022 14:24:41 +0100 Subject: [PATCH 40/92] Stop using log package for init function --- ulimit.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ulimit.go b/ulimit.go index 5728b18..da5748e 100644 --- a/ulimit.go +++ b/ulimit.go @@ -3,16 +3,15 @@ package main import ( + "fmt" "os" "syscall" - - "github.com/zitryss/aye-and-nay/pkg/log" ) func init() { err := setUlimit() if err != nil { - log.Critical(err) + _, _ = fmt.Fprintln(os.Stderr, "critical:", err) os.Exit(1) } } From c89bfe2795611266e143bf7afcd4b3115b2c6178 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Tue, 1 Feb 2022 11:40:07 +0100 Subject: [PATCH 41/92] Use assert package where possible --- domain/service/service_integration_test.go | 24 +++++++++---------- domain/service/service_test.go | 24 +++++++++---------- .../storage/minio_integration_test.go | 4 ++-- internal/testing/testing.go | 24 ------------------- 4 files changed, 26 insertions(+), 50 deletions(-) diff --git a/domain/service/service_integration_test.go b/domain/service/service_integration_test.go index 9903302..194ac10 100644 --- a/domain/service/service_integration_test.go +++ b/domain/service/service_integration_test.go @@ -203,24 +203,24 @@ func TestServiceIntegrationPair(t *testing.T) { img2 := model.Image{Id: 0x3BC8, Token: 0x3BCA, Src: "/api/images/yjsAAAAAAAA/"} imgs1 := []model.Image{img1, img2} assert.NotEqual(t, img7, img8) - AssertContains(t, imgs1, img7) - AssertContains(t, imgs1, img8) + assert.Contains(t, imgs1, img7) + assert.Contains(t, imgs1, img8) img9, img10, err := serv.Pair(ctx, album) assert.NoError(t, err) img3 := model.Image{Id: 0x3BC8, Token: 0x3BCB, Src: "/api/images/yzsAAAAAAAA/"} img4 := model.Image{Id: 0x3BC7, Token: 0x3BCC, Src: "/api/images/zDsAAAAAAAA/"} imgs2 := []model.Image{img3, img4} assert.NotEqual(t, img9, img10) - AssertContains(t, imgs2, img9) - AssertContains(t, imgs2, img10) + assert.Contains(t, imgs2, img9) + assert.Contains(t, imgs2, img10) img11, img12, err := serv.Pair(ctx, album) assert.NoError(t, err) img5 := model.Image{Id: 0x3BC7, Token: 0x3BCD, Src: "/api/images/zTsAAAAAAAA/"} img6 := model.Image{Id: 0x3BC8, Token: 0x3BCE, Src: "/api/images/zjsAAAAAAAA/"} imgs3 := []model.Image{img5, img6} assert.NotEqual(t, img11, img12) - AssertContains(t, imgs3, img11) - AssertContains(t, imgs3, img12) + assert.Contains(t, imgs3, img11) + assert.Contains(t, imgs3, img12) }) t.Run("Positive2", func(t *testing.T) { fn1 := func() func() (uint64, error) { @@ -259,24 +259,24 @@ func TestServiceIntegrationPair(t *testing.T) { img2 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} imgs1 := []model.Image{img1, img2} assert.NotEqual(t, img7, img8) - AssertContains(t, imgs1, img7) - AssertContains(t, imgs1, img8) + assert.Contains(t, imgs1, img7) + assert.Contains(t, imgs1, img8) img9, img10, err := serv.Pair(ctx, album) assert.NoError(t, err) img3 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} img4 := model.Image{Id: 0xFAFF, Token: 0xFAFF, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/__oAAAAAAAA"} imgs2 := []model.Image{img3, img4} assert.NotEqual(t, img9, img10) - AssertContains(t, imgs2, img9) - AssertContains(t, imgs2, img10) + assert.Contains(t, imgs2, img9) + assert.Contains(t, imgs2, img10) img11, img12, err := serv.Pair(ctx, album) assert.NoError(t, err) img5 := model.Image{Id: 0xFAFF, Token: 0xFAFF, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/__oAAAAAAAA"} img6 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} imgs3 := []model.Image{img5, img6} assert.NotEqual(t, img11, img12) - AssertContains(t, imgs3, img11) - AssertContains(t, imgs3, img12) + assert.Contains(t, imgs3, img11) + assert.Contains(t, imgs3, img12) }) t.Run("Negative", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) diff --git a/domain/service/service_test.go b/domain/service/service_test.go index 19da214..1f500d1 100644 --- a/domain/service/service_test.go +++ b/domain/service/service_test.go @@ -157,24 +157,24 @@ func TestServicePair(t *testing.T) { img2 := model.Image{Id: 0x3BC8, Token: 0x3BCA, Src: "/api/images/yjsAAAAAAAA/"} imgs1 := []model.Image{img1, img2} assert.NotEqual(t, img7, img8) - AssertContains(t, imgs1, img7) - AssertContains(t, imgs1, img8) + assert.Contains(t, imgs1, img7) + assert.Contains(t, imgs1, img8) img9, img10, err := serv.Pair(ctx, album) assert.NoError(t, err) img3 := model.Image{Id: 0x3BC8, Token: 0x3BCB, Src: "/api/images/yzsAAAAAAAA/"} img4 := model.Image{Id: 0x3BC7, Token: 0x3BCC, Src: "/api/images/zDsAAAAAAAA/"} imgs2 := []model.Image{img3, img4} assert.NotEqual(t, img9, img10) - AssertContains(t, imgs2, img9) - AssertContains(t, imgs2, img10) + assert.Contains(t, imgs2, img9) + assert.Contains(t, imgs2, img10) img11, img12, err := serv.Pair(ctx, album) assert.NoError(t, err) img5 := model.Image{Id: 0x3BC7, Token: 0x3BCD, Src: "/api/images/zTsAAAAAAAA/"} img6 := model.Image{Id: 0x3BC8, Token: 0x3BCE, Src: "/api/images/zjsAAAAAAAA/"} imgs3 := []model.Image{img5, img6} assert.NotEqual(t, img11, img12) - AssertContains(t, imgs3, img11) - AssertContains(t, imgs3, img12) + assert.Contains(t, imgs3, img11) + assert.Contains(t, imgs3, img12) }) t.Run("Positive2", func(t *testing.T) { fn1 := func() func() (uint64, error) { @@ -209,24 +209,24 @@ func TestServicePair(t *testing.T) { img2 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} imgs1 := []model.Image{img1, img2} assert.NotEqual(t, img7, img8) - AssertContains(t, imgs1, img7) - AssertContains(t, imgs1, img8) + assert.Contains(t, imgs1, img7) + assert.Contains(t, imgs1, img8) img9, img10, err := serv.Pair(ctx, album) assert.NoError(t, err) img3 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} img4 := model.Image{Id: 0xFAFF, Token: 0xFAFF, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/__oAAAAAAAA"} imgs2 := []model.Image{img3, img4} assert.NotEqual(t, img9, img10) - AssertContains(t, imgs2, img9) - AssertContains(t, imgs2, img10) + assert.Contains(t, imgs2, img9) + assert.Contains(t, imgs2, img10) img11, img12, err := serv.Pair(ctx, album) assert.NoError(t, err) img5 := model.Image{Id: 0xFAFF, Token: 0xFAFF, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/__oAAAAAAAA"} img6 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} imgs3 := []model.Image{img5, img6} assert.NotEqual(t, img11, img12) - AssertContains(t, imgs3, img11) - AssertContains(t, imgs3, img12) + assert.Contains(t, imgs3, img11) + assert.Contains(t, imgs3, img12) }) t.Run("Negative", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) diff --git a/infrastructure/storage/minio_integration_test.go b/infrastructure/storage/minio_integration_test.go index f05a1a3..71fe8ba 100644 --- a/infrastructure/storage/minio_integration_test.go +++ b/infrastructure/storage/minio_integration_test.go @@ -26,7 +26,7 @@ func TestMinio(t *testing.T) { assert.Equal(t, "/aye-and-nay/albums/2HAAAAAAAAA/images/x9UAAAAAAAA", src) f, err = minio.Get(context.Background(), 0x70D8, 0xD5C7) assert.NoError(t, err) - AssertEqualFile(t, f, Png()) + assert.Equal(t, Png(), f) err = minio.Remove(context.Background(), 0x70D8, 0xD5C7) assert.NoError(t, err) f, err = minio.Get(context.Background(), 0x70D8, 0xD5C7) @@ -42,7 +42,7 @@ func TestMinio(t *testing.T) { assert.Equal(t, "/aye-and-nay/albums/LYcAAAAAAAA/images/LYgAAAAAAAA", src) f, err := minio.Get(context.Background(), 0x872D, 0x882D) assert.NoError(t, err) - AssertEqualFile(t, f, Png()) + assert.Equal(t, Png(), f) err = minio.Remove(context.Background(), 0x872D, 0x882D) assert.NoError(t, err) src, err = minio.Put(context.Background(), 0x872D, 0x882D, Png()) diff --git a/internal/testing/testing.go b/internal/testing/testing.go index 6efd1e6..8ea4437 100644 --- a/internal/testing/testing.go +++ b/internal/testing/testing.go @@ -4,12 +4,9 @@ import ( "bytes" _ "embed" "net/http/httptest" - "reflect" "testing" "time" - "github.com/stretchr/testify/assert" - "github.com/zitryss/aye-and-nay/domain/model" "github.com/zitryss/aye-and-nay/pkg/base64" ) @@ -113,24 +110,3 @@ func AssertNotChannel(t *testing.T, heartbeat <-chan interface{}) { case <-time.After(1 * time.Second): } } - -func AssertContains(t *testing.T, imgs []model.Image, image model.Image) { - t.Helper() - for _, img := range imgs { - if reflect.DeepEqual(image, img) { - return - } - } - t.Errorf("%#v does not contain %#v", imgs, image) -} - -func AssertEqualFile(t *testing.T, x, y model.File) { - t.Helper() - bx := make([]byte, x.Size) - _, err := x.Read(bx) - assert.NoError(t, err) - by := make([]byte, y.Size) - _, err = y.Read(by) - assert.NoError(t, err) - assert.Equal(t, bx, by) -} From 18ad93c846bfa0aa36734aa0ecc1be166c1d2754 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Wed, 2 Feb 2022 23:23:17 +0100 Subject: [PATCH 42/92] Reset state --- infrastructure/cache/mem.go | 19 +++++++++++++++++++ infrastructure/cache/redis.go | 8 ++++++++ infrastructure/database/badger.go | 9 +++++++++ infrastructure/database/mem.go | 7 +++++++ infrastructure/database/mongo.go | 9 +++++++++ infrastructure/storage/minio.go | 24 ++++++++++++++++++++++++ 6 files changed, 76 insertions(+) diff --git a/infrastructure/cache/mem.go b/infrastructure/cache/mem.go index fe3e4e0..4eb72cd 100644 --- a/infrastructure/cache/mem.go +++ b/infrastructure/cache/mem.go @@ -328,3 +328,22 @@ func (m *Mem) Del(_ context.Context, token uint64) error { func (m *Mem) Health(_ context.Context) (bool, error) { return true, nil } + +func (m *Mem) Reset() error { + m.syncVisitors.Lock() + defer m.syncVisitors.Unlock() + m.visitors = map[uint64]*visitorTime{} + m.syncQueues.Lock() + defer m.syncQueues.Unlock() + m.queues = map[uint64]*linkedhashset.Set{} + m.syncPQueues.Lock() + defer m.syncPQueues.Unlock() + m.pqueues = map[uint64]*binaryheap.Heap{} + m.syncPairs.Lock() + defer m.syncPairs.Unlock() + m.pairs = map[uint64]*pairsTime{} + m.syncTokens.Lock() + defer m.syncTokens.Unlock() + m.tokens = map[uint64]*tokenTime{} + return nil +} diff --git a/infrastructure/cache/redis.go b/infrastructure/cache/redis.go index c025efc..b5a6c48 100644 --- a/infrastructure/cache/redis.go +++ b/infrastructure/cache/redis.go @@ -264,3 +264,11 @@ func (r *Redis) Close(_ context.Context) error { } return nil } + +func (r *Redis) Reset() error { + err := r.client.FlushAll(context.Background()).Err() + if err != nil { + return errors.Wrap(err) + } + return nil +} diff --git a/infrastructure/database/badger.go b/infrastructure/database/badger.go index ff71440..dfed3f2 100644 --- a/infrastructure/database/badger.go +++ b/infrastructure/database/badger.go @@ -352,3 +352,12 @@ func (b *Badger) Close(_ context.Context) error { } return nil } + +func (b *Badger) Reset() error { + err := b.db.DropAll() + if err != nil { + return errors.Wrap(err) + } + b.cache.Purge() + return nil +} diff --git a/infrastructure/database/mem.go b/infrastructure/database/mem.go index 4398c37..6324f8c 100644 --- a/infrastructure/database/mem.go +++ b/infrastructure/database/mem.go @@ -222,3 +222,10 @@ func (m *Mem) AlbumsToBeDeleted(_ context.Context) ([]model.Album, error) { func (m *Mem) Health(_ context.Context) (bool, error) { return true, nil } + +func (m *Mem) Reset() error { + m.syncAlbums.Lock() + defer m.syncAlbums.Unlock() + m.albums = map[uint64]model.Album{} + return nil +} diff --git a/infrastructure/database/mongo.go b/infrastructure/database/mongo.go index 47851b8..8a7a8d9 100644 --- a/infrastructure/database/mongo.go +++ b/infrastructure/database/mongo.go @@ -362,3 +362,12 @@ func (m *Mongo) Close(ctx context.Context) error { } return nil } + +func (m *Mongo) Reset() error { + err := m.db.Drop(context.Background()) + if err != nil { + return errors.Wrap(err) + } + m.cache.Purge() + return nil +} diff --git a/infrastructure/storage/minio.go b/infrastructure/storage/minio.go index 54a7144..2a5bc48 100644 --- a/infrastructure/storage/minio.go +++ b/infrastructure/storage/minio.go @@ -166,3 +166,27 @@ func (m *Minio) Health(ctx context.Context) (bool, error) { } return true, nil } + +func (m *Minio) Reset() error { + bb, err := m.client.ListBuckets(context.Background()) + if err != nil { + return errors.Wrap(err) + } + for _, b := range bb { + for obj := range m.client.ListObjects(context.Background(), b.Name, minioS3.ListObjectsOptions{Recursive: true}) { + err := m.client.RemoveObject(context.Background(), b.Name, obj.Key, minioS3.RemoveObjectOptions{ForceDelete: true}) + if err != nil { + return errors.Wrap(err) + } + } + err := m.client.RemoveBucket(context.Background(), b.Name) + if err != nil { + return errors.Wrap(err) + } + } + err = m.client.MakeBucket(context.Background(), "aye-and-nay", minioS3.MakeBucketOptions{Region: m.conf.Location}) + if err != nil { + return errors.Wrap(err) + } + return nil +} From f88ab1a1eb3049c79bdbf907f2c356f7b60cbd26 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Thu, 3 Feb 2022 22:31:59 +0100 Subject: [PATCH 43/92] Write helper id generator --- internal/generator/generator.go | 58 ++++++++++++++++++++++++++++ internal/generator/generator_test.go | 40 +++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 internal/generator/generator.go create mode 100644 internal/generator/generator_test.go diff --git a/internal/generator/generator.go b/internal/generator/generator.go new file mode 100644 index 0000000..5d511f8 --- /dev/null +++ b/internal/generator/generator.go @@ -0,0 +1,58 @@ +package generator + +import ( + "sync" +) + +const ( + IDS_SPAN = 100 +) + +var ( + m sync.Mutex + indexId uint64 +) + +func GenId() (func() uint64, *syncLogBook) { + lb := syncLogBook{m: sync.Mutex{}, logBook: map[int]uint64{}} + fn := func() func() uint64 { + m.Lock() + firstId := indexId + indexId += IDS_SPAN + m.Unlock() + mFn := sync.Mutex{} + i := -1 + curId := firstId - 1 + lastId := firstId + IDS_SPAN - 1 + return func() uint64 { + mFn.Lock() + i++ + curId++ + if curId > lastId { + panic("id out of bounds") + } + lb.set(i, curId) + id := curId + mFn.Unlock() + return id + } + } + return fn(), &lb +} + +type syncLogBook struct { + m sync.Mutex + logBook map[int]uint64 +} + +func (lb *syncLogBook) Get(i int) uint64 { + lb.m.Lock() + defer lb.m.Unlock() + return lb.logBook[i] +} + +func (lb *syncLogBook) set(i int, id uint64) { + lb.m.Lock() + defer lb.m.Unlock() + lb.logBook[i] = id +} diff --git a/internal/generator/generator_test.go b/internal/generator/generator_test.go new file mode 100644 index 0000000..6679b8c --- /dev/null +++ b/internal/generator/generator_test.go @@ -0,0 +1,40 @@ +package generator + +import ( + "sync" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGenId(t *testing.T) { + id, ids := GenId() + id, ids = GenId() + wg := sync.WaitGroup{} + wg.Add(2) + assert.NotPanics(t, func() { + go func() { + defer wg.Done() + for i := 0; i < IDS_SPAN/2; i++ { + id() + } + for i := 0; i < IDS_SPAN/2; i++ { + _ = ids.Get(i) + } + }() + go func() { + defer wg.Done() + for i := IDS_SPAN / 2; i < IDS_SPAN; i++ { + id() + } + for i := IDS_SPAN / 2; i < IDS_SPAN; i++ { + _ = ids.Get(i) + } + }() + }) + wg.Wait() + assert.Len(t, ids.logBook, IDS_SPAN) + assert.Equal(t, ids.logBook[0], uint64(100)) + assert.Equal(t, ids.logBook[len(ids.logBook)-1], uint64(199)) + assert.Panics(t, func() { id() }) +} From 4439ab7b5b7ce7b737f473da61dda6368fea26c6 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Thu, 3 Feb 2022 22:32:12 +0100 Subject: [PATCH 44/92] Return helper function to compare files --- infrastructure/storage/minio_integration_test.go | 4 ++-- internal/testing/testing.go | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/infrastructure/storage/minio_integration_test.go b/infrastructure/storage/minio_integration_test.go index 71fe8ba..f05a1a3 100644 --- a/infrastructure/storage/minio_integration_test.go +++ b/infrastructure/storage/minio_integration_test.go @@ -26,7 +26,7 @@ func TestMinio(t *testing.T) { assert.Equal(t, "/aye-and-nay/albums/2HAAAAAAAAA/images/x9UAAAAAAAA", src) f, err = minio.Get(context.Background(), 0x70D8, 0xD5C7) assert.NoError(t, err) - assert.Equal(t, Png(), f) + AssertEqualFile(t, f, Png()) err = minio.Remove(context.Background(), 0x70D8, 0xD5C7) assert.NoError(t, err) f, err = minio.Get(context.Background(), 0x70D8, 0xD5C7) @@ -42,7 +42,7 @@ func TestMinio(t *testing.T) { assert.Equal(t, "/aye-and-nay/albums/LYcAAAAAAAA/images/LYgAAAAAAAA", src) f, err := minio.Get(context.Background(), 0x872D, 0x882D) assert.NoError(t, err) - assert.Equal(t, Png(), f) + AssertEqualFile(t, f, Png()) err = minio.Remove(context.Background(), 0x872D, 0x882D) assert.NoError(t, err) src, err = minio.Put(context.Background(), 0x872D, 0x882D, Png()) diff --git a/internal/testing/testing.go b/internal/testing/testing.go index 8ea4437..fa3a6b0 100644 --- a/internal/testing/testing.go +++ b/internal/testing/testing.go @@ -7,6 +7,8 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/zitryss/aye-and-nay/domain/model" "github.com/zitryss/aye-and-nay/pkg/base64" ) @@ -110,3 +112,14 @@ func AssertNotChannel(t *testing.T, heartbeat <-chan interface{}) { case <-time.After(1 * time.Second): } } + +func AssertEqualFile(t *testing.T, x, y model.File) { + t.Helper() + bx := make([]byte, x.Size) + _, err := x.Read(bx) + assert.NoError(t, err) + by := make([]byte, y.Size) + _, err = y.Read(by) + assert.NoError(t, err) + assert.Equal(t, bx, by) +} From a962da5eab39190ba912091d4976606c14894765 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Mon, 7 Feb 2022 18:47:38 +0100 Subject: [PATCH 45/92] Generate IDs for the tests --- delivery/http/controller_test.go | 166 ++++++++-------- delivery/http/middleware_test.go | 4 +- delivery/http/server_test.go | 10 +- domain/domain/error.go | 44 ++--- domain/service/queue_integration_test.go | 20 +- domain/service/queue_test.go | 20 +- domain/service/service.go | 6 +- domain/service/service_integration_test.go | 178 +++++++++--------- domain/service/service_test.go | 174 ++++++++--------- infrastructure/cache/mem_test.go | 66 ++++--- .../cache/redis_integration_test.go | 150 +++++++++------ infrastructure/database/badger_test.go | 166 +++++++++------- infrastructure/database/mem_test.go | 157 ++++++++------- .../database/mongo_integration_test.go | 166 +++++++++------- .../storage/minio_integration_test.go | 31 +-- internal/generator/generator.go | 19 +- internal/generator/generator_test.go | 15 +- internal/testing/testing.go | 56 +++--- 18 files changed, 806 insertions(+), 642 deletions(-) diff --git a/delivery/http/controller_test.go b/delivery/http/controller_test.go index 1b16d99..4cc08ef 100644 --- a/delivery/http/controller_test.go +++ b/delivery/http/controller_test.go @@ -60,7 +60,7 @@ func TestControllerHandleAlbum(t *testing.T) { want: want{ code: 413, typ: "application/json; charset=utf-8", - body: `{"error":{"code":1,"msg":"body too large"}}` + "\n", + body: `{"error":{"code":2,"msg":"body too large"}}` + "\n", }, }, { @@ -73,7 +73,7 @@ func TestControllerHandleAlbum(t *testing.T) { want: want{ code: 400, typ: "application/json; charset=utf-8", - body: `{"error":{"code":3,"msg":"not enough images"}}` + "\n", + body: `{"error":{"code":4,"msg":"not enough images"}}` + "\n", }, }, { @@ -86,7 +86,7 @@ func TestControllerHandleAlbum(t *testing.T) { want: want{ code: 413, typ: "application/json; charset=utf-8", - body: `{"error":{"code":4,"msg":"too many images"}}` + "\n", + body: `{"error":{"code":5,"msg":"too many images"}}` + "\n", }, }, { @@ -99,7 +99,7 @@ func TestControllerHandleAlbum(t *testing.T) { want: want{ code: 413, typ: "application/json; charset=utf-8", - body: `{"error":{"code":5,"msg":"image too large"}}` + "\n", + body: `{"error":{"code":6,"msg":"image too large"}}` + "\n", }, }, { @@ -112,7 +112,7 @@ func TestControllerHandleAlbum(t *testing.T) { want: want{ code: 415, typ: "application/json; charset=utf-8", - body: `{"error":{"code":6,"msg":"unsupported media type"}}` + "\n", + body: `{"error":{"code":7,"msg":"unsupported media type"}}` + "\n", }, }, { @@ -124,7 +124,7 @@ func TestControllerHandleAlbum(t *testing.T) { want: want{ code: 400, typ: "application/json; charset=utf-8", - body: `{"error":{"code":7,"msg":"duration not set"}}` + "\n", + body: `{"error":{"code":8,"msg":"duration not set"}}` + "\n", }, }, { @@ -137,7 +137,7 @@ func TestControllerHandleAlbum(t *testing.T) { want: want{ code: 400, typ: "application/json; charset=utf-8", - body: `{"error":{"code":8,"msg":"duration invalid"}}` + "\n", + body: `{"error":{"code":9,"msg":"duration invalid"}}` + "\n", }, }, { @@ -150,7 +150,7 @@ func TestControllerHandleAlbum(t *testing.T) { want: want{ code: 429, typ: "application/json; charset=utf-8", - body: `{"error":{"code":0,"msg":"too many requests"}}` + "\n", + body: `{"error":{"code":1,"msg":"too many requests"}}` + "\n", }, }, { @@ -163,7 +163,7 @@ func TestControllerHandleAlbum(t *testing.T) { want: want{ code: 413, typ: "application/json; charset=utf-8", - body: `{"error":{"code":1,"msg":"body too large"}}` + "\n", + body: `{"error":{"code":2,"msg":"body too large"}}` + "\n", }, }, { @@ -176,7 +176,7 @@ func TestControllerHandleAlbum(t *testing.T) { want: want{ code: 415, typ: "application/json; charset=utf-8", - body: `{"error":{"code":2,"msg":"unsupported media type"}}` + "\n", + body: `{"error":{"code":3,"msg":"unsupported media type"}}` + "\n", }, }, { @@ -189,7 +189,7 @@ func TestControllerHandleAlbum(t *testing.T) { want: want{ code: 400, typ: "application/json; charset=utf-8", - body: `{"error":{"code":3,"msg":"not enough images"}}` + "\n", + body: `{"error":{"code":4,"msg":"not enough images"}}` + "\n", }, }, { @@ -202,7 +202,7 @@ func TestControllerHandleAlbum(t *testing.T) { want: want{ code: 413, typ: "application/json; charset=utf-8", - body: `{"error":{"code":4,"msg":"too many images"}}` + "\n", + body: `{"error":{"code":5,"msg":"too many images"}}` + "\n", }, }, { @@ -215,7 +215,7 @@ func TestControllerHandleAlbum(t *testing.T) { want: want{ code: 413, typ: "application/json; charset=utf-8", - body: `{"error":{"code":5,"msg":"image too large"}}` + "\n", + body: `{"error":{"code":6,"msg":"image too large"}}` + "\n", }, }, { @@ -228,7 +228,7 @@ func TestControllerHandleAlbum(t *testing.T) { want: want{ code: 415, typ: "application/json; charset=utf-8", - body: `{"error":{"code":6,"msg":"unsupported media type"}}` + "\n", + body: `{"error":{"code":7,"msg":"unsupported media type"}}` + "\n", }, }, { @@ -241,7 +241,7 @@ func TestControllerHandleAlbum(t *testing.T) { want: want{ code: 400, typ: "application/json; charset=utf-8", - body: `{"error":{"code":7,"msg":"duration not set"}}` + "\n", + body: `{"error":{"code":8,"msg":"duration not set"}}` + "\n", }, }, { @@ -254,7 +254,7 @@ func TestControllerHandleAlbum(t *testing.T) { want: want{ code: 400, typ: "application/json; charset=utf-8", - body: `{"error":{"code":8,"msg":"duration invalid"}}` + "\n", + body: `{"error":{"code":9,"msg":"duration invalid"}}` + "\n", }, }, { @@ -267,7 +267,7 @@ func TestControllerHandleAlbum(t *testing.T) { want: want{ code: 404, typ: "application/json; charset=utf-8", - body: `{"error":{"code":9,"msg":"album not found"}}` + "\n", + body: `{"error":{"code":10,"msg":"album not found"}}` + "\n", }, }, { @@ -280,7 +280,7 @@ func TestControllerHandleAlbum(t *testing.T) { want: want{ code: 404, typ: "application/json; charset=utf-8", - body: `{"error":{"code":11,"msg":"token not found"}}` + "\n", + body: `{"error":{"code":12,"msg":"token not found"}}` + "\n", }, }, { @@ -293,7 +293,7 @@ func TestControllerHandleAlbum(t *testing.T) { want: want{ code: 500, typ: "application/json; charset=utf-8", - body: `{"error":{"code":16,"msg":"internal server error"}}` + "\n", + body: `{"error":{"code":17,"msg":"internal server error"}}` + "\n", }, }, { @@ -385,7 +385,7 @@ func TestControllerHandleStatus(t *testing.T) { want: want{ code: 429, typ: "application/json; charset=utf-8", - body: `{"error":{"code":0,"msg":"too many requests"}}` + "\n", + body: `{"error":{"code":1,"msg":"too many requests"}}` + "\n", }, }, { @@ -395,7 +395,7 @@ func TestControllerHandleStatus(t *testing.T) { want: want{ code: 413, typ: "application/json; charset=utf-8", - body: `{"error":{"code":1,"msg":"body too large"}}` + "\n", + body: `{"error":{"code":2,"msg":"body too large"}}` + "\n", }, }, { @@ -405,7 +405,7 @@ func TestControllerHandleStatus(t *testing.T) { want: want{ code: 415, typ: "application/json; charset=utf-8", - body: `{"error":{"code":2,"msg":"unsupported media type"}}` + "\n", + body: `{"error":{"code":3,"msg":"unsupported media type"}}` + "\n", }, }, { @@ -415,7 +415,7 @@ func TestControllerHandleStatus(t *testing.T) { want: want{ code: 400, typ: "application/json; charset=utf-8", - body: `{"error":{"code":3,"msg":"not enough images"}}` + "\n", + body: `{"error":{"code":4,"msg":"not enough images"}}` + "\n", }, }, { @@ -425,7 +425,7 @@ func TestControllerHandleStatus(t *testing.T) { want: want{ code: 413, typ: "application/json; charset=utf-8", - body: `{"error":{"code":4,"msg":"too many images"}}` + "\n", + body: `{"error":{"code":5,"msg":"too many images"}}` + "\n", }, }, { @@ -435,7 +435,7 @@ func TestControllerHandleStatus(t *testing.T) { want: want{ code: 413, typ: "application/json; charset=utf-8", - body: `{"error":{"code":5,"msg":"image too large"}}` + "\n", + body: `{"error":{"code":6,"msg":"image too large"}}` + "\n", }, }, { @@ -445,7 +445,7 @@ func TestControllerHandleStatus(t *testing.T) { want: want{ code: 415, typ: "application/json; charset=utf-8", - body: `{"error":{"code":6,"msg":"unsupported media type"}}` + "\n", + body: `{"error":{"code":7,"msg":"unsupported media type"}}` + "\n", }, }, { @@ -455,7 +455,7 @@ func TestControllerHandleStatus(t *testing.T) { want: want{ code: 400, typ: "application/json; charset=utf-8", - body: `{"error":{"code":7,"msg":"duration not set"}}` + "\n", + body: `{"error":{"code":8,"msg":"duration not set"}}` + "\n", }, }, { @@ -465,7 +465,7 @@ func TestControllerHandleStatus(t *testing.T) { want: want{ code: 400, typ: "application/json; charset=utf-8", - body: `{"error":{"code":8,"msg":"duration invalid"}}` + "\n", + body: `{"error":{"code":9,"msg":"duration invalid"}}` + "\n", }, }, { @@ -475,7 +475,7 @@ func TestControllerHandleStatus(t *testing.T) { want: want{ code: 404, typ: "application/json; charset=utf-8", - body: `{"error":{"code":9,"msg":"album not found"}}` + "\n", + body: `{"error":{"code":10,"msg":"album not found"}}` + "\n", }, }, { @@ -485,7 +485,7 @@ func TestControllerHandleStatus(t *testing.T) { want: want{ code: 404, typ: "application/json; charset=utf-8", - body: `{"error":{"code":11,"msg":"token not found"}}` + "\n", + body: `{"error":{"code":12,"msg":"token not found"}}` + "\n", }, }, { @@ -495,7 +495,7 @@ func TestControllerHandleStatus(t *testing.T) { want: want{ code: 500, typ: "application/json; charset=utf-8", - body: `{"error":{"code":16,"msg":"internal server error"}}` + "\n", + body: `{"error":{"code":17,"msg":"internal server error"}}` + "\n", }, }, { @@ -565,7 +565,7 @@ func TestControllerHandlePair(t *testing.T) { want: want{ code: 429, typ: "application/json; charset=utf-8", - body: `{"error":{"code":0,"msg":"too many requests"}}` + "\n", + body: `{"error":{"code":1,"msg":"too many requests"}}` + "\n", }, }, { @@ -575,7 +575,7 @@ func TestControllerHandlePair(t *testing.T) { want: want{ code: 413, typ: "application/json; charset=utf-8", - body: `{"error":{"code":1,"msg":"body too large"}}` + "\n", + body: `{"error":{"code":2,"msg":"body too large"}}` + "\n", }, }, { @@ -585,7 +585,7 @@ func TestControllerHandlePair(t *testing.T) { want: want{ code: 415, typ: "application/json; charset=utf-8", - body: `{"error":{"code":2,"msg":"unsupported media type"}}` + "\n", + body: `{"error":{"code":3,"msg":"unsupported media type"}}` + "\n", }, }, { @@ -595,7 +595,7 @@ func TestControllerHandlePair(t *testing.T) { want: want{ code: 400, typ: "application/json; charset=utf-8", - body: `{"error":{"code":3,"msg":"not enough images"}}` + "\n", + body: `{"error":{"code":4,"msg":"not enough images"}}` + "\n", }, }, { @@ -605,7 +605,7 @@ func TestControllerHandlePair(t *testing.T) { want: want{ code: 413, typ: "application/json; charset=utf-8", - body: `{"error":{"code":4,"msg":"too many images"}}` + "\n", + body: `{"error":{"code":5,"msg":"too many images"}}` + "\n", }, }, { @@ -615,7 +615,7 @@ func TestControllerHandlePair(t *testing.T) { want: want{ code: 413, typ: "application/json; charset=utf-8", - body: `{"error":{"code":5,"msg":"image too large"}}` + "\n", + body: `{"error":{"code":6,"msg":"image too large"}}` + "\n", }, }, { @@ -625,7 +625,7 @@ func TestControllerHandlePair(t *testing.T) { want: want{ code: 415, typ: "application/json; charset=utf-8", - body: `{"error":{"code":6,"msg":"unsupported media type"}}` + "\n", + body: `{"error":{"code":7,"msg":"unsupported media type"}}` + "\n", }, }, { @@ -635,7 +635,7 @@ func TestControllerHandlePair(t *testing.T) { want: want{ code: 400, typ: "application/json; charset=utf-8", - body: `{"error":{"code":7,"msg":"duration not set"}}` + "\n", + body: `{"error":{"code":8,"msg":"duration not set"}}` + "\n", }, }, { @@ -645,7 +645,7 @@ func TestControllerHandlePair(t *testing.T) { want: want{ code: 400, typ: "application/json; charset=utf-8", - body: `{"error":{"code":8,"msg":"duration invalid"}}` + "\n", + body: `{"error":{"code":9,"msg":"duration invalid"}}` + "\n", }, }, { @@ -655,7 +655,7 @@ func TestControllerHandlePair(t *testing.T) { want: want{ code: 404, typ: "application/json; charset=utf-8", - body: `{"error":{"code":9,"msg":"album not found"}}` + "\n", + body: `{"error":{"code":10,"msg":"album not found"}}` + "\n", }, }, { @@ -665,7 +665,7 @@ func TestControllerHandlePair(t *testing.T) { want: want{ code: 404, typ: "application/json; charset=utf-8", - body: `{"error":{"code":11,"msg":"token not found"}}` + "\n", + body: `{"error":{"code":12,"msg":"token not found"}}` + "\n", }, }, { @@ -675,7 +675,7 @@ func TestControllerHandlePair(t *testing.T) { want: want{ code: 500, typ: "application/json; charset=utf-8", - body: `{"error":{"code":16,"msg":"internal server error"}}` + "\n", + body: `{"error":{"code":17,"msg":"internal server error"}}` + "\n", }, }, { @@ -746,7 +746,7 @@ func TestControllerHandleImage(t *testing.T) { want: want{ code: 429, typ: "application/json; charset=utf-8", - body: `{"error":{"code":0,"msg":"too many requests"}}` + "\n", + body: `{"error":{"code":1,"msg":"too many requests"}}` + "\n", }, }, { @@ -756,7 +756,7 @@ func TestControllerHandleImage(t *testing.T) { want: want{ code: 413, typ: "application/json; charset=utf-8", - body: `{"error":{"code":1,"msg":"body too large"}}` + "\n", + body: `{"error":{"code":2,"msg":"body too large"}}` + "\n", }, }, { @@ -766,7 +766,7 @@ func TestControllerHandleImage(t *testing.T) { want: want{ code: 415, typ: "application/json; charset=utf-8", - body: `{"error":{"code":2,"msg":"unsupported media type"}}` + "\n", + body: `{"error":{"code":3,"msg":"unsupported media type"}}` + "\n", }, }, { @@ -776,7 +776,7 @@ func TestControllerHandleImage(t *testing.T) { want: want{ code: 400, typ: "application/json; charset=utf-8", - body: `{"error":{"code":3,"msg":"not enough images"}}` + "\n", + body: `{"error":{"code":4,"msg":"not enough images"}}` + "\n", }, }, { @@ -786,7 +786,7 @@ func TestControllerHandleImage(t *testing.T) { want: want{ code: 413, typ: "application/json; charset=utf-8", - body: `{"error":{"code":4,"msg":"too many images"}}` + "\n", + body: `{"error":{"code":5,"msg":"too many images"}}` + "\n", }, }, { @@ -796,7 +796,7 @@ func TestControllerHandleImage(t *testing.T) { want: want{ code: 413, typ: "application/json; charset=utf-8", - body: `{"error":{"code":5,"msg":"image too large"}}` + "\n", + body: `{"error":{"code":6,"msg":"image too large"}}` + "\n", }, }, { @@ -806,7 +806,7 @@ func TestControllerHandleImage(t *testing.T) { want: want{ code: 415, typ: "application/json; charset=utf-8", - body: `{"error":{"code":6,"msg":"unsupported media type"}}` + "\n", + body: `{"error":{"code":7,"msg":"unsupported media type"}}` + "\n", }, }, { @@ -816,7 +816,7 @@ func TestControllerHandleImage(t *testing.T) { want: want{ code: 400, typ: "application/json; charset=utf-8", - body: `{"error":{"code":7,"msg":"duration not set"}}` + "\n", + body: `{"error":{"code":8,"msg":"duration not set"}}` + "\n", }, }, { @@ -826,7 +826,7 @@ func TestControllerHandleImage(t *testing.T) { want: want{ code: 400, typ: "application/json; charset=utf-8", - body: `{"error":{"code":8,"msg":"duration invalid"}}` + "\n", + body: `{"error":{"code":9,"msg":"duration invalid"}}` + "\n", }, }, { @@ -836,7 +836,7 @@ func TestControllerHandleImage(t *testing.T) { want: want{ code: 404, typ: "application/json; charset=utf-8", - body: `{"error":{"code":9,"msg":"album not found"}}` + "\n", + body: `{"error":{"code":10,"msg":"album not found"}}` + "\n", }, }, { @@ -846,7 +846,7 @@ func TestControllerHandleImage(t *testing.T) { want: want{ code: 404, typ: "application/json; charset=utf-8", - body: `{"error":{"code":11,"msg":"token not found"}}` + "\n", + body: `{"error":{"code":12,"msg":"token not found"}}` + "\n", }, }, { @@ -856,7 +856,7 @@ func TestControllerHandleImage(t *testing.T) { want: want{ code: 500, typ: "application/json; charset=utf-8", - body: `{"error":{"code":16,"msg":"internal server error"}}` + "\n", + body: `{"error":{"code":17,"msg":"internal server error"}}` + "\n", }, }, { @@ -926,7 +926,7 @@ func TestControllerHandleVote(t *testing.T) { want: want{ code: 429, typ: "application/json; charset=utf-8", - body: `{"error":{"code":0,"msg":"too many requests"}}` + "\n", + body: `{"error":{"code":1,"msg":"too many requests"}}` + "\n", }, }, { @@ -936,7 +936,7 @@ func TestControllerHandleVote(t *testing.T) { want: want{ code: 413, typ: "application/json; charset=utf-8", - body: `{"error":{"code":1,"msg":"body too large"}}` + "\n", + body: `{"error":{"code":2,"msg":"body too large"}}` + "\n", }, }, { @@ -946,7 +946,7 @@ func TestControllerHandleVote(t *testing.T) { want: want{ code: 415, typ: "application/json; charset=utf-8", - body: `{"error":{"code":2,"msg":"unsupported media type"}}` + "\n", + body: `{"error":{"code":3,"msg":"unsupported media type"}}` + "\n", }, }, { @@ -956,7 +956,7 @@ func TestControllerHandleVote(t *testing.T) { want: want{ code: 400, typ: "application/json; charset=utf-8", - body: `{"error":{"code":3,"msg":"not enough images"}}` + "\n", + body: `{"error":{"code":4,"msg":"not enough images"}}` + "\n", }, }, { @@ -966,7 +966,7 @@ func TestControllerHandleVote(t *testing.T) { want: want{ code: 413, typ: "application/json; charset=utf-8", - body: `{"error":{"code":4,"msg":"too many images"}}` + "\n", + body: `{"error":{"code":5,"msg":"too many images"}}` + "\n", }, }, { @@ -976,7 +976,7 @@ func TestControllerHandleVote(t *testing.T) { want: want{ code: 413, typ: "application/json; charset=utf-8", - body: `{"error":{"code":5,"msg":"image too large"}}` + "\n", + body: `{"error":{"code":6,"msg":"image too large"}}` + "\n", }, }, { @@ -986,7 +986,7 @@ func TestControllerHandleVote(t *testing.T) { want: want{ code: 415, typ: "application/json; charset=utf-8", - body: `{"error":{"code":6,"msg":"unsupported media type"}}` + "\n", + body: `{"error":{"code":7,"msg":"unsupported media type"}}` + "\n", }, }, { @@ -996,7 +996,7 @@ func TestControllerHandleVote(t *testing.T) { want: want{ code: 400, typ: "application/json; charset=utf-8", - body: `{"error":{"code":7,"msg":"duration not set"}}` + "\n", + body: `{"error":{"code":8,"msg":"duration not set"}}` + "\n", }, }, { @@ -1006,7 +1006,7 @@ func TestControllerHandleVote(t *testing.T) { want: want{ code: 400, typ: "application/json; charset=utf-8", - body: `{"error":{"code":8,"msg":"duration invalid"}}` + "\n", + body: `{"error":{"code":9,"msg":"duration invalid"}}` + "\n", }, }, { @@ -1016,7 +1016,7 @@ func TestControllerHandleVote(t *testing.T) { want: want{ code: 404, typ: "application/json; charset=utf-8", - body: `{"error":{"code":9,"msg":"album not found"}}` + "\n", + body: `{"error":{"code":10,"msg":"album not found"}}` + "\n", }, }, { @@ -1026,7 +1026,7 @@ func TestControllerHandleVote(t *testing.T) { want: want{ code: 404, typ: "application/json; charset=utf-8", - body: `{"error":{"code":11,"msg":"token not found"}}` + "\n", + body: `{"error":{"code":12,"msg":"token not found"}}` + "\n", }, }, { @@ -1036,7 +1036,7 @@ func TestControllerHandleVote(t *testing.T) { want: want{ code: 500, typ: "application/json; charset=utf-8", - body: `{"error":{"code":16,"msg":"internal server error"}}` + "\n", + body: `{"error":{"code":17,"msg":"internal server error"}}` + "\n", }, }, { @@ -1108,7 +1108,7 @@ func TestControllerHandleTop(t *testing.T) { want: want{ code: 429, typ: "application/json; charset=utf-8", - body: `{"error":{"code":0,"msg":"too many requests"}}` + "\n", + body: `{"error":{"code":1,"msg":"too many requests"}}` + "\n", }, }, { @@ -1118,7 +1118,7 @@ func TestControllerHandleTop(t *testing.T) { want: want{ code: 413, typ: "application/json; charset=utf-8", - body: `{"error":{"code":1,"msg":"body too large"}}` + "\n", + body: `{"error":{"code":2,"msg":"body too large"}}` + "\n", }, }, { @@ -1128,7 +1128,7 @@ func TestControllerHandleTop(t *testing.T) { want: want{ code: 415, typ: "application/json; charset=utf-8", - body: `{"error":{"code":2,"msg":"unsupported media type"}}` + "\n", + body: `{"error":{"code":3,"msg":"unsupported media type"}}` + "\n", }, }, { @@ -1138,7 +1138,7 @@ func TestControllerHandleTop(t *testing.T) { want: want{ code: 400, typ: "application/json; charset=utf-8", - body: `{"error":{"code":3,"msg":"not enough images"}}` + "\n", + body: `{"error":{"code":4,"msg":"not enough images"}}` + "\n", }, }, { @@ -1148,7 +1148,7 @@ func TestControllerHandleTop(t *testing.T) { want: want{ code: 413, typ: "application/json; charset=utf-8", - body: `{"error":{"code":4,"msg":"too many images"}}` + "\n", + body: `{"error":{"code":5,"msg":"too many images"}}` + "\n", }, }, { @@ -1158,7 +1158,7 @@ func TestControllerHandleTop(t *testing.T) { want: want{ code: 413, typ: "application/json; charset=utf-8", - body: `{"error":{"code":5,"msg":"image too large"}}` + "\n", + body: `{"error":{"code":6,"msg":"image too large"}}` + "\n", }, }, { @@ -1168,7 +1168,7 @@ func TestControllerHandleTop(t *testing.T) { want: want{ code: 415, typ: "application/json; charset=utf-8", - body: `{"error":{"code":6,"msg":"unsupported media type"}}` + "\n", + body: `{"error":{"code":7,"msg":"unsupported media type"}}` + "\n", }, }, { @@ -1178,7 +1178,7 @@ func TestControllerHandleTop(t *testing.T) { want: want{ code: 400, typ: "application/json; charset=utf-8", - body: `{"error":{"code":7,"msg":"duration not set"}}` + "\n", + body: `{"error":{"code":8,"msg":"duration not set"}}` + "\n", }, }, { @@ -1188,7 +1188,7 @@ func TestControllerHandleTop(t *testing.T) { want: want{ code: 400, typ: "application/json; charset=utf-8", - body: `{"error":{"code":8,"msg":"duration invalid"}}` + "\n", + body: `{"error":{"code":9,"msg":"duration invalid"}}` + "\n", }, }, { @@ -1198,7 +1198,7 @@ func TestControllerHandleTop(t *testing.T) { want: want{ code: 404, typ: "application/json; charset=utf-8", - body: `{"error":{"code":9,"msg":"album not found"}}` + "\n", + body: `{"error":{"code":10,"msg":"album not found"}}` + "\n", }, }, { @@ -1208,7 +1208,7 @@ func TestControllerHandleTop(t *testing.T) { want: want{ code: 404, typ: "application/json; charset=utf-8", - body: `{"error":{"code":11,"msg":"token not found"}}` + "\n", + body: `{"error":{"code":12,"msg":"token not found"}}` + "\n", }, }, { @@ -1218,7 +1218,7 @@ func TestControllerHandleTop(t *testing.T) { want: want{ code: 500, typ: "application/json; charset=utf-8", - body: `{"error":{"code":16,"msg":"internal server error"}}` + "\n", + body: `{"error":{"code":17,"msg":"internal server error"}}` + "\n", }, }, { @@ -1288,7 +1288,7 @@ func TestControllerHandleHealth(t *testing.T) { want: want{ code: 500, typ: "application/json; charset=utf-8", - body: `{"error":{"code":17,"msg":"internal server error"}}` + "\n", + body: `{"error":{"code":18,"msg":"internal server error"}}` + "\n", }, }, { @@ -1298,7 +1298,7 @@ func TestControllerHandleHealth(t *testing.T) { want: want{ code: 500, typ: "application/json; charset=utf-8", - body: `{"error":{"code":18,"msg":"internal server error"}}` + "\n", + body: `{"error":{"code":19,"msg":"internal server error"}}` + "\n", }, }, { @@ -1308,7 +1308,7 @@ func TestControllerHandleHealth(t *testing.T) { want: want{ code: 500, typ: "application/json; charset=utf-8", - body: `{"error":{"code":19,"msg":"internal server error"}}` + "\n", + body: `{"error":{"code":20,"msg":"internal server error"}}` + "\n", }, }, { @@ -1318,7 +1318,7 @@ func TestControllerHandleHealth(t *testing.T) { want: want{ code: 500, typ: "application/json; charset=utf-8", - body: `{"error":{"code":20,"msg":"internal server error"}}` + "\n", + body: `{"error":{"code":21,"msg":"internal server error"}}` + "\n", }, }, } diff --git a/delivery/http/middleware_test.go b/delivery/http/middleware_test.go index 7132afd..d2f1dca 100644 --- a/delivery/http/middleware_test.go +++ b/delivery/http/middleware_test.go @@ -55,7 +55,7 @@ func TestMiddlewareRecover(t *testing.T) { handler.ServeHTTP(w, r) AssertStatusCode(t, w, 500) AssertContentType(t, w, "application/json; charset=utf-8") - AssertBody(t, w, `{"error":{"code":17,"msg":"internal server error"}}`+"\n") + AssertBody(t, w, `{"error":{"code":22,"msg":"internal server error"}}`+"\n") }) } @@ -90,7 +90,7 @@ func TestMiddlewareLimit(t *testing.T) { handler.ServeHTTP(w, r) AssertStatusCode(t, w, 429) AssertContentType(t, w, "application/json; charset=utf-8") - AssertBody(t, w, `{"error":{"code":0,"msg":"too many requests"}}`+"\n") + AssertBody(t, w, `{"error":{"code":1,"msg":"too many requests"}}`+"\n") }) } diff --git a/delivery/http/server_test.go b/delivery/http/server_test.go index 07b62e0..32d74ab 100644 --- a/delivery/http/server_test.go +++ b/delivery/http/server_test.go @@ -43,10 +43,12 @@ func TestServer(t *testing.T) { assert.NoError(t, err) p, err := c.Pair(album) assert.NoError(t, err) - err = c.Do(http.MethodGet, mockserver.URL+p.One.Src, http.NoBody) - assert.NoError(t, err) - err = c.Do(http.MethodGet, mockserver.URL+p.Two.Src, http.NoBody) - assert.NoError(t, err) + if service.DefaultServiceConfig.TempLinks == true { + err = c.Do(http.MethodGet, mockserver.URL+p.One.Src, http.NoBody) + assert.NoError(t, err) + err = c.Do(http.MethodGet, mockserver.URL+p.Two.Src, http.NoBody) + assert.NoError(t, err) + } err = c.Vote(album, p.One.Token, p.Two.Token) assert.NoError(t, err) _, err = c.Top(album) diff --git a/domain/domain/error.go b/domain/domain/error.go index 5cfba1b..af1b3b9 100644 --- a/domain/domain/error.go +++ b/domain/domain/error.go @@ -17,7 +17,7 @@ var ( ErrTooManyRequests = &domainError{ outerError: outerError{ StatusCode: http.StatusTooManyRequests, - AppCode: 0x0, + AppCode: 0x1, UserMsg: "too many requests", }, innerError: innerError{ @@ -28,7 +28,7 @@ var ( ErrBodyTooLarge = &domainError{ outerError: outerError{ StatusCode: http.StatusRequestEntityTooLarge, - AppCode: 0x1, + AppCode: 0x2, UserMsg: "body too large", }, innerError: innerError{ @@ -39,7 +39,7 @@ var ( ErrWrongContentType = &domainError{ outerError: outerError{ StatusCode: http.StatusUnsupportedMediaType, - AppCode: 0x2, + AppCode: 0x3, UserMsg: "unsupported media type", }, innerError: innerError{ @@ -50,7 +50,7 @@ var ( ErrNotEnoughImages = &domainError{ outerError: outerError{ StatusCode: http.StatusBadRequest, - AppCode: 0x3, + AppCode: 0x4, UserMsg: "not enough images", }, innerError: innerError{ @@ -61,7 +61,7 @@ var ( ErrTooManyImages = &domainError{ outerError: outerError{ StatusCode: http.StatusRequestEntityTooLarge, - AppCode: 0x4, + AppCode: 0x5, UserMsg: "too many images", }, innerError: innerError{ @@ -72,7 +72,7 @@ var ( ErrImageTooLarge = &domainError{ outerError: outerError{ StatusCode: http.StatusRequestEntityTooLarge, - AppCode: 0x5, + AppCode: 0x6, UserMsg: "image too large", }, innerError: innerError{ @@ -83,7 +83,7 @@ var ( ErrNotImage = &domainError{ outerError: outerError{ StatusCode: http.StatusUnsupportedMediaType, - AppCode: 0x6, + AppCode: 0x7, UserMsg: "unsupported media type", }, innerError: innerError{ @@ -94,7 +94,7 @@ var ( ErrDurationNotSet = &domainError{ outerError: outerError{ StatusCode: http.StatusBadRequest, - AppCode: 0x7, + AppCode: 0x8, UserMsg: "duration not set", }, innerError: innerError{ @@ -105,7 +105,7 @@ var ( ErrDurationInvalid = &domainError{ outerError: outerError{ StatusCode: http.StatusBadRequest, - AppCode: 0x8, + AppCode: 0x9, UserMsg: "duration invalid", }, innerError: innerError{ @@ -116,7 +116,7 @@ var ( ErrAlbumNotFound = &domainError{ outerError: outerError{ StatusCode: http.StatusNotFound, - AppCode: 0x9, + AppCode: 0xA, UserMsg: "album not found", }, innerError: innerError{ @@ -127,7 +127,7 @@ var ( ErrPairNotFound = &domainError{ outerError: outerError{ StatusCode: http.StatusInternalServerError, - AppCode: 0xA, + AppCode: 0xB, UserMsg: "internal server error", }, innerError: innerError{ @@ -138,7 +138,7 @@ var ( ErrTokenNotFound = &domainError{ outerError: outerError{ StatusCode: http.StatusNotFound, - AppCode: 0xB, + AppCode: 0xC, UserMsg: "token not found", }, innerError: innerError{ @@ -149,7 +149,7 @@ var ( ErrImageNotFound = &domainError{ outerError: outerError{ StatusCode: http.StatusInternalServerError, - AppCode: 0xC, + AppCode: 0xD, UserMsg: "internal server error", }, innerError: innerError{ @@ -160,7 +160,7 @@ var ( ErrAlbumAlreadyExists = &domainError{ outerError: outerError{ StatusCode: http.StatusInternalServerError, - AppCode: 0xD, + AppCode: 0xE, UserMsg: "internal server error", }, innerError: innerError{ @@ -171,7 +171,7 @@ var ( ErrTokenAlreadyExists = &domainError{ outerError: outerError{ StatusCode: http.StatusInternalServerError, - AppCode: 0xE, + AppCode: 0xF, UserMsg: "internal server error", }, innerError: innerError{ @@ -182,7 +182,7 @@ var ( ErrUnsupportedMediaType = &domainError{ outerError: outerError{ StatusCode: http.StatusUnsupportedMediaType, - AppCode: 0xF, + AppCode: 0x10, UserMsg: "unsupported media type", }, innerError: innerError{ @@ -193,7 +193,7 @@ var ( ErrThirdPartyUnavailable = &domainError{ outerError: outerError{ StatusCode: http.StatusInternalServerError, - AppCode: 0x10, + AppCode: 0x11, UserMsg: "internal server error", }, innerError: innerError{ @@ -204,7 +204,7 @@ var ( ErrBadHealthCompressor = &domainError{ outerError: outerError{ StatusCode: http.StatusInternalServerError, - AppCode: 0x11, + AppCode: 0x12, UserMsg: "internal server error", }, innerError: innerError{ @@ -215,7 +215,7 @@ var ( ErrBadHealthStorage = &domainError{ outerError: outerError{ StatusCode: http.StatusInternalServerError, - AppCode: 0x12, + AppCode: 0x13, UserMsg: "internal server error", }, innerError: innerError{ @@ -226,7 +226,7 @@ var ( ErrBadHealthDatabase = &domainError{ outerError: outerError{ StatusCode: http.StatusInternalServerError, - AppCode: 0x13, + AppCode: 0x14, UserMsg: "internal server error", }, innerError: innerError{ @@ -237,7 +237,7 @@ var ( ErrBadHealthCache = &domainError{ outerError: outerError{ StatusCode: http.StatusInternalServerError, - AppCode: 0x14, + AppCode: 0x15, UserMsg: "internal server error", }, innerError: innerError{ @@ -248,7 +248,7 @@ var ( ErrUnknown = &domainError{ outerError: outerError{ StatusCode: http.StatusInternalServerError, - AppCode: 0x11, + AppCode: 0x16, UserMsg: "internal server error", }, innerError: innerError{ diff --git a/domain/service/queue_integration_test.go b/domain/service/queue_integration_test.go index bbed00e..2b71313 100644 --- a/domain/service/queue_integration_test.go +++ b/domain/service/queue_integration_test.go @@ -11,33 +11,39 @@ import ( "github.com/stretchr/testify/require" "github.com/zitryss/aye-and-nay/infrastructure/cache" + . "github.com/zitryss/aye-and-nay/internal/generator" ) func TestPQueueIntegration(t *testing.T) { + id, _ := GenId() redis, err := cache.NewRedis(context.Background(), cache.DefaultRedisConfig) require.NoError(t, err) - pq := newPQueue(0xFE28, redis) + pqueue := id() + album1 := id() + album2 := id() + album3 := id() + pq := newPQueue(pqueue, redis) ctx, cancel := context.WithCancel(context.Background()) defer cancel() pq.Monitor(ctx) go func() { time.Sleep(100 * time.Millisecond) - err := pq.add(ctx, 0x85D5, time.Now().Add(400*time.Millisecond)) + err := pq.add(ctx, album1, time.Now().Add(400*time.Millisecond)) assert.NoError(t, err) time.Sleep(100 * time.Millisecond) - err = pq.add(ctx, 0x89C1, time.Now().Add(200*time.Millisecond)) + err = pq.add(ctx, album2, time.Now().Add(200*time.Millisecond)) assert.NoError(t, err) time.Sleep(100 * time.Millisecond) - err = pq.add(ctx, 0x97D3, time.Now().Add(400*time.Millisecond)) + err = pq.add(ctx, album3, time.Now().Add(400*time.Millisecond)) assert.NoError(t, err) }() album, err := pq.poll(ctx) assert.NoError(t, err) - assert.Equal(t, uint64(0x89C1), album) + assert.Equal(t, album2, album) album, err = pq.poll(ctx) assert.NoError(t, err) - assert.Equal(t, uint64(0x85D5), album) + assert.Equal(t, album1, album) album, err = pq.poll(ctx) assert.NoError(t, err) - assert.Equal(t, uint64(0x97D3), album) + assert.Equal(t, album3, album) } diff --git a/domain/service/queue_test.go b/domain/service/queue_test.go index 54b6381..0eaf6fc 100644 --- a/domain/service/queue_test.go +++ b/domain/service/queue_test.go @@ -10,41 +10,47 @@ import ( "github.com/stretchr/testify/assert" "github.com/zitryss/aye-and-nay/infrastructure/cache" + . "github.com/zitryss/aye-and-nay/internal/generator" ) func TestPQueue(t *testing.T) { + id, _ := GenId() mem := cache.NewMem(cache.DefaultMemConfig) - pq := newPQueue(0xFE28, mem) + pqueue := id() + album1 := id() + album2 := id() + album3 := id() + pq := newPQueue(pqueue, mem) ctx, cancel := context.WithCancel(context.Background()) defer cancel() pq.Monitor(ctx) go func() { time.Sleep(100 * time.Millisecond) - err := pq.add(ctx, 0x85D5, time.Now().Add(400*time.Millisecond)) + err := pq.add(ctx, album1, time.Now().Add(400*time.Millisecond)) assert.NoError(t, err) time.Sleep(100 * time.Millisecond) - err = pq.add(ctx, 0x89C1, time.Now().Add(200*time.Millisecond)) + err = pq.add(ctx, album2, time.Now().Add(200*time.Millisecond)) assert.NoError(t, err) time.Sleep(100 * time.Millisecond) - err = pq.add(ctx, 0x97D3, time.Now().Add(400*time.Millisecond)) + err = pq.add(ctx, album3, time.Now().Add(400*time.Millisecond)) assert.NoError(t, err) }() start := time.Now() album, err := pq.poll(ctx) d := time.Since(start) assert.NoError(t, err) - assert.Equal(t, uint64(0x89C1), album) + assert.Equal(t, album2, album) assert.True(t, 380*time.Millisecond < d && d < 420*time.Millisecond) start = time.Now() album, err = pq.poll(ctx) d = time.Since(start) assert.NoError(t, err) - assert.Equal(t, uint64(0x85D5), album) + assert.Equal(t, album1, album) assert.True(t, 80*time.Millisecond < d && d < 120*time.Millisecond) start = time.Now() album, err = pq.poll(ctx) d = time.Since(start) assert.NoError(t, err) - assert.Equal(t, uint64(0x97D3), album) + assert.Equal(t, album3, album) assert.True(t, 180*time.Millisecond < d && d < 220*time.Millisecond) } diff --git a/domain/service/service.go b/domain/service/service.go index 7e8acb6..db89b3b 100644 --- a/domain/service/service.go +++ b/domain/service/service.go @@ -59,7 +59,7 @@ func New( } func NewQueueCalc(q domain.Queuer) *QueueCalc { - return &QueueCalc{newQueue(0x6CF9, q)} + return &QueueCalc{newQueue(0x1, q)} } type QueueCalc struct { @@ -67,7 +67,7 @@ type QueueCalc struct { } func NewQueueComp(q domain.Queuer) *QueueComp { - return &QueueComp{newQueue(0xDD66, q)} + return &QueueComp{newQueue(0x2, q)} } type QueueComp struct { @@ -75,7 +75,7 @@ type QueueComp struct { } func NewQueueDel(q domain.PQueuer) *QueueDel { - return &QueueDel{newPQueue(0xCDF9, q)} + return &QueueDel{newPQueue(0x3, q)} } type QueueDel struct { diff --git a/domain/service/service_integration_test.go b/domain/service/service_integration_test.go index 194ac10..73779b8 100644 --- a/domain/service/service_integration_test.go +++ b/domain/service/service_integration_test.go @@ -20,6 +20,7 @@ import ( "github.com/zitryss/aye-and-nay/infrastructure/database" "github.com/zitryss/aye-and-nay/infrastructure/storage" "github.com/zitryss/aye-and-nay/internal/dockertest" + . "github.com/zitryss/aye-and-nay/internal/generator" . "github.com/zitryss/aye-and-nay/internal/testing" "github.com/zitryss/aye-and-nay/pkg/env" "github.com/zitryss/aye-and-nay/pkg/log" @@ -56,11 +57,11 @@ func TestMain(m *testing.M) { func TestServiceIntegrationAlbum(t *testing.T) { t.Run("Positive", func(t *testing.T) { - fn1 := func() func() (uint64, error) { - i := uint64(0) + id, _ := GenId() + idQ, _ := GenId() + fnId := func() func() (uint64, error) { return func() (uint64, error) { - i++ - return 0x463E + i, nil + return id(), nil } }() ctx, cancel := context.WithCancel(context.Background()) @@ -75,12 +76,12 @@ func TestServiceIntegrationAlbum(t *testing.T) { require.NoError(t, err) qCalc := &QueueCalc{} qCalc.Monitor(ctx) - qComp := &QueueComp{newQueue(0xB273, redis)} + qComp := &QueueComp{newQueue(idQ(), redis)} qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) heartbeatComp := make(chan interface{}) - serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithHeartbeatComp(heartbeatComp)) + serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fnId), WithHeartbeatComp(heartbeatComp)) gComp, ctxComp := errgroup.WithContext(ctx) serv.StartWorkingPoolComp(ctxComp, gComp) files := []model.File{Png(), Png()} @@ -96,11 +97,11 @@ func TestServiceIntegrationAlbum(t *testing.T) { assert.InDelta(t, 1, p, TOLERANCE) }) t.Run("Negative", func(t *testing.T) { - fn1 := func() func() (uint64, error) { - i := uint64(0) + id, _ := GenId() + idQ, _ := GenId() + fnId := func() func() (uint64, error) { return func() (uint64, error) { - i++ - return 0x915C + i, nil + return id(), nil } }() ctx, cancel := context.WithCancel(context.Background()) @@ -116,12 +117,12 @@ func TestServiceIntegrationAlbum(t *testing.T) { require.NoError(t, err) qCalc := &QueueCalc{} qCalc.Monitor(ctx) - qComp := &QueueComp{newQueue(0x88AB, redis)} + qComp := &QueueComp{newQueue(idQ(), redis)} qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) heartbeatComp := make(chan interface{}) - serv := New(DefaultServiceConfig, comp, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithHeartbeatComp(heartbeatComp)) + serv := New(DefaultServiceConfig, comp, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fnId), WithHeartbeatComp(heartbeatComp)) gComp, ctxComp := errgroup.WithContext(ctx) serv.StartWorkingPoolComp(ctxComp, gComp) files := []model.File{Png(), Png()} @@ -169,14 +170,13 @@ func TestServiceIntegrationAlbum(t *testing.T) { func TestServiceIntegrationPair(t *testing.T) { t.Run("Positive1", func(t *testing.T) { - fn1 := func() func() (uint64, error) { - i := uint64(0) + id, ids := GenId() + fnId := func() func() (uint64, error) { return func() (uint64, error) { - i++ - return 0x3BC5 + i, nil + return id(), nil } }() - fn2 := func(n int, swap func(i int, j int)) {} + fnS := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) @@ -193,44 +193,43 @@ func TestServiceIntegrationPair(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) assert.NoError(t, err) img7, img8, err := serv.Pair(ctx, album) assert.NoError(t, err) - img1 := model.Image{Id: 0x3BC7, Token: 0x3BC9, Src: "/api/images/yTsAAAAAAAA/"} - img2 := model.Image{Id: 0x3BC8, Token: 0x3BCA, Src: "/api/images/yjsAAAAAAAA/"} + img1 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(3), Src: "/api/images/" + ids.Base64(3) + "/"} + img2 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(4), Src: "/api/images/" + ids.Base64(4) + "/"} imgs1 := []model.Image{img1, img2} assert.NotEqual(t, img7, img8) assert.Contains(t, imgs1, img7) assert.Contains(t, imgs1, img8) img9, img10, err := serv.Pair(ctx, album) assert.NoError(t, err) - img3 := model.Image{Id: 0x3BC8, Token: 0x3BCB, Src: "/api/images/yzsAAAAAAAA/"} - img4 := model.Image{Id: 0x3BC7, Token: 0x3BCC, Src: "/api/images/zDsAAAAAAAA/"} + img3 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(5), Src: "/api/images/" + ids.Base64(5) + "/"} + img4 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(6), Src: "/api/images/" + ids.Base64(6) + "/"} imgs2 := []model.Image{img3, img4} assert.NotEqual(t, img9, img10) assert.Contains(t, imgs2, img9) assert.Contains(t, imgs2, img10) img11, img12, err := serv.Pair(ctx, album) assert.NoError(t, err) - img5 := model.Image{Id: 0x3BC7, Token: 0x3BCD, Src: "/api/images/zTsAAAAAAAA/"} - img6 := model.Image{Id: 0x3BC8, Token: 0x3BCE, Src: "/api/images/zjsAAAAAAAA/"} + img5 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(7), Src: "/api/images/" + ids.Base64(7) + "/"} + img6 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(8), Src: "/api/images/" + ids.Base64(8) + "/"} imgs3 := []model.Image{img5, img6} assert.NotEqual(t, img11, img12) assert.Contains(t, imgs3, img11) assert.Contains(t, imgs3, img12) }) t.Run("Positive2", func(t *testing.T) { - fn1 := func() func() (uint64, error) { - i := uint64(0) + id, ids := GenId() + fnId := func() func() (uint64, error) { return func() (uint64, error) { - i++ - return 0xFAFD + i, nil + return id(), nil } }() - fn2 := func(n int, swap func(i int, j int)) {} + fnS := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) @@ -249,36 +248,37 @@ func TestServiceIntegrationPair(t *testing.T) { qDel.Monitor(ctx) conf := DefaultServiceConfig conf.TempLinks = false - serv := New(conf, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(conf, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) assert.NoError(t, err) img7, img8, err := serv.Pair(ctx, album) assert.NoError(t, err) - img1 := model.Image{Id: 0xFAFF, Token: 0xFAFF, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/__oAAAAAAAA"} - img2 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} + img1 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1)} + img2 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2)} imgs1 := []model.Image{img1, img2} assert.NotEqual(t, img7, img8) assert.Contains(t, imgs1, img7) assert.Contains(t, imgs1, img8) img9, img10, err := serv.Pair(ctx, album) assert.NoError(t, err) - img3 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} - img4 := model.Image{Id: 0xFAFF, Token: 0xFAFF, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/__oAAAAAAAA"} + img3 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2)} + img4 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1)} imgs2 := []model.Image{img3, img4} assert.NotEqual(t, img9, img10) assert.Contains(t, imgs2, img9) assert.Contains(t, imgs2, img10) img11, img12, err := serv.Pair(ctx, album) assert.NoError(t, err) - img5 := model.Image{Id: 0xFAFF, Token: 0xFAFF, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/__oAAAAAAAA"} - img6 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} + img5 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1)} + img6 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2)} imgs3 := []model.Image{img5, img6} assert.NotEqual(t, img11, img12) assert.Contains(t, imgs3, img11) assert.Contains(t, imgs3, img12) }) t.Run("Negative", func(t *testing.T) { + id, _ := GenId() ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) @@ -296,21 +296,20 @@ func TestServiceIntegrationPair(t *testing.T) { qDel := &QueueDel{} qDel.Monitor(ctx) serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel) - _, _, err = serv.Pair(ctx, 0xEB46) + _, _, err = serv.Pair(ctx, id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestServiceIntegrationImage(t *testing.T) { t.Run("Positive", func(t *testing.T) { - fn1 := func() func() (uint64, error) { - i := uint64(0) + id, _ := GenId() + fnId := func() func() (uint64, error) { return func() (uint64, error) { - i++ - return 0xA83F + i, nil + return id(), nil } }() - fn2 := func(n int, swap func(i int, j int)) {} + fnS := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) @@ -327,7 +326,7 @@ func TestServiceIntegrationImage(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) assert.NoError(t, err) @@ -341,6 +340,7 @@ func TestServiceIntegrationImage(t *testing.T) { assert.NotNil(t, f.Reader) }) t.Run("Negative", func(t *testing.T) { + id, _ := GenId() ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) @@ -358,21 +358,20 @@ func TestServiceIntegrationImage(t *testing.T) { qDel := &QueueDel{} qDel.Monitor(ctx) serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel) - _, err = serv.Image(ctx, 0xE283) + _, err = serv.Image(ctx, id()) assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) } func TestServiceIntegrationVote(t *testing.T) { t.Run("Positive1", func(t *testing.T) { - fn1 := func() func() (uint64, error) { - i := uint64(0) + id, _ := GenId() + fnId := func() func() (uint64, error) { return func() (uint64, error) { - i++ - return 0xC389 + i, nil + return id(), nil } }() - fn2 := func(n int, swap func(i int, j int)) {} + fnS := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) @@ -389,7 +388,7 @@ func TestServiceIntegrationVote(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) assert.NoError(t, err) @@ -399,14 +398,13 @@ func TestServiceIntegrationVote(t *testing.T) { assert.NoError(t, err) }) t.Run("Positive2", func(t *testing.T) { - fn1 := func() func() (uint64, error) { - i := uint64(0) + id, _ := GenId() + fnId := func() func() (uint64, error) { return func() (uint64, error) { - i++ - return 0x1E58 + i, nil + return id(), nil } }() - fn2 := func(n int, swap func(i int, j int)) {} + fnS := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) @@ -425,7 +423,7 @@ func TestServiceIntegrationVote(t *testing.T) { qDel.Monitor(ctx) conf := DefaultServiceConfig conf.TempLinks = false - serv := New(conf, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(conf, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) assert.NoError(t, err) @@ -435,14 +433,13 @@ func TestServiceIntegrationVote(t *testing.T) { assert.NoError(t, err) }) t.Run("Negative1", func(t *testing.T) { - fn1 := func() func() (uint64, error) { - i := uint64(0) + id, _ := GenId() + fnId := func() func() (uint64, error) { return func() (uint64, error) { - i++ - return 0xE24F + i, nil + return id(), nil } }() - fn2 := func(n int, swap func(i int, j int)) {} + fnS := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) @@ -459,24 +456,23 @@ func TestServiceIntegrationVote(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) assert.NoError(t, err) img1, img2, err := serv.Pair(ctx, album) assert.NoError(t, err) - err = serv.Vote(ctx, 0x12E6, img1.Token, img2.Token) + err = serv.Vote(ctx, id(), img1.Token, img2.Token) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative2", func(t *testing.T) { - fn1 := func() func() (uint64, error) { - i := uint64(0) + id, _ := GenId() + fnId := func() func() (uint64, error) { return func() (uint64, error) { - i++ - return 0xBC43 + i, nil + return id(), nil } }() - fn2 := func(n int, swap func(i int, j int)) {} + fnS := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) @@ -493,27 +489,27 @@ func TestServiceIntegrationVote(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) assert.NoError(t, err) _, _, err = serv.Pair(ctx, album) assert.NoError(t, err) - err = serv.Vote(ctx, album, 0x1CC1, 0xF83C) + err = serv.Vote(ctx, album, id(), id()) assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) } func TestServiceIntegrationTop(t *testing.T) { t.Run("Positive", func(t *testing.T) { - fn1 := func() func() (uint64, error) { - i := uint64(0) + id, ids := GenId() + idQ, _ := GenId() + fnId := func() func() (uint64, error) { return func() (uint64, error) { - i++ - return 0x4DB8 + i, nil + return id(), nil } }() - fn2 := func(n int, swap func(i int, j int)) {} + fnS := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) @@ -524,14 +520,14 @@ func TestServiceIntegrationTop(t *testing.T) { require.NoError(t, err) redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) require.NoError(t, err) - qCalc := &QueueCalc{newQueue(0x1A01, redis)} + qCalc := &QueueCalc{newQueue(idQ(), redis)} qCalc.Monitor(ctx) qComp := &QueueComp{} qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) heartbeatCalc := make(chan interface{}) - serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2), WithHeartbeatCalc(heartbeatCalc)) + serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS), WithHeartbeatCalc(heartbeatCalc)) gCalc, ctxCalc := errgroup.WithContext(ctx) serv.StartWorkingPoolCalc(ctxCalc, gCalc) files := []model.File{Png(), Png()} @@ -549,12 +545,13 @@ func TestServiceIntegrationTop(t *testing.T) { AssertChannel(t, heartbeatCalc) imgs1, err := serv.Top(ctx, album) assert.NoError(t, err) - img5 := model.Image{Id: 0x4DBA, Src: "/aye-and-nay/albums/uU0AAAAAAAA/images/uk0AAAAAAAA", Rating: 0.5, Compressed: false} - img6 := model.Image{Id: 0x4DBB, Src: "/aye-and-nay/albums/uU0AAAAAAAA/images/u00AAAAAAAA", Rating: 0.5, Compressed: false} + img5 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.5, Compressed: false} + img6 := model.Image{Id: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.5, Compressed: false} imgs2 := []model.Image{img5, img6} assert.Equal(t, imgs2, imgs1) }) t.Run("Negative", func(t *testing.T) { + id, _ := GenId() ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) @@ -572,13 +569,16 @@ func TestServiceIntegrationTop(t *testing.T) { qDel := &QueueDel{} qDel.Monitor(ctx) serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel) - _, err = serv.Top(ctx, 0x83CD) + _, err = serv.Top(ctx, id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestServiceIntegrationDelete(t *testing.T) { t.Run("Positive1", func(t *testing.T) { + id1, ids1 := GenId() + id2, ids2 := GenId() + idPQ, _ := GenId() ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) @@ -593,13 +593,13 @@ func TestServiceIntegrationDelete(t *testing.T) { qCalc.Monitor(ctx) qComp := &QueueComp{} qComp.Monitor(ctx) - qDel := &QueueDel{newPQueue(0xE3FF, redis)} + qDel := &QueueDel{newPQueue(idPQ(), redis)} qDel.Monitor(ctx) - alb1 := AlbumEmptyFactory(0x101F) + alb1 := AlbumEmptyFactory(id1, ids1) alb1.Expires = time.Now().Add(-1 * time.Hour) err = mongo.SaveAlbum(ctx, alb1) assert.NoError(t, err) - alb2 := AlbumEmptyFactory(0xFFBB) + alb2 := AlbumEmptyFactory(id2, ids2) alb2.Expires = time.Now().Add(1 * time.Hour) err = mongo.SaveAlbum(ctx, alb2) assert.NoError(t, err) @@ -612,13 +612,14 @@ func TestServiceIntegrationDelete(t *testing.T) { v := AssertChannel(t, heartbeatDel) album, ok := v.(uint64) assert.True(t, ok) - assert.Equal(t, uint64(0x101F), album) + assert.Equal(t, ids1.Uint64(0), album) t.Cleanup(func() { - _ = mongo.DeleteAlbum(context.Background(), 0x101F) - _ = mongo.DeleteAlbum(context.Background(), 0xFFBB) + _ = mongo.DeleteAlbum(context.Background(), ids1.Uint64(0)) + _ = mongo.DeleteAlbum(context.Background(), ids2.Uint64(0)) }) }) t.Run("Positive2", func(t *testing.T) { + idPQ, _ := GenId() ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) @@ -633,7 +634,7 @@ func TestServiceIntegrationDelete(t *testing.T) { qCalc.Monitor(ctx) qComp := &QueueComp{} qComp.Monitor(ctx) - qDel := &QueueDel{newPQueue(0xEF3F, redis)} + qDel := &QueueDel{newPQueue(idPQ(), redis)} qDel.Monitor(ctx) heartbeatDel := make(chan interface{}) serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) @@ -648,6 +649,7 @@ func TestServiceIntegrationDelete(t *testing.T) { assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative", func(t *testing.T) { + idPQ, _ := GenId() ctx, cancel := context.WithCancel(context.Background()) defer cancel() imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) @@ -662,7 +664,7 @@ func TestServiceIntegrationDelete(t *testing.T) { qCalc.Monitor(ctx) qComp := &QueueComp{} qComp.Monitor(ctx) - qDel := &QueueDel{newPQueue(0xEF3F, redis)} + qDel := &QueueDel{newPQueue(idPQ(), redis)} qDel.Monitor(ctx) heartbeatDel := make(chan interface{}) serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) diff --git a/domain/service/service_test.go b/domain/service/service_test.go index 1f500d1..86ab3d4 100644 --- a/domain/service/service_test.go +++ b/domain/service/service_test.go @@ -16,16 +16,17 @@ import ( "github.com/zitryss/aye-and-nay/infrastructure/compressor" "github.com/zitryss/aye-and-nay/infrastructure/database" "github.com/zitryss/aye-and-nay/infrastructure/storage" + . "github.com/zitryss/aye-and-nay/internal/generator" . "github.com/zitryss/aye-and-nay/internal/testing" ) func TestServiceAlbum(t *testing.T) { t.Run("Positive", func(t *testing.T) { - fn1 := func() func() (uint64, error) { - i := uint64(0) + id, _ := GenId() + idQ, _ := GenId() + fnId := func() func() (uint64, error) { return func() (uint64, error) { - i++ - return 0x463E + i, nil + return id(), nil } }() ctx, cancel := context.WithCancel(context.Background()) @@ -36,12 +37,12 @@ func TestServiceAlbum(t *testing.T) { mCache := cache.NewMem(cache.DefaultMemConfig) qCalc := &QueueCalc{} qCalc.Monitor(ctx) - qComp := &QueueComp{newQueue(0xB273, mCache)} + qComp := &QueueComp{newQueue(idQ(), mCache)} qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) heartbeatComp := make(chan interface{}) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithHeartbeatComp(heartbeatComp)) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fnId), WithHeartbeatComp(heartbeatComp)) gComp, ctxComp := errgroup.WithContext(ctx) serv.StartWorkingPoolComp(ctxComp, gComp) files := []model.File{Png(), Png()} @@ -57,11 +58,11 @@ func TestServiceAlbum(t *testing.T) { assert.InDelta(t, 1, p, TOLERANCE) }) t.Run("Negative", func(t *testing.T) { - fn1 := func() func() (uint64, error) { - i := uint64(0) + id, _ := GenId() + idQ, _ := GenId() + fnId := func() func() (uint64, error) { return func() (uint64, error) { - i++ - return 0x915C + i, nil + return id(), nil } }() ctx, cancel := context.WithCancel(context.Background()) @@ -74,12 +75,12 @@ func TestServiceAlbum(t *testing.T) { mCache := cache.NewMem(cache.DefaultMemConfig) qCalc := &QueueCalc{} qCalc.Monitor(ctx) - qComp := &QueueComp{newQueue(0x88AB, mCache)} + qComp := &QueueComp{newQueue(idQ(), mCache)} qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) heartbeatComp := make(chan interface{}) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithHeartbeatComp(heartbeatComp)) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fnId), WithHeartbeatComp(heartbeatComp)) gComp, ctxComp := errgroup.WithContext(ctx) serv.StartWorkingPoolComp(ctxComp, gComp) files := []model.File{Png(), Png()} @@ -127,14 +128,13 @@ func TestServiceAlbum(t *testing.T) { func TestServicePair(t *testing.T) { t.Run("Positive1", func(t *testing.T) { - fn1 := func() func() (uint64, error) { - i := uint64(0) + id, ids := GenId() + fnId := func() func() (uint64, error) { return func() (uint64, error) { - i++ - return 0x3BC5 + i, nil + return id(), nil } }() - fn2 := func(n int, swap func(i int, j int)) {} + fnS := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() comp := compressor.NewMock() @@ -147,44 +147,43 @@ func TestServicePair(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) assert.NoError(t, err) img7, img8, err := serv.Pair(ctx, album) assert.NoError(t, err) - img1 := model.Image{Id: 0x3BC7, Token: 0x3BC9, Src: "/api/images/yTsAAAAAAAA/"} - img2 := model.Image{Id: 0x3BC8, Token: 0x3BCA, Src: "/api/images/yjsAAAAAAAA/"} + img1 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(3), Src: "/api/images/" + ids.Base64(3) + "/"} + img2 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(4), Src: "/api/images/" + ids.Base64(4) + "/"} imgs1 := []model.Image{img1, img2} assert.NotEqual(t, img7, img8) assert.Contains(t, imgs1, img7) assert.Contains(t, imgs1, img8) img9, img10, err := serv.Pair(ctx, album) assert.NoError(t, err) - img3 := model.Image{Id: 0x3BC8, Token: 0x3BCB, Src: "/api/images/yzsAAAAAAAA/"} - img4 := model.Image{Id: 0x3BC7, Token: 0x3BCC, Src: "/api/images/zDsAAAAAAAA/"} + img3 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(5), Src: "/api/images/" + ids.Base64(5) + "/"} + img4 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(6), Src: "/api/images/" + ids.Base64(6) + "/"} imgs2 := []model.Image{img3, img4} assert.NotEqual(t, img9, img10) assert.Contains(t, imgs2, img9) assert.Contains(t, imgs2, img10) img11, img12, err := serv.Pair(ctx, album) assert.NoError(t, err) - img5 := model.Image{Id: 0x3BC7, Token: 0x3BCD, Src: "/api/images/zTsAAAAAAAA/"} - img6 := model.Image{Id: 0x3BC8, Token: 0x3BCE, Src: "/api/images/zjsAAAAAAAA/"} + img5 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(7), Src: "/api/images/" + ids.Base64(7) + "/"} + img6 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(8), Src: "/api/images/" + ids.Base64(8) + "/"} imgs3 := []model.Image{img5, img6} assert.NotEqual(t, img11, img12) assert.Contains(t, imgs3, img11) assert.Contains(t, imgs3, img12) }) t.Run("Positive2", func(t *testing.T) { - fn1 := func() func() (uint64, error) { - i := uint64(0) + id, ids := GenId() + fnId := func() func() (uint64, error) { return func() (uint64, error) { - i++ - return 0xFAFD + i, nil + return id(), nil } }() - fn2 := func(n int, swap func(i int, j int)) {} + fnS := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() comp := compressor.NewMock() @@ -199,36 +198,37 @@ func TestServicePair(t *testing.T) { qDel.Monitor(ctx) conf := DefaultServiceConfig conf.TempLinks = false - serv := New(conf, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(conf, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) assert.NoError(t, err) img7, img8, err := serv.Pair(ctx, album) assert.NoError(t, err) - img1 := model.Image{Id: 0xFAFF, Token: 0xFAFF, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/__oAAAAAAAA"} - img2 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} + img1 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1)} + img2 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2)} imgs1 := []model.Image{img1, img2} assert.NotEqual(t, img7, img8) assert.Contains(t, imgs1, img7) assert.Contains(t, imgs1, img8) img9, img10, err := serv.Pair(ctx, album) assert.NoError(t, err) - img3 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} - img4 := model.Image{Id: 0xFAFF, Token: 0xFAFF, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/__oAAAAAAAA"} + img3 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2)} + img4 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1)} imgs2 := []model.Image{img3, img4} assert.NotEqual(t, img9, img10) assert.Contains(t, imgs2, img9) assert.Contains(t, imgs2, img10) img11, img12, err := serv.Pair(ctx, album) assert.NoError(t, err) - img5 := model.Image{Id: 0xFAFF, Token: 0xFAFF, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/__oAAAAAAAA"} - img6 := model.Image{Id: 0xFB00, Token: 0xFB00, Src: "/aye-and-nay/albums/_voAAAAAAAA/images/APsAAAAAAAA"} + img5 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1)} + img6 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2)} imgs3 := []model.Image{img5, img6} assert.NotEqual(t, img11, img12) assert.Contains(t, imgs3, img11) assert.Contains(t, imgs3, img12) }) t.Run("Negative", func(t *testing.T) { + id, _ := GenId() ctx, cancel := context.WithCancel(context.Background()) defer cancel() comp := compressor.NewMock() @@ -242,21 +242,20 @@ func TestServicePair(t *testing.T) { qDel := &QueueDel{} qDel.Monitor(ctx) serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel) - _, _, err := serv.Pair(ctx, 0xEB46) + _, _, err := serv.Pair(ctx, id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestServiceImage(t *testing.T) { t.Run("Positive", func(t *testing.T) { - fn1 := func() func() (uint64, error) { - i := uint64(0) + id, _ := GenId() + fnId := func() func() (uint64, error) { return func() (uint64, error) { - i++ - return 0xA83F + i, nil + return id(), nil } }() - fn2 := func(n int, swap func(i int, j int)) {} + fnS := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() comp := compressor.NewMock() @@ -269,7 +268,7 @@ func TestServiceImage(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) assert.NoError(t, err) @@ -283,6 +282,7 @@ func TestServiceImage(t *testing.T) { assert.NotNil(t, f.Reader) }) t.Run("Negative", func(t *testing.T) { + id, _ := GenId() ctx, cancel := context.WithCancel(context.Background()) defer cancel() comp := compressor.NewMock() @@ -296,21 +296,20 @@ func TestServiceImage(t *testing.T) { qDel := &QueueDel{} qDel.Monitor(ctx) serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel) - _, err := serv.Image(ctx, 0xE283) + _, err := serv.Image(ctx, id()) assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) } func TestServiceVote(t *testing.T) { t.Run("Positive1", func(t *testing.T) { - fn1 := func() func() (uint64, error) { - i := uint64(0) + id, _ := GenId() + fnId := func() func() (uint64, error) { return func() (uint64, error) { - i++ - return 0xC389 + i, nil + return id(), nil } }() - fn2 := func(n int, swap func(i int, j int)) {} + fnS := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() comp := compressor.NewMock() @@ -323,7 +322,7 @@ func TestServiceVote(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) assert.NoError(t, err) @@ -333,14 +332,13 @@ func TestServiceVote(t *testing.T) { assert.NoError(t, err) }) t.Run("Positive2", func(t *testing.T) { - fn1 := func() func() (uint64, error) { - i := uint64(0) + id, _ := GenId() + fnId := func() func() (uint64, error) { return func() (uint64, error) { - i++ - return 0x1E58 + i, nil + return id(), nil } }() - fn2 := func(n int, swap func(i int, j int)) {} + fnS := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() comp := compressor.NewMock() @@ -355,7 +353,7 @@ func TestServiceVote(t *testing.T) { qDel.Monitor(ctx) conf := DefaultServiceConfig conf.TempLinks = false - serv := New(conf, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(conf, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) assert.NoError(t, err) @@ -365,14 +363,13 @@ func TestServiceVote(t *testing.T) { assert.NoError(t, err) }) t.Run("Negative1", func(t *testing.T) { - fn1 := func() func() (uint64, error) { - i := uint64(0) + id, _ := GenId() + fnId := func() func() (uint64, error) { return func() (uint64, error) { - i++ - return 0xE24F + i, nil + return id(), nil } }() - fn2 := func(n int, swap func(i int, j int)) {} + fnS := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() comp := compressor.NewMock() @@ -385,24 +382,23 @@ func TestServiceVote(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) assert.NoError(t, err) img1, img2, err := serv.Pair(ctx, album) assert.NoError(t, err) - err = serv.Vote(ctx, 0x12E6, img1.Token, img2.Token) + err = serv.Vote(ctx, id(), img1.Token, img2.Token) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative2", func(t *testing.T) { - fn1 := func() func() (uint64, error) { - i := uint64(0) + id, _ := GenId() + fnId := func() func() (uint64, error) { return func() (uint64, error) { - i++ - return 0xBC43 + i, nil + return id(), nil } }() - fn2 := func(n int, swap func(i int, j int)) {} + fnS := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() comp := compressor.NewMock() @@ -415,41 +411,41 @@ func TestServiceVote(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2)) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) files := []model.File{Png(), Png()} album, err := serv.Album(ctx, files, 0*time.Millisecond) assert.NoError(t, err) _, _, err = serv.Pair(ctx, album) assert.NoError(t, err) - err = serv.Vote(ctx, album, 0x1CC1, 0xF83C) + err = serv.Vote(ctx, album, id(), id()) assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) } func TestServiceTop(t *testing.T) { t.Run("Positive", func(t *testing.T) { - fn1 := func() func() (uint64, error) { - i := uint64(0) + id, ids := GenId() + idQ, _ := GenId() + fnId := func() func() (uint64, error) { return func() (uint64, error) { - i++ - return 0x4DB8 + i, nil + return id(), nil } }() - fn2 := func(n int, swap func(i int, j int)) {} + fnS := func(n int, swap func(i int, j int)) {} ctx, cancel := context.WithCancel(context.Background()) defer cancel() comp := compressor.NewMock() stor := storage.NewMock() mDb := database.NewMem(database.DefaultMemConfig) mCache := cache.NewMem(cache.DefaultMemConfig) - qCalc := &QueueCalc{newQueue(0x1A01, mCache)} + qCalc := &QueueCalc{newQueue(idQ(), mCache)} qCalc.Monitor(ctx) qComp := &QueueComp{} qComp.Monitor(ctx) qDel := &QueueDel{} qDel.Monitor(ctx) heartbeatCalc := make(chan interface{}) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fn1), WithRandShuffle(fn2), WithHeartbeatCalc(heartbeatCalc)) + serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS), WithHeartbeatCalc(heartbeatCalc)) gCalc, ctxCalc := errgroup.WithContext(ctx) serv.StartWorkingPoolCalc(ctxCalc, gCalc) files := []model.File{Png(), Png()} @@ -467,12 +463,13 @@ func TestServiceTop(t *testing.T) { AssertChannel(t, heartbeatCalc) imgs1, err := serv.Top(ctx, album) assert.NoError(t, err) - img5 := model.Image{Id: 0x4DBA, Src: "/aye-and-nay/albums/uU0AAAAAAAA/images/uk0AAAAAAAA", Rating: 0.5, Compressed: false} - img6 := model.Image{Id: 0x4DBB, Src: "/aye-and-nay/albums/uU0AAAAAAAA/images/u00AAAAAAAA", Rating: 0.5, Compressed: false} + img5 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.5, Compressed: false} + img6 := model.Image{Id: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.5, Compressed: false} imgs2 := []model.Image{img5, img6} assert.Equal(t, imgs2, imgs1) }) t.Run("Negative", func(t *testing.T) { + id, _ := GenId() ctx, cancel := context.WithCancel(context.Background()) defer cancel() comp := compressor.NewMock() @@ -486,13 +483,16 @@ func TestServiceTop(t *testing.T) { qDel := &QueueDel{} qDel.Monitor(ctx) serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel) - _, err := serv.Top(ctx, 0x83CD) + _, err := serv.Top(ctx, id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestServiceDelete(t *testing.T) { t.Run("Positive1", func(t *testing.T) { + id1, ids1 := GenId() + id2, ids2 := GenId() + idPQ, _ := GenId() ctx, cancel := context.WithCancel(context.Background()) defer cancel() comp := compressor.NewMock() @@ -503,13 +503,13 @@ func TestServiceDelete(t *testing.T) { qCalc.Monitor(ctx) qComp := &QueueComp{} qComp.Monitor(ctx) - qDel := &QueueDel{newPQueue(0xE3FF, mCache)} + qDel := &QueueDel{newPQueue(idPQ(), mCache)} qDel.Monitor(ctx) - alb1 := AlbumEmptyFactory(0x101F) + alb1 := AlbumEmptyFactory(id1, ids1) alb1.Expires = time.Now().Add(-1 * time.Hour) err := mDb.SaveAlbum(ctx, alb1) assert.NoError(t, err) - alb2 := AlbumEmptyFactory(0xFFBB) + alb2 := AlbumEmptyFactory(id2, ids2) alb2.Expires = time.Now().Add(1 * time.Hour) err = mDb.SaveAlbum(ctx, alb2) assert.NoError(t, err) @@ -522,9 +522,10 @@ func TestServiceDelete(t *testing.T) { v := AssertChannel(t, heartbeatDel) album, ok := v.(uint64) assert.True(t, ok) - assert.Equal(t, uint64(0x101F), album) + assert.Equal(t, ids1.Uint64(0), album) }) t.Run("Positive2", func(t *testing.T) { + idPQ, _ := GenId() ctx, cancel := context.WithCancel(context.Background()) defer cancel() comp := compressor.NewMock() @@ -535,7 +536,7 @@ func TestServiceDelete(t *testing.T) { qCalc.Monitor(ctx) qComp := &QueueComp{} qComp.Monitor(ctx) - qDel := &QueueDel{newPQueue(0xEF3F, mCache)} + qDel := &QueueDel{newPQueue(idPQ(), mCache)} qDel.Monitor(ctx) heartbeatDel := make(chan interface{}) serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) @@ -550,6 +551,7 @@ func TestServiceDelete(t *testing.T) { assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative", func(t *testing.T) { + idPQ, _ := GenId() ctx, cancel := context.WithCancel(context.Background()) defer cancel() comp := compressor.NewMock() @@ -560,7 +562,7 @@ func TestServiceDelete(t *testing.T) { qCalc.Monitor(ctx) qComp := &QueueComp{} qComp.Monitor(ctx) - qDel := &QueueDel{newPQueue(0xEF3F, mCache)} + qDel := &QueueDel{newPQueue(idPQ(), mCache)} qDel.Monitor(ctx) heartbeatDel := make(chan interface{}) serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) diff --git a/infrastructure/cache/mem_test.go b/infrastructure/cache/mem_test.go index d09dfd4..3ef1004 100644 --- a/infrastructure/cache/mem_test.go +++ b/infrastructure/cache/mem_test.go @@ -10,53 +10,66 @@ import ( "github.com/stretchr/testify/assert" "github.com/zitryss/aye-and-nay/domain/domain" + . "github.com/zitryss/aye-and-nay/internal/generator" . "github.com/zitryss/aye-and-nay/internal/testing" ) func TestMemPair(t *testing.T) { t.Run("Positive", func(t *testing.T) { + id, ids := GenId() mem := NewMem(DefaultMemConfig) - err := mem.Push(context.Background(), 0x23D2, [][2]uint64{{0x3E3D, 0xB399}}) + album := id() + pairs := [][2]uint64{{id(), id()}} + err := mem.Push(context.Background(), album, pairs) assert.NoError(t, err) - image1, image2, err := mem.Pop(context.Background(), 0x23D2) + image1, image2, err := mem.Pop(context.Background(), album) assert.NoError(t, err) - assert.Equal(t, uint64(0x3E3D), image1) - assert.Equal(t, uint64(0xB399), image2) + assert.Equal(t, ids.Uint64(1), image1) + assert.Equal(t, ids.Uint64(2), image2) }) t.Run("Negative1", func(t *testing.T) { + id, _ := GenId() mem := NewMem(DefaultMemConfig) - _, _, err := mem.Pop(context.Background(), 0x73BF) + album := id() + _, _, err := mem.Pop(context.Background(), album) assert.ErrorIs(t, err, domain.ErrPairNotFound) }) t.Run("Negative2", func(t *testing.T) { + id, _ := GenId() mem := NewMem(DefaultMemConfig) - err := mem.Push(context.Background(), 0x1AE9, [][2]uint64{{0x44DC, 0x721B}}) + album := id() + pairs := [][2]uint64{{id(), id()}} + err := mem.Push(context.Background(), album, pairs) assert.NoError(t, err) - _, _, err = mem.Pop(context.Background(), 0x1AE9) + _, _, err = mem.Pop(context.Background(), album) assert.NoError(t, err) - _, _, err = mem.Pop(context.Background(), 0x1AE9) + _, _, err = mem.Pop(context.Background(), album) assert.ErrorIs(t, err, domain.ErrPairNotFound) }) t.Run("Negative3", func(t *testing.T) { + id, _ := GenId() heartbeatPair := make(chan interface{}) mem := NewMem(DefaultMemConfig, WithHeartbeatPair(heartbeatPair)) mem.Monitor() - err := mem.Push(context.Background(), 0xF51A, [][2]uint64{{0x4BB0, 0x3A87}}) + album := id() + pairs := [][2]uint64{{id(), id()}} + err := mem.Push(context.Background(), album, pairs) assert.NoError(t, err) time.Sleep(mem.conf.TimeToLive) AssertChannel(t, heartbeatPair) AssertChannel(t, heartbeatPair) - _, _, err = mem.Pop(context.Background(), 0xF51A) + _, _, err = mem.Pop(context.Background(), album) assert.ErrorIs(t, err, domain.ErrPairNotFound) }) } func TestMemToken(t *testing.T) { t.Run("Positive", func(t *testing.T) { + id, _ := GenId() mem := NewMem(DefaultMemConfig) - token := uint64(0xC2E7) - album1 := uint64(0xB41C) - image1 := uint64(0x52BD) + token := id() + album1 := id() + image1 := id() err := mem.Set(context.Background(), token, album1, image1) assert.NoError(t, err) album2, image2, err := mem.Get(context.Background(), token) @@ -65,26 +78,29 @@ func TestMemToken(t *testing.T) { assert.Equal(t, image1, image2) }) t.Run("Negative1", func(t *testing.T) { + id, _ := GenId() mem := NewMem(DefaultMemConfig) - token := uint64(0x1C4A) - album := uint64(0xF0EE) - image := uint64(0x583C) + token := id() + album := id() + image := id() err := mem.Set(context.Background(), token, album, image) assert.NoError(t, err) err = mem.Set(context.Background(), token, album, image) assert.ErrorIs(t, err, domain.ErrTokenAlreadyExists) }) t.Run("Negative2", func(t *testing.T) { + id, _ := GenId() mem := NewMem(DefaultMemConfig) - token := uint64(0xC4F8) + token := id() _, _, err := mem.Get(context.Background(), token) assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) t.Run("Negative3", func(t *testing.T) { + id, _ := GenId() mem := NewMem(DefaultMemConfig) - token := uint64(0xEB96) - album := uint64(0xC67F) - image := uint64(0x7C45) + token := id() + album := id() + image := id() err := mem.Set(context.Background(), token, album, image) assert.NoError(t, err) _, _, err = mem.Get(context.Background(), token) @@ -97,18 +113,20 @@ func TestMemToken(t *testing.T) { assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) t.Run("Negative4", func(t *testing.T) { + id, _ := GenId() mem := NewMem(DefaultMemConfig) - token := uint64(0xD3BF) + token := id() err := mem.Del(context.Background(), token) assert.NoError(t, err) }) t.Run("Negative5", func(t *testing.T) { + id, _ := GenId() heartbeatToken := make(chan interface{}) mem := NewMem(DefaultMemConfig, WithHeartbeatToken(heartbeatToken)) mem.Monitor() - token := uint64(0xE0AF) - album := uint64(0xCF1E) - image := uint64(0xDD0A) + token := id() + album := id() + image := id() err := mem.Set(context.Background(), token, album, image) assert.NoError(t, err) time.Sleep(mem.conf.TimeToLive) diff --git a/infrastructure/cache/redis_integration_test.go b/infrastructure/cache/redis_integration_test.go index 4f1d2ad..4a4cb3c 100644 --- a/infrastructure/cache/redis_integration_test.go +++ b/infrastructure/cache/redis_integration_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" "github.com/zitryss/aye-and-nay/domain/domain" + . "github.com/zitryss/aye-and-nay/internal/generator" ) func TestRedisAllow(t *testing.T) { @@ -18,189 +19,215 @@ func TestRedisAllow(t *testing.T) { if testing.Short() { t.Skip("short flag is set") } + id, _ := GenId() redis, err := NewRedis(context.Background(), DefaultRedisConfig) require.NoError(t, err) rpm := redis.conf.LimiterRequestsPerSecond + ip := id() for j := 0; j < rpm; j++ { - allowed, err := redis.Allow(context.Background(), 0xDEAD) + allowed, err := redis.Allow(context.Background(), ip) assert.NoError(t, err) assert.True(t, allowed) } time.Sleep(1 * time.Second) for j := 0; j < rpm; j++ { - allowed, err := redis.Allow(context.Background(), 0xDEAD) + allowed, err := redis.Allow(context.Background(), ip) assert.NoError(t, err) assert.True(t, allowed) } }) t.Run("Negative", func(t *testing.T) { t.Skip("flaky test") + id, _ := GenId() redis, err := NewRedis(context.Background(), DefaultRedisConfig) require.NoError(t, err) rps := redis.conf.LimiterRequestsPerSecond + ip := id() for i := 0; i < rps; i++ { - allowed, err := redis.Allow(context.Background(), 0xBEEF) + allowed, err := redis.Allow(context.Background(), ip) assert.NoError(t, err) assert.True(t, allowed) } - allowed, err := redis.Allow(context.Background(), 0xBEEF) + allowed, err := redis.Allow(context.Background(), ip) assert.NoError(t, err) assert.False(t, allowed) }) } func TestRedisQueue(t *testing.T) { + id, _ := GenId() redis, err := NewRedis(context.Background(), DefaultRedisConfig) require.NoError(t, err) - n, err := redis.Size(context.Background(), 0x5D6D) + queue := id() + albumExp1 := id() + albumExp2 := id() + albumExp3 := id() + n, err := redis.Size(context.Background(), queue) assert.NoError(t, err) assert.Equal(t, 0, n) - err = redis.Add(context.Background(), 0x5D6D, 0x1ED1) + err = redis.Add(context.Background(), queue, albumExp1) assert.NoError(t, err) - err = redis.Add(context.Background(), 0x5D6D, 0x1ED1) + err = redis.Add(context.Background(), queue, albumExp1) assert.NoError(t, err) - err = redis.Add(context.Background(), 0x5D6D, 0xF612) + err = redis.Add(context.Background(), queue, albumExp2) assert.NoError(t, err) - err = redis.Add(context.Background(), 0x5D6D, 0x1A83) + err = redis.Add(context.Background(), queue, albumExp3) assert.NoError(t, err) - err = redis.Add(context.Background(), 0x5D6D, 0xF612) + err = redis.Add(context.Background(), queue, albumExp2) assert.NoError(t, err) - n, err = redis.Size(context.Background(), 0x5D6D) + n, err = redis.Size(context.Background(), queue) assert.NoError(t, err) assert.Equal(t, 3, n) - album, err := redis.Poll(context.Background(), 0x5D6D) + album, err := redis.Poll(context.Background(), queue) assert.NoError(t, err) - assert.Equal(t, uint64(0x1ED1), album) - n, err = redis.Size(context.Background(), 0x5D6D) + assert.Equal(t, albumExp1, album) + n, err = redis.Size(context.Background(), queue) assert.NoError(t, err) assert.Equal(t, 2, n) - album, err = redis.Poll(context.Background(), 0x5D6D) + album, err = redis.Poll(context.Background(), queue) assert.NoError(t, err) - assert.Equal(t, uint64(0xF612), album) - album, err = redis.Poll(context.Background(), 0x5D6D) + assert.Equal(t, albumExp2, album) + album, err = redis.Poll(context.Background(), queue) assert.NoError(t, err) - assert.Equal(t, uint64(0x1A83), album) - n, err = redis.Size(context.Background(), 0x5D6D) + assert.Equal(t, albumExp3, album) + n, err = redis.Size(context.Background(), queue) assert.NoError(t, err) assert.Equal(t, 0, n) - album, err = redis.Poll(context.Background(), 0x5D6D) + album, err = redis.Poll(context.Background(), queue) assert.Error(t, err) assert.Equal(t, uint64(0x0), album) - n, err = redis.Size(context.Background(), 0x5D6D) + n, err = redis.Size(context.Background(), queue) assert.NoError(t, err) assert.Equal(t, 0, n) - _, err = redis.Poll(context.Background(), 0x5D6D) + _, err = redis.Poll(context.Background(), queue) assert.ErrorIs(t, err, domain.ErrUnknown) } func TestRedisPQueue(t *testing.T) { + id, _ := GenId() redis, err := NewRedis(context.Background(), DefaultRedisConfig) require.NoError(t, err) - n, err := redis.PSize(context.Background(), 0x7D31) + pqueue := id() + albumExp1 := id() + albumExp2 := id() + albumExp3 := id() + n, err := redis.PSize(context.Background(), pqueue) assert.NoError(t, err) assert.Equal(t, 0, n) - err = redis.PAdd(context.Background(), 0x7D31, 0xE976, time.Unix(904867200, 0)) + err = redis.PAdd(context.Background(), pqueue, albumExp1, time.Unix(904867200, 0)) assert.NoError(t, err) - err = redis.PAdd(context.Background(), 0x7D31, 0xEC0E, time.Unix(1075852800, 0)) + err = redis.PAdd(context.Background(), pqueue, albumExp2, time.Unix(1075852800, 0)) assert.NoError(t, err) - err = redis.PAdd(context.Background(), 0x7D31, 0x4CAF, time.Unix(681436800, 0)) + err = redis.PAdd(context.Background(), pqueue, albumExp3, time.Unix(681436800, 0)) assert.NoError(t, err) - n, err = redis.PSize(context.Background(), 0x7D31) + n, err = redis.PSize(context.Background(), pqueue) assert.NoError(t, err) assert.Equal(t, 3, n) - album, expires, err := redis.PPoll(context.Background(), 0x7D31) + album, expires, err := redis.PPoll(context.Background(), pqueue) assert.NoError(t, err) - assert.Equal(t, uint64(0x4CAF), album) + assert.Equal(t, albumExp3, album) assert.True(t, expires.Equal(time.Unix(681436800, 0))) - n, err = redis.PSize(context.Background(), 0x7D31) + n, err = redis.PSize(context.Background(), pqueue) assert.NoError(t, err) assert.Equal(t, 2, n) - album, expires, err = redis.PPoll(context.Background(), 0x7D31) + album, expires, err = redis.PPoll(context.Background(), pqueue) assert.NoError(t, err) - assert.Equal(t, uint64(0xE976), album) + assert.Equal(t, albumExp1, album) assert.True(t, expires.Equal(time.Unix(904867200, 0))) - album, expires, err = redis.PPoll(context.Background(), 0x7D31) + album, expires, err = redis.PPoll(context.Background(), pqueue) assert.NoError(t, err) - assert.Equal(t, uint64(0xEC0E), album) + assert.Equal(t, albumExp2, album) assert.True(t, expires.Equal(time.Unix(1075852800, 0))) - n, err = redis.PSize(context.Background(), 0x7D31) + n, err = redis.PSize(context.Background(), pqueue) assert.NoError(t, err) assert.Equal(t, 0, n) - _, _, err = redis.PPoll(context.Background(), 0x7D31) + _, _, err = redis.PPoll(context.Background(), pqueue) assert.ErrorIs(t, err, domain.ErrUnknown) } func TestRedisPair(t *testing.T) { t.Run("Positive", func(t *testing.T) { + id, _ := GenId() redis, err := NewRedis(context.Background(), DefaultRedisConfig) require.NoError(t, err) - image1 := uint64(0x3E3D) - image2 := uint64(0xB399) - err = redis.Push(context.Background(), 0x23D2, [][2]uint64{{image1, image2}}) + album := id() + image1 := id() + image2 := id() + pairs := [][2]uint64{{image1, image2}} + err = redis.Push(context.Background(), album, pairs) assert.NoError(t, err) - image3, image4, err := redis.Pop(context.Background(), 0x23D2) + image3, image4, err := redis.Pop(context.Background(), album) assert.NoError(t, err) assert.Equal(t, image1, image3) assert.Equal(t, image2, image4) }) t.Run("Negative1", func(t *testing.T) { + id, _ := GenId() redis, err := NewRedis(context.Background(), DefaultRedisConfig) require.NoError(t, err) - _, _, err = redis.Pop(context.Background(), 0x73BF) + album := id() + _, _, err = redis.Pop(context.Background(), album) assert.ErrorIs(t, err, domain.ErrPairNotFound) }) t.Run("Negative2", func(t *testing.T) { + id, _ := GenId() redis, err := NewRedis(context.Background(), DefaultRedisConfig) require.NoError(t, err) - image1 := uint64(0x44DC) - image2 := uint64(0x721B) - err = redis.Push(context.Background(), 0x1AE9, [][2]uint64{{image1, image2}}) + album := id() + image1 := id() + image2 := id() + pairs := [][2]uint64{{image1, image2}} + err = redis.Push(context.Background(), album, pairs) assert.NoError(t, err) - _, _, err = redis.Pop(context.Background(), 0x1AE9) + _, _, err = redis.Pop(context.Background(), album) assert.NoError(t, err) - _, _, err = redis.Pop(context.Background(), 0x1AE9) + _, _, err = redis.Pop(context.Background(), album) assert.ErrorIs(t, err, domain.ErrPairNotFound) }) } func TestRedisToken(t *testing.T) { t.Run("Positive", func(t *testing.T) { + id, _ := GenId() redis, err := NewRedis(context.Background(), DefaultRedisConfig) require.NoError(t, err) - token := uint64(0xC2E7) - album1 := uint64(0xB41C) - image1 := uint64(0x52BD) - err = redis.Set(context.Background(), token, album1, image1) + token := id() + albumExp := id() + imageExp := id() + err = redis.Set(context.Background(), token, albumExp, imageExp) assert.NoError(t, err) - album2, image2, err := redis.Get(context.Background(), token) + album, image, err := redis.Get(context.Background(), token) assert.NoError(t, err) - assert.Equal(t, album1, album2) - assert.Equal(t, image1, image2) + assert.Equal(t, albumExp, album) + assert.Equal(t, imageExp, image) }) t.Run("Negative1", func(t *testing.T) { + id, _ := GenId() redis, err := NewRedis(context.Background(), DefaultRedisConfig) require.NoError(t, err) - token := uint64(0x1C4A) - album := uint64(0xF0EE) - image := uint64(0x583C) + token := id() + album := id() + image := id() err = redis.Set(context.Background(), token, album, image) assert.NoError(t, err) err = redis.Set(context.Background(), token, album, image) assert.ErrorIs(t, err, domain.ErrTokenAlreadyExists) }) t.Run("Negative2", func(t *testing.T) { + id, _ := GenId() redis, err := NewRedis(context.Background(), DefaultRedisConfig) require.NoError(t, err) - token := uint64(0xC4F8) + token := id() _, _, err = redis.Get(context.Background(), token) assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) t.Run("Negative3", func(t *testing.T) { + id, _ := GenId() redis, err := NewRedis(context.Background(), DefaultRedisConfig) require.NoError(t, err) - token := uint64(0xEB96) - album := uint64(0xC67F) - image := uint64(0x7C45) + token := id() + album := id() + image := id() err = redis.Set(context.Background(), token, album, image) assert.NoError(t, err) _, _, err = redis.Get(context.Background(), token) @@ -213,9 +240,10 @@ func TestRedisToken(t *testing.T) { assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) t.Run("Negative4", func(t *testing.T) { + id, _ := GenId() redis, err := NewRedis(context.Background(), DefaultRedisConfig) require.NoError(t, err) - token := uint64(0xD3BF) + token := id() err = redis.Del(context.Background(), token) assert.NoError(t, err) }) diff --git a/infrastructure/database/badger_test.go b/infrastructure/database/badger_test.go index ac68b47..6e827e2 100644 --- a/infrastructure/database/badger_test.go +++ b/infrastructure/database/badger_test.go @@ -13,202 +13,220 @@ import ( "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/model" + . "github.com/zitryss/aye-and-nay/internal/generator" . "github.com/zitryss/aye-and-nay/internal/testing" ) func TestBadgerAlbum(t *testing.T) { t.Run("Positive", func(t *testing.T) { + id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(0x6CC4) + alb := AlbumEmptyFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - edgs, err := badger.GetEdges(context.Background(), 0x6CC4) + edgs, err := badger.GetEdges(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, alb.Edges, edgs) }) t.Run("Negative1", func(t *testing.T) { + id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumFullFactory(0xA566) + alb := AlbumFullFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - alb = AlbumFullFactory(0xA566) err = badger.SaveAlbum(context.Background(), alb) assert.ErrorIs(t, err, domain.ErrAlbumAlreadyExists) }) t.Run("Negative2", func(t *testing.T) { + id, _ := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - _, err = badger.GetImagesIds(context.Background(), 0xA9B4) + _, err = badger.GetImagesIds(context.Background(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative3", func(t *testing.T) { + id, _ := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - _, err = badger.GetEdges(context.Background(), 0x3F1E) + _, err = badger.GetEdges(context.Background(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestBadgerCount(t *testing.T) { t.Run("Positive", func(t *testing.T) { + id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(0x746C) + alb := AlbumEmptyFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - n, err := badger.CountImages(context.Background(), 0x746C) + n, err := badger.CountImages(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 5, n) - n, err = badger.CountImagesCompressed(context.Background(), 0x746C) + n, err = badger.CountImagesCompressed(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 0, n) - err = badger.UpdateCompressionStatus(context.Background(), 0x746C, 0x3E3D) + err = badger.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(1)) assert.NoError(t, err) - n, err = badger.CountImages(context.Background(), 0x746C) + n, err = badger.CountImages(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 5, n) - n, err = badger.CountImagesCompressed(context.Background(), 0x746C) + n, err = badger.CountImagesCompressed(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 1, n) - err = badger.UpdateCompressionStatus(context.Background(), 0x746C, 0xB399) + err = badger.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(2)) assert.NoError(t, err) - n, err = badger.CountImagesCompressed(context.Background(), 0x746C) + n, err = badger.CountImagesCompressed(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 2, n) }) t.Run("Negative1", func(t *testing.T) { + id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(0x99DF) + alb := AlbumEmptyFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - err = badger.UpdateCompressionStatus(context.Background(), 0x99DF, 0x3E3D) + err = badger.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(1)) assert.NoError(t, err) - err = badger.UpdateCompressionStatus(context.Background(), 0x99DF, 0x3E3D) + err = badger.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(1)) assert.NoError(t, err) - n, err := badger.CountImagesCompressed(context.Background(), 0x99DF) + n, err := badger.CountImagesCompressed(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 1, n) }) t.Run("Negative2", func(t *testing.T) { + id, _ := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - _, err = badger.CountImages(context.Background(), 0xF256) + _, err = badger.CountImages(context.Background(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative3", func(t *testing.T) { + id, _ := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - _, err = badger.CountImagesCompressed(context.Background(), 0xC52A) + _, err = badger.CountImagesCompressed(context.Background(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative4", func(t *testing.T) { + id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - err = badger.UpdateCompressionStatus(context.Background(), 0xF73E, 0x3E3D) + err = badger.UpdateCompressionStatus(context.Background(), id(), ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative5", func(t *testing.T) { + id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(0xDF75) + alb := AlbumEmptyFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - err = badger.UpdateCompressionStatus(context.Background(), 0xDF75, 0xE7A4) + err = badger.UpdateCompressionStatus(context.Background(), ids.Uint64(0), id()) assert.ErrorIs(t, err, domain.ErrImageNotFound) }) } func TestBadgerImage(t *testing.T) { t.Run("Positive", func(t *testing.T) { + id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(0xB0C4) + alb := AlbumEmptyFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - src, err := badger.GetImageSrc(context.Background(), 0xB0C4, 0x51DE) + src, err := badger.GetImageSrc(context.Background(), ids.Uint64(0), ids.Uint64(4)) assert.NoError(t, err) - assert.Equal(t, "/aye-and-nay/albums/xLAAAAAAAAA/images/3lEAAAAAAAA", src) + assert.Equal(t, "/aye-and-nay/albums/"+ids.Base64(0)+"/images/"+ids.Base64(4), src) }) t.Run("Negative1", func(t *testing.T) { + id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - _, err = badger.GetImageSrc(context.Background(), 0x12EE, 0x51DE) + _, err = badger.GetImageSrc(context.Background(), id(), ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative2", func(t *testing.T) { + id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(0xD585) + alb := AlbumEmptyFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - _, err = badger.GetImageSrc(context.Background(), 0xD585, 0xDA30) + _, err = badger.GetImageSrc(context.Background(), ids.Uint64(0), id()) assert.ErrorIs(t, err, domain.ErrImageNotFound) }) } func TestBadgerVote(t *testing.T) { t.Run("Positive", func(t *testing.T) { + id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumFullFactory(0x4D76) + alb := AlbumFullFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - err = badger.SaveVote(context.Background(), 0x4D76, 0xDA2A, 0xDA52) + err = badger.SaveVote(context.Background(), ids.Uint64(0), ids.Uint64(3), ids.Uint64(5)) assert.NoError(t, err) - err = badger.SaveVote(context.Background(), 0x4D76, 0xDA2A, 0xDA52) + err = badger.SaveVote(context.Background(), ids.Uint64(0), ids.Uint64(3), ids.Uint64(5)) assert.NoError(t, err) - edgs, err := badger.GetEdges(context.Background(), 0x4D76) + edgs, err := badger.GetEdges(context.Background(), ids.Uint64(0)) assert.NoError(t, err) - assert.Equal(t, 2, edgs[0xDA2A][0xDA52]) + assert.Equal(t, 2, edgs[ids.Uint64(3)][ids.Uint64(5)]) }) t.Run("Negative", func(t *testing.T) { + id, _ := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - err = badger.SaveVote(context.Background(), 0x1FAD, 0x84E6, 0x308E) + err = badger.SaveVote(context.Background(), id(), id(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestBadgerSort(t *testing.T) { t.Run("Positive", func(t *testing.T) { + id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumFullFactory(0x5A96) + alb := AlbumFullFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - imgs1, err := badger.GetImagesOrdered(context.Background(), 0x5A96) + imgs1, err := badger.GetImagesOrdered(context.Background(), ids.Uint64(0)) assert.NoError(t, err) - img1 := model.Image{Id: 0x51DE, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/3lEAAAAAAAA", Rating: 0.77920413} - img2 := model.Image{Id: 0x3E3D, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/PT4AAAAAAAA", Rating: 0.48954984} - img3 := model.Image{Id: 0xDA2A, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/KtoAAAAAAAA", Rating: 0.41218211} - img4 := model.Image{Id: 0xB399, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/mbMAAAAAAAA", Rating: 0.19186324} - img5 := model.Image{Id: 0xDA52, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/UtoAAAAAAAA", Rating: 0.13278389} + img1 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4) + "", Rating: 0.77920413} + img2 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.48954984} + img3 := model.Image{Id: ids.Uint64(3), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.41218211} + img4 := model.Image{Id: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.19186324} + img5 := model.Image{Id: ids.Uint64(5), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5), Rating: 0.13278389} imgs2 := []model.Image{img1, img2, img3, img4, img5} assert.Equal(t, imgs2, imgs1) }) t.Run("Negative", func(t *testing.T) { + id, _ := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - _, err = badger.GetImagesOrdered(context.Background(), 0x66BE) + _, err = badger.GetImagesOrdered(context.Background(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestBadgerRatings(t *testing.T) { t.Run("Positive", func(t *testing.T) { + id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumFullFactory(0x4E54) + alb := AlbumFullFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - img1 := model.Image{Id: 0x3E3D, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/PT4AAAAAAAA", Rating: 0.54412788} - img2 := model.Image{Id: 0xB399, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/mbMAAAAAAAA", Rating: 0.32537162} - img3 := model.Image{Id: 0xDA2A, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/KtoAAAAAAAA", Rating: 0.43185491} - img4 := model.Image{Id: 0x51DE, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/3lEAAAAAAAA", Rating: 0.57356209} - img5 := model.Image{Id: 0xDA52, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/UtoAAAAAAAA", Rating: 0.61438023} + img1 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} + img2 := model.Image{Id: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.32537162} + img3 := model.Image{Id: ids.Uint64(3), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.43185491} + img4 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4) + "", Rating: 0.57356209} + img5 := model.Image{Id: ids.Uint64(5), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5), Rating: 0.61438023} imgs1 := []model.Image{img1, img2, img3, img4, img5} vector := map[uint64]float64{} vector[img1.Id] = img1.Rating @@ -216,89 +234,95 @@ func TestBadgerRatings(t *testing.T) { vector[img3.Id] = img3.Rating vector[img4.Id] = img4.Rating vector[img5.Id] = img5.Rating - err = badger.UpdateRatings(context.Background(), 0x4E54, vector) + err = badger.UpdateRatings(context.Background(), ids.Uint64(0), vector) assert.NoError(t, err) - imgs2, err := badger.GetImagesOrdered(context.Background(), 0x4E54) + imgs2, err := badger.GetImagesOrdered(context.Background(), ids.Uint64(0)) assert.NoError(t, err) sort.Slice(imgs1, func(i, j int) bool { return imgs1[i].Rating > imgs1[j].Rating }) assert.Equal(t, imgs1, imgs2) }) t.Run("Negative", func(t *testing.T) { + id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - img1 := model.Image{Id: 0x3E3D, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/PT4AAAAAAAA", Rating: 0.54412788} - img2 := model.Image{Id: 0xB399, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/mbMAAAAAAAA", Rating: 0.32537162} - img3 := model.Image{Id: 0xDA2A, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/KtoAAAAAAAA", Rating: 0.43185491} - img4 := model.Image{Id: 0x51DE, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/3lEAAAAAAAA", Rating: 0.57356209} - img5 := model.Image{Id: 0xDA52, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/UtoAAAAAAAA", Rating: 0.61438023} + album := id() + img1 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} + img2 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.32537162} + img3 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.43185491} + img4 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4) + "", Rating: 0.57356209} + img5 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5), Rating: 0.61438023} vector := map[uint64]float64{} vector[img1.Id] = img1.Rating vector[img2.Id] = img2.Rating vector[img3.Id] = img3.Rating vector[img4.Id] = img4.Rating vector[img5.Id] = img5.Rating - err = badger.UpdateRatings(context.Background(), 0xA293, vector) + err = badger.UpdateRatings(context.Background(), album, vector) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestBadgerDelete(t *testing.T) { t.Run("Positive1", func(t *testing.T) { + id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(0x748C) - _, err = badger.CountImages(context.Background(), 0x748C) + alb := AlbumEmptyFactory(id, ids) + _, err = badger.CountImages(context.Background(), ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - n, err := badger.CountImages(context.Background(), 0x748C) + n, err := badger.CountImages(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 5, n) albums, err := badger.AlbumsToBeDeleted(context.Background()) assert.NoError(t, err) assert.Len(t, albums, 0) - err = badger.DeleteAlbum(context.Background(), 0x748C) + err = badger.DeleteAlbum(context.Background(), ids.Uint64(0)) assert.NoError(t, err) - _, err = badger.CountImages(context.Background(), 0x748C) + _, err = badger.CountImages(context.Background(), ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Positive2", func(t *testing.T) { + id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(0x7B43) + alb := AlbumEmptyFactory(id, ids) alb.Expires = time.Now().Add(-1 * time.Hour) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) albums, err := badger.AlbumsToBeDeleted(context.Background()) assert.NoError(t, err) assert.True(t, len(albums) == 1 && albums[0].Id == alb.Id && !albums[0].Expires.IsZero()) - err = badger.DeleteAlbum(context.Background(), 0x7B43) + err = badger.DeleteAlbum(context.Background(), ids.Uint64(0)) assert.NoError(t, err) - _, err = badger.CountImages(context.Background(), 0x7B43) + _, err = badger.CountImages(context.Background(), ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - t.Cleanup(func() { _ = badger.DeleteAlbum(context.Background(), 0x7B43) }) + t.Cleanup(func() { _ = badger.DeleteAlbum(context.Background(), ids.Uint64(0)) }) }) t.Run("Negative", func(t *testing.T) { + id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(0x608C) + alb := AlbumEmptyFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - err = badger.DeleteAlbum(context.Background(), 0xB7FF) + err = badger.DeleteAlbum(context.Background(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestBadgerLru(t *testing.T) { + id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb1 := AlbumEmptyFactory(0x36FC) + alb1 := AlbumEmptyFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb1) assert.NoError(t, err) - alb2 := AlbumEmptyFactory(0xB020) + alb2 := AlbumEmptyFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb2) assert.NoError(t, err) - edgs, err := badger.GetEdges(context.Background(), 0x36FC) + edgs, err := badger.GetEdges(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, alb1.Edges, edgs) } diff --git a/infrastructure/database/mem_test.go b/infrastructure/database/mem_test.go index 2db6ff9..4ee3614 100644 --- a/infrastructure/database/mem_test.go +++ b/infrastructure/database/mem_test.go @@ -12,184 +12,202 @@ import ( "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/model" + . "github.com/zitryss/aye-and-nay/internal/generator" . "github.com/zitryss/aye-and-nay/internal/testing" ) func TestMemAlbum(t *testing.T) { t.Run("Positive", func(t *testing.T) { + id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumEmptyFactory(0x6CC4) + alb := AlbumEmptyFactory(id, ids) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - edgs, err := mem.GetEdges(context.Background(), 0x6CC4) + edgs, err := mem.GetEdges(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, alb.Edges, edgs) }) t.Run("Negative1", func(t *testing.T) { + id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumFullFactory(0xA566) + alb := AlbumFullFactory(id, ids) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - alb = AlbumFullFactory(0xA566) err = mem.SaveAlbum(context.Background(), alb) assert.ErrorIs(t, err, domain.ErrAlbumAlreadyExists) }) t.Run("Negative2", func(t *testing.T) { + id, _ := GenId() mem := NewMem(DefaultMemConfig) - _, err := mem.GetImagesIds(context.Background(), 0xA9B4) + _, err := mem.GetImagesIds(context.Background(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative3", func(t *testing.T) { + id, _ := GenId() mem := NewMem(DefaultMemConfig) - _, err := mem.GetEdges(context.Background(), 0x3F1E) + _, err := mem.GetEdges(context.Background(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestMemCount(t *testing.T) { t.Run("Positive", func(t *testing.T) { + id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumEmptyFactory(0x746C) + alb := AlbumEmptyFactory(id, ids) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - n, err := mem.CountImages(context.Background(), 0x746C) + n, err := mem.CountImages(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 5, n) - n, err = mem.CountImagesCompressed(context.Background(), 0x746C) + n, err = mem.CountImagesCompressed(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 0, n) - err = mem.UpdateCompressionStatus(context.Background(), 0x746C, 0x3E3D) + err = mem.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(1)) assert.NoError(t, err) - n, err = mem.CountImages(context.Background(), 0x746C) + n, err = mem.CountImages(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 5, n) - n, err = mem.CountImagesCompressed(context.Background(), 0x746C) + n, err = mem.CountImagesCompressed(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 1, n) - err = mem.UpdateCompressionStatus(context.Background(), 0x746C, 0xB399) + err = mem.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(2)) assert.NoError(t, err) - n, err = mem.CountImagesCompressed(context.Background(), 0x746C) + n, err = mem.CountImagesCompressed(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 2, n) }) t.Run("Negative1", func(t *testing.T) { + id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumEmptyFactory(0x99DF) + alb := AlbumEmptyFactory(id, ids) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - err = mem.UpdateCompressionStatus(context.Background(), 0x99DF, 0x3E3D) + err = mem.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(1)) assert.NoError(t, err) - err = mem.UpdateCompressionStatus(context.Background(), 0x99DF, 0x3E3D) + err = mem.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(1)) assert.NoError(t, err) - n, err := mem.CountImagesCompressed(context.Background(), 0x99DF) + n, err := mem.CountImagesCompressed(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 1, n) }) t.Run("Negative2", func(t *testing.T) { + id, _ := GenId() mem := NewMem(DefaultMemConfig) - _, err := mem.CountImages(context.Background(), 0xF256) + _, err := mem.CountImages(context.Background(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative3", func(t *testing.T) { + id, _ := GenId() mem := NewMem(DefaultMemConfig) - _, err := mem.CountImagesCompressed(context.Background(), 0xC52A) + _, err := mem.CountImagesCompressed(context.Background(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative4", func(t *testing.T) { + id, ids := GenId() mem := NewMem(DefaultMemConfig) - err := mem.UpdateCompressionStatus(context.Background(), 0xF73E, 0x3E3D) + err := mem.UpdateCompressionStatus(context.Background(), id(), ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative5", func(t *testing.T) { + id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumEmptyFactory(0xDF75) + alb := AlbumEmptyFactory(id, ids) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - err = mem.UpdateCompressionStatus(context.Background(), 0xDF75, 0xE7A4) + err = mem.UpdateCompressionStatus(context.Background(), ids.Uint64(0), id()) assert.ErrorIs(t, err, domain.ErrImageNotFound) }) } func TestMemImage(t *testing.T) { t.Run("Positive", func(t *testing.T) { + id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumEmptyFactory(0xB0C4) + alb := AlbumEmptyFactory(id, ids) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - src, err := mem.GetImageSrc(context.Background(), 0xB0C4, 0x51DE) + src, err := mem.GetImageSrc(context.Background(), ids.Uint64(0), ids.Uint64(4)) assert.NoError(t, err) - assert.Equal(t, "/aye-and-nay/albums/xLAAAAAAAAA/images/3lEAAAAAAAA", src) + assert.Equal(t, "/aye-and-nay/albums/"+ids.Base64(0)+"/images/"+ids.Base64(4), src) }) t.Run("Negative1", func(t *testing.T) { + id, ids := GenId() mem := NewMem(DefaultMemConfig) - _, err := mem.GetImageSrc(context.Background(), 0x12EE, 0x51DE) + _, err := mem.GetImageSrc(context.Background(), id(), ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative2", func(t *testing.T) { + id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumEmptyFactory(0xD585) + alb := AlbumEmptyFactory(id, ids) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - _, err = mem.GetImageSrc(context.Background(), 0xD585, 0xDA30) + _, err = mem.GetImageSrc(context.Background(), ids.Uint64(0), id()) assert.ErrorIs(t, err, domain.ErrImageNotFound) }) } func TestMemVote(t *testing.T) { t.Run("Positive", func(t *testing.T) { + id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumFullFactory(0x4D76) + alb := AlbumFullFactory(id, ids) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - err = mem.SaveVote(context.Background(), 0x4D76, 0xDA2A, 0xDA52) + err = mem.SaveVote(context.Background(), ids.Uint64(0), ids.Uint64(3), ids.Uint64(5)) assert.NoError(t, err) - err = mem.SaveVote(context.Background(), 0x4D76, 0xDA2A, 0xDA52) + err = mem.SaveVote(context.Background(), ids.Uint64(0), ids.Uint64(3), ids.Uint64(5)) assert.NoError(t, err) - edgs, err := mem.GetEdges(context.Background(), 0x4D76) + edgs, err := mem.GetEdges(context.Background(), ids.Uint64(0)) assert.NoError(t, err) - assert.Equal(t, 2, edgs[0xDA2A][0xDA52]) + assert.Equal(t, 2, edgs[ids.Uint64(3)][ids.Uint64(5)]) }) t.Run("Negative", func(t *testing.T) { + id, _ := GenId() mem := NewMem(DefaultMemConfig) - err := mem.SaveVote(context.Background(), 0x1FAD, 0x84E6, 0x308E) + err := mem.SaveVote(context.Background(), id(), id(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestMemSort(t *testing.T) { t.Run("Positive", func(t *testing.T) { + id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumFullFactory(0x5A96) + alb := AlbumFullFactory(id, ids) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - imgs1, err := mem.GetImagesOrdered(context.Background(), 0x5A96) + imgs1, err := mem.GetImagesOrdered(context.Background(), ids.Uint64(0)) assert.NoError(t, err) - img1 := model.Image{Id: 0x51DE, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/3lEAAAAAAAA", Rating: 0.77920413} - img2 := model.Image{Id: 0x3E3D, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/PT4AAAAAAAA", Rating: 0.48954984} - img3 := model.Image{Id: 0xDA2A, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/KtoAAAAAAAA", Rating: 0.41218211} - img4 := model.Image{Id: 0xB399, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/mbMAAAAAAAA", Rating: 0.19186324} - img5 := model.Image{Id: 0xDA52, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/UtoAAAAAAAA", Rating: 0.13278389} + img1 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4) + "", Rating: 0.77920413} + img2 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.48954984} + img3 := model.Image{Id: ids.Uint64(3), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.41218211} + img4 := model.Image{Id: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.19186324} + img5 := model.Image{Id: ids.Uint64(5), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5), Rating: 0.13278389} imgs2 := []model.Image{img1, img2, img3, img4, img5} assert.Equal(t, imgs2, imgs1) }) t.Run("Negative", func(t *testing.T) { + id, _ := GenId() mem := NewMem(DefaultMemConfig) - _, err := mem.GetImagesOrdered(context.Background(), 0x66BE) + _, err := mem.GetImagesOrdered(context.Background(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestMemRatings(t *testing.T) { t.Run("Positive", func(t *testing.T) { + id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumFullFactory(0x4E54) + alb := AlbumFullFactory(id, ids) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - img1 := model.Image{Id: 0x3E3D, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/PT4AAAAAAAA", Rating: 0.54412788} - img2 := model.Image{Id: 0xB399, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/mbMAAAAAAAA", Rating: 0.32537162} - img3 := model.Image{Id: 0xDA2A, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/KtoAAAAAAAA", Rating: 0.43185491} - img4 := model.Image{Id: 0x51DE, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/3lEAAAAAAAA", Rating: 0.57356209} - img5 := model.Image{Id: 0xDA52, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/UtoAAAAAAAA", Rating: 0.61438023} + img1 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} + img2 := model.Image{Id: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.32537162} + img3 := model.Image{Id: ids.Uint64(3), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.43185491} + img4 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4) + "", Rating: 0.57356209} + img5 := model.Image{Id: ids.Uint64(5), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5), Rating: 0.61438023} imgs1 := []model.Image{img1, img2, img3, img4, img5} vector := map[uint64]float64{} vector[img1.Id] = img1.Rating @@ -197,70 +215,75 @@ func TestMemRatings(t *testing.T) { vector[img3.Id] = img3.Rating vector[img4.Id] = img4.Rating vector[img5.Id] = img5.Rating - err = mem.UpdateRatings(context.Background(), 0x4E54, vector) + err = mem.UpdateRatings(context.Background(), ids.Uint64(0), vector) assert.NoError(t, err) - imgs2, err := mem.GetImagesOrdered(context.Background(), 0x4E54) + imgs2, err := mem.GetImagesOrdered(context.Background(), ids.Uint64(0)) assert.NoError(t, err) sort.Slice(imgs1, func(i, j int) bool { return imgs1[i].Rating > imgs1[j].Rating }) assert.Equal(t, imgs1, imgs2) }) t.Run("Negative", func(t *testing.T) { + id, ids := GenId() mem := NewMem(DefaultMemConfig) - img1 := model.Image{Id: 0x3E3D, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/PT4AAAAAAAA", Rating: 0.54412788} - img2 := model.Image{Id: 0xB399, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/mbMAAAAAAAA", Rating: 0.32537162} - img3 := model.Image{Id: 0xDA2A, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/KtoAAAAAAAA", Rating: 0.43185491} - img4 := model.Image{Id: 0x51DE, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/3lEAAAAAAAA", Rating: 0.57356209} - img5 := model.Image{Id: 0xDA52, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/UtoAAAAAAAA", Rating: 0.61438023} + album := id() + img1 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} + img2 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.32537162} + img3 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.43185491} + img4 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4) + "", Rating: 0.57356209} + img5 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5), Rating: 0.61438023} vector := map[uint64]float64{} vector[img1.Id] = img1.Rating vector[img2.Id] = img2.Rating vector[img3.Id] = img3.Rating vector[img4.Id] = img4.Rating vector[img5.Id] = img5.Rating - err := mem.UpdateRatings(context.Background(), 0xA293, vector) + err := mem.UpdateRatings(context.Background(), album, vector) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestMemDelete(t *testing.T) { t.Run("Positive1", func(t *testing.T) { + id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumEmptyFactory(0x748C) - _, err := mem.CountImages(context.Background(), 0x748C) + alb := AlbumEmptyFactory(id, ids) + _, err := mem.CountImages(context.Background(), ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) err = mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - n, err := mem.CountImages(context.Background(), 0x748C) + n, err := mem.CountImages(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 5, n) albums, err := mem.AlbumsToBeDeleted(context.Background()) assert.NoError(t, err) assert.Len(t, albums, 0) - err = mem.DeleteAlbum(context.Background(), 0x748C) + err = mem.DeleteAlbum(context.Background(), ids.Uint64(0)) assert.NoError(t, err) - _, err = mem.CountImages(context.Background(), 0x748C) + _, err = mem.CountImages(context.Background(), ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Positive2", func(t *testing.T) { + id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumEmptyFactory(0x7B43) + alb := AlbumEmptyFactory(id, ids) alb.Expires = time.Now().Add(-1 * time.Hour) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) albums, err := mem.AlbumsToBeDeleted(context.Background()) assert.NoError(t, err) assert.True(t, len(albums) == 1 && albums[0].Id == alb.Id && !albums[0].Expires.IsZero()) - err = mem.DeleteAlbum(context.Background(), 0x7B43) + err = mem.DeleteAlbum(context.Background(), ids.Uint64(0)) assert.NoError(t, err) - _, err = mem.CountImages(context.Background(), 0x7B43) + _, err = mem.CountImages(context.Background(), ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative", func(t *testing.T) { + id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumEmptyFactory(0x608C) + alb := AlbumEmptyFactory(id, ids) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - err = mem.DeleteAlbum(context.Background(), 0xB7FF) + err = mem.DeleteAlbum(context.Background(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } diff --git a/infrastructure/database/mongo_integration_test.go b/infrastructure/database/mongo_integration_test.go index 6f8db10..7c4f046 100644 --- a/infrastructure/database/mongo_integration_test.go +++ b/infrastructure/database/mongo_integration_test.go @@ -13,202 +13,220 @@ import ( "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/model" + . "github.com/zitryss/aye-and-nay/internal/generator" . "github.com/zitryss/aye-and-nay/internal/testing" ) func TestMongoAlbum(t *testing.T) { t.Run("Positive", func(t *testing.T) { + id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(0x6CC4) + alb := AlbumEmptyFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - edgs, err := mongo.GetEdges(context.Background(), 0x6CC4) + edgs, err := mongo.GetEdges(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, alb.Edges, edgs) }) t.Run("Negative1", func(t *testing.T) { + id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumFullFactory(0xA566) + alb := AlbumFullFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - alb = AlbumFullFactory(0xA566) err = mongo.SaveAlbum(context.Background(), alb) assert.ErrorIs(t, err, domain.ErrAlbumAlreadyExists) }) t.Run("Negative2", func(t *testing.T) { + id, _ := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - _, err = mongo.GetImagesIds(context.Background(), 0xA9B4) + _, err = mongo.GetImagesIds(context.Background(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative3", func(t *testing.T) { + id, _ := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - _, err = mongo.GetEdges(context.Background(), 0x3F1E) + _, err = mongo.GetEdges(context.Background(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestMongoCount(t *testing.T) { t.Run("Positive", func(t *testing.T) { + id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(0x746C) + alb := AlbumEmptyFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - n, err := mongo.CountImages(context.Background(), 0x746C) + n, err := mongo.CountImages(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 5, n) - n, err = mongo.CountImagesCompressed(context.Background(), 0x746C) + n, err = mongo.CountImagesCompressed(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 0, n) - err = mongo.UpdateCompressionStatus(context.Background(), 0x746C, 0x3E3D) + err = mongo.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(1)) assert.NoError(t, err) - n, err = mongo.CountImages(context.Background(), 0x746C) + n, err = mongo.CountImages(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 5, n) - n, err = mongo.CountImagesCompressed(context.Background(), 0x746C) + n, err = mongo.CountImagesCompressed(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 1, n) - err = mongo.UpdateCompressionStatus(context.Background(), 0x746C, 0xB399) + err = mongo.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(2)) assert.NoError(t, err) - n, err = mongo.CountImagesCompressed(context.Background(), 0x746C) + n, err = mongo.CountImagesCompressed(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 2, n) }) t.Run("Negative1", func(t *testing.T) { + id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(0x99DF) + alb := AlbumEmptyFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - err = mongo.UpdateCompressionStatus(context.Background(), 0x99DF, 0x3E3D) + err = mongo.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(1)) assert.NoError(t, err) - err = mongo.UpdateCompressionStatus(context.Background(), 0x99DF, 0x3E3D) + err = mongo.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(1)) assert.NoError(t, err) - n, err := mongo.CountImagesCompressed(context.Background(), 0x99DF) + n, err := mongo.CountImagesCompressed(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 1, n) }) t.Run("Negative2", func(t *testing.T) { + id, _ := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - _, err = mongo.CountImages(context.Background(), 0xF256) + _, err = mongo.CountImages(context.Background(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative3", func(t *testing.T) { + id, _ := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - _, err = mongo.CountImagesCompressed(context.Background(), 0xC52A) + _, err = mongo.CountImagesCompressed(context.Background(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative4", func(t *testing.T) { + id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - err = mongo.UpdateCompressionStatus(context.Background(), 0xF73E, 0x3E3D) + err = mongo.UpdateCompressionStatus(context.Background(), id(), ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative5", func(t *testing.T) { + id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(0xDF75) + alb := AlbumEmptyFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - err = mongo.UpdateCompressionStatus(context.Background(), 0xDF75, 0xE7A4) + err = mongo.UpdateCompressionStatus(context.Background(), ids.Uint64(0), id()) assert.ErrorIs(t, err, domain.ErrImageNotFound) }) } func TestMongoImage(t *testing.T) { t.Run("Positive", func(t *testing.T) { + id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(0xB0C4) + alb := AlbumEmptyFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - src, err := mongo.GetImageSrc(context.Background(), 0xB0C4, 0x51DE) + src, err := mongo.GetImageSrc(context.Background(), ids.Uint64(0), ids.Uint64(4)) assert.NoError(t, err) - assert.Equal(t, "/aye-and-nay/albums/xLAAAAAAAAA/images/3lEAAAAAAAA", src) + assert.Equal(t, "/aye-and-nay/albums/"+ids.Base64(0)+"/images/"+ids.Base64(4), src) }) t.Run("Negative1", func(t *testing.T) { + id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - _, err = mongo.GetImageSrc(context.Background(), 0x12EE, 0x51DE) + _, err = mongo.GetImageSrc(context.Background(), id(), ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Negative2", func(t *testing.T) { + id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(0xD585) + alb := AlbumEmptyFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - _, err = mongo.GetImageSrc(context.Background(), 0xD585, 0xDA30) + _, err = mongo.GetImageSrc(context.Background(), ids.Uint64(0), id()) assert.ErrorIs(t, err, domain.ErrImageNotFound) }) } func TestMongoVote(t *testing.T) { t.Run("Positive", func(t *testing.T) { + id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumFullFactory(0x4D76) + alb := AlbumFullFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - err = mongo.SaveVote(context.Background(), 0x4D76, 0xDA2A, 0xDA52) + err = mongo.SaveVote(context.Background(), ids.Uint64(0), ids.Uint64(3), ids.Uint64(5)) assert.NoError(t, err) - err = mongo.SaveVote(context.Background(), 0x4D76, 0xDA2A, 0xDA52) + err = mongo.SaveVote(context.Background(), ids.Uint64(0), ids.Uint64(3), ids.Uint64(5)) assert.NoError(t, err) - edgs, err := mongo.GetEdges(context.Background(), 0x4D76) + edgs, err := mongo.GetEdges(context.Background(), ids.Uint64(0)) assert.NoError(t, err) - assert.Equal(t, 2, edgs[0xDA2A][0xDA52]) + assert.Equal(t, 2, edgs[ids.Uint64(3)][ids.Uint64(5)]) }) t.Run("Negative", func(t *testing.T) { + id, _ := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - err = mongo.SaveVote(context.Background(), 0x1FAD, 0x84E6, 0x308E) + err = mongo.SaveVote(context.Background(), id(), id(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestMongoSort(t *testing.T) { t.Run("Positive", func(t *testing.T) { + id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumFullFactory(0x5A96) + alb := AlbumFullFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - imgs1, err := mongo.GetImagesOrdered(context.Background(), 0x5A96) + imgs1, err := mongo.GetImagesOrdered(context.Background(), ids.Uint64(0)) assert.NoError(t, err) - img1 := model.Image{Id: 0x51DE, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/3lEAAAAAAAA", Rating: 0.77920413} - img2 := model.Image{Id: 0x3E3D, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/PT4AAAAAAAA", Rating: 0.48954984} - img3 := model.Image{Id: 0xDA2A, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/KtoAAAAAAAA", Rating: 0.41218211} - img4 := model.Image{Id: 0xB399, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/mbMAAAAAAAA", Rating: 0.19186324} - img5 := model.Image{Id: 0xDA52, Src: "/aye-and-nay/albums/lloAAAAAAAA/images/UtoAAAAAAAA", Rating: 0.13278389} + img1 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4) + "", Rating: 0.77920413} + img2 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.48954984} + img3 := model.Image{Id: ids.Uint64(3), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.41218211} + img4 := model.Image{Id: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.19186324} + img5 := model.Image{Id: ids.Uint64(5), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5), Rating: 0.13278389} imgs2 := []model.Image{img1, img2, img3, img4, img5} assert.Equal(t, imgs2, imgs1) }) t.Run("Negative", func(t *testing.T) { + id, _ := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - _, err = mongo.GetImagesOrdered(context.Background(), 0x66BE) + _, err = mongo.GetImagesOrdered(context.Background(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestMongoRatings(t *testing.T) { t.Run("Positive", func(t *testing.T) { + id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumFullFactory(0x4E54) + alb := AlbumFullFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - img1 := model.Image{Id: 0x3E3D, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/PT4AAAAAAAA", Rating: 0.54412788} - img2 := model.Image{Id: 0xB399, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/mbMAAAAAAAA", Rating: 0.32537162} - img3 := model.Image{Id: 0xDA2A, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/KtoAAAAAAAA", Rating: 0.43185491} - img4 := model.Image{Id: 0x51DE, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/3lEAAAAAAAA", Rating: 0.57356209} - img5 := model.Image{Id: 0xDA52, Src: "/aye-and-nay/albums/VE4AAAAAAAA/images/UtoAAAAAAAA", Rating: 0.61438023} + img1 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} + img2 := model.Image{Id: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.32537162} + img3 := model.Image{Id: ids.Uint64(3), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.43185491} + img4 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4) + "", Rating: 0.57356209} + img5 := model.Image{Id: ids.Uint64(5), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5), Rating: 0.61438023} imgs1 := []model.Image{img1, img2, img3, img4, img5} vector := map[uint64]float64{} vector[img1.Id] = img1.Rating @@ -216,89 +234,95 @@ func TestMongoRatings(t *testing.T) { vector[img3.Id] = img3.Rating vector[img4.Id] = img4.Rating vector[img5.Id] = img5.Rating - err = mongo.UpdateRatings(context.Background(), 0x4E54, vector) + err = mongo.UpdateRatings(context.Background(), ids.Uint64(0), vector) assert.NoError(t, err) - imgs2, err := mongo.GetImagesOrdered(context.Background(), 0x4E54) + imgs2, err := mongo.GetImagesOrdered(context.Background(), ids.Uint64(0)) assert.NoError(t, err) sort.Slice(imgs1, func(i, j int) bool { return imgs1[i].Rating > imgs1[j].Rating }) assert.Equal(t, imgs1, imgs2) }) t.Run("Negative", func(t *testing.T) { + id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - img1 := model.Image{Id: 0x3E3D, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/PT4AAAAAAAA", Rating: 0.54412788} - img2 := model.Image{Id: 0xB399, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/mbMAAAAAAAA", Rating: 0.32537162} - img3 := model.Image{Id: 0xDA2A, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/KtoAAAAAAAA", Rating: 0.43185491} - img4 := model.Image{Id: 0x51DE, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/3lEAAAAAAAA", Rating: 0.57356209} - img5 := model.Image{Id: 0xDA52, Src: "/aye-and-nay/albums/k6IAAAAAAAA/images/UtoAAAAAAAA", Rating: 0.61438023} + album := id() + img1 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} + img2 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.32537162} + img3 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.43185491} + img4 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4) + "", Rating: 0.57356209} + img5 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5), Rating: 0.61438023} vector := map[uint64]float64{} vector[img1.Id] = img1.Rating vector[img2.Id] = img2.Rating vector[img3.Id] = img3.Rating vector[img4.Id] = img4.Rating vector[img5.Id] = img5.Rating - err = mongo.UpdateRatings(context.Background(), 0xA293, vector) + err = mongo.UpdateRatings(context.Background(), album, vector) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestMongoDelete(t *testing.T) { t.Run("Positive1", func(t *testing.T) { + id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(0x748C) - _, err = mongo.CountImages(context.Background(), 0x748C) + alb := AlbumEmptyFactory(id, ids) + _, err = mongo.CountImages(context.Background(), ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - n, err := mongo.CountImages(context.Background(), 0x748C) + n, err := mongo.CountImages(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 5, n) albums, err := mongo.AlbumsToBeDeleted(context.Background()) assert.NoError(t, err) assert.Len(t, albums, 0) - err = mongo.DeleteAlbum(context.Background(), 0x748C) + err = mongo.DeleteAlbum(context.Background(), ids.Uint64(0)) assert.NoError(t, err) - _, err = mongo.CountImages(context.Background(), 0x748C) + _, err = mongo.CountImages(context.Background(), ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) t.Run("Positive2", func(t *testing.T) { + id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(0x7B43) + alb := AlbumEmptyFactory(id, ids) alb.Expires = time.Now().Add(-1 * time.Hour) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) albums, err := mongo.AlbumsToBeDeleted(context.Background()) assert.NoError(t, err) assert.True(t, len(albums) == 1 && albums[0].Id == alb.Id && !albums[0].Expires.IsZero()) - err = mongo.DeleteAlbum(context.Background(), 0x7B43) + err = mongo.DeleteAlbum(context.Background(), ids.Uint64(0)) assert.NoError(t, err) - _, err = mongo.CountImages(context.Background(), 0x7B43) + _, err = mongo.CountImages(context.Background(), ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - t.Cleanup(func() { _ = mongo.DeleteAlbum(context.Background(), 0x7B43) }) + t.Cleanup(func() { _ = mongo.DeleteAlbum(context.Background(), ids.Uint64(0)) }) }) t.Run("Negative", func(t *testing.T) { + id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(0x608C) + alb := AlbumEmptyFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) - err = mongo.DeleteAlbum(context.Background(), 0xB7FF) + err = mongo.DeleteAlbum(context.Background(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } func TestMongoLru(t *testing.T) { + id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb1 := AlbumEmptyFactory(0x36FC) + alb1 := AlbumEmptyFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb1) assert.NoError(t, err) - alb2 := AlbumEmptyFactory(0xB020) + alb2 := AlbumEmptyFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb2) assert.NoError(t, err) - edgs, err := mongo.GetEdges(context.Background(), 0x36FC) + edgs, err := mongo.GetEdges(context.Background(), ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, alb1.Edges, edgs) } diff --git a/infrastructure/storage/minio_integration_test.go b/infrastructure/storage/minio_integration_test.go index f05a1a3..22d605b 100644 --- a/infrastructure/storage/minio_integration_test.go +++ b/infrastructure/storage/minio_integration_test.go @@ -10,44 +10,51 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + . "github.com/zitryss/aye-and-nay/internal/generator" . "github.com/zitryss/aye-and-nay/internal/testing" ) func TestMinio(t *testing.T) { t.Run("", func(t *testing.T) { + id, ids := GenId() + album := id() + image := id() minio, err := NewMinio(context.Background(), DefaultMinioConfig) require.NoError(t, err) - f, err := minio.Get(context.Background(), 0x70D8, 0xD5C7) + f, err := minio.Get(context.Background(), album, image) e := minioS3.ErrorResponse{} assert.ErrorAs(t, err, &e) assert.Nil(t, f.Reader) - src, err := minio.Put(context.Background(), 0x70D8, 0xD5C7, Png()) + src, err := minio.Put(context.Background(), album, image, Png()) assert.NoError(t, err) - assert.Equal(t, "/aye-and-nay/albums/2HAAAAAAAAA/images/x9UAAAAAAAA", src) - f, err = minio.Get(context.Background(), 0x70D8, 0xD5C7) + assert.Equal(t, "/aye-and-nay/albums/"+ids.Base64(0)+"/images/"+ids.Base64(1), src) + f, err = minio.Get(context.Background(), album, image) assert.NoError(t, err) AssertEqualFile(t, f, Png()) - err = minio.Remove(context.Background(), 0x70D8, 0xD5C7) + err = minio.Remove(context.Background(), album, image) assert.NoError(t, err) - f, err = minio.Get(context.Background(), 0x70D8, 0xD5C7) + f, err = minio.Get(context.Background(), album, image) e = minioS3.ErrorResponse{} assert.ErrorAs(t, err, &e) assert.Nil(t, f.Reader) }) t.Run("", func(t *testing.T) { + id, ids := GenId() + album := id() + image := id() minio, err := NewMinio(context.Background(), DefaultMinioConfig) require.NoError(t, err) - src, err := minio.Put(context.Background(), 0x872D, 0x882D, Png()) + src, err := minio.Put(context.Background(), album, image, Png()) assert.NoError(t, err) - assert.Equal(t, "/aye-and-nay/albums/LYcAAAAAAAA/images/LYgAAAAAAAA", src) - f, err := minio.Get(context.Background(), 0x872D, 0x882D) + assert.Equal(t, "/aye-and-nay/albums/"+ids.Base64(0)+"/images/"+ids.Base64(1), src) + f, err := minio.Get(context.Background(), album, image) assert.NoError(t, err) AssertEqualFile(t, f, Png()) - err = minio.Remove(context.Background(), 0x872D, 0x882D) + err = minio.Remove(context.Background(), album, image) assert.NoError(t, err) - src, err = minio.Put(context.Background(), 0x872D, 0x882D, Png()) + src, err = minio.Put(context.Background(), album, image, Png()) assert.NoError(t, err) - assert.Equal(t, "/aye-and-nay/albums/LYcAAAAAAAA/images/LYgAAAAAAAA", src) + assert.Equal(t, "/aye-and-nay/albums/"+ids.Base64(0)+"/images/"+ids.Base64(1), src) }) } diff --git a/internal/generator/generator.go b/internal/generator/generator.go index 5d511f8..0d168e7 100644 --- a/internal/generator/generator.go +++ b/internal/generator/generator.go @@ -1,7 +1,10 @@ package generator import ( + "fmt" "sync" + + "github.com/zitryss/aye-and-nay/pkg/base64" ) const ( @@ -45,14 +48,22 @@ type syncLogBook struct { logBook map[int]uint64 } -func (lb *syncLogBook) Get(i int) uint64 { +func (lb *syncLogBook) set(i int, id uint64) { lb.m.Lock() defer lb.m.Unlock() - return lb.logBook[i] + lb.logBook[i] = id } -func (lb *syncLogBook) set(i int, id uint64) { +func (lb *syncLogBook) Uint64(i int) uint64 { lb.m.Lock() defer lb.m.Unlock() - lb.logBook[i] = id + id, ok := lb.logBook[i] + if !ok { + panic(fmt.Sprintf("id #%d not found", i)) + } + return id +} + +func (lb *syncLogBook) Base64(i int) string { + return base64.FromUint64(lb.Uint64(i)) } diff --git a/internal/generator/generator_test.go b/internal/generator/generator_test.go index 6679b8c..ad25a7c 100644 --- a/internal/generator/generator_test.go +++ b/internal/generator/generator_test.go @@ -12,23 +12,26 @@ func TestGenId(t *testing.T) { id, ids = GenId() wg := sync.WaitGroup{} wg.Add(2) + ch := make(chan struct{}, 1) assert.NotPanics(t, func() { go func() { defer wg.Done() for i := 0; i < IDS_SPAN/2; i++ { - id() + _ = id() } + ch <- struct{}{} for i := 0; i < IDS_SPAN/2; i++ { - _ = ids.Get(i) + _ = ids.Uint64(i) } }() go func() { defer wg.Done() for i := IDS_SPAN / 2; i < IDS_SPAN; i++ { - id() + _ = id() } + <-ch for i := IDS_SPAN / 2; i < IDS_SPAN; i++ { - _ = ids.Get(i) + _ = ids.Uint64(i) } }() }) @@ -37,4 +40,8 @@ func TestGenId(t *testing.T) { assert.Equal(t, ids.logBook[0], uint64(100)) assert.Equal(t, ids.logBook[len(ids.logBook)-1], uint64(199)) assert.Panics(t, func() { id() }) + assert.Panics(t, func() { + _, ids := GenId() + _ = ids.Base64(0) + }) } diff --git a/internal/testing/testing.go b/internal/testing/testing.go index fa3a6b0..9f8a90b 100644 --- a/internal/testing/testing.go +++ b/internal/testing/testing.go @@ -10,7 +10,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/zitryss/aye-and-nay/domain/model" - "github.com/zitryss/aye-and-nay/pkg/base64" ) const ( @@ -27,42 +26,47 @@ func Png() model.File { return model.File{Reader: buf, Size: int64(buf.Len())} } -func AlbumEmptyFactory(id uint64) model.Album { - idB64 := base64.FromUint64(id) - img1 := model.Image{Id: 0x3E3D, Src: "/aye-and-nay/albums/" + idB64 + "/images/PT4AAAAAAAA"} - img2 := model.Image{Id: 0xB399, Src: "/aye-and-nay/albums/" + idB64 + "/images/mbMAAAAAAAA"} - img3 := model.Image{Id: 0xDA2A, Src: "/aye-and-nay/albums/" + idB64 + "/images/KtoAAAAAAAA"} - img4 := model.Image{Id: 0x51DE, Src: "/aye-and-nay/albums/" + idB64 + "/images/3lEAAAAAAAA"} - img5 := model.Image{Id: 0xDA52, Src: "/aye-and-nay/albums/" + idB64 + "/images/UtoAAAAAAAA"} +type ids interface { + Uint64(i int) uint64 + Base64(i int) string +} + +func AlbumEmptyFactory(id func() uint64, ids ids) model.Album { + album := id() + img1 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1)} + img2 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2)} + img3 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3)} + img4 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4)} + img5 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5)} imgs := []model.Image{img1, img2, img3, img4, img5} edgs := map[uint64]map[uint64]int{} - edgs[0x3E3D] = map[uint64]int{} - edgs[0xB399] = map[uint64]int{} - edgs[0xDA2A] = map[uint64]int{} - edgs[0x51DE] = map[uint64]int{} - edgs[0xDA52] = map[uint64]int{} + edgs[ids.Uint64(1)] = map[uint64]int{} + edgs[ids.Uint64(2)] = map[uint64]int{} + edgs[ids.Uint64(3)] = map[uint64]int{} + edgs[ids.Uint64(4)] = map[uint64]int{} + edgs[ids.Uint64(5)] = map[uint64]int{} expires := time.Time{} - alb := model.Album{id, imgs, edgs, expires} + alb := model.Album{album, imgs, edgs, expires} return alb } -func AlbumFullFactory(id uint64) model.Album { - alb := AlbumEmptyFactory(id) +func AlbumFullFactory(id func() uint64, ids ids) model.Album { + alb := AlbumEmptyFactory(id, ids) alb.Images[0].Rating = 0.48954984 alb.Images[1].Rating = 0.19186324 alb.Images[2].Rating = 0.41218211 alb.Images[3].Rating = 0.77920413 alb.Images[4].Rating = 0.13278389 - alb.Edges[0x51DE][0xDA2A]++ - alb.Edges[0x3E3D][0xDA2A]++ - alb.Edges[0x3E3D][0x51DE]++ - alb.Edges[0xB399][0xDA2A]++ - alb.Edges[0xB399][0x51DE]++ - alb.Edges[0xB399][0x3E3D]++ - alb.Edges[0xDA52][0xDA2A]++ - alb.Edges[0xDA52][0x51DE]++ - alb.Edges[0xDA52][0x3E3D]++ - alb.Edges[0xDA52][0xB399]++ + alb.Edges[ids.Uint64(4)][ids.Uint64(3)]++ + alb.Edges[ids.Uint64(1)][ids.Uint64(3)]++ + alb.Edges[ids.Uint64(1)][ids.Uint64(4)]++ + alb.Edges[ids.Uint64(2)][ids.Uint64(3)]++ + alb.Edges[ids.Uint64(2)][ids.Uint64(4)]++ + alb.Edges[ids.Uint64(2)][ids.Uint64(1)]++ + alb.Edges[ids.Uint64(5)][ids.Uint64(3)]++ + alb.Edges[ids.Uint64(5)][ids.Uint64(4)]++ + alb.Edges[ids.Uint64(5)][ids.Uint64(1)]++ + alb.Edges[ids.Uint64(5)][ids.Uint64(2)]++ return alb } From 8a7131041b5d945ba7b0b5ebcda926e307fc328d Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Wed, 9 Feb 2022 22:55:12 +0100 Subject: [PATCH 46/92] Refactor controller tests --- delivery/http/controller_test.go | 1286 ++++++------------------------ 1 file changed, 250 insertions(+), 1036 deletions(-) diff --git a/delivery/http/controller_test.go b/delivery/http/controller_test.go index 4cc08ef..b2c6652 100644 --- a/delivery/http/controller_test.go +++ b/delivery/http/controller_test.go @@ -21,912 +21,289 @@ import ( . "github.com/zitryss/aye-and-nay/internal/testing" ) -func TestControllerHandleAlbum(t *testing.T) { +func TestControllerHandle(t *testing.T) { type give struct { - err error - filenames []string - durationOn bool - duration string + handle func() httprouter.Handle + method string + target string + reqBody io.Reader + headers map[string]string + params []httprouter.Param } type want struct { - code int - typ string - body string + code int + typ string + respBody string } + contr := controller{} + payload := content{} tests := []struct { give want }{ { give: give{ - err: nil, - filenames: []string{"alan.jpg", "john.bmp", "dennis.png"}, - durationOn: true, - duration: "1h", + handle: contr.handleAlbum, + method: http.MethodPost, + target: "/api/albums/", + reqBody: payload.body(t, []string{"alan.jpg", "john.bmp", "dennis.png"}, true, "1h"), + headers: map[string]string{"Content-Type": payload.boundary}, }, want: want{ - code: 201, - typ: "application/json; charset=utf-8", - body: `{"album":{"id":"rRsAAAAAAAA"}}` + "\n", + code: http.StatusCreated, + typ: "application/json; charset=utf-8", + respBody: `{"album":{"id":"rRsAAAAAAAA"}}` + "\n", }, }, { give: give{ - err: nil, - filenames: []string{"big.jpg", "big.jpg", "big.jpg"}, - durationOn: true, - duration: "1h", + handle: contr.handleAlbum, + method: http.MethodPost, + target: "/api/albums/", + reqBody: payload.body(t, []string{"big.jpg", "big.jpg", "big.jpg"}, true, "1h"), + headers: map[string]string{"Content-Type": payload.boundary}, }, want: want{ - code: 413, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":2,"msg":"body too large"}}` + "\n", + code: http.StatusRequestEntityTooLarge, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":2,"msg":"body too large"}}` + "\n", }, }, { give: give{ - err: nil, - filenames: []string{"alan.jpg"}, - durationOn: true, - duration: "1h", + handle: contr.handleAlbum, + method: http.MethodPost, + target: "/api/albums/", + reqBody: payload.body(t, []string{"alan.jpg"}, true, "1h"), + headers: map[string]string{"Content-Type": payload.boundary}, }, want: want{ - code: 400, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":4,"msg":"not enough images"}}` + "\n", + code: http.StatusBadRequest, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":4,"msg":"not enough images"}}` + "\n", }, }, { give: give{ - err: nil, - filenames: []string{"alan.jpg", "john.bmp", "dennis.png", "alan.jpg"}, - durationOn: true, - duration: "1h", + handle: contr.handleAlbum, + method: http.MethodPost, + target: "/api/albums/", + reqBody: payload.body(t, []string{"alan.jpg", "john.bmp", "dennis.png", "alan.jpg"}, true, "1h"), + headers: map[string]string{"Content-Type": payload.boundary}, }, want: want{ - code: 413, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":5,"msg":"too many images"}}` + "\n", + code: http.StatusRequestEntityTooLarge, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":5,"msg":"too many images"}}` + "\n", }, }, { give: give{ - err: nil, - filenames: []string{"alan.jpg", "john.bmp", "big.jpg"}, - durationOn: true, - duration: "1h", + handle: contr.handleAlbum, + method: http.MethodPost, + target: "/api/albums/", + reqBody: payload.body(t, []string{"alan.jpg", "john.bmp", "big.jpg"}, true, "1h"), + headers: map[string]string{"Content-Type": payload.boundary}, }, want: want{ - code: 413, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":6,"msg":"image too large"}}` + "\n", + code: http.StatusRequestEntityTooLarge, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":6,"msg":"image too large"}}` + "\n", }, }, { give: give{ - err: nil, - filenames: []string{"alan.jpg", "john.bmp", "audio.ogg"}, - durationOn: true, - duration: "1h", + handle: contr.handleAlbum, + method: http.MethodPost, + target: "/api/albums/", + reqBody: payload.body(t, []string{"alan.jpg", "john.bmp", "audio.ogg"}, true, "1h"), + headers: map[string]string{"Content-Type": payload.boundary}, }, want: want{ - code: 415, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":7,"msg":"unsupported media type"}}` + "\n", + code: http.StatusUnsupportedMediaType, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":7,"msg":"unsupported media type"}}` + "\n", }, }, { give: give{ - err: nil, - filenames: []string{"alan.jpg", "john.bmp", "dennis.png"}, - durationOn: false, + handle: contr.handleAlbum, + method: http.MethodPost, + target: "/api/albums/", + reqBody: payload.body(t, []string{"alan.jpg", "john.bmp", "dennis.png"}, false, ""), + headers: map[string]string{"Content-Type": payload.boundary}, }, want: want{ - code: 400, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":8,"msg":"duration not set"}}` + "\n", + code: http.StatusBadRequest, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":8,"msg":"duration not set"}}` + "\n", }, }, { give: give{ - err: nil, - filenames: []string{"alan.jpg", "john.bmp", "dennis.png"}, - durationOn: true, - duration: "", + handle: contr.handleAlbum, + method: http.MethodPost, + target: "/api/albums/", + reqBody: payload.body(t, []string{"alan.jpg", "john.bmp", "dennis.png"}, true, ""), + headers: map[string]string{"Content-Type": payload.boundary}, }, want: want{ - code: 400, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":9,"msg":"duration invalid"}}` + "\n", + code: http.StatusBadRequest, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":9,"msg":"duration invalid"}}` + "\n", }, }, { give: give{ - err: domain.ErrTooManyRequests, - filenames: []string{"alan.jpg", "john.bmp", "dennis.png"}, - durationOn: true, - duration: "1h", + handle: contr.handleStatus, + method: http.MethodGet, + target: "/api/albums/rRsAAAAAAAA/status", + params: httprouter.Params{httprouter.Param{Key: "album", Value: "rRsAAAAAAAA"}}, }, want: want{ - code: 429, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":1,"msg":"too many requests"}}` + "\n", + code: http.StatusOK, + typ: "application/json; charset=utf-8", + respBody: `{"album":{"compression":{"progress":1}}}` + "\n", }, }, { give: give{ - err: domain.ErrBodyTooLarge, - filenames: []string{"alan.jpg", "john.bmp", "dennis.png"}, - durationOn: true, - duration: "1h", + handle: contr.handlePair, + method: http.MethodGet, + target: "/api/albums/nkUAAAAAAAA/", + params: httprouter.Params{httprouter.Param{Key: "album", Value: "nkUAAAAAAAA"}}, }, want: want{ - code: 413, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":2,"msg":"body too large"}}` + "\n", + code: http.StatusOK, + typ: "application/json; charset=utf-8", + respBody: `{"album":{"img1":{"token":"f8cAAAAAAAA","src":"/aye-and-nay/albums/nkUAAAAAAAA/images/21EAAAAAAAA"},"img2":{"token":"iakAAAAAAAA","src":"/aye-and-nay/albums/nkUAAAAAAAA/images/K2IAAAAAAAA"}}}` + "\n", }, }, { give: give{ - err: domain.ErrWrongContentType, - filenames: []string{"alan.jpg", "john.bmp", "dennis.png"}, - durationOn: true, - duration: "1h", + handle: contr.handleImage, + method: http.MethodGet, + target: "/api/images/8v7AAAAAAAA/", + params: httprouter.Params{httprouter.Param{Key: "token", Value: "8v7AAAAAAAA"}}, }, want: want{ - code: 415, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":3,"msg":"unsupported media type"}}` + "\n", + code: http.StatusOK, + typ: "image/png", + respBody: png(), }, }, { give: give{ - err: domain.ErrNotEnoughImages, - filenames: []string{"alan.jpg", "john.bmp", "dennis.png"}, - durationOn: true, - duration: "1h", + handle: contr.handleVote, + method: http.MethodPatch, + target: "/api/albums/fIIAAAAAAAA/", + reqBody: strings.NewReader(`{"album":{"imgFrom":{"token":"fYIAAAAAAAA"},"imgTo":{"token":"foIAAAAAAAA"}}}`), + headers: map[string]string{"Content-Type": "application/json; charset=utf-8"}, + params: httprouter.Params{httprouter.Param{Key: "album", Value: "fIIAAAAAAAA"}}, }, want: want{ - code: 400, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":4,"msg":"not enough images"}}` + "\n", + code: http.StatusOK, + typ: "", + respBody: ``, }, }, { give: give{ - err: domain.ErrTooManyImages, - filenames: []string{"alan.jpg", "john.bmp", "dennis.png"}, - durationOn: true, - duration: "11h", + handle: contr.handleTop, + method: http.MethodGet, + target: "/api/albums/byYAAAAAAAA/top/", + params: httprouter.Params{httprouter.Param{Key: "album", Value: "byYAAAAAAAA"}}, }, want: want{ - code: 413, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":5,"msg":"too many images"}}` + "\n", + code: http.StatusOK, + typ: "application/json; charset=utf-8", + respBody: `{"album":{"images":[{"src":"/aye-and-nay/albums/byYAAAAAAAA/images/yFwAAAAAAAA","rating":0.5},{"src":"/aye-and-nay/albums/byYAAAAAAAA/images/jVgAAAAAAAA","rating":0.5}]}}` + "\n", }, }, { give: give{ - err: domain.ErrImageTooLarge, - filenames: []string{"alan.jpg", "john.bmp", "dennis.png"}, - durationOn: true, - duration: "1h", + handle: contr.handleHealth, + method: http.MethodGet, + target: "/api/health/", }, want: want{ - code: 413, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":6,"msg":"image too large"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrNotImage, - filenames: []string{"alan.jpg", "john.bmp", "dennis.png"}, - durationOn: true, - duration: "1h", - }, - want: want{ - code: 415, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":7,"msg":"unsupported media type"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrDurationNotSet, - filenames: []string{"alan.jpg", "john.bmp", "dennis.png"}, - durationOn: true, - duration: "1h", - }, - want: want{ - code: 400, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":8,"msg":"duration not set"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrDurationInvalid, - filenames: []string{"alan.jpg", "john.bmp", "dennis.png"}, - durationOn: true, - duration: "1h", - }, - want: want{ - code: 400, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":9,"msg":"duration invalid"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrAlbumNotFound, - filenames: []string{"alan.jpg", "john.bmp", "dennis.png"}, - durationOn: true, - duration: "1h", - }, - want: want{ - code: 404, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":10,"msg":"album not found"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrTokenNotFound, - filenames: []string{"alan.jpg", "john.bmp", "dennis.png"}, - durationOn: true, - duration: "1h", - }, - want: want{ - code: 404, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":12,"msg":"token not found"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrThirdPartyUnavailable, - filenames: []string{"alan.jpg", "john.bmp", "dennis.png"}, - durationOn: true, - duration: "1h", - }, - want: want{ - code: 500, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":17,"msg":"internal server error"}}` + "\n", - }, - }, - { - give: give{ - err: context.Canceled, - filenames: []string{"alan.jpg", "john.bmp", "dennis.png"}, - durationOn: true, - duration: "1h", - }, - want: want{ - code: 500, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":-1,"msg":"internal server error"}}` + "\n", - }, - }, - { - give: give{ - err: context.DeadlineExceeded, - filenames: []string{"alan.jpg", "john.bmp", "dennis.png"}, - durationOn: true, - duration: "1h", - }, - want: want{ - code: 500, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":-2,"msg":"internal server error"}}` + "\n", - }, - }, - } - for _, tt := range tests { - t.Run("", func(t *testing.T) { - serv := service.NewMock(tt.give.err) - contr := newController(DefaultControllerConfig, serv) - fn := contr.handleAlbum() - w := httptest.NewRecorder() - body := bytes.Buffer{} - multi := multipart.NewWriter(&body) - for _, filename := range tt.give.filenames { - part, err := multi.CreateFormFile("images", filename) - assert.NoError(t, err) - b, err := os.ReadFile("../../testdata/" + filename) - assert.NoError(t, err) - _, err = part.Write(b) - assert.NoError(t, err) - } - if tt.give.durationOn { - err := multi.WriteField("duration", tt.give.duration) - assert.NoError(t, err) - } - err := multi.Close() - assert.NoError(t, err) - r := httptest.NewRequest(http.MethodPost, "/api/albums/", &body) - r.Header.Set("Content-Type", multi.FormDataContentType()) - fn(w, r, nil) - AssertStatusCode(t, w, tt.want.code) - AssertContentType(t, w, tt.want.typ) - AssertBody(t, w, tt.want.body) - }) - } -} - -func TestControllerHandleStatus(t *testing.T) { - type give struct { - err error - } - type want struct { - code int - typ string - body string - } - tests := []struct { - give - want - }{ - { - give: give{ - err: nil, - }, - want: want{ - code: 200, - typ: "application/json; charset=utf-8", - body: `{"album":{"compression":{"progress":1}}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrTooManyRequests, - }, - want: want{ - code: 429, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":1,"msg":"too many requests"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrBodyTooLarge, - }, - want: want{ - code: 413, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":2,"msg":"body too large"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrWrongContentType, - }, - want: want{ - code: 415, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":3,"msg":"unsupported media type"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrNotEnoughImages, - }, - want: want{ - code: 400, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":4,"msg":"not enough images"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrTooManyImages, - }, - want: want{ - code: 413, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":5,"msg":"too many images"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrImageTooLarge, - }, - want: want{ - code: 413, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":6,"msg":"image too large"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrNotImage, - }, - want: want{ - code: 415, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":7,"msg":"unsupported media type"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrDurationNotSet, - }, - want: want{ - code: 400, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":8,"msg":"duration not set"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrDurationInvalid, - }, - want: want{ - code: 400, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":9,"msg":"duration invalid"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrAlbumNotFound, - }, - want: want{ - code: 404, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":10,"msg":"album not found"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrTokenNotFound, - }, - want: want{ - code: 404, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":12,"msg":"token not found"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrThirdPartyUnavailable, - }, - want: want{ - code: 500, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":17,"msg":"internal server error"}}` + "\n", - }, - }, - { - give: give{ - err: context.Canceled, - }, - want: want{ - code: 500, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":-1,"msg":"internal server error"}}` + "\n", - }, - }, - { - give: give{ - err: context.DeadlineExceeded, - }, - want: want{ - code: 500, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":-2,"msg":"internal server error"}}` + "\n", - }, - }, - } - for _, tt := range tests { - t.Run("", func(t *testing.T) { - serv := service.NewMock(tt.give.err) - contr := newController(DefaultControllerConfig, serv) - fn := contr.handleStatus() - w := httptest.NewRecorder() - r := httptest.NewRequest(http.MethodGet, "/api/albums/rRsAAAAAAAA/status", http.NoBody) - ps := httprouter.Params{httprouter.Param{Key: "album", Value: "rRsAAAAAAAA"}} - fn(w, r, ps) - AssertStatusCode(t, w, tt.want.code) - AssertContentType(t, w, tt.want.typ) - AssertBody(t, w, tt.want.body) - }) - } -} - -func TestControllerHandlePair(t *testing.T) { - type give struct { - err error - } - type want struct { - code int - typ string - body string - } - tests := []struct { - give - want - }{ - { - give: give{ - err: nil, - }, - want: want{ - code: 200, - typ: "application/json; charset=utf-8", - body: `{"album":{"img1":{"token":"f8cAAAAAAAA","src":"/aye-and-nay/albums/nkUAAAAAAAA/images/21EAAAAAAAA"},"img2":{"token":"iakAAAAAAAA","src":"/aye-and-nay/albums/nkUAAAAAAAA/images/K2IAAAAAAAA"}}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrTooManyRequests, - }, - want: want{ - code: 429, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":1,"msg":"too many requests"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrBodyTooLarge, - }, - want: want{ - code: 413, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":2,"msg":"body too large"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrWrongContentType, - }, - want: want{ - code: 415, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":3,"msg":"unsupported media type"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrNotEnoughImages, - }, - want: want{ - code: 400, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":4,"msg":"not enough images"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrTooManyImages, - }, - want: want{ - code: 413, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":5,"msg":"too many images"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrImageTooLarge, - }, - want: want{ - code: 413, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":6,"msg":"image too large"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrNotImage, - }, - want: want{ - code: 415, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":7,"msg":"unsupported media type"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrDurationNotSet, - }, - want: want{ - code: 400, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":8,"msg":"duration not set"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrDurationInvalid, - }, - want: want{ - code: 400, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":9,"msg":"duration invalid"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrAlbumNotFound, - }, - want: want{ - code: 404, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":10,"msg":"album not found"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrTokenNotFound, - }, - want: want{ - code: 404, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":12,"msg":"token not found"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrThirdPartyUnavailable, - }, - want: want{ - code: 500, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":17,"msg":"internal server error"}}` + "\n", - }, - }, - { - give: give{ - err: context.Canceled, - }, - want: want{ - code: 500, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":-1,"msg":"internal server error"}}` + "\n", - }, - }, - { - give: give{ - err: context.DeadlineExceeded, - }, - want: want{ - code: 500, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":-2,"msg":"internal server error"}}` + "\n", - }, - }, - } - for _, tt := range tests { - t.Run("", func(t *testing.T) { - serv := service.NewMock(tt.give.err) - contr := newController(DefaultControllerConfig, serv) - fn := contr.handlePair() - w := httptest.NewRecorder() - r := httptest.NewRequest(http.MethodGet, "/api/albums/nkUAAAAAAAA/", http.NoBody) - ps := httprouter.Params{httprouter.Param{Key: "album", Value: "nkUAAAAAAAA"}} - fn(w, r, ps) - AssertStatusCode(t, w, tt.want.code) - AssertContentType(t, w, tt.want.typ) - AssertBody(t, w, tt.want.body) - }) - } -} - -func TestControllerHandleImage(t *testing.T) { - body, _ := io.ReadAll(Png()) - type give struct { - err error - } - type want struct { - code int - typ string - body string - } - tests := []struct { - give - want - }{ - { - give: give{ - err: nil, - }, - want: want{ - code: 200, - typ: "image/png", - body: string(body), - }, - }, - { - give: give{ - err: domain.ErrTooManyRequests, - }, - want: want{ - code: 429, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":1,"msg":"too many requests"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrBodyTooLarge, - }, - want: want{ - code: 413, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":2,"msg":"body too large"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrWrongContentType, - }, - want: want{ - code: 415, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":3,"msg":"unsupported media type"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrNotEnoughImages, - }, - want: want{ - code: 400, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":4,"msg":"not enough images"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrTooManyImages, - }, - want: want{ - code: 413, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":5,"msg":"too many images"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrImageTooLarge, - }, - want: want{ - code: 413, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":6,"msg":"image too large"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrNotImage, - }, - want: want{ - code: 415, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":7,"msg":"unsupported media type"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrDurationNotSet, - }, - want: want{ - code: 400, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":8,"msg":"duration not set"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrDurationInvalid, - }, - want: want{ - code: 400, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":9,"msg":"duration invalid"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrAlbumNotFound, - }, - want: want{ - code: 404, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":10,"msg":"album not found"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrTokenNotFound, - }, - want: want{ - code: 404, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":12,"msg":"token not found"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrThirdPartyUnavailable, - }, - want: want{ - code: 500, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":17,"msg":"internal server error"}}` + "\n", - }, - }, - { - give: give{ - err: context.Canceled, - }, - want: want{ - code: 500, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":-1,"msg":"internal server error"}}` + "\n", - }, - }, - { - give: give{ - err: context.DeadlineExceeded, - }, - want: want{ - code: 500, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":-2,"msg":"internal server error"}}` + "\n", + code: http.StatusOK, + typ: "", + respBody: ``, }, }, } for _, tt := range tests { t.Run("", func(t *testing.T) { - serv := service.NewMock(tt.give.err) - contr := newController(DefaultControllerConfig, serv) - fn := contr.handleImage() + err := error(nil) + serv := service.NewMock(err) + contr = newController(DefaultControllerConfig, serv) + fn := tt.give.handle() w := httptest.NewRecorder() - r := httptest.NewRequest(http.MethodGet, "/api/images/8v7AAAAAAAA/", http.NoBody) - ps := httprouter.Params{httprouter.Param{Key: "token", Value: "8v7AAAAAAAA"}} - fn(w, r, ps) + r := httptest.NewRequest(tt.give.method, tt.give.target, tt.give.reqBody) + for k, v := range tt.give.headers { + r.Header.Set(k, v) + } + fn(w, r, tt.give.params) AssertStatusCode(t, w, tt.want.code) AssertContentType(t, w, tt.want.typ) - AssertBody(t, w, tt.want.body) + AssertBody(t, w, tt.want.respBody) }) } } -func TestControllerHandleVote(t *testing.T) { +type content struct { + boundary string +} + +func (c *content) body(t *testing.T, filenames []string, durationOn bool, duration string) io.Reader { + t.Helper() + body := bytes.Buffer{} + multi := multipart.NewWriter(&body) + for _, filename := range filenames { + part, err := multi.CreateFormFile("images", filename) + assert.NoError(t, err) + b, err := os.ReadFile("../../testdata/" + filename) + assert.NoError(t, err) + _, err = part.Write(b) + assert.NoError(t, err) + } + if durationOn { + err := multi.WriteField("duration", duration) + assert.NoError(t, err) + } + err := multi.Close() + assert.NoError(t, err) + c.boundary = multi.FormDataContentType() + return &body +} + +func png() string { + body, _ := io.ReadAll(Png()) + return string(body) +} + +func TestControllerError(t *testing.T) { type give struct { err error } type want struct { - code int - typ string - body string + code int + typ string + respBody string } tests := []struct { give want }{ - { - give: give{ - err: nil, - }, - want: want{ - code: 200, - typ: "", - body: ``, - }, - }, { give: give{ err: domain.ErrTooManyRequests, }, want: want{ - code: 429, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":1,"msg":"too many requests"}}` + "\n", + code: http.StatusTooManyRequests, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":1,"msg":"too many requests"}}` + "\n", }, }, { @@ -934,9 +311,9 @@ func TestControllerHandleVote(t *testing.T) { err: domain.ErrBodyTooLarge, }, want: want{ - code: 413, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":2,"msg":"body too large"}}` + "\n", + code: http.StatusRequestEntityTooLarge, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":2,"msg":"body too large"}}` + "\n", }, }, { @@ -944,9 +321,9 @@ func TestControllerHandleVote(t *testing.T) { err: domain.ErrWrongContentType, }, want: want{ - code: 415, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":3,"msg":"unsupported media type"}}` + "\n", + code: http.StatusUnsupportedMediaType, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":3,"msg":"unsupported media type"}}` + "\n", }, }, { @@ -954,9 +331,9 @@ func TestControllerHandleVote(t *testing.T) { err: domain.ErrNotEnoughImages, }, want: want{ - code: 400, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":4,"msg":"not enough images"}}` + "\n", + code: http.StatusBadRequest, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":4,"msg":"not enough images"}}` + "\n", }, }, { @@ -964,9 +341,9 @@ func TestControllerHandleVote(t *testing.T) { err: domain.ErrTooManyImages, }, want: want{ - code: 413, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":5,"msg":"too many images"}}` + "\n", + code: http.StatusRequestEntityTooLarge, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":5,"msg":"too many images"}}` + "\n", }, }, { @@ -974,9 +351,9 @@ func TestControllerHandleVote(t *testing.T) { err: domain.ErrImageTooLarge, }, want: want{ - code: 413, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":6,"msg":"image too large"}}` + "\n", + code: http.StatusRequestEntityTooLarge, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":6,"msg":"image too large"}}` + "\n", }, }, { @@ -984,9 +361,9 @@ func TestControllerHandleVote(t *testing.T) { err: domain.ErrNotImage, }, want: want{ - code: 415, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":7,"msg":"unsupported media type"}}` + "\n", + code: http.StatusUnsupportedMediaType, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":7,"msg":"unsupported media type"}}` + "\n", }, }, { @@ -994,9 +371,9 @@ func TestControllerHandleVote(t *testing.T) { err: domain.ErrDurationNotSet, }, want: want{ - code: 400, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":8,"msg":"duration not set"}}` + "\n", + code: http.StatusBadRequest, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":8,"msg":"duration not set"}}` + "\n", }, }, { @@ -1004,9 +381,9 @@ func TestControllerHandleVote(t *testing.T) { err: domain.ErrDurationInvalid, }, want: want{ - code: 400, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":9,"msg":"duration invalid"}}` + "\n", + code: http.StatusBadRequest, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":9,"msg":"duration invalid"}}` + "\n", }, }, { @@ -1014,211 +391,129 @@ func TestControllerHandleVote(t *testing.T) { err: domain.ErrAlbumNotFound, }, want: want{ - code: 404, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":10,"msg":"album not found"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrTokenNotFound, - }, - want: want{ - code: 404, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":12,"msg":"token not found"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrThirdPartyUnavailable, - }, - want: want{ - code: 500, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":17,"msg":"internal server error"}}` + "\n", - }, - }, - { - give: give{ - err: context.Canceled, - }, - want: want{ - code: 500, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":-1,"msg":"internal server error"}}` + "\n", - }, - }, - { - give: give{ - err: context.DeadlineExceeded, - }, - want: want{ - code: 500, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":-2,"msg":"internal server error"}}` + "\n", - }, - }, - } - for _, tt := range tests { - t.Run("", func(t *testing.T) { - serv := service.NewMock(tt.give.err) - contr := newController(DefaultControllerConfig, serv) - fn := contr.handleVote() - w := httptest.NewRecorder() - json := strings.NewReader(`{"album":{"imgFrom":{"token":"fYIAAAAAAAA"},"imgTo":{"token":"foIAAAAAAAA"}}}`) - r := httptest.NewRequest(http.MethodPatch, "/api/albums/fIIAAAAAAAA/", json) - r.Header.Set("Content-Type", "application/json; charset=utf-8") - ps := httprouter.Params{httprouter.Param{Key: "album", Value: "fIIAAAAAAAA"}} - fn(w, r, ps) - AssertStatusCode(t, w, tt.want.code) - AssertContentType(t, w, tt.want.typ) - AssertBody(t, w, tt.want.body) - }) - } -} - -func TestControllerHandleTop(t *testing.T) { - type give struct { - err error - } - type want struct { - code int - typ string - body string - } - tests := []struct { - give - want - }{ - { - give: give{ - err: nil, - }, - want: want{ - code: 200, - typ: "application/json; charset=utf-8", - body: `{"album":{"images":[{"src":"/aye-and-nay/albums/byYAAAAAAAA/images/yFwAAAAAAAA","rating":0.5},{"src":"/aye-and-nay/albums/byYAAAAAAAA/images/jVgAAAAAAAA","rating":0.5}]}}` + "\n", + code: http.StatusNotFound, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":10,"msg":"album not found"}}` + "\n", }, }, { give: give{ - err: domain.ErrTooManyRequests, + err: domain.ErrPairNotFound, }, want: want{ - code: 429, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":1,"msg":"too many requests"}}` + "\n", + code: http.StatusInternalServerError, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":11,"msg":"internal server error"}}` + "\n", }, }, { give: give{ - err: domain.ErrBodyTooLarge, + err: domain.ErrTokenNotFound, }, want: want{ - code: 413, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":2,"msg":"body too large"}}` + "\n", + code: http.StatusNotFound, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":12,"msg":"token not found"}}` + "\n", }, }, { give: give{ - err: domain.ErrWrongContentType, + err: domain.ErrImageNotFound, }, want: want{ - code: 415, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":3,"msg":"unsupported media type"}}` + "\n", + code: http.StatusInternalServerError, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":13,"msg":"internal server error"}}` + "\n", }, }, { give: give{ - err: domain.ErrNotEnoughImages, + err: domain.ErrAlbumAlreadyExists, }, want: want{ - code: 400, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":4,"msg":"not enough images"}}` + "\n", + code: http.StatusInternalServerError, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":14,"msg":"internal server error"}}` + "\n", }, }, { give: give{ - err: domain.ErrTooManyImages, + err: domain.ErrTokenAlreadyExists, }, want: want{ - code: 413, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":5,"msg":"too many images"}}` + "\n", + code: http.StatusInternalServerError, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":15,"msg":"internal server error"}}` + "\n", }, }, { give: give{ - err: domain.ErrImageTooLarge, + err: domain.ErrUnsupportedMediaType, }, want: want{ - code: 413, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":6,"msg":"image too large"}}` + "\n", + code: http.StatusUnsupportedMediaType, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":16,"msg":"unsupported media type"}}` + "\n", }, }, { give: give{ - err: domain.ErrNotImage, + err: domain.ErrThirdPartyUnavailable, }, want: want{ - code: 415, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":7,"msg":"unsupported media type"}}` + "\n", + code: http.StatusInternalServerError, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":17,"msg":"internal server error"}}` + "\n", }, }, { give: give{ - err: domain.ErrDurationNotSet, + err: domain.ErrBadHealthCompressor, }, want: want{ - code: 400, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":8,"msg":"duration not set"}}` + "\n", + code: http.StatusInternalServerError, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":18,"msg":"internal server error"}}` + "\n", }, }, { give: give{ - err: domain.ErrDurationInvalid, + err: domain.ErrBadHealthStorage, }, want: want{ - code: 400, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":9,"msg":"duration invalid"}}` + "\n", + code: http.StatusInternalServerError, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":19,"msg":"internal server error"}}` + "\n", }, }, { give: give{ - err: domain.ErrAlbumNotFound, + err: domain.ErrBadHealthDatabase, }, want: want{ - code: 404, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":10,"msg":"album not found"}}` + "\n", + code: http.StatusInternalServerError, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":20,"msg":"internal server error"}}` + "\n", }, }, { give: give{ - err: domain.ErrTokenNotFound, + err: domain.ErrBadHealthCache, }, want: want{ - code: 404, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":12,"msg":"token not found"}}` + "\n", + code: http.StatusInternalServerError, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":21,"msg":"internal server error"}}` + "\n", }, }, { give: give{ - err: domain.ErrThirdPartyUnavailable, + err: domain.ErrUnknown, }, want: want{ - code: 500, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":17,"msg":"internal server error"}}` + "\n", + code: http.StatusInternalServerError, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":22,"msg":"internal server error"}}` + "\n", }, }, { @@ -1226,9 +521,9 @@ func TestControllerHandleTop(t *testing.T) { err: context.Canceled, }, want: want{ - code: 500, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":-1,"msg":"internal server error"}}` + "\n", + code: http.StatusInternalServerError, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":-1,"msg":"internal server error"}}` + "\n", }, }, { @@ -1236,89 +531,9 @@ func TestControllerHandleTop(t *testing.T) { err: context.DeadlineExceeded, }, want: want{ - code: 500, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":-2,"msg":"internal server error"}}` + "\n", - }, - }, - } - for _, tt := range tests { - t.Run("", func(t *testing.T) { - serv := service.NewMock(tt.give.err) - contr := newController(DefaultControllerConfig, serv) - fn := contr.handleTop() - w := httptest.NewRecorder() - r := httptest.NewRequest(http.MethodGet, "/api/albums/byYAAAAAAAA/top/", http.NoBody) - ps := httprouter.Params{httprouter.Param{Key: "album", Value: "byYAAAAAAAA"}} - fn(w, r, ps) - AssertStatusCode(t, w, tt.want.code) - AssertContentType(t, w, tt.want.typ) - AssertBody(t, w, tt.want.body) - }) - } -} - -func TestControllerHandleHealth(t *testing.T) { - type give struct { - err error - } - type want struct { - code int - typ string - body string - } - tests := []struct { - give - want - }{ - { - give: give{ - err: nil, - }, - want: want{ - code: 200, - typ: "", - body: ``, - }, - }, - { - give: give{ - err: domain.ErrBadHealthCompressor, - }, - want: want{ - code: 500, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":18,"msg":"internal server error"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrBadHealthStorage, - }, - want: want{ - code: 500, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":19,"msg":"internal server error"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrBadHealthDatabase, - }, - want: want{ - code: 500, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":20,"msg":"internal server error"}}` + "\n", - }, - }, - { - give: give{ - err: domain.ErrBadHealthCache, - }, - want: want{ - code: 500, - typ: "application/json; charset=utf-8", - body: `{"error":{"code":21,"msg":"internal server error"}}` + "\n", + code: http.StatusInternalServerError, + typ: "application/json; charset=utf-8", + respBody: `{"error":{"code":-2,"msg":"internal server error"}}` + "\n", }, }, } @@ -1329,11 +544,10 @@ func TestControllerHandleHealth(t *testing.T) { fn := contr.handleHealth() w := httptest.NewRecorder() r := httptest.NewRequest(http.MethodGet, "/api/health/", http.NoBody) - ps := httprouter.Params{} - fn(w, r, ps) + fn(w, r, nil) AssertStatusCode(t, w, tt.want.code) AssertContentType(t, w, tt.want.typ) - AssertBody(t, w, tt.want.body) + AssertBody(t, w, tt.want.respBody) }) } } From 76512a5fe1cdea78e947c60e6a7b20ec223b387b Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Wed, 9 Feb 2022 23:30:06 +0100 Subject: [PATCH 47/92] Set sane default settings --- infrastructure/cache/config.go | 6 +++--- infrastructure/cache/redis_integration_test.go | 4 ---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/infrastructure/cache/config.go b/infrastructure/cache/config.go index 20543b7..c5c40a9 100644 --- a/infrastructure/cache/config.go +++ b/infrastructure/cache/config.go @@ -41,8 +41,8 @@ var ( RetryTimes: 4, RetryPause: 5 * time.Second, Timeout: 30 * time.Second, - LimiterRequestsPerSecond: 100, - LimiterBurst: 10, - TimeToLive: 1 * time.Second, + LimiterRequestsPerSecond: 1, + LimiterBurst: 1, + TimeToLive: 5 * time.Second, } ) diff --git a/infrastructure/cache/redis_integration_test.go b/infrastructure/cache/redis_integration_test.go index 4a4cb3c..8d078dc 100644 --- a/infrastructure/cache/redis_integration_test.go +++ b/infrastructure/cache/redis_integration_test.go @@ -16,9 +16,6 @@ import ( func TestRedisAllow(t *testing.T) { t.Run("Positive", func(t *testing.T) { - if testing.Short() { - t.Skip("short flag is set") - } id, _ := GenId() redis, err := NewRedis(context.Background(), DefaultRedisConfig) require.NoError(t, err) @@ -37,7 +34,6 @@ func TestRedisAllow(t *testing.T) { } }) t.Run("Negative", func(t *testing.T) { - t.Skip("flaky test") id, _ := GenId() redis, err := NewRedis(context.Background(), DefaultRedisConfig) require.NoError(t, err) From b801d27940ac69b938ab731b5e7169d553cf8ceb Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Thu, 10 Feb 2022 22:37:34 +0100 Subject: [PATCH 48/92] Apply testing suits --- .../storage/minio_integration_test.go | 72 +++++++++++++------ 1 file changed, 51 insertions(+), 21 deletions(-) diff --git a/infrastructure/storage/minio_integration_test.go b/infrastructure/storage/minio_integration_test.go index 22d605b..d53c9fe 100644 --- a/infrastructure/storage/minio_integration_test.go +++ b/infrastructure/storage/minio_integration_test.go @@ -9,58 +9,88 @@ import ( minioS3 "github.com/minio/minio-go/v7" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "github.com/zitryss/aye-and-nay/domain/domain" . "github.com/zitryss/aye-and-nay/internal/generator" . "github.com/zitryss/aye-and-nay/internal/testing" ) -func TestMinio(t *testing.T) { - t.Run("", func(t *testing.T) { +func TestExampleTestSuite(t *testing.T) { + suite.Run(t, &MinioTestSuite{}) +} + +type MinioTestSuite struct { + suite.Suite + ctx context.Context + cancel context.CancelFunc + storage domain.Storager +} + +func (suite *MinioTestSuite) SetupSuite() { + ctx, cancel := context.WithCancel(context.Background()) + minio, err := NewMinio(ctx, DefaultMinioConfig) + require.NoError(suite.T(), err) + suite.ctx = ctx + suite.cancel = cancel + suite.storage = minio +} + +func (suite *MinioTestSuite) SetupTest() { + err := suite.storage.(*Minio).Reset() + require.NoError(suite.T(), err) +} + +func (suite *MinioTestSuite) TestMinio() { + suite.T().Run("", func(t *testing.T) { id, ids := GenId() album := id() image := id() - minio, err := NewMinio(context.Background(), DefaultMinioConfig) - require.NoError(t, err) - f, err := minio.Get(context.Background(), album, image) + f, err := suite.storage.Get(suite.ctx, album, image) e := minioS3.ErrorResponse{} assert.ErrorAs(t, err, &e) assert.Nil(t, f.Reader) - src, err := minio.Put(context.Background(), album, image, Png()) + src, err := suite.storage.Put(suite.ctx, album, image, Png()) assert.NoError(t, err) assert.Equal(t, "/aye-and-nay/albums/"+ids.Base64(0)+"/images/"+ids.Base64(1), src) - f, err = minio.Get(context.Background(), album, image) + f, err = suite.storage.Get(suite.ctx, album, image) assert.NoError(t, err) AssertEqualFile(t, f, Png()) - err = minio.Remove(context.Background(), album, image) + err = suite.storage.Remove(suite.ctx, album, image) assert.NoError(t, err) - f, err = minio.Get(context.Background(), album, image) + f, err = suite.storage.Get(suite.ctx, album, image) e = minioS3.ErrorResponse{} assert.ErrorAs(t, err, &e) assert.Nil(t, f.Reader) }) - t.Run("", func(t *testing.T) { + suite.T().Run("", func(t *testing.T) { id, ids := GenId() album := id() image := id() - minio, err := NewMinio(context.Background(), DefaultMinioConfig) - require.NoError(t, err) - src, err := minio.Put(context.Background(), album, image, Png()) + src, err := suite.storage.Put(suite.ctx, album, image, Png()) assert.NoError(t, err) assert.Equal(t, "/aye-and-nay/albums/"+ids.Base64(0)+"/images/"+ids.Base64(1), src) - f, err := minio.Get(context.Background(), album, image) + f, err := suite.storage.Get(suite.ctx, album, image) assert.NoError(t, err) AssertEqualFile(t, f, Png()) - err = minio.Remove(context.Background(), album, image) + err = suite.storage.Remove(suite.ctx, album, image) assert.NoError(t, err) - src, err = minio.Put(context.Background(), album, image, Png()) + src, err = suite.storage.Put(suite.ctx, album, image, Png()) assert.NoError(t, err) assert.Equal(t, "/aye-and-nay/albums/"+ids.Base64(0)+"/images/"+ids.Base64(1), src) }) } -func TestMinioHealth(t *testing.T) { - minio, err := NewMinio(context.Background(), DefaultMinioConfig) - require.NoError(t, err) - _, err = minio.Health(context.Background()) - assert.NoError(t, err) +func (suite *MinioTestSuite) TestMinioHealth() { + _, err := suite.storage.Health(suite.ctx) + assert.NoError(suite.T(), err) +} + +func (suite *MinioTestSuite) TearDownTest() { +} + +func (suite *MinioTestSuite) TearDownSuite() { + err := suite.storage.(*Minio).Reset() + require.NoError(suite.T(), err) + suite.cancel() } From 3e74711808b0a2f68a6ecb882e8a2f71ab99161e Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Thu, 10 Feb 2022 22:37:41 +0100 Subject: [PATCH 49/92] Refactor --- infrastructure/database/badger_test.go | 6 +++--- infrastructure/database/mem_test.go | 6 +++--- infrastructure/database/mongo_integration_test.go | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/infrastructure/database/badger_test.go b/infrastructure/database/badger_test.go index 6e827e2..6c7c0ec 100644 --- a/infrastructure/database/badger_test.go +++ b/infrastructure/database/badger_test.go @@ -197,7 +197,7 @@ func TestBadgerSort(t *testing.T) { assert.NoError(t, err) imgs1, err := badger.GetImagesOrdered(context.Background(), ids.Uint64(0)) assert.NoError(t, err) - img1 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4) + "", Rating: 0.77920413} + img1 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4), Rating: 0.77920413} img2 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.48954984} img3 := model.Image{Id: ids.Uint64(3), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.41218211} img4 := model.Image{Id: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.19186324} @@ -225,7 +225,7 @@ func TestBadgerRatings(t *testing.T) { img1 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} img2 := model.Image{Id: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.32537162} img3 := model.Image{Id: ids.Uint64(3), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.43185491} - img4 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4) + "", Rating: 0.57356209} + img4 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4), Rating: 0.57356209} img5 := model.Image{Id: ids.Uint64(5), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5), Rating: 0.61438023} imgs1 := []model.Image{img1, img2, img3, img4, img5} vector := map[uint64]float64{} @@ -249,7 +249,7 @@ func TestBadgerRatings(t *testing.T) { img1 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} img2 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.32537162} img3 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.43185491} - img4 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4) + "", Rating: 0.57356209} + img4 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4), Rating: 0.57356209} img5 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5), Rating: 0.61438023} vector := map[uint64]float64{} vector[img1.Id] = img1.Rating diff --git a/infrastructure/database/mem_test.go b/infrastructure/database/mem_test.go index 4ee3614..acaeb12 100644 --- a/infrastructure/database/mem_test.go +++ b/infrastructure/database/mem_test.go @@ -180,7 +180,7 @@ func TestMemSort(t *testing.T) { assert.NoError(t, err) imgs1, err := mem.GetImagesOrdered(context.Background(), ids.Uint64(0)) assert.NoError(t, err) - img1 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4) + "", Rating: 0.77920413} + img1 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4), Rating: 0.77920413} img2 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.48954984} img3 := model.Image{Id: ids.Uint64(3), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.41218211} img4 := model.Image{Id: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.19186324} @@ -206,7 +206,7 @@ func TestMemRatings(t *testing.T) { img1 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} img2 := model.Image{Id: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.32537162} img3 := model.Image{Id: ids.Uint64(3), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.43185491} - img4 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4) + "", Rating: 0.57356209} + img4 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4), Rating: 0.57356209} img5 := model.Image{Id: ids.Uint64(5), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5), Rating: 0.61438023} imgs1 := []model.Image{img1, img2, img3, img4, img5} vector := map[uint64]float64{} @@ -229,7 +229,7 @@ func TestMemRatings(t *testing.T) { img1 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} img2 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.32537162} img3 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.43185491} - img4 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4) + "", Rating: 0.57356209} + img4 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4), Rating: 0.57356209} img5 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5), Rating: 0.61438023} vector := map[uint64]float64{} vector[img1.Id] = img1.Rating diff --git a/infrastructure/database/mongo_integration_test.go b/infrastructure/database/mongo_integration_test.go index 7c4f046..0201eed 100644 --- a/infrastructure/database/mongo_integration_test.go +++ b/infrastructure/database/mongo_integration_test.go @@ -197,7 +197,7 @@ func TestMongoSort(t *testing.T) { assert.NoError(t, err) imgs1, err := mongo.GetImagesOrdered(context.Background(), ids.Uint64(0)) assert.NoError(t, err) - img1 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4) + "", Rating: 0.77920413} + img1 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4), Rating: 0.77920413} img2 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.48954984} img3 := model.Image{Id: ids.Uint64(3), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.41218211} img4 := model.Image{Id: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.19186324} @@ -225,7 +225,7 @@ func TestMongoRatings(t *testing.T) { img1 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} img2 := model.Image{Id: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.32537162} img3 := model.Image{Id: ids.Uint64(3), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.43185491} - img4 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4) + "", Rating: 0.57356209} + img4 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4), Rating: 0.57356209} img5 := model.Image{Id: ids.Uint64(5), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5), Rating: 0.61438023} imgs1 := []model.Image{img1, img2, img3, img4, img5} vector := map[uint64]float64{} @@ -249,7 +249,7 @@ func TestMongoRatings(t *testing.T) { img1 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} img2 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.32537162} img3 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.43185491} - img4 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4) + "", Rating: 0.57356209} + img4 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4), Rating: 0.57356209} img5 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5), Rating: 0.61438023} vector := map[uint64]float64{} vector[img1.Id] = img1.Rating From 14fecdc8f8894b3783ecbe0a8fa4403930453fc8 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Fri, 11 Feb 2022 08:55:14 +0100 Subject: [PATCH 50/92] Use one factory --- domain/service/service_integration_test.go | 4 +-- domain/service/service_test.go | 4 +-- infrastructure/database/badger_test.go | 30 ++++++++--------- infrastructure/database/mem_test.go | 26 +++++++-------- .../database/mongo_integration_test.go | 30 ++++++++--------- internal/testing/testing.go | 32 ++++--------------- 6 files changed, 53 insertions(+), 73 deletions(-) diff --git a/domain/service/service_integration_test.go b/domain/service/service_integration_test.go index 73779b8..c2e51ca 100644 --- a/domain/service/service_integration_test.go +++ b/domain/service/service_integration_test.go @@ -595,11 +595,11 @@ func TestServiceIntegrationDelete(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{newPQueue(idPQ(), redis)} qDel.Monitor(ctx) - alb1 := AlbumEmptyFactory(id1, ids1) + alb1 := AlbumFactory(id1, ids1) alb1.Expires = time.Now().Add(-1 * time.Hour) err = mongo.SaveAlbum(ctx, alb1) assert.NoError(t, err) - alb2 := AlbumEmptyFactory(id2, ids2) + alb2 := AlbumFactory(id2, ids2) alb2.Expires = time.Now().Add(1 * time.Hour) err = mongo.SaveAlbum(ctx, alb2) assert.NoError(t, err) diff --git a/domain/service/service_test.go b/domain/service/service_test.go index 86ab3d4..2f907b4 100644 --- a/domain/service/service_test.go +++ b/domain/service/service_test.go @@ -505,11 +505,11 @@ func TestServiceDelete(t *testing.T) { qComp.Monitor(ctx) qDel := &QueueDel{newPQueue(idPQ(), mCache)} qDel.Monitor(ctx) - alb1 := AlbumEmptyFactory(id1, ids1) + alb1 := AlbumFactory(id1, ids1) alb1.Expires = time.Now().Add(-1 * time.Hour) err := mDb.SaveAlbum(ctx, alb1) assert.NoError(t, err) - alb2 := AlbumEmptyFactory(id2, ids2) + alb2 := AlbumFactory(id2, ids2) alb2.Expires = time.Now().Add(1 * time.Hour) err = mDb.SaveAlbum(ctx, alb2) assert.NoError(t, err) diff --git a/infrastructure/database/badger_test.go b/infrastructure/database/badger_test.go index 6c7c0ec..8f9481e 100644 --- a/infrastructure/database/badger_test.go +++ b/infrastructure/database/badger_test.go @@ -22,7 +22,7 @@ func TestBadgerAlbum(t *testing.T) { id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) edgs, err := badger.GetEdges(context.Background(), ids.Uint64(0)) @@ -33,7 +33,7 @@ func TestBadgerAlbum(t *testing.T) { id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumFullFactory(id, ids) + alb := AlbumFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) err = badger.SaveAlbum(context.Background(), alb) @@ -60,7 +60,7 @@ func TestBadgerCount(t *testing.T) { id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) n, err := badger.CountImages(context.Background(), ids.Uint64(0)) @@ -87,7 +87,7 @@ func TestBadgerCount(t *testing.T) { id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) err = badger.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(1)) @@ -123,7 +123,7 @@ func TestBadgerCount(t *testing.T) { id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) err = badger.UpdateCompressionStatus(context.Background(), ids.Uint64(0), id()) @@ -136,7 +136,7 @@ func TestBadgerImage(t *testing.T) { id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) src, err := badger.GetImageSrc(context.Background(), ids.Uint64(0), ids.Uint64(4)) @@ -154,7 +154,7 @@ func TestBadgerImage(t *testing.T) { id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) _, err = badger.GetImageSrc(context.Background(), ids.Uint64(0), id()) @@ -167,7 +167,7 @@ func TestBadgerVote(t *testing.T) { id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumFullFactory(id, ids) + alb := AlbumFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) err = badger.SaveVote(context.Background(), ids.Uint64(0), ids.Uint64(3), ids.Uint64(5)) @@ -192,7 +192,7 @@ func TestBadgerSort(t *testing.T) { id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumFullFactory(id, ids) + alb := AlbumFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) imgs1, err := badger.GetImagesOrdered(context.Background(), ids.Uint64(0)) @@ -219,7 +219,7 @@ func TestBadgerRatings(t *testing.T) { id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumFullFactory(id, ids) + alb := AlbumFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) img1 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} @@ -267,7 +267,7 @@ func TestBadgerDelete(t *testing.T) { id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) _, err = badger.CountImages(context.Background(), ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) err = badger.SaveAlbum(context.Background(), alb) @@ -287,7 +287,7 @@ func TestBadgerDelete(t *testing.T) { id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) alb.Expires = time.Now().Add(-1 * time.Hour) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) @@ -304,7 +304,7 @@ func TestBadgerDelete(t *testing.T) { id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb) assert.NoError(t, err) err = badger.DeleteAlbum(context.Background(), id()) @@ -316,10 +316,10 @@ func TestBadgerLru(t *testing.T) { id, ids := GenId() badger, err := NewBadger(DefaultBadgerConfig) require.NoError(t, err) - alb1 := AlbumEmptyFactory(id, ids) + alb1 := AlbumFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb1) assert.NoError(t, err) - alb2 := AlbumEmptyFactory(id, ids) + alb2 := AlbumFactory(id, ids) err = badger.SaveAlbum(context.Background(), alb2) assert.NoError(t, err) edgs, err := badger.GetEdges(context.Background(), ids.Uint64(0)) diff --git a/infrastructure/database/mem_test.go b/infrastructure/database/mem_test.go index acaeb12..59d257d 100644 --- a/infrastructure/database/mem_test.go +++ b/infrastructure/database/mem_test.go @@ -20,7 +20,7 @@ func TestMemAlbum(t *testing.T) { t.Run("Positive", func(t *testing.T) { id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) edgs, err := mem.GetEdges(context.Background(), ids.Uint64(0)) @@ -30,7 +30,7 @@ func TestMemAlbum(t *testing.T) { t.Run("Negative1", func(t *testing.T) { id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumFullFactory(id, ids) + alb := AlbumFactory(id, ids) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) err = mem.SaveAlbum(context.Background(), alb) @@ -54,7 +54,7 @@ func TestMemCount(t *testing.T) { t.Run("Positive", func(t *testing.T) { id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) n, err := mem.CountImages(context.Background(), ids.Uint64(0)) @@ -80,7 +80,7 @@ func TestMemCount(t *testing.T) { t.Run("Negative1", func(t *testing.T) { id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) err = mem.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(1)) @@ -112,7 +112,7 @@ func TestMemCount(t *testing.T) { t.Run("Negative5", func(t *testing.T) { id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) err = mem.UpdateCompressionStatus(context.Background(), ids.Uint64(0), id()) @@ -124,7 +124,7 @@ func TestMemImage(t *testing.T) { t.Run("Positive", func(t *testing.T) { id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) src, err := mem.GetImageSrc(context.Background(), ids.Uint64(0), ids.Uint64(4)) @@ -140,7 +140,7 @@ func TestMemImage(t *testing.T) { t.Run("Negative2", func(t *testing.T) { id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) _, err = mem.GetImageSrc(context.Background(), ids.Uint64(0), id()) @@ -152,7 +152,7 @@ func TestMemVote(t *testing.T) { t.Run("Positive", func(t *testing.T) { id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumFullFactory(id, ids) + alb := AlbumFactory(id, ids) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) err = mem.SaveVote(context.Background(), ids.Uint64(0), ids.Uint64(3), ids.Uint64(5)) @@ -175,7 +175,7 @@ func TestMemSort(t *testing.T) { t.Run("Positive", func(t *testing.T) { id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumFullFactory(id, ids) + alb := AlbumFactory(id, ids) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) imgs1, err := mem.GetImagesOrdered(context.Background(), ids.Uint64(0)) @@ -200,7 +200,7 @@ func TestMemRatings(t *testing.T) { t.Run("Positive", func(t *testing.T) { id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumFullFactory(id, ids) + alb := AlbumFactory(id, ids) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) img1 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} @@ -246,7 +246,7 @@ func TestMemDelete(t *testing.T) { t.Run("Positive1", func(t *testing.T) { id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) _, err := mem.CountImages(context.Background(), ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) err = mem.SaveAlbum(context.Background(), alb) @@ -265,7 +265,7 @@ func TestMemDelete(t *testing.T) { t.Run("Positive2", func(t *testing.T) { id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) alb.Expires = time.Now().Add(-1 * time.Hour) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) @@ -280,7 +280,7 @@ func TestMemDelete(t *testing.T) { t.Run("Negative", func(t *testing.T) { id, ids := GenId() mem := NewMem(DefaultMemConfig) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) err := mem.SaveAlbum(context.Background(), alb) assert.NoError(t, err) err = mem.DeleteAlbum(context.Background(), id()) diff --git a/infrastructure/database/mongo_integration_test.go b/infrastructure/database/mongo_integration_test.go index 0201eed..0daf166 100644 --- a/infrastructure/database/mongo_integration_test.go +++ b/infrastructure/database/mongo_integration_test.go @@ -22,7 +22,7 @@ func TestMongoAlbum(t *testing.T) { id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) edgs, err := mongo.GetEdges(context.Background(), ids.Uint64(0)) @@ -33,7 +33,7 @@ func TestMongoAlbum(t *testing.T) { id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumFullFactory(id, ids) + alb := AlbumFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) err = mongo.SaveAlbum(context.Background(), alb) @@ -60,7 +60,7 @@ func TestMongoCount(t *testing.T) { id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) n, err := mongo.CountImages(context.Background(), ids.Uint64(0)) @@ -87,7 +87,7 @@ func TestMongoCount(t *testing.T) { id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) err = mongo.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(1)) @@ -123,7 +123,7 @@ func TestMongoCount(t *testing.T) { id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) err = mongo.UpdateCompressionStatus(context.Background(), ids.Uint64(0), id()) @@ -136,7 +136,7 @@ func TestMongoImage(t *testing.T) { id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) src, err := mongo.GetImageSrc(context.Background(), ids.Uint64(0), ids.Uint64(4)) @@ -154,7 +154,7 @@ func TestMongoImage(t *testing.T) { id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) _, err = mongo.GetImageSrc(context.Background(), ids.Uint64(0), id()) @@ -167,7 +167,7 @@ func TestMongoVote(t *testing.T) { id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumFullFactory(id, ids) + alb := AlbumFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) err = mongo.SaveVote(context.Background(), ids.Uint64(0), ids.Uint64(3), ids.Uint64(5)) @@ -192,7 +192,7 @@ func TestMongoSort(t *testing.T) { id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumFullFactory(id, ids) + alb := AlbumFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) imgs1, err := mongo.GetImagesOrdered(context.Background(), ids.Uint64(0)) @@ -219,7 +219,7 @@ func TestMongoRatings(t *testing.T) { id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumFullFactory(id, ids) + alb := AlbumFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) img1 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} @@ -267,7 +267,7 @@ func TestMongoDelete(t *testing.T) { id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) _, err = mongo.CountImages(context.Background(), ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) err = mongo.SaveAlbum(context.Background(), alb) @@ -287,7 +287,7 @@ func TestMongoDelete(t *testing.T) { id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) alb.Expires = time.Now().Add(-1 * time.Hour) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) @@ -304,7 +304,7 @@ func TestMongoDelete(t *testing.T) { id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb := AlbumEmptyFactory(id, ids) + alb := AlbumFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb) assert.NoError(t, err) err = mongo.DeleteAlbum(context.Background(), id()) @@ -316,10 +316,10 @@ func TestMongoLru(t *testing.T) { id, ids := GenId() mongo, err := NewMongo(context.Background(), DefaultMongoConfig) require.NoError(t, err) - alb1 := AlbumEmptyFactory(id, ids) + alb1 := AlbumFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb1) assert.NoError(t, err) - alb2 := AlbumEmptyFactory(id, ids) + alb2 := AlbumFactory(id, ids) err = mongo.SaveAlbum(context.Background(), alb2) assert.NoError(t, err) edgs, err := mongo.GetEdges(context.Background(), ids.Uint64(0)) diff --git a/internal/testing/testing.go b/internal/testing/testing.go index 9f8a90b..00d13c4 100644 --- a/internal/testing/testing.go +++ b/internal/testing/testing.go @@ -31,13 +31,13 @@ type ids interface { Base64(i int) string } -func AlbumEmptyFactory(id func() uint64, ids ids) model.Album { +func AlbumFactory(id func() uint64, ids ids) model.Album { album := id() - img1 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1)} - img2 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2)} - img3 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3)} - img4 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4)} - img5 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5)} + img1 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.48954984} + img2 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.19186324} + img3 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.41218211} + img4 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4), Rating: 0.77920413} + img5 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5), Rating: 0.13278389} imgs := []model.Image{img1, img2, img3, img4, img5} edgs := map[uint64]map[uint64]int{} edgs[ids.Uint64(1)] = map[uint64]int{} @@ -50,26 +50,6 @@ func AlbumEmptyFactory(id func() uint64, ids ids) model.Album { return alb } -func AlbumFullFactory(id func() uint64, ids ids) model.Album { - alb := AlbumEmptyFactory(id, ids) - alb.Images[0].Rating = 0.48954984 - alb.Images[1].Rating = 0.19186324 - alb.Images[2].Rating = 0.41218211 - alb.Images[3].Rating = 0.77920413 - alb.Images[4].Rating = 0.13278389 - alb.Edges[ids.Uint64(4)][ids.Uint64(3)]++ - alb.Edges[ids.Uint64(1)][ids.Uint64(3)]++ - alb.Edges[ids.Uint64(1)][ids.Uint64(4)]++ - alb.Edges[ids.Uint64(2)][ids.Uint64(3)]++ - alb.Edges[ids.Uint64(2)][ids.Uint64(4)]++ - alb.Edges[ids.Uint64(2)][ids.Uint64(1)]++ - alb.Edges[ids.Uint64(5)][ids.Uint64(3)]++ - alb.Edges[ids.Uint64(5)][ids.Uint64(4)]++ - alb.Edges[ids.Uint64(5)][ids.Uint64(1)]++ - alb.Edges[ids.Uint64(5)][ids.Uint64(2)]++ - return alb -} - func AssertStatusCode(t *testing.T, w *httptest.ResponseRecorder, code int) { t.Helper() got := w.Code From b60d5838539d0c407282246e0be56411a35404e0 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sun, 13 Feb 2022 14:45:33 +0100 Subject: [PATCH 51/92] Minimize database tests --- delivery/http/server_test.go | 2 + .../database/badger_integration_test.go | 87 +++++ infrastructure/database/badger_test.go | 328 ---------------- .../database/database_integration_test.go | 31 -- infrastructure/database/database_test.go | 35 ++ infrastructure/database/mem_test.go | 255 ++++++------- .../database/mongo_integration_test.go | 359 +++--------------- .../storage/minio_integration_test.go | 2 +- internal/generator/generator.go | 5 + internal/generator/generator_test.go | 11 +- internal/testing/testing.go | 8 +- 11 files changed, 327 insertions(+), 796 deletions(-) create mode 100644 infrastructure/database/badger_integration_test.go delete mode 100644 infrastructure/database/badger_test.go delete mode 100644 infrastructure/database/database_integration_test.go create mode 100644 infrastructure/database/database_test.go diff --git a/delivery/http/server_test.go b/delivery/http/server_test.go index 32d74ab..0bdbc91 100644 --- a/delivery/http/server_test.go +++ b/delivery/http/server_test.go @@ -1,3 +1,5 @@ +//go:build unit + package http import ( diff --git a/infrastructure/database/badger_integration_test.go b/infrastructure/database/badger_integration_test.go new file mode 100644 index 0000000..9323b63 --- /dev/null +++ b/infrastructure/database/badger_integration_test.go @@ -0,0 +1,87 @@ +package database + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + + . "github.com/zitryss/aye-and-nay/internal/generator" +) + +func TestBadgerTestSuite(t *testing.T) { + suite.Run(t, &BadgerTestSuite{}) +} + +type BadgerTestSuite struct { + suite.Suite + base MemTestSuite +} + +func (suite *BadgerTestSuite) SetupSuite() { + if !*integration { + suite.T().Skip() + } + suite.base = MemTestSuite{} + suite.base.SetT(suite.T()) + ctx, cancel := context.WithCancel(context.Background()) + badger, err := NewBadger(DefaultBadgerConfig) + require.NoError(suite.T(), err) + suite.base.ctx = ctx + suite.base.cancel = cancel + suite.base.db = badger +} + +func (suite *BadgerTestSuite) SetupTest() { + err := suite.base.db.(*Badger).Reset() + require.NoError(suite.T(), err) +} + +func (suite *BadgerTestSuite) TearDownTest() { + +} + +func (suite *BadgerTestSuite) TearDownSuite() { + err := suite.base.db.(*Badger).Reset() + require.NoError(suite.T(), err) + suite.base.cancel() +} + +func (suite *BadgerTestSuite) TestBadgerAlbum() { + suite.base.TestAlbum() +} + +func (suite *BadgerTestSuite) TestBadgerCount() { + suite.base.TestCount() +} + +func (suite *BadgerTestSuite) TestBadgerImage() { + suite.base.TestImage() +} + +func (suite *BadgerTestSuite) TestBadgerVote() { + suite.base.TestVote() +} + +func (suite *BadgerTestSuite) TestBadgerSort() { + suite.base.TestSort() +} + +func (suite *BadgerTestSuite) TestBadgerRatings() { + suite.base.TestRatings() +} + +func (suite *BadgerTestSuite) TestBadgerDelete() { + suite.base.TestDelete() +} + +func (suite *BadgerTestSuite) TestBadgerLru() { + id, ids := GenId() + alb1 := suite.base.saveAlbum(id, ids) + _ = suite.base.saveAlbum(id, ids) + edgs, err := suite.base.db.GetEdges(suite.base.ctx, ids.Uint64(0)) + assert.NoError(suite.base.T(), err) + assert.Equal(suite.base.T(), alb1.Edges, edgs) +} diff --git a/infrastructure/database/badger_test.go b/infrastructure/database/badger_test.go deleted file mode 100644 index 8f9481e..0000000 --- a/infrastructure/database/badger_test.go +++ /dev/null @@ -1,328 +0,0 @@ -//go:build unit - -package database - -import ( - "context" - "sort" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/zitryss/aye-and-nay/domain/domain" - "github.com/zitryss/aye-and-nay/domain/model" - . "github.com/zitryss/aye-and-nay/internal/generator" - . "github.com/zitryss/aye-and-nay/internal/testing" -) - -func TestBadgerAlbum(t *testing.T) { - t.Run("Positive", func(t *testing.T) { - id, ids := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - err = badger.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - edgs, err := badger.GetEdges(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - assert.Equal(t, alb.Edges, edgs) - }) - t.Run("Negative1", func(t *testing.T) { - id, ids := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - err = badger.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - err = badger.SaveAlbum(context.Background(), alb) - assert.ErrorIs(t, err, domain.ErrAlbumAlreadyExists) - }) - t.Run("Negative2", func(t *testing.T) { - id, _ := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - _, err = badger.GetImagesIds(context.Background(), id()) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) - t.Run("Negative3", func(t *testing.T) { - id, _ := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - _, err = badger.GetEdges(context.Background(), id()) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) -} - -func TestBadgerCount(t *testing.T) { - t.Run("Positive", func(t *testing.T) { - id, ids := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - err = badger.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - n, err := badger.CountImages(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - assert.Equal(t, 5, n) - n, err = badger.CountImagesCompressed(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - assert.Equal(t, 0, n) - err = badger.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(1)) - assert.NoError(t, err) - n, err = badger.CountImages(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - assert.Equal(t, 5, n) - n, err = badger.CountImagesCompressed(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - assert.Equal(t, 1, n) - err = badger.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(2)) - assert.NoError(t, err) - n, err = badger.CountImagesCompressed(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - assert.Equal(t, 2, n) - }) - t.Run("Negative1", func(t *testing.T) { - id, ids := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - err = badger.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - err = badger.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(1)) - assert.NoError(t, err) - err = badger.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(1)) - assert.NoError(t, err) - n, err := badger.CountImagesCompressed(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - assert.Equal(t, 1, n) - }) - t.Run("Negative2", func(t *testing.T) { - id, _ := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - _, err = badger.CountImages(context.Background(), id()) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) - t.Run("Negative3", func(t *testing.T) { - id, _ := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - _, err = badger.CountImagesCompressed(context.Background(), id()) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) - t.Run("Negative4", func(t *testing.T) { - id, ids := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - err = badger.UpdateCompressionStatus(context.Background(), id(), ids.Uint64(0)) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) - t.Run("Negative5", func(t *testing.T) { - id, ids := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - err = badger.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - err = badger.UpdateCompressionStatus(context.Background(), ids.Uint64(0), id()) - assert.ErrorIs(t, err, domain.ErrImageNotFound) - }) -} - -func TestBadgerImage(t *testing.T) { - t.Run("Positive", func(t *testing.T) { - id, ids := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - err = badger.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - src, err := badger.GetImageSrc(context.Background(), ids.Uint64(0), ids.Uint64(4)) - assert.NoError(t, err) - assert.Equal(t, "/aye-and-nay/albums/"+ids.Base64(0)+"/images/"+ids.Base64(4), src) - }) - t.Run("Negative1", func(t *testing.T) { - id, ids := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - _, err = badger.GetImageSrc(context.Background(), id(), ids.Uint64(0)) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) - t.Run("Negative2", func(t *testing.T) { - id, ids := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - err = badger.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - _, err = badger.GetImageSrc(context.Background(), ids.Uint64(0), id()) - assert.ErrorIs(t, err, domain.ErrImageNotFound) - }) -} - -func TestBadgerVote(t *testing.T) { - t.Run("Positive", func(t *testing.T) { - id, ids := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - err = badger.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - err = badger.SaveVote(context.Background(), ids.Uint64(0), ids.Uint64(3), ids.Uint64(5)) - assert.NoError(t, err) - err = badger.SaveVote(context.Background(), ids.Uint64(0), ids.Uint64(3), ids.Uint64(5)) - assert.NoError(t, err) - edgs, err := badger.GetEdges(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - assert.Equal(t, 2, edgs[ids.Uint64(3)][ids.Uint64(5)]) - }) - t.Run("Negative", func(t *testing.T) { - id, _ := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - err = badger.SaveVote(context.Background(), id(), id(), id()) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) -} - -func TestBadgerSort(t *testing.T) { - t.Run("Positive", func(t *testing.T) { - id, ids := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - err = badger.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - imgs1, err := badger.GetImagesOrdered(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - img1 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4), Rating: 0.77920413} - img2 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.48954984} - img3 := model.Image{Id: ids.Uint64(3), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.41218211} - img4 := model.Image{Id: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.19186324} - img5 := model.Image{Id: ids.Uint64(5), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5), Rating: 0.13278389} - imgs2 := []model.Image{img1, img2, img3, img4, img5} - assert.Equal(t, imgs2, imgs1) - }) - t.Run("Negative", func(t *testing.T) { - id, _ := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - _, err = badger.GetImagesOrdered(context.Background(), id()) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) -} - -func TestBadgerRatings(t *testing.T) { - t.Run("Positive", func(t *testing.T) { - id, ids := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - err = badger.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - img1 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} - img2 := model.Image{Id: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.32537162} - img3 := model.Image{Id: ids.Uint64(3), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.43185491} - img4 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4), Rating: 0.57356209} - img5 := model.Image{Id: ids.Uint64(5), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5), Rating: 0.61438023} - imgs1 := []model.Image{img1, img2, img3, img4, img5} - vector := map[uint64]float64{} - vector[img1.Id] = img1.Rating - vector[img2.Id] = img2.Rating - vector[img3.Id] = img3.Rating - vector[img4.Id] = img4.Rating - vector[img5.Id] = img5.Rating - err = badger.UpdateRatings(context.Background(), ids.Uint64(0), vector) - assert.NoError(t, err) - imgs2, err := badger.GetImagesOrdered(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - sort.Slice(imgs1, func(i, j int) bool { return imgs1[i].Rating > imgs1[j].Rating }) - assert.Equal(t, imgs1, imgs2) - }) - t.Run("Negative", func(t *testing.T) { - id, ids := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - album := id() - img1 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} - img2 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.32537162} - img3 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.43185491} - img4 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4), Rating: 0.57356209} - img5 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5), Rating: 0.61438023} - vector := map[uint64]float64{} - vector[img1.Id] = img1.Rating - vector[img2.Id] = img2.Rating - vector[img3.Id] = img3.Rating - vector[img4.Id] = img4.Rating - vector[img5.Id] = img5.Rating - err = badger.UpdateRatings(context.Background(), album, vector) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) -} - -func TestBadgerDelete(t *testing.T) { - t.Run("Positive1", func(t *testing.T) { - id, ids := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - _, err = badger.CountImages(context.Background(), ids.Uint64(0)) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - err = badger.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - n, err := badger.CountImages(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - assert.Equal(t, 5, n) - albums, err := badger.AlbumsToBeDeleted(context.Background()) - assert.NoError(t, err) - assert.Len(t, albums, 0) - err = badger.DeleteAlbum(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - _, err = badger.CountImages(context.Background(), ids.Uint64(0)) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) - t.Run("Positive2", func(t *testing.T) { - id, ids := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - alb.Expires = time.Now().Add(-1 * time.Hour) - err = badger.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - albums, err := badger.AlbumsToBeDeleted(context.Background()) - assert.NoError(t, err) - assert.True(t, len(albums) == 1 && albums[0].Id == alb.Id && !albums[0].Expires.IsZero()) - err = badger.DeleteAlbum(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - _, err = badger.CountImages(context.Background(), ids.Uint64(0)) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - t.Cleanup(func() { _ = badger.DeleteAlbum(context.Background(), ids.Uint64(0)) }) - }) - t.Run("Negative", func(t *testing.T) { - id, ids := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - err = badger.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - err = badger.DeleteAlbum(context.Background(), id()) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) -} - -func TestBadgerLru(t *testing.T) { - id, ids := GenId() - badger, err := NewBadger(DefaultBadgerConfig) - require.NoError(t, err) - alb1 := AlbumFactory(id, ids) - err = badger.SaveAlbum(context.Background(), alb1) - assert.NoError(t, err) - alb2 := AlbumFactory(id, ids) - err = badger.SaveAlbum(context.Background(), alb2) - assert.NoError(t, err) - edgs, err := badger.GetEdges(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - assert.Equal(t, alb1.Edges, edgs) -} diff --git a/infrastructure/database/database_integration_test.go b/infrastructure/database/database_integration_test.go deleted file mode 100644 index a635197..0000000 --- a/infrastructure/database/database_integration_test.go +++ /dev/null @@ -1,31 +0,0 @@ -//go:build integration - -package database - -import ( - "io" - "os" - "testing" - - "github.com/zitryss/aye-and-nay/internal/dockertest" - "github.com/zitryss/aye-and-nay/pkg/env" - "github.com/zitryss/aye-and-nay/pkg/log" -) - -func TestMain(m *testing.M) { - _, err := env.Lookup("CONTINUOUS_INTEGRATION") - if err != nil { - log.SetOutput(os.Stderr) - log.SetLevel(log.CRITICAL) - docker := dockertest.New() - host := &DefaultMongoConfig.Host - port := &DefaultMongoConfig.Port - docker.RunMongo(host, port) - log.SetOutput(io.Discard) - code := m.Run() - docker.Purge() - os.Exit(code) - } - code := m.Run() - os.Exit(code) -} diff --git a/infrastructure/database/database_test.go b/infrastructure/database/database_test.go new file mode 100644 index 0000000..0d7c1eb --- /dev/null +++ b/infrastructure/database/database_test.go @@ -0,0 +1,35 @@ +package database + +import ( + "flag" + "io" + "os" + "testing" + + "github.com/zitryss/aye-and-nay/internal/dockertest" + "github.com/zitryss/aye-and-nay/pkg/log" +) + +var ( + unit = flag.Bool("unit", false, "") + integration = flag.Bool("int", false, "") + ci = flag.Bool("ci", false, "") +) + +func TestMain(m *testing.M) { + flag.Parse() + if *ci || !*integration { + code := m.Run() + os.Exit(code) + } + log.SetOutput(os.Stderr) + log.SetLevel(log.CRITICAL) + docker := dockertest.New() + host := &DefaultMongoConfig.Host + port := &DefaultMongoConfig.Port + docker.RunMongo(host, port) + log.SetOutput(io.Discard) + code := m.Run() + docker.Purge() + os.Exit(code) +} diff --git a/infrastructure/database/mem_test.go b/infrastructure/database/mem_test.go index 59d257d..e1310e4 100644 --- a/infrastructure/database/mem_test.go +++ b/infrastructure/database/mem_test.go @@ -1,5 +1,3 @@ -//go:build unit - package database import ( @@ -9,6 +7,8 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/model" @@ -16,169 +16,180 @@ import ( . "github.com/zitryss/aye-and-nay/internal/testing" ) -func TestMemAlbum(t *testing.T) { - t.Run("Positive", func(t *testing.T) { +func TestMemTestSuite(t *testing.T) { + suite.Run(t, &MemTestSuite{}) +} + +type MemTestSuite struct { + suite.Suite + ctx context.Context + cancel context.CancelFunc + db domain.Databaser +} + +func (suite *MemTestSuite) SetupSuite() { + if !*unit { + suite.T().Skip() + } + ctx, cancel := context.WithCancel(context.Background()) + mem := NewMem(DefaultMemConfig) + suite.ctx = ctx + suite.cancel = cancel + suite.db = mem +} + +func (suite *MemTestSuite) SetupTest() { + err := suite.db.(*Mem).Reset() + require.NoError(suite.T(), err) +} + +func (suite *MemTestSuite) TearDownTest() { + +} + +func (suite *MemTestSuite) TearDownSuite() { + err := suite.db.(*Mem).Reset() + require.NoError(suite.T(), err) + suite.cancel() +} + +func (suite *MemTestSuite) saveAlbum(id func() uint64, ids Ids) model.Album { + suite.T().Helper() + alb := AlbumFactory(id, ids) + err := suite.db.SaveAlbum(suite.ctx, alb) + assert.NoError(suite.T(), err) + return alb +} + +func (suite *MemTestSuite) TestAlbum() { + suite.T().Run("Positive", func(t *testing.T) { id, ids := GenId() - mem := NewMem(DefaultMemConfig) - alb := AlbumFactory(id, ids) - err := mem.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - edgs, err := mem.GetEdges(context.Background(), ids.Uint64(0)) + alb := suite.saveAlbum(id, ids) + edgs, err := suite.db.GetEdges(suite.ctx, ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, alb.Edges, edgs) }) - t.Run("Negative1", func(t *testing.T) { + suite.T().Run("Negative1", func(t *testing.T) { id, ids := GenId() - mem := NewMem(DefaultMemConfig) - alb := AlbumFactory(id, ids) - err := mem.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - err = mem.SaveAlbum(context.Background(), alb) + alb := suite.saveAlbum(id, ids) + err := suite.db.SaveAlbum(suite.ctx, alb) assert.ErrorIs(t, err, domain.ErrAlbumAlreadyExists) }) - t.Run("Negative2", func(t *testing.T) { + suite.T().Run("Negative2", func(t *testing.T) { id, _ := GenId() - mem := NewMem(DefaultMemConfig) - _, err := mem.GetImagesIds(context.Background(), id()) + _, err := suite.db.GetImagesIds(suite.ctx, id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) - t.Run("Negative3", func(t *testing.T) { + suite.T().Run("Negative3", func(t *testing.T) { id, _ := GenId() - mem := NewMem(DefaultMemConfig) - _, err := mem.GetEdges(context.Background(), id()) + _, err := suite.db.GetEdges(suite.ctx, id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } -func TestMemCount(t *testing.T) { - t.Run("Positive", func(t *testing.T) { +func (suite *MemTestSuite) TestCount() { + suite.T().Run("Positive", func(t *testing.T) { id, ids := GenId() - mem := NewMem(DefaultMemConfig) - alb := AlbumFactory(id, ids) - err := mem.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - n, err := mem.CountImages(context.Background(), ids.Uint64(0)) + _ = suite.saveAlbum(id, ids) + n, err := suite.db.CountImages(suite.ctx, ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 5, n) - n, err = mem.CountImagesCompressed(context.Background(), ids.Uint64(0)) + n, err = suite.db.CountImagesCompressed(suite.ctx, ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 0, n) - err = mem.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(1)) + err = suite.db.UpdateCompressionStatus(suite.ctx, ids.Uint64(0), ids.Uint64(1)) assert.NoError(t, err) - n, err = mem.CountImages(context.Background(), ids.Uint64(0)) + n, err = suite.db.CountImages(suite.ctx, ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 5, n) - n, err = mem.CountImagesCompressed(context.Background(), ids.Uint64(0)) + n, err = suite.db.CountImagesCompressed(suite.ctx, ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 1, n) - err = mem.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(2)) + err = suite.db.UpdateCompressionStatus(suite.ctx, ids.Uint64(0), ids.Uint64(2)) assert.NoError(t, err) - n, err = mem.CountImagesCompressed(context.Background(), ids.Uint64(0)) + n, err = suite.db.CountImagesCompressed(suite.ctx, ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 2, n) }) - t.Run("Negative1", func(t *testing.T) { + suite.T().Run("Negative1", func(t *testing.T) { id, ids := GenId() - mem := NewMem(DefaultMemConfig) - alb := AlbumFactory(id, ids) - err := mem.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - err = mem.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(1)) + _ = suite.saveAlbum(id, ids) + err := suite.db.UpdateCompressionStatus(suite.ctx, ids.Uint64(0), ids.Uint64(1)) assert.NoError(t, err) - err = mem.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(1)) + err = suite.db.UpdateCompressionStatus(suite.ctx, ids.Uint64(0), ids.Uint64(1)) assert.NoError(t, err) - n, err := mem.CountImagesCompressed(context.Background(), ids.Uint64(0)) + n, err := suite.db.CountImagesCompressed(suite.ctx, ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 1, n) }) - t.Run("Negative2", func(t *testing.T) { + suite.T().Run("Negative2", func(t *testing.T) { id, _ := GenId() - mem := NewMem(DefaultMemConfig) - _, err := mem.CountImages(context.Background(), id()) + _, err := suite.db.CountImages(suite.ctx, id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) - t.Run("Negative3", func(t *testing.T) { + suite.T().Run("Negative3", func(t *testing.T) { id, _ := GenId() - mem := NewMem(DefaultMemConfig) - _, err := mem.CountImagesCompressed(context.Background(), id()) + _, err := suite.db.CountImagesCompressed(suite.ctx, id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) - t.Run("Negative4", func(t *testing.T) { + suite.T().Run("Negative4", func(t *testing.T) { id, ids := GenId() - mem := NewMem(DefaultMemConfig) - err := mem.UpdateCompressionStatus(context.Background(), id(), ids.Uint64(0)) + err := suite.db.UpdateCompressionStatus(suite.ctx, id(), ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) - t.Run("Negative5", func(t *testing.T) { + suite.T().Run("Negative5", func(t *testing.T) { id, ids := GenId() - mem := NewMem(DefaultMemConfig) - alb := AlbumFactory(id, ids) - err := mem.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - err = mem.UpdateCompressionStatus(context.Background(), ids.Uint64(0), id()) + _ = suite.saveAlbum(id, ids) + err := suite.db.UpdateCompressionStatus(suite.ctx, ids.Uint64(0), id()) assert.ErrorIs(t, err, domain.ErrImageNotFound) }) } -func TestMemImage(t *testing.T) { - t.Run("Positive", func(t *testing.T) { +func (suite *MemTestSuite) TestImage() { + suite.T().Run("Positive", func(t *testing.T) { id, ids := GenId() - mem := NewMem(DefaultMemConfig) - alb := AlbumFactory(id, ids) - err := mem.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - src, err := mem.GetImageSrc(context.Background(), ids.Uint64(0), ids.Uint64(4)) + _ = suite.saveAlbum(id, ids) + src, err := suite.db.GetImageSrc(suite.ctx, ids.Uint64(0), ids.Uint64(4)) assert.NoError(t, err) assert.Equal(t, "/aye-and-nay/albums/"+ids.Base64(0)+"/images/"+ids.Base64(4), src) }) - t.Run("Negative1", func(t *testing.T) { + suite.T().Run("Negative1", func(t *testing.T) { id, ids := GenId() - mem := NewMem(DefaultMemConfig) - _, err := mem.GetImageSrc(context.Background(), id(), ids.Uint64(0)) + _, err := suite.db.GetImageSrc(suite.ctx, id(), ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) - t.Run("Negative2", func(t *testing.T) { + suite.T().Run("Negative2", func(t *testing.T) { id, ids := GenId() - mem := NewMem(DefaultMemConfig) - alb := AlbumFactory(id, ids) - err := mem.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - _, err = mem.GetImageSrc(context.Background(), ids.Uint64(0), id()) + _ = suite.saveAlbum(id, ids) + _, err := suite.db.GetImageSrc(suite.ctx, ids.Uint64(0), id()) assert.ErrorIs(t, err, domain.ErrImageNotFound) }) } -func TestMemVote(t *testing.T) { - t.Run("Positive", func(t *testing.T) { +func (suite *MemTestSuite) TestVote() { + suite.T().Run("Positive", func(t *testing.T) { id, ids := GenId() - mem := NewMem(DefaultMemConfig) - alb := AlbumFactory(id, ids) - err := mem.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - err = mem.SaveVote(context.Background(), ids.Uint64(0), ids.Uint64(3), ids.Uint64(5)) + _ = suite.saveAlbum(id, ids) + err := suite.db.SaveVote(suite.ctx, ids.Uint64(0), ids.Uint64(3), ids.Uint64(5)) assert.NoError(t, err) - err = mem.SaveVote(context.Background(), ids.Uint64(0), ids.Uint64(3), ids.Uint64(5)) + err = suite.db.SaveVote(suite.ctx, ids.Uint64(0), ids.Uint64(3), ids.Uint64(5)) assert.NoError(t, err) - edgs, err := mem.GetEdges(context.Background(), ids.Uint64(0)) + edgs, err := suite.db.GetEdges(suite.ctx, ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 2, edgs[ids.Uint64(3)][ids.Uint64(5)]) }) - t.Run("Negative", func(t *testing.T) { + suite.T().Run("Negative", func(t *testing.T) { id, _ := GenId() - mem := NewMem(DefaultMemConfig) - err := mem.SaveVote(context.Background(), id(), id(), id()) + err := suite.db.SaveVote(suite.ctx, id(), id(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } -func TestMemSort(t *testing.T) { - t.Run("Positive", func(t *testing.T) { +func (suite *MemTestSuite) TestSort() { + suite.T().Run("Positive", func(t *testing.T) { id, ids := GenId() - mem := NewMem(DefaultMemConfig) - alb := AlbumFactory(id, ids) - err := mem.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - imgs1, err := mem.GetImagesOrdered(context.Background(), ids.Uint64(0)) + _ = suite.saveAlbum(id, ids) + imgs1, err := suite.db.GetImagesOrdered(suite.ctx, ids.Uint64(0)) assert.NoError(t, err) img1 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4), Rating: 0.77920413} img2 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.48954984} @@ -188,21 +199,17 @@ func TestMemSort(t *testing.T) { imgs2 := []model.Image{img1, img2, img3, img4, img5} assert.Equal(t, imgs2, imgs1) }) - t.Run("Negative", func(t *testing.T) { + suite.T().Run("Negative", func(t *testing.T) { id, _ := GenId() - mem := NewMem(DefaultMemConfig) - _, err := mem.GetImagesOrdered(context.Background(), id()) + _, err := suite.db.GetImagesOrdered(suite.ctx, id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } -func TestMemRatings(t *testing.T) { - t.Run("Positive", func(t *testing.T) { +func (suite *MemTestSuite) TestRatings() { + suite.T().Run("Positive", func(t *testing.T) { id, ids := GenId() - mem := NewMem(DefaultMemConfig) - alb := AlbumFactory(id, ids) - err := mem.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) + _ = suite.saveAlbum(id, ids) img1 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} img2 := model.Image{Id: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.32537162} img3 := model.Image{Id: ids.Uint64(3), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.43185491} @@ -215,16 +222,15 @@ func TestMemRatings(t *testing.T) { vector[img3.Id] = img3.Rating vector[img4.Id] = img4.Rating vector[img5.Id] = img5.Rating - err = mem.UpdateRatings(context.Background(), ids.Uint64(0), vector) + err := suite.db.UpdateRatings(suite.ctx, ids.Uint64(0), vector) assert.NoError(t, err) - imgs2, err := mem.GetImagesOrdered(context.Background(), ids.Uint64(0)) + imgs2, err := suite.db.GetImagesOrdered(suite.ctx, ids.Uint64(0)) assert.NoError(t, err) sort.Slice(imgs1, func(i, j int) bool { return imgs1[i].Rating > imgs1[j].Rating }) assert.Equal(t, imgs1, imgs2) }) - t.Run("Negative", func(t *testing.T) { + suite.T().Run("Negative", func(t *testing.T) { id, ids := GenId() - mem := NewMem(DefaultMemConfig) album := id() img1 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} img2 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.32537162} @@ -237,53 +243,48 @@ func TestMemRatings(t *testing.T) { vector[img3.Id] = img3.Rating vector[img4.Id] = img4.Rating vector[img5.Id] = img5.Rating - err := mem.UpdateRatings(context.Background(), album, vector) + err := suite.db.UpdateRatings(suite.ctx, album, vector) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } -func TestMemDelete(t *testing.T) { - t.Run("Positive1", func(t *testing.T) { +func (suite *MemTestSuite) TestDelete() { + suite.T().Run("Positive1", func(t *testing.T) { id, ids := GenId() - mem := NewMem(DefaultMemConfig) alb := AlbumFactory(id, ids) - _, err := mem.CountImages(context.Background(), ids.Uint64(0)) + _, err := suite.db.CountImages(suite.ctx, ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - err = mem.SaveAlbum(context.Background(), alb) + err = suite.db.SaveAlbum(suite.ctx, alb) assert.NoError(t, err) - n, err := mem.CountImages(context.Background(), ids.Uint64(0)) + n, err := suite.db.CountImages(suite.ctx, ids.Uint64(0)) assert.NoError(t, err) assert.Equal(t, 5, n) - albums, err := mem.AlbumsToBeDeleted(context.Background()) + albums, err := suite.db.AlbumsToBeDeleted(suite.ctx) assert.NoError(t, err) assert.Len(t, albums, 0) - err = mem.DeleteAlbum(context.Background(), ids.Uint64(0)) + err = suite.db.DeleteAlbum(suite.ctx, ids.Uint64(0)) assert.NoError(t, err) - _, err = mem.CountImages(context.Background(), ids.Uint64(0)) + _, err = suite.db.CountImages(suite.ctx, ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) - t.Run("Positive2", func(t *testing.T) { + suite.T().Run("Positive2", func(t *testing.T) { id, ids := GenId() - mem := NewMem(DefaultMemConfig) alb := AlbumFactory(id, ids) alb.Expires = time.Now().Add(-1 * time.Hour) - err := mem.SaveAlbum(context.Background(), alb) + err := suite.db.SaveAlbum(suite.ctx, alb) assert.NoError(t, err) - albums, err := mem.AlbumsToBeDeleted(context.Background()) + albums, err := suite.db.AlbumsToBeDeleted(suite.ctx) assert.NoError(t, err) assert.True(t, len(albums) == 1 && albums[0].Id == alb.Id && !albums[0].Expires.IsZero()) - err = mem.DeleteAlbum(context.Background(), ids.Uint64(0)) + err = suite.db.DeleteAlbum(suite.ctx, ids.Uint64(0)) assert.NoError(t, err) - _, err = mem.CountImages(context.Background(), ids.Uint64(0)) + _, err = suite.db.CountImages(suite.ctx, ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) - t.Run("Negative", func(t *testing.T) { + suite.T().Run("Negative", func(t *testing.T) { id, ids := GenId() - mem := NewMem(DefaultMemConfig) - alb := AlbumFactory(id, ids) - err := mem.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - err = mem.DeleteAlbum(context.Background(), id()) + _ = suite.saveAlbum(id, ids) + err := suite.db.DeleteAlbum(suite.ctx, id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } diff --git a/infrastructure/database/mongo_integration_test.go b/infrastructure/database/mongo_integration_test.go index 0daf166..a728576 100644 --- a/infrastructure/database/mongo_integration_test.go +++ b/infrastructure/database/mongo_integration_test.go @@ -1,328 +1,87 @@ -//go:build integration - package database import ( "context" - "sort" "testing" - "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" - "github.com/zitryss/aye-and-nay/domain/domain" - "github.com/zitryss/aye-and-nay/domain/model" . "github.com/zitryss/aye-and-nay/internal/generator" - . "github.com/zitryss/aye-and-nay/internal/testing" ) -func TestMongoAlbum(t *testing.T) { - t.Run("Positive", func(t *testing.T) { - id, ids := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - err = mongo.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - edgs, err := mongo.GetEdges(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - assert.Equal(t, alb.Edges, edgs) - }) - t.Run("Negative1", func(t *testing.T) { - id, ids := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - err = mongo.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - err = mongo.SaveAlbum(context.Background(), alb) - assert.ErrorIs(t, err, domain.ErrAlbumAlreadyExists) - }) - t.Run("Negative2", func(t *testing.T) { - id, _ := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - _, err = mongo.GetImagesIds(context.Background(), id()) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) - t.Run("Negative3", func(t *testing.T) { - id, _ := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - _, err = mongo.GetEdges(context.Background(), id()) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) +func TestMongoTestSuite(t *testing.T) { + suite.Run(t, &MongoTestSuite{}) +} + +type MongoTestSuite struct { + suite.Suite + base MemTestSuite +} + +func (suite *MongoTestSuite) SetupSuite() { + if !*integration { + suite.T().Skip() + } + suite.base = MemTestSuite{} + suite.base.SetT(suite.T()) + ctx, cancel := context.WithCancel(context.Background()) + mongo, err := NewMongo(ctx, DefaultMongoConfig) + require.NoError(suite.T(), err) + suite.base.ctx = ctx + suite.base.cancel = cancel + suite.base.db = mongo +} + +func (suite *MongoTestSuite) SetupTest() { + err := suite.base.db.(*Mongo).Reset() + require.NoError(suite.T(), err) +} + +func (suite *MongoTestSuite) TearDownTest() { + +} + +func (suite *MongoTestSuite) TearDownSuite() { + err := suite.base.db.(*Mongo).Reset() + require.NoError(suite.T(), err) + suite.base.cancel() +} + +func (suite *MongoTestSuite) TestMongoAlbum() { + suite.base.TestAlbum() } -func TestMongoCount(t *testing.T) { - t.Run("Positive", func(t *testing.T) { - id, ids := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - err = mongo.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - n, err := mongo.CountImages(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - assert.Equal(t, 5, n) - n, err = mongo.CountImagesCompressed(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - assert.Equal(t, 0, n) - err = mongo.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(1)) - assert.NoError(t, err) - n, err = mongo.CountImages(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - assert.Equal(t, 5, n) - n, err = mongo.CountImagesCompressed(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - assert.Equal(t, 1, n) - err = mongo.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(2)) - assert.NoError(t, err) - n, err = mongo.CountImagesCompressed(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - assert.Equal(t, 2, n) - }) - t.Run("Negative1", func(t *testing.T) { - id, ids := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - err = mongo.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - err = mongo.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(1)) - assert.NoError(t, err) - err = mongo.UpdateCompressionStatus(context.Background(), ids.Uint64(0), ids.Uint64(1)) - assert.NoError(t, err) - n, err := mongo.CountImagesCompressed(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - assert.Equal(t, 1, n) - }) - t.Run("Negative2", func(t *testing.T) { - id, _ := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - _, err = mongo.CountImages(context.Background(), id()) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) - t.Run("Negative3", func(t *testing.T) { - id, _ := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - _, err = mongo.CountImagesCompressed(context.Background(), id()) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) - t.Run("Negative4", func(t *testing.T) { - id, ids := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - err = mongo.UpdateCompressionStatus(context.Background(), id(), ids.Uint64(0)) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) - t.Run("Negative5", func(t *testing.T) { - id, ids := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - err = mongo.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - err = mongo.UpdateCompressionStatus(context.Background(), ids.Uint64(0), id()) - assert.ErrorIs(t, err, domain.ErrImageNotFound) - }) +func (suite *MongoTestSuite) TestMongoCount() { + suite.base.TestCount() } -func TestMongoImage(t *testing.T) { - t.Run("Positive", func(t *testing.T) { - id, ids := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - err = mongo.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - src, err := mongo.GetImageSrc(context.Background(), ids.Uint64(0), ids.Uint64(4)) - assert.NoError(t, err) - assert.Equal(t, "/aye-and-nay/albums/"+ids.Base64(0)+"/images/"+ids.Base64(4), src) - }) - t.Run("Negative1", func(t *testing.T) { - id, ids := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - _, err = mongo.GetImageSrc(context.Background(), id(), ids.Uint64(0)) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) - t.Run("Negative2", func(t *testing.T) { - id, ids := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - err = mongo.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - _, err = mongo.GetImageSrc(context.Background(), ids.Uint64(0), id()) - assert.ErrorIs(t, err, domain.ErrImageNotFound) - }) +func (suite *MongoTestSuite) TestMongoImage() { + suite.base.TestImage() } -func TestMongoVote(t *testing.T) { - t.Run("Positive", func(t *testing.T) { - id, ids := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - err = mongo.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - err = mongo.SaveVote(context.Background(), ids.Uint64(0), ids.Uint64(3), ids.Uint64(5)) - assert.NoError(t, err) - err = mongo.SaveVote(context.Background(), ids.Uint64(0), ids.Uint64(3), ids.Uint64(5)) - assert.NoError(t, err) - edgs, err := mongo.GetEdges(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - assert.Equal(t, 2, edgs[ids.Uint64(3)][ids.Uint64(5)]) - }) - t.Run("Negative", func(t *testing.T) { - id, _ := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - err = mongo.SaveVote(context.Background(), id(), id(), id()) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) +func (suite *MongoTestSuite) TestMongoVote() { + suite.base.TestVote() } -func TestMongoSort(t *testing.T) { - t.Run("Positive", func(t *testing.T) { - id, ids := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - err = mongo.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - imgs1, err := mongo.GetImagesOrdered(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - img1 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4), Rating: 0.77920413} - img2 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.48954984} - img3 := model.Image{Id: ids.Uint64(3), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.41218211} - img4 := model.Image{Id: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.19186324} - img5 := model.Image{Id: ids.Uint64(5), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5), Rating: 0.13278389} - imgs2 := []model.Image{img1, img2, img3, img4, img5} - assert.Equal(t, imgs2, imgs1) - }) - t.Run("Negative", func(t *testing.T) { - id, _ := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - _, err = mongo.GetImagesOrdered(context.Background(), id()) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) +func (suite *MongoTestSuite) TestMongoSort() { + suite.base.TestSort() } -func TestMongoRatings(t *testing.T) { - t.Run("Positive", func(t *testing.T) { - id, ids := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - err = mongo.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - img1 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} - img2 := model.Image{Id: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.32537162} - img3 := model.Image{Id: ids.Uint64(3), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.43185491} - img4 := model.Image{Id: ids.Uint64(4), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4), Rating: 0.57356209} - img5 := model.Image{Id: ids.Uint64(5), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5), Rating: 0.61438023} - imgs1 := []model.Image{img1, img2, img3, img4, img5} - vector := map[uint64]float64{} - vector[img1.Id] = img1.Rating - vector[img2.Id] = img2.Rating - vector[img3.Id] = img3.Rating - vector[img4.Id] = img4.Rating - vector[img5.Id] = img5.Rating - err = mongo.UpdateRatings(context.Background(), ids.Uint64(0), vector) - assert.NoError(t, err) - imgs2, err := mongo.GetImagesOrdered(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - sort.Slice(imgs1, func(i, j int) bool { return imgs1[i].Rating > imgs1[j].Rating }) - assert.Equal(t, imgs1, imgs2) - }) - t.Run("Negative", func(t *testing.T) { - id, ids := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - album := id() - img1 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} - img2 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.32537162} - img3 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(3), Rating: 0.43185491} - img4 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(4), Rating: 0.57356209} - img5 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(5), Rating: 0.61438023} - vector := map[uint64]float64{} - vector[img1.Id] = img1.Rating - vector[img2.Id] = img2.Rating - vector[img3.Id] = img3.Rating - vector[img4.Id] = img4.Rating - vector[img5.Id] = img5.Rating - err = mongo.UpdateRatings(context.Background(), album, vector) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) +func (suite *MongoTestSuite) TestMongoRatings() { + suite.base.TestRatings() } -func TestMongoDelete(t *testing.T) { - t.Run("Positive1", func(t *testing.T) { - id, ids := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - _, err = mongo.CountImages(context.Background(), ids.Uint64(0)) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - err = mongo.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - n, err := mongo.CountImages(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - assert.Equal(t, 5, n) - albums, err := mongo.AlbumsToBeDeleted(context.Background()) - assert.NoError(t, err) - assert.Len(t, albums, 0) - err = mongo.DeleteAlbum(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - _, err = mongo.CountImages(context.Background(), ids.Uint64(0)) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) - t.Run("Positive2", func(t *testing.T) { - id, ids := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - alb.Expires = time.Now().Add(-1 * time.Hour) - err = mongo.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - albums, err := mongo.AlbumsToBeDeleted(context.Background()) - assert.NoError(t, err) - assert.True(t, len(albums) == 1 && albums[0].Id == alb.Id && !albums[0].Expires.IsZero()) - err = mongo.DeleteAlbum(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - _, err = mongo.CountImages(context.Background(), ids.Uint64(0)) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - t.Cleanup(func() { _ = mongo.DeleteAlbum(context.Background(), ids.Uint64(0)) }) - }) - t.Run("Negative", func(t *testing.T) { - id, ids := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - alb := AlbumFactory(id, ids) - err = mongo.SaveAlbum(context.Background(), alb) - assert.NoError(t, err) - err = mongo.DeleteAlbum(context.Background(), id()) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) +func (suite *MongoTestSuite) TestMongoDelete() { + suite.base.TestDelete() } -func TestMongoLru(t *testing.T) { +func (suite *MongoTestSuite) TestMongoLru() { id, ids := GenId() - mongo, err := NewMongo(context.Background(), DefaultMongoConfig) - require.NoError(t, err) - alb1 := AlbumFactory(id, ids) - err = mongo.SaveAlbum(context.Background(), alb1) - assert.NoError(t, err) - alb2 := AlbumFactory(id, ids) - err = mongo.SaveAlbum(context.Background(), alb2) - assert.NoError(t, err) - edgs, err := mongo.GetEdges(context.Background(), ids.Uint64(0)) - assert.NoError(t, err) - assert.Equal(t, alb1.Edges, edgs) + alb1 := suite.base.saveAlbum(id, ids) + _ = suite.base.saveAlbum(id, ids) + edgs, err := suite.base.db.GetEdges(suite.base.ctx, ids.Uint64(0)) + assert.NoError(suite.base.T(), err) + assert.Equal(suite.base.T(), alb1.Edges, edgs) } diff --git a/infrastructure/storage/minio_integration_test.go b/infrastructure/storage/minio_integration_test.go index d53c9fe..77dc734 100644 --- a/infrastructure/storage/minio_integration_test.go +++ b/infrastructure/storage/minio_integration_test.go @@ -16,7 +16,7 @@ import ( . "github.com/zitryss/aye-and-nay/internal/testing" ) -func TestExampleTestSuite(t *testing.T) { +func TestMinioTestSuite(t *testing.T) { suite.Run(t, &MinioTestSuite{}) } diff --git a/internal/generator/generator.go b/internal/generator/generator.go index 0d168e7..c3bdcf2 100644 --- a/internal/generator/generator.go +++ b/internal/generator/generator.go @@ -16,6 +16,11 @@ var ( indexId uint64 ) +type Ids interface { + Uint64(i int) uint64 + Base64(i int) string +} + func GenId() (func() uint64, *syncLogBook) { lb := syncLogBook{m: sync.Mutex{}, logBook: map[int]uint64{}} fn := func() func() uint64 { diff --git a/internal/generator/generator_test.go b/internal/generator/generator_test.go index ad25a7c..1bb036a 100644 --- a/internal/generator/generator_test.go +++ b/internal/generator/generator_test.go @@ -1,3 +1,5 @@ +//go:build unit + package generator import ( @@ -12,14 +14,16 @@ func TestGenId(t *testing.T) { id, ids = GenId() wg := sync.WaitGroup{} wg.Add(2) - ch := make(chan struct{}, 1) + ch1 := make(chan struct{}, 1) + ch2 := make(chan struct{}, 1) assert.NotPanics(t, func() { go func() { defer wg.Done() for i := 0; i < IDS_SPAN/2; i++ { _ = id() } - ch <- struct{}{} + ch1 <- struct{}{} + <-ch2 for i := 0; i < IDS_SPAN/2; i++ { _ = ids.Uint64(i) } @@ -29,7 +33,8 @@ func TestGenId(t *testing.T) { for i := IDS_SPAN / 2; i < IDS_SPAN; i++ { _ = id() } - <-ch + ch2 <- struct{}{} + <-ch1 for i := IDS_SPAN / 2; i < IDS_SPAN; i++ { _ = ids.Uint64(i) } diff --git a/internal/testing/testing.go b/internal/testing/testing.go index 00d13c4..7a483b0 100644 --- a/internal/testing/testing.go +++ b/internal/testing/testing.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/zitryss/aye-and-nay/domain/model" + . "github.com/zitryss/aye-and-nay/internal/generator" ) const ( @@ -26,12 +27,7 @@ func Png() model.File { return model.File{Reader: buf, Size: int64(buf.Len())} } -type ids interface { - Uint64(i int) uint64 - Base64(i int) string -} - -func AlbumFactory(id func() uint64, ids ids) model.Album { +func AlbumFactory(id func() uint64, ids Ids) model.Album { album := id() img1 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.48954984} img2 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.19186324} From 54b50ce3f07b6a8ca3bb1477fbf8806e4f52bbc3 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sun, 13 Feb 2022 14:48:17 +0100 Subject: [PATCH 52/92] Optimize storage tests --- .../storage/minio_integration_test.go | 5 ++- .../storage/storage_integration_test.go | 33 ----------------- infrastructure/storage/storage_test.go | 37 +++++++++++++++++++ 3 files changed, 40 insertions(+), 35 deletions(-) delete mode 100644 infrastructure/storage/storage_integration_test.go create mode 100644 infrastructure/storage/storage_test.go diff --git a/infrastructure/storage/minio_integration_test.go b/infrastructure/storage/minio_integration_test.go index 77dc734..484d6fc 100644 --- a/infrastructure/storage/minio_integration_test.go +++ b/infrastructure/storage/minio_integration_test.go @@ -1,5 +1,3 @@ -//go:build integration - package storage import ( @@ -28,6 +26,9 @@ type MinioTestSuite struct { } func (suite *MinioTestSuite) SetupSuite() { + if !*integration { + suite.T().Skip() + } ctx, cancel := context.WithCancel(context.Background()) minio, err := NewMinio(ctx, DefaultMinioConfig) require.NoError(suite.T(), err) diff --git a/infrastructure/storage/storage_integration_test.go b/infrastructure/storage/storage_integration_test.go deleted file mode 100644 index 68b8831..0000000 --- a/infrastructure/storage/storage_integration_test.go +++ /dev/null @@ -1,33 +0,0 @@ -//go:build integration - -package storage - -import ( - "io" - "os" - "testing" - - "github.com/zitryss/aye-and-nay/internal/dockertest" - "github.com/zitryss/aye-and-nay/pkg/env" - "github.com/zitryss/aye-and-nay/pkg/log" -) - -func TestMain(m *testing.M) { - _, err := env.Lookup("CONTINUOUS_INTEGRATION") - if err != nil { - log.SetOutput(os.Stderr) - log.SetLevel(log.CRITICAL) - docker := dockertest.New() - host := &DefaultMinioConfig.Host - port := &DefaultMinioConfig.Port - accessKey := DefaultMinioConfig.AccessKey - secretKey := DefaultMinioConfig.SecretKey - docker.RunMinio(host, port, accessKey, secretKey) - log.SetOutput(io.Discard) - code := m.Run() - docker.Purge() - os.Exit(code) - } - code := m.Run() - os.Exit(code) -} diff --git a/infrastructure/storage/storage_test.go b/infrastructure/storage/storage_test.go new file mode 100644 index 0000000..119d6e2 --- /dev/null +++ b/infrastructure/storage/storage_test.go @@ -0,0 +1,37 @@ +package storage + +import ( + "flag" + "io" + "os" + "testing" + + "github.com/zitryss/aye-and-nay/internal/dockertest" + "github.com/zitryss/aye-and-nay/pkg/log" +) + +var ( + unit = flag.Bool("unit", false, "") + integration = flag.Bool("int", false, "") + ci = flag.Bool("ci", false, "") +) + +func TestMain(m *testing.M) { + flag.Parse() + if *ci || !*integration { + code := m.Run() + os.Exit(code) + } + log.SetOutput(os.Stderr) + log.SetLevel(log.CRITICAL) + docker := dockertest.New() + host := &DefaultMinioConfig.Host + port := &DefaultMinioConfig.Port + accessKey := DefaultMinioConfig.AccessKey + secretKey := DefaultMinioConfig.SecretKey + docker.RunMinio(host, port, accessKey, secretKey) + log.SetOutput(io.Discard) + code := m.Run() + docker.Purge() + os.Exit(code) +} From 62c0ae63b3299e048853d7f3227df23035d713f6 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sun, 13 Feb 2022 15:00:23 +0100 Subject: [PATCH 53/92] Optimize compressor tests --- .../compressor/compressor_integration_test.go | 31 ---------------- infrastructure/compressor/compressor_test.go | 35 +++++++++++++++++++ .../compressor/imaginary_integration_test.go | 11 ++++-- infrastructure/compressor/shortpixel_test.go | 5 +-- 4 files changed, 47 insertions(+), 35 deletions(-) delete mode 100644 infrastructure/compressor/compressor_integration_test.go create mode 100644 infrastructure/compressor/compressor_test.go diff --git a/infrastructure/compressor/compressor_integration_test.go b/infrastructure/compressor/compressor_integration_test.go deleted file mode 100644 index 3b51fd4..0000000 --- a/infrastructure/compressor/compressor_integration_test.go +++ /dev/null @@ -1,31 +0,0 @@ -//go:build integration - -package compressor - -import ( - "io" - "os" - "testing" - - "github.com/zitryss/aye-and-nay/internal/dockertest" - "github.com/zitryss/aye-and-nay/pkg/env" - "github.com/zitryss/aye-and-nay/pkg/log" -) - -func TestMain(m *testing.M) { - _, err := env.Lookup("CONTINUOUS_INTEGRATION") - if err != nil { - log.SetOutput(os.Stderr) - log.SetLevel(log.CRITICAL) - docker := dockertest.New() - host := &DefaultImaginaryConfig.Host - port := &DefaultImaginaryConfig.Port - docker.RunImaginary(host, port) - log.SetOutput(io.Discard) - code := m.Run() - docker.Purge() - os.Exit(code) - } - code := m.Run() - os.Exit(code) -} diff --git a/infrastructure/compressor/compressor_test.go b/infrastructure/compressor/compressor_test.go new file mode 100644 index 0000000..fff35ee --- /dev/null +++ b/infrastructure/compressor/compressor_test.go @@ -0,0 +1,35 @@ +package compressor + +import ( + "flag" + "io" + "os" + "testing" + + "github.com/zitryss/aye-and-nay/internal/dockertest" + "github.com/zitryss/aye-and-nay/pkg/log" +) + +var ( + unit = flag.Bool("unit", false, "") + integration = flag.Bool("int", false, "") + ci = flag.Bool("ci", false, "") +) + +func TestMain(m *testing.M) { + flag.Parse() + if *ci || !*integration { + code := m.Run() + os.Exit(code) + } + log.SetOutput(os.Stderr) + log.SetLevel(log.CRITICAL) + docker := dockertest.New() + host := &DefaultImaginaryConfig.Host + port := &DefaultImaginaryConfig.Port + docker.RunImaginary(host, port) + log.SetOutput(io.Discard) + code := m.Run() + docker.Purge() + os.Exit(code) +} diff --git a/infrastructure/compressor/imaginary_integration_test.go b/infrastructure/compressor/imaginary_integration_test.go index 3e1ef3f..3ac2af3 100644 --- a/infrastructure/compressor/imaginary_integration_test.go +++ b/infrastructure/compressor/imaginary_integration_test.go @@ -1,5 +1,3 @@ -//go:build integration - package compressor import ( @@ -15,6 +13,9 @@ import ( ) func TestImaginaryPositive(t *testing.T) { + if !*integration { + t.Skip() + } tests := []struct { filename string }{ @@ -46,6 +47,9 @@ func TestImaginaryPositive(t *testing.T) { } func TestImaginaryNegative(t *testing.T) { + if !*integration { + t.Skip() + } if testing.Short() { t.Skip("short flag is set") } @@ -61,6 +65,9 @@ func TestImaginaryNegative(t *testing.T) { } func TestImaginaryHealth(t *testing.T) { + if !*integration { + t.Skip() + } im, err := NewImaginary(context.Background(), DefaultImaginaryConfig) require.NoError(t, err) _, err = im.Health(context.Background()) diff --git a/infrastructure/compressor/shortpixel_test.go b/infrastructure/compressor/shortpixel_test.go index ed077e1..ea8f396 100644 --- a/infrastructure/compressor/shortpixel_test.go +++ b/infrastructure/compressor/shortpixel_test.go @@ -1,5 +1,3 @@ -//go:build unit - package compressor import ( @@ -41,6 +39,9 @@ type response []struct { } func TestShortpixel(t *testing.T) { + if !*unit { + t.Skip() + } t.Run("Positive1", func(t *testing.T) { fn1 := func(w http.ResponseWriter, r *http.Request) { _, err := io.Copy(w, Png()) From 1be20dce404add2145f4748a860cd7227f3343df Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Mon, 14 Feb 2022 20:01:04 +0100 Subject: [PATCH 54/92] Test cache in a suite --- domain/service/service_integration_test.go | 2 +- domain/service/service_test.go | 2 +- infrastructure/cache/cache.go | 4 +- .../cache/cache_integration_test.go | 31 -- infrastructure/cache/cache_test.go | 35 ++ infrastructure/cache/config.go | 2 +- infrastructure/cache/mem.go | 34 +- infrastructure/cache/mem_test.go | 154 +++++--- .../cache/redis_integration_test.go | 328 +++++++----------- infrastructure/compressor/compressor.go | 2 +- infrastructure/compressor/shortpixel.go | 7 +- infrastructure/database/badger.go | 7 +- .../database/badger_integration_test.go | 2 + infrastructure/database/database.go | 1 + .../database/mongo_integration_test.go | 2 + .../storage/minio_integration_test.go | 19 +- internal/testing/testing.go | 6 + 17 files changed, 337 insertions(+), 301 deletions(-) delete mode 100644 infrastructure/cache/cache_integration_test.go create mode 100644 infrastructure/cache/cache_test.go diff --git a/domain/service/service_integration_test.go b/domain/service/service_integration_test.go index c2e51ca..c16cd50 100644 --- a/domain/service/service_integration_test.go +++ b/domain/service/service_integration_test.go @@ -108,7 +108,7 @@ func TestServiceIntegrationAlbum(t *testing.T) { defer cancel() heartbeatRestart := make(chan interface{}) comp := compressor.NewShortpixel(compressor.DefaultShortpixelConfig, compressor.WithHeartbeatRestart(heartbeatRestart)) - comp.Monitor() + comp.Monitor(ctx) minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) require.NoError(t, err) mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) diff --git a/domain/service/service_test.go b/domain/service/service_test.go index 2f907b4..fa108d3 100644 --- a/domain/service/service_test.go +++ b/domain/service/service_test.go @@ -69,7 +69,7 @@ func TestServiceAlbum(t *testing.T) { defer cancel() heartbeatRestart := make(chan interface{}) comp := compressor.NewShortpixel(compressor.DefaultShortpixelConfig, compressor.WithHeartbeatRestart(heartbeatRestart)) - comp.Monitor() + comp.Monitor(ctx) stor := storage.NewMock() mDb := database.NewMem(database.DefaultMemConfig) mCache := cache.NewMem(cache.DefaultMemConfig) diff --git a/infrastructure/cache/cache.go b/infrastructure/cache/cache.go index 68b7d3f..a368190 100644 --- a/infrastructure/cache/cache.go +++ b/infrastructure/cache/cache.go @@ -14,11 +14,11 @@ func New(ctx context.Context, conf CacheConfig) (domain.Cacher, error) { return NewRedis(ctx, conf.Redis) case "mem": mem := NewMem(conf.Mem) - mem.Monitor() + mem.Monitor(ctx) return mem, nil default: mem := NewMem(conf.Mem) - mem.Monitor() + mem.Monitor(ctx) return mem, nil } } diff --git a/infrastructure/cache/cache_integration_test.go b/infrastructure/cache/cache_integration_test.go deleted file mode 100644 index e523e22..0000000 --- a/infrastructure/cache/cache_integration_test.go +++ /dev/null @@ -1,31 +0,0 @@ -//go:build integration - -package cache - -import ( - "io" - "os" - "testing" - - "github.com/zitryss/aye-and-nay/internal/dockertest" - "github.com/zitryss/aye-and-nay/pkg/env" - "github.com/zitryss/aye-and-nay/pkg/log" -) - -func TestMain(m *testing.M) { - _, err := env.Lookup("CONTINUOUS_INTEGRATION") - if err != nil { - log.SetOutput(os.Stderr) - log.SetLevel(log.CRITICAL) - docker := dockertest.New() - host := &DefaultRedisConfig.Host - port := &DefaultRedisConfig.Port - docker.RunRedis(host, port) - log.SetOutput(io.Discard) - code := m.Run() - docker.Purge() - os.Exit(code) - } - code := m.Run() - os.Exit(code) -} diff --git a/infrastructure/cache/cache_test.go b/infrastructure/cache/cache_test.go new file mode 100644 index 0000000..246c45a --- /dev/null +++ b/infrastructure/cache/cache_test.go @@ -0,0 +1,35 @@ +package cache + +import ( + "flag" + "io" + "os" + "testing" + + "github.com/zitryss/aye-and-nay/internal/dockertest" + "github.com/zitryss/aye-and-nay/pkg/log" +) + +var ( + unit = flag.Bool("unit", false, "") + integration = flag.Bool("int", false, "") + ci = flag.Bool("ci", false, "") +) + +func TestMain(m *testing.M) { + flag.Parse() + if *ci || !*integration { + code := m.Run() + os.Exit(code) + } + log.SetOutput(os.Stderr) + log.SetLevel(log.CRITICAL) + docker := dockertest.New() + host := &DefaultRedisConfig.Host + port := &DefaultRedisConfig.Port + docker.RunRedis(host, port) + log.SetOutput(io.Discard) + code := m.Run() + docker.Purge() + os.Exit(code) +} diff --git a/infrastructure/cache/config.go b/infrastructure/cache/config.go index c5c40a9..c4ad289 100644 --- a/infrastructure/cache/config.go +++ b/infrastructure/cache/config.go @@ -43,6 +43,6 @@ var ( Timeout: 30 * time.Second, LimiterRequestsPerSecond: 1, LimiterBurst: 1, - TimeToLive: 5 * time.Second, + TimeToLive: 3 * time.Second, } ) diff --git a/infrastructure/cache/mem.go b/infrastructure/cache/mem.go index 4eb72cd..b98ac27 100644 --- a/infrastructure/cache/mem.go +++ b/infrastructure/cache/mem.go @@ -34,6 +34,12 @@ func NewMem(conf MemConfig, opts ...options) *Mem { type options func(*Mem) +func WithHeartbeatCleanup(ch chan<- interface{}) options { + return func(m *Mem) { + m.heartbeat.cleanup = ch + } +} + func WithHeartbeatPair(ch chan<- interface{}) options { return func(m *Mem) { m.heartbeat.pair = ch @@ -54,8 +60,9 @@ type Mem struct { syncPairs syncTokens heartbeat struct { - pair chan<- interface{} - token chan<- interface{} + cleanup chan<- interface{} + pair chan<- interface{} + token chan<- interface{} } } @@ -118,9 +125,17 @@ func timeComparator(a, b interface{}) int { } } -func (m *Mem) Monitor() { +func (m *Mem) Monitor(ctx context.Context) { go func() { for { + select { + case <-ctx.Done(): + return + default: + } + if m.heartbeat.cleanup != nil { + m.heartbeat.cleanup <- struct{}{} + } now := time.Now() m.syncVisitors.Lock() for k, v := range m.visitors { @@ -130,10 +145,18 @@ func (m *Mem) Monitor() { } m.syncVisitors.Unlock() time.Sleep(m.conf.CleanupInterval) + if m.heartbeat.cleanup != nil { + m.heartbeat.cleanup <- struct{}{} + } } }() go func() { for { + select { + case <-ctx.Done(): + return + default: + } if m.heartbeat.pair != nil { m.heartbeat.pair <- struct{}{} } @@ -153,6 +176,11 @@ func (m *Mem) Monitor() { }() go func() { for { + select { + case <-ctx.Done(): + return + default: + } if m.heartbeat.token != nil { m.heartbeat.token <- struct{}{} } diff --git a/infrastructure/cache/mem_test.go b/infrastructure/cache/mem_test.go index 3ef1004..7e623d3 100644 --- a/infrastructure/cache/mem_test.go +++ b/infrastructure/cache/mem_test.go @@ -1,5 +1,3 @@ -//go:build unit - package cache import ( @@ -8,131 +6,177 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" "github.com/zitryss/aye-and-nay/domain/domain" . "github.com/zitryss/aye-and-nay/internal/generator" . "github.com/zitryss/aye-and-nay/internal/testing" ) -func TestMemPair(t *testing.T) { - t.Run("Positive", func(t *testing.T) { +func TestMemTestSuite(t *testing.T) { + suite.Run(t, &MemTestSuite{}) +} + +type MemTestSuite struct { + suite.Suite + ctx context.Context + cancel context.CancelFunc + conf MemConfig + heartbeatCleanup chan interface{} + heartbeatPair chan interface{} + heartbeatToken chan interface{} + cache domain.Cacher +} + +func (suite *MemTestSuite) SetupSuite() { + if !*unit { + suite.T().Skip() + } + ctx, cancel := context.WithCancel(context.Background()) + conf := DefaultMemConfig + hc := make(chan interface{}) + hp := make(chan interface{}) + ht := make(chan interface{}) + mem := NewMem(conf, WithHeartbeatCleanup(hc), WithHeartbeatPair(hp), WithHeartbeatToken(ht)) + mem.Monitor(ctx) + suite.ctx = ctx + suite.cancel = cancel + suite.conf = conf + suite.heartbeatCleanup = hc + suite.heartbeatPair = hp + suite.heartbeatToken = ht + suite.cache = mem +} + +func (suite *MemTestSuite) SetupTest() { + err := suite.cache.(*Mem).Reset() + require.NoError(suite.T(), err) +} + +func (suite *MemTestSuite) TearDownTest() { + +} + +func (suite *MemTestSuite) TearDownSuite() { + err := suite.cache.(*Mem).Reset() + require.NoError(suite.T(), err) + suite.cancel() +} + +func (suite *MemTestSuite) TestPair() { + suite.T().Run("Positive", func(t *testing.T) { id, ids := GenId() - mem := NewMem(DefaultMemConfig) album := id() pairs := [][2]uint64{{id(), id()}} - err := mem.Push(context.Background(), album, pairs) + err := suite.cache.Push(suite.ctx, album, pairs) assert.NoError(t, err) - image1, image2, err := mem.Pop(context.Background(), album) + image1, image2, err := suite.cache.Pop(suite.ctx, album) assert.NoError(t, err) assert.Equal(t, ids.Uint64(1), image1) assert.Equal(t, ids.Uint64(2), image2) }) - t.Run("Negative1", func(t *testing.T) { + suite.T().Run("Negative1", func(t *testing.T) { id, _ := GenId() - mem := NewMem(DefaultMemConfig) album := id() - _, _, err := mem.Pop(context.Background(), album) + _, _, err := suite.cache.Pop(suite.ctx, album) assert.ErrorIs(t, err, domain.ErrPairNotFound) }) - t.Run("Negative2", func(t *testing.T) { + suite.T().Run("Negative2", func(t *testing.T) { id, _ := GenId() - mem := NewMem(DefaultMemConfig) album := id() pairs := [][2]uint64{{id(), id()}} - err := mem.Push(context.Background(), album, pairs) + err := suite.cache.Push(suite.ctx, album, pairs) assert.NoError(t, err) - _, _, err = mem.Pop(context.Background(), album) + _, _, err = suite.cache.Pop(suite.ctx, album) assert.NoError(t, err) - _, _, err = mem.Pop(context.Background(), album) + _, _, err = suite.cache.Pop(suite.ctx, album) assert.ErrorIs(t, err, domain.ErrPairNotFound) }) - t.Run("Negative3", func(t *testing.T) { + suite.T().Run("Negative3", func(t *testing.T) { + _, ok := suite.cache.(*Redis) + if testing.Short() && ok { + t.Skip("short flag is set") + } id, _ := GenId() - heartbeatPair := make(chan interface{}) - mem := NewMem(DefaultMemConfig, WithHeartbeatPair(heartbeatPair)) - mem.Monitor() album := id() pairs := [][2]uint64{{id(), id()}} - err := mem.Push(context.Background(), album, pairs) + err := suite.cache.Push(suite.ctx, album, pairs) assert.NoError(t, err) - time.Sleep(mem.conf.TimeToLive) - AssertChannel(t, heartbeatPair) - AssertChannel(t, heartbeatPair) - _, _, err = mem.Pop(context.Background(), album) + time.Sleep(suite.conf.TimeToLive * 2) + AssertChannel(t, suite.heartbeatPair) + AssertChannel(t, suite.heartbeatPair) + _, _, err = suite.cache.Pop(suite.ctx, album) assert.ErrorIs(t, err, domain.ErrPairNotFound) }) } -func TestMemToken(t *testing.T) { - t.Run("Positive", func(t *testing.T) { +func (suite *MemTestSuite) TestToken() { + suite.T().Run("Positive", func(t *testing.T) { id, _ := GenId() - mem := NewMem(DefaultMemConfig) token := id() album1 := id() image1 := id() - err := mem.Set(context.Background(), token, album1, image1) + err := suite.cache.Set(suite.ctx, token, album1, image1) assert.NoError(t, err) - album2, image2, err := mem.Get(context.Background(), token) + album2, image2, err := suite.cache.Get(suite.ctx, token) assert.NoError(t, err) assert.Equal(t, album1, album2) assert.Equal(t, image1, image2) }) - t.Run("Negative1", func(t *testing.T) { + suite.T().Run("Negative1", func(t *testing.T) { id, _ := GenId() - mem := NewMem(DefaultMemConfig) token := id() album := id() image := id() - err := mem.Set(context.Background(), token, album, image) + err := suite.cache.Set(suite.ctx, token, album, image) assert.NoError(t, err) - err = mem.Set(context.Background(), token, album, image) + err = suite.cache.Set(suite.ctx, token, album, image) assert.ErrorIs(t, err, domain.ErrTokenAlreadyExists) }) - t.Run("Negative2", func(t *testing.T) { + suite.T().Run("Negative2", func(t *testing.T) { id, _ := GenId() - mem := NewMem(DefaultMemConfig) token := id() - _, _, err := mem.Get(context.Background(), token) + _, _, err := suite.cache.Get(suite.ctx, token) assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) - t.Run("Negative3", func(t *testing.T) { + suite.T().Run("Negative3", func(t *testing.T) { id, _ := GenId() - mem := NewMem(DefaultMemConfig) token := id() album := id() image := id() - err := mem.Set(context.Background(), token, album, image) + err := suite.cache.Set(suite.ctx, token, album, image) assert.NoError(t, err) - _, _, err = mem.Get(context.Background(), token) + _, _, err = suite.cache.Get(suite.ctx, token) assert.NoError(t, err) - err = mem.Del(context.Background(), token) + err = suite.cache.Del(suite.ctx, token) assert.NoError(t, err) - err = mem.Del(context.Background(), token) + err = suite.cache.Del(suite.ctx, token) assert.NoError(t, err) - _, _, err = mem.Get(context.Background(), token) + _, _, err = suite.cache.Get(suite.ctx, token) assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) - t.Run("Negative4", func(t *testing.T) { + suite.T().Run("Negative4", func(t *testing.T) { id, _ := GenId() - mem := NewMem(DefaultMemConfig) token := id() - err := mem.Del(context.Background(), token) + err := suite.cache.Del(suite.ctx, token) assert.NoError(t, err) }) - t.Run("Negative5", func(t *testing.T) { + suite.T().Run("Negative5", func(t *testing.T) { + _, ok := suite.cache.(*Redis) + if testing.Short() && ok { + t.Skip("short flag is set") + } id, _ := GenId() - heartbeatToken := make(chan interface{}) - mem := NewMem(DefaultMemConfig, WithHeartbeatToken(heartbeatToken)) - mem.Monitor() token := id() album := id() image := id() - err := mem.Set(context.Background(), token, album, image) + err := suite.cache.Set(suite.ctx, token, album, image) assert.NoError(t, err) - time.Sleep(mem.conf.TimeToLive) - AssertChannel(t, heartbeatToken) - AssertChannel(t, heartbeatToken) - _, _, err = mem.Get(context.Background(), token) + time.Sleep(suite.conf.TimeToLive * 2) + AssertChannel(t, suite.heartbeatToken) + AssertChannel(t, suite.heartbeatToken) + _, _, err = suite.cache.Get(suite.ctx, token) assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) } diff --git a/infrastructure/cache/redis_integration_test.go b/infrastructure/cache/redis_integration_test.go index 8d078dc..1a68f16 100644 --- a/infrastructure/cache/redis_integration_test.go +++ b/infrastructure/cache/redis_integration_test.go @@ -1,5 +1,3 @@ -//go:build integration - package cache import ( @@ -9,238 +7,178 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" "github.com/zitryss/aye-and-nay/domain/domain" . "github.com/zitryss/aye-and-nay/internal/generator" ) -func TestRedisAllow(t *testing.T) { - t.Run("Positive", func(t *testing.T) { +func TestRedisTestSuite(t *testing.T) { + suite.Run(t, &RedisTestSuite{}) +} + +type RedisTestSuite struct { + suite.Suite + base MemTestSuite +} + +func (suite *RedisTestSuite) SetupSuite() { + if !*integration { + suite.T().Skip() + } + suite.base = MemTestSuite{} + suite.base.SetT(suite.T()) + ctx, cancel := context.WithCancel(context.Background()) + conf := DefaultRedisConfig + redis, err := NewRedis(ctx, conf) + require.NoError(suite.T(), err) + suite.base.ctx = ctx + suite.base.cancel = cancel + suite.base.conf.LimiterRequestsPerSecond = float64(conf.LimiterRequestsPerSecond) + suite.base.conf.TimeToLive = conf.TimeToLive + suite.base.cache = redis +} + +func (suite *RedisTestSuite) SetupTest() { + err := suite.base.cache.(*Redis).Reset() + require.NoError(suite.T(), err) +} + +func (suite *RedisTestSuite) TearDownTest() { + +} + +func (suite *RedisTestSuite) TearDownSuite() { + err := suite.base.cache.(*Redis).Reset() + require.NoError(suite.T(), err) + err = suite.base.cache.(*Redis).Close(suite.base.ctx) + require.NoError(suite.T(), err) + suite.base.cancel() +} + +func (suite *RedisTestSuite) TestRedisAllow() { + suite.T().Run("Positive", func(t *testing.T) { id, _ := GenId() - redis, err := NewRedis(context.Background(), DefaultRedisConfig) - require.NoError(t, err) - rpm := redis.conf.LimiterRequestsPerSecond + rpm := suite.base.conf.LimiterRequestsPerSecond ip := id() - for j := 0; j < rpm; j++ { - allowed, err := redis.Allow(context.Background(), ip) + for j := float64(0); j < rpm; j++ { + allowed, err := suite.base.cache.Allow(suite.base.ctx, ip) assert.NoError(t, err) assert.True(t, allowed) } time.Sleep(1 * time.Second) - for j := 0; j < rpm; j++ { - allowed, err := redis.Allow(context.Background(), ip) + for j := float64(0); j < rpm; j++ { + allowed, err := suite.base.cache.Allow(suite.base.ctx, ip) assert.NoError(t, err) assert.True(t, allowed) } }) - t.Run("Negative", func(t *testing.T) { + suite.T().Run("Negative", func(t *testing.T) { id, _ := GenId() - redis, err := NewRedis(context.Background(), DefaultRedisConfig) - require.NoError(t, err) - rps := redis.conf.LimiterRequestsPerSecond + rps := suite.base.conf.LimiterRequestsPerSecond ip := id() - for i := 0; i < rps; i++ { - allowed, err := redis.Allow(context.Background(), ip) + for i := float64(0); i < rps; i++ { + allowed, err := suite.base.cache.Allow(suite.base.ctx, ip) assert.NoError(t, err) assert.True(t, allowed) } - allowed, err := redis.Allow(context.Background(), ip) + allowed, err := suite.base.cache.Allow(suite.base.ctx, ip) assert.NoError(t, err) assert.False(t, allowed) }) } -func TestRedisQueue(t *testing.T) { +func (suite *RedisTestSuite) TestRedisQueue() { id, _ := GenId() - redis, err := NewRedis(context.Background(), DefaultRedisConfig) - require.NoError(t, err) queue := id() albumExp1 := id() albumExp2 := id() albumExp3 := id() - n, err := redis.Size(context.Background(), queue) - assert.NoError(t, err) - assert.Equal(t, 0, n) - err = redis.Add(context.Background(), queue, albumExp1) - assert.NoError(t, err) - err = redis.Add(context.Background(), queue, albumExp1) - assert.NoError(t, err) - err = redis.Add(context.Background(), queue, albumExp2) - assert.NoError(t, err) - err = redis.Add(context.Background(), queue, albumExp3) - assert.NoError(t, err) - err = redis.Add(context.Background(), queue, albumExp2) - assert.NoError(t, err) - n, err = redis.Size(context.Background(), queue) - assert.NoError(t, err) - assert.Equal(t, 3, n) - album, err := redis.Poll(context.Background(), queue) - assert.NoError(t, err) - assert.Equal(t, albumExp1, album) - n, err = redis.Size(context.Background(), queue) - assert.NoError(t, err) - assert.Equal(t, 2, n) - album, err = redis.Poll(context.Background(), queue) - assert.NoError(t, err) - assert.Equal(t, albumExp2, album) - album, err = redis.Poll(context.Background(), queue) - assert.NoError(t, err) - assert.Equal(t, albumExp3, album) - n, err = redis.Size(context.Background(), queue) - assert.NoError(t, err) - assert.Equal(t, 0, n) - album, err = redis.Poll(context.Background(), queue) - assert.Error(t, err) - assert.Equal(t, uint64(0x0), album) - n, err = redis.Size(context.Background(), queue) - assert.NoError(t, err) - assert.Equal(t, 0, n) - _, err = redis.Poll(context.Background(), queue) - assert.ErrorIs(t, err, domain.ErrUnknown) + n, err := suite.base.cache.Size(suite.base.ctx, queue) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), 0, n) + err = suite.base.cache.Add(suite.base.ctx, queue, albumExp1) + assert.NoError(suite.T(), err) + err = suite.base.cache.Add(suite.base.ctx, queue, albumExp1) + assert.NoError(suite.T(), err) + err = suite.base.cache.Add(suite.base.ctx, queue, albumExp2) + assert.NoError(suite.T(), err) + err = suite.base.cache.Add(suite.base.ctx, queue, albumExp3) + assert.NoError(suite.T(), err) + err = suite.base.cache.Add(suite.base.ctx, queue, albumExp2) + assert.NoError(suite.T(), err) + n, err = suite.base.cache.Size(suite.base.ctx, queue) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), 3, n) + album, err := suite.base.cache.Poll(suite.base.ctx, queue) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), albumExp1, album) + n, err = suite.base.cache.Size(suite.base.ctx, queue) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), 2, n) + album, err = suite.base.cache.Poll(suite.base.ctx, queue) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), albumExp2, album) + album, err = suite.base.cache.Poll(suite.base.ctx, queue) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), albumExp3, album) + n, err = suite.base.cache.Size(suite.base.ctx, queue) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), 0, n) + album, err = suite.base.cache.Poll(suite.base.ctx, queue) + assert.Error(suite.T(), err) + assert.Equal(suite.T(), uint64(0x0), album) + n, err = suite.base.cache.Size(suite.base.ctx, queue) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), 0, n) + _, err = suite.base.cache.Poll(suite.base.ctx, queue) + assert.ErrorIs(suite.T(), err, domain.ErrUnknown) } -func TestRedisPQueue(t *testing.T) { +func (suite *RedisTestSuite) TestRedisPQueue() { id, _ := GenId() - redis, err := NewRedis(context.Background(), DefaultRedisConfig) - require.NoError(t, err) pqueue := id() albumExp1 := id() albumExp2 := id() albumExp3 := id() - n, err := redis.PSize(context.Background(), pqueue) - assert.NoError(t, err) - assert.Equal(t, 0, n) - err = redis.PAdd(context.Background(), pqueue, albumExp1, time.Unix(904867200, 0)) - assert.NoError(t, err) - err = redis.PAdd(context.Background(), pqueue, albumExp2, time.Unix(1075852800, 0)) - assert.NoError(t, err) - err = redis.PAdd(context.Background(), pqueue, albumExp3, time.Unix(681436800, 0)) - assert.NoError(t, err) - n, err = redis.PSize(context.Background(), pqueue) - assert.NoError(t, err) - assert.Equal(t, 3, n) - album, expires, err := redis.PPoll(context.Background(), pqueue) - assert.NoError(t, err) - assert.Equal(t, albumExp3, album) - assert.True(t, expires.Equal(time.Unix(681436800, 0))) - n, err = redis.PSize(context.Background(), pqueue) - assert.NoError(t, err) - assert.Equal(t, 2, n) - album, expires, err = redis.PPoll(context.Background(), pqueue) - assert.NoError(t, err) - assert.Equal(t, albumExp1, album) - assert.True(t, expires.Equal(time.Unix(904867200, 0))) - album, expires, err = redis.PPoll(context.Background(), pqueue) - assert.NoError(t, err) - assert.Equal(t, albumExp2, album) - assert.True(t, expires.Equal(time.Unix(1075852800, 0))) - n, err = redis.PSize(context.Background(), pqueue) - assert.NoError(t, err) - assert.Equal(t, 0, n) - _, _, err = redis.PPoll(context.Background(), pqueue) - assert.ErrorIs(t, err, domain.ErrUnknown) + n, err := suite.base.cache.PSize(suite.base.ctx, pqueue) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), 0, n) + err = suite.base.cache.PAdd(suite.base.ctx, pqueue, albumExp1, time.Unix(904867200, 0)) + assert.NoError(suite.T(), err) + err = suite.base.cache.PAdd(suite.base.ctx, pqueue, albumExp2, time.Unix(1075852800, 0)) + assert.NoError(suite.T(), err) + err = suite.base.cache.PAdd(suite.base.ctx, pqueue, albumExp3, time.Unix(681436800, 0)) + assert.NoError(suite.T(), err) + n, err = suite.base.cache.PSize(suite.base.ctx, pqueue) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), 3, n) + album, expires, err := suite.base.cache.PPoll(suite.base.ctx, pqueue) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), albumExp3, album) + assert.True(suite.T(), expires.Equal(time.Unix(681436800, 0))) + n, err = suite.base.cache.PSize(suite.base.ctx, pqueue) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), 2, n) + album, expires, err = suite.base.cache.PPoll(suite.base.ctx, pqueue) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), albumExp1, album) + assert.True(suite.T(), expires.Equal(time.Unix(904867200, 0))) + album, expires, err = suite.base.cache.PPoll(suite.base.ctx, pqueue) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), albumExp2, album) + assert.True(suite.T(), expires.Equal(time.Unix(1075852800, 0))) + n, err = suite.base.cache.PSize(suite.base.ctx, pqueue) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), 0, n) + _, _, err = suite.base.cache.PPoll(suite.base.ctx, pqueue) + assert.ErrorIs(suite.T(), err, domain.ErrUnknown) } -func TestRedisPair(t *testing.T) { - t.Run("Positive", func(t *testing.T) { - id, _ := GenId() - redis, err := NewRedis(context.Background(), DefaultRedisConfig) - require.NoError(t, err) - album := id() - image1 := id() - image2 := id() - pairs := [][2]uint64{{image1, image2}} - err = redis.Push(context.Background(), album, pairs) - assert.NoError(t, err) - image3, image4, err := redis.Pop(context.Background(), album) - assert.NoError(t, err) - assert.Equal(t, image1, image3) - assert.Equal(t, image2, image4) - }) - t.Run("Negative1", func(t *testing.T) { - id, _ := GenId() - redis, err := NewRedis(context.Background(), DefaultRedisConfig) - require.NoError(t, err) - album := id() - _, _, err = redis.Pop(context.Background(), album) - assert.ErrorIs(t, err, domain.ErrPairNotFound) - }) - t.Run("Negative2", func(t *testing.T) { - id, _ := GenId() - redis, err := NewRedis(context.Background(), DefaultRedisConfig) - require.NoError(t, err) - album := id() - image1 := id() - image2 := id() - pairs := [][2]uint64{{image1, image2}} - err = redis.Push(context.Background(), album, pairs) - assert.NoError(t, err) - _, _, err = redis.Pop(context.Background(), album) - assert.NoError(t, err) - _, _, err = redis.Pop(context.Background(), album) - assert.ErrorIs(t, err, domain.ErrPairNotFound) - }) +func (suite *RedisTestSuite) TestRedisPair() { + suite.base.TestPair() } -func TestRedisToken(t *testing.T) { - t.Run("Positive", func(t *testing.T) { - id, _ := GenId() - redis, err := NewRedis(context.Background(), DefaultRedisConfig) - require.NoError(t, err) - token := id() - albumExp := id() - imageExp := id() - err = redis.Set(context.Background(), token, albumExp, imageExp) - assert.NoError(t, err) - album, image, err := redis.Get(context.Background(), token) - assert.NoError(t, err) - assert.Equal(t, albumExp, album) - assert.Equal(t, imageExp, image) - }) - t.Run("Negative1", func(t *testing.T) { - id, _ := GenId() - redis, err := NewRedis(context.Background(), DefaultRedisConfig) - require.NoError(t, err) - token := id() - album := id() - image := id() - err = redis.Set(context.Background(), token, album, image) - assert.NoError(t, err) - err = redis.Set(context.Background(), token, album, image) - assert.ErrorIs(t, err, domain.ErrTokenAlreadyExists) - }) - t.Run("Negative2", func(t *testing.T) { - id, _ := GenId() - redis, err := NewRedis(context.Background(), DefaultRedisConfig) - require.NoError(t, err) - token := id() - _, _, err = redis.Get(context.Background(), token) - assert.ErrorIs(t, err, domain.ErrTokenNotFound) - }) - t.Run("Negative3", func(t *testing.T) { - id, _ := GenId() - redis, err := NewRedis(context.Background(), DefaultRedisConfig) - require.NoError(t, err) - token := id() - album := id() - image := id() - err = redis.Set(context.Background(), token, album, image) - assert.NoError(t, err) - _, _, err = redis.Get(context.Background(), token) - assert.NoError(t, err) - err = redis.Del(context.Background(), token) - assert.NoError(t, err) - err = redis.Del(context.Background(), token) - assert.NoError(t, err) - _, _, err = redis.Get(context.Background(), token) - assert.ErrorIs(t, err, domain.ErrTokenNotFound) - }) - t.Run("Negative4", func(t *testing.T) { - id, _ := GenId() - redis, err := NewRedis(context.Background(), DefaultRedisConfig) - require.NoError(t, err) - token := id() - err = redis.Del(context.Background(), token) - assert.NoError(t, err) - }) +func (suite *RedisTestSuite) TestRedisToken() { + suite.base.TestToken() } diff --git a/infrastructure/compressor/compressor.go b/infrastructure/compressor/compressor.go index 9debdc7..97a67e8 100644 --- a/infrastructure/compressor/compressor.go +++ b/infrastructure/compressor/compressor.go @@ -16,7 +16,7 @@ func New(ctx context.Context, conf CompressorConfig) (domain.Compresser, error) if err != nil { return nil, err } - sp.Monitor() + sp.Monitor(ctx) return sp, nil case "imaginary": log.Info("connecting to imaginary") diff --git a/infrastructure/compressor/shortpixel.go b/infrastructure/compressor/shortpixel.go index df3095a..97843b9 100644 --- a/infrastructure/compressor/shortpixel.go +++ b/infrastructure/compressor/shortpixel.go @@ -59,9 +59,14 @@ func (sp *Shortpixel) Ping(ctx context.Context) error { return nil } -func (sp *Shortpixel) Monitor() { +func (sp *Shortpixel) Monitor(ctx context.Context) { go func() { for { + select { + case <-ctx.Done(): + return + default: + } <-sp.ch if sp.heartbeat.restart != nil { sp.heartbeat.restart <- struct{}{} diff --git a/infrastructure/database/badger.go b/infrastructure/database/badger.go index dfed3f2..26273a8 100644 --- a/infrastructure/database/badger.go +++ b/infrastructure/database/badger.go @@ -46,9 +46,14 @@ type Badger struct { cache *lru.Cache } -func (b *Badger) Monitor() { +func (b *Badger) Monitor(ctx context.Context) { go func() { for { + select { + case <-ctx.Done(): + return + default: + } _ = b.db.RunValueLogGC(b.conf.GcRatio) time.Sleep(b.conf.CleanupInterval) } diff --git a/infrastructure/database/badger_integration_test.go b/infrastructure/database/badger_integration_test.go index 9323b63..368864d 100644 --- a/infrastructure/database/badger_integration_test.go +++ b/infrastructure/database/badger_integration_test.go @@ -46,6 +46,8 @@ func (suite *BadgerTestSuite) TearDownTest() { func (suite *BadgerTestSuite) TearDownSuite() { err := suite.base.db.(*Badger).Reset() require.NoError(suite.T(), err) + err = suite.base.db.(*Badger).Close(suite.base.ctx) + require.NoError(suite.T(), err) suite.base.cancel() } diff --git a/infrastructure/database/database.go b/infrastructure/database/database.go index bbda2c4..7ea8d8c 100644 --- a/infrastructure/database/database.go +++ b/infrastructure/database/database.go @@ -18,6 +18,7 @@ func New(ctx context.Context, conf DatabaseConfig) (domain.Databaser, error) { if err != nil { return nil, err } + b.Monitor(ctx) return b, nil case "mem": return NewMem(conf.Mem), nil diff --git a/infrastructure/database/mongo_integration_test.go b/infrastructure/database/mongo_integration_test.go index a728576..057c5cc 100644 --- a/infrastructure/database/mongo_integration_test.go +++ b/infrastructure/database/mongo_integration_test.go @@ -46,6 +46,8 @@ func (suite *MongoTestSuite) TearDownTest() { func (suite *MongoTestSuite) TearDownSuite() { err := suite.base.db.(*Mongo).Reset() require.NoError(suite.T(), err) + err = suite.base.db.(*Mongo).Close(suite.base.ctx) + require.NoError(suite.T(), err) suite.base.cancel() } diff --git a/infrastructure/storage/minio_integration_test.go b/infrastructure/storage/minio_integration_test.go index 484d6fc..5a32636 100644 --- a/infrastructure/storage/minio_integration_test.go +++ b/infrastructure/storage/minio_integration_test.go @@ -42,6 +42,16 @@ func (suite *MinioTestSuite) SetupTest() { require.NoError(suite.T(), err) } +func (suite *MinioTestSuite) TearDownTest() { + +} + +func (suite *MinioTestSuite) TearDownSuite() { + err := suite.storage.(*Minio).Reset() + require.NoError(suite.T(), err) + suite.cancel() +} + func (suite *MinioTestSuite) TestMinio() { suite.T().Run("", func(t *testing.T) { id, ids := GenId() @@ -86,12 +96,3 @@ func (suite *MinioTestSuite) TestMinioHealth() { _, err := suite.storage.Health(suite.ctx) assert.NoError(suite.T(), err) } - -func (suite *MinioTestSuite) TearDownTest() { -} - -func (suite *MinioTestSuite) TearDownSuite() { - err := suite.storage.(*Minio).Reset() - require.NoError(suite.T(), err) - suite.cancel() -} diff --git a/internal/testing/testing.go b/internal/testing/testing.go index 7a483b0..bfb071a 100644 --- a/internal/testing/testing.go +++ b/internal/testing/testing.go @@ -75,6 +75,9 @@ func AssertBody(t *testing.T, w *httptest.ResponseRecorder, body string) { func AssertChannel(t *testing.T, heartbeat <-chan interface{}) interface{} { t.Helper() + if heartbeat == nil { + return nil + } v := interface{}(nil) select { case v = <-heartbeat: @@ -86,6 +89,9 @@ func AssertChannel(t *testing.T, heartbeat <-chan interface{}) interface{} { func AssertNotChannel(t *testing.T, heartbeat <-chan interface{}) { t.Helper() + if heartbeat == nil { + return + } select { case <-heartbeat: t.Error("<-heartbeatDel") From bc3290afdc04305f3cad774979abff15366e0171 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Wed, 16 Feb 2022 09:12:03 +0100 Subject: [PATCH 55/92] Remove deadlock in testing --- domain/service/workerpool.go | 24 ++++++++++++++--- infrastructure/cache/mem.go | 36 ++++++++++++++++++++----- infrastructure/cache/mem_test.go | 3 +++ infrastructure/compressor/shortpixel.go | 12 +++++++-- 4 files changed, 63 insertions(+), 12 deletions(-) diff --git a/domain/service/workerpool.go b/domain/service/workerpool.go index 2d010e7..4a46286 100644 --- a/domain/service/workerpool.go +++ b/domain/service/workerpool.go @@ -67,7 +67,11 @@ func (s *Service) StartWorkingPoolCalc(ctx context.Context, g *errgroup.Group) { continue } if s.heartbeat.calc != nil { - s.heartbeat.calc <- struct{}{} + select { + case <-ctx.Done(): + return + case s.heartbeat.calc <- struct{}{}: + } } } }) @@ -134,7 +138,11 @@ func (s *Service) StartWorkingPoolComp(ctx context.Context, g *errgroup.Group) { f, err = s.comp.Compress(ctx, f) if errors.Is(err, domain.ErrThirdPartyUnavailable) { if s.heartbeat.comp != nil { - s.heartbeat.comp <- err + select { + case <-ctx.Done(): + return + case s.heartbeat.comp <- err: + } } } if err != nil { @@ -159,7 +167,11 @@ func (s *Service) StartWorkingPoolComp(ctx context.Context, g *errgroup.Group) { } if s.heartbeat.comp != nil { p, _ := s.Progress(ctx, album) - s.heartbeat.comp <- p + select { + case <-ctx.Done(): + return + case s.heartbeat.comp <- p: + } } } } @@ -224,7 +236,11 @@ func (s *Service) StartWorkingPoolDel(ctx context.Context, g *errgroup.Group) { } } if s.heartbeat.del != nil { - s.heartbeat.del <- album + select { + case <-ctx.Done(): + return + case s.heartbeat.del <- album: + } } } }) diff --git a/infrastructure/cache/mem.go b/infrastructure/cache/mem.go index b98ac27..1d821bd 100644 --- a/infrastructure/cache/mem.go +++ b/infrastructure/cache/mem.go @@ -134,7 +134,11 @@ func (m *Mem) Monitor(ctx context.Context) { default: } if m.heartbeat.cleanup != nil { - m.heartbeat.cleanup <- struct{}{} + select { + case <-ctx.Done(): + return + case m.heartbeat.cleanup <- struct{}{}: + } } now := time.Now() m.syncVisitors.Lock() @@ -146,7 +150,11 @@ func (m *Mem) Monitor(ctx context.Context) { m.syncVisitors.Unlock() time.Sleep(m.conf.CleanupInterval) if m.heartbeat.cleanup != nil { - m.heartbeat.cleanup <- struct{}{} + select { + case <-ctx.Done(): + return + case m.heartbeat.cleanup <- struct{}{}: + } } } }() @@ -158,7 +166,11 @@ func (m *Mem) Monitor(ctx context.Context) { default: } if m.heartbeat.pair != nil { - m.heartbeat.pair <- struct{}{} + select { + case <-ctx.Done(): + return + case m.heartbeat.pair <- struct{}{}: + } } now := time.Now() m.syncPairs.Lock() @@ -170,7 +182,11 @@ func (m *Mem) Monitor(ctx context.Context) { m.syncPairs.Unlock() time.Sleep(m.conf.CleanupInterval) if m.heartbeat.pair != nil { - m.heartbeat.pair <- struct{}{} + select { + case <-ctx.Done(): + return + case m.heartbeat.pair <- struct{}{}: + } } } }() @@ -182,7 +198,11 @@ func (m *Mem) Monitor(ctx context.Context) { default: } if m.heartbeat.token != nil { - m.heartbeat.token <- struct{}{} + select { + case <-ctx.Done(): + return + case m.heartbeat.token <- struct{}{}: + } } now := time.Now() m.syncTokens.Lock() @@ -194,7 +214,11 @@ func (m *Mem) Monitor(ctx context.Context) { m.syncTokens.Unlock() time.Sleep(m.conf.CleanupInterval) if m.heartbeat.token != nil { - m.heartbeat.token <- struct{}{} + select { + case <-ctx.Done(): + return + case m.heartbeat.token <- struct{}{}: + } } } }() diff --git a/infrastructure/cache/mem_test.go b/infrastructure/cache/mem_test.go index 7e623d3..3e19f3d 100644 --- a/infrastructure/cache/mem_test.go +++ b/infrastructure/cache/mem_test.go @@ -61,6 +61,9 @@ func (suite *MemTestSuite) TearDownTest() { func (suite *MemTestSuite) TearDownSuite() { err := suite.cache.(*Mem).Reset() require.NoError(suite.T(), err) + close(suite.heartbeatCleanup) + close(suite.heartbeatPair) + close(suite.heartbeatToken) suite.cancel() } diff --git a/infrastructure/compressor/shortpixel.go b/infrastructure/compressor/shortpixel.go index 97843b9..48ce503 100644 --- a/infrastructure/compressor/shortpixel.go +++ b/infrastructure/compressor/shortpixel.go @@ -69,12 +69,20 @@ func (sp *Shortpixel) Monitor(ctx context.Context) { } <-sp.ch if sp.heartbeat.restart != nil { - sp.heartbeat.restart <- struct{}{} + select { + case <-ctx.Done(): + return + case sp.heartbeat.restart <- struct{}{}: + } } time.Sleep(sp.conf.RestartIn) atomic.StoreUint32(&sp.done, 0) if sp.heartbeat.restart != nil { - sp.heartbeat.restart <- struct{}{} + select { + case <-ctx.Done(): + return + case sp.heartbeat.restart <- struct{}{}: + } } } }() From edf2adc76dc819540ed7029da365eff1561426e2 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Wed, 16 Feb 2022 09:12:27 +0100 Subject: [PATCH 56/92] Use optimized library --- go.mod | 1 + go.sum | 3 +++ pkg/base64/base64.go | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index b05b4fb..87befbc 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/ory/dockertest/v3 v3.6.5 github.com/radovskyb/watcher v1.0.7 github.com/rs/cors v1.8.0 + github.com/segmentio/asm v1.1.3 github.com/spf13/viper v1.9.0 github.com/stretchr/testify v1.7.0 go.mongodb.org/mongo-driver v1.8.0 diff --git a/go.sum b/go.sum index 0189211..32ab776 100644 --- a/go.sum +++ b/go.sum @@ -454,6 +454,8 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb github.com/sagikazarmark/crypt v0.1.0/go.mod h1:B/mN0msZuINBtQ1zZLEQcegFJJf9vnYIR88KRMEuODE= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/segmentio/asm v1.1.3 h1:WM03sfUOENvvKexOLp+pCqgb/WDjsi7EK8gIsICtzhc= +github.com/segmentio/asm v1.1.3/go.mod h1:Ld3L4ZXGNcSLRg4JBsZ3//1+f/TjYl0Mzen/DQy1EJg= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= @@ -764,6 +766,7 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 h1:TyHqChC80pFkXWraUUf6RuB5IqFdQieMLwwCJokV2pc= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= diff --git a/pkg/base64/base64.go b/pkg/base64/base64.go index 799fd4c..859082c 100644 --- a/pkg/base64/base64.go +++ b/pkg/base64/base64.go @@ -1,8 +1,9 @@ package base64 import ( - "encoding/base64" "encoding/binary" + + "github.com/segmentio/asm/base64" ) func FromUint64(u uint64) string { From 401b046badb531aeeaee6cfa5ea62cc78415abef Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Wed, 16 Feb 2022 19:20:47 +0100 Subject: [PATCH 57/92] Remove gobuild directive --- delivery/http/controller_test.go | 8 +++-- delivery/http/middleware_test.go | 11 +++++-- delivery/http/server_test.go | 12 ++++++-- domain/service/queue_integration_test.go | 5 +-- domain/service/queue_test.go | 5 +-- domain/service/service_integration_test.go | 36 ---------------------- internal/dockertest/dockertest.go | 5 ++- internal/generator/generator_test.go | 12 ++++++-- pkg/env/env.go | 17 ---------- pkg/errors/errors_test.go | 12 ++++++-- pkg/linalg/linalg_test.go | 12 ++++++-- pkg/log/log_test.go | 15 +++++++-- pkg/retry/retry_test.go | 18 +++++++++-- 13 files changed, 92 insertions(+), 76 deletions(-) delete mode 100644 pkg/env/env.go diff --git a/delivery/http/controller_test.go b/delivery/http/controller_test.go index b2c6652..fd1ff1c 100644 --- a/delivery/http/controller_test.go +++ b/delivery/http/controller_test.go @@ -1,5 +1,3 @@ -//go:build unit - package http import ( @@ -22,6 +20,9 @@ import ( ) func TestControllerHandle(t *testing.T) { + if !*unit { + t.Skip() + } type give struct { handle func() httprouter.Handle method string @@ -284,6 +285,9 @@ func png() string { } func TestControllerError(t *testing.T) { + if !*unit { + t.Skip() + } type give struct { err error } diff --git a/delivery/http/middleware_test.go b/delivery/http/middleware_test.go index d2f1dca..18632fa 100644 --- a/delivery/http/middleware_test.go +++ b/delivery/http/middleware_test.go @@ -1,5 +1,3 @@ -//go:build unit - package http import ( @@ -27,6 +25,9 @@ func (l limiterMockNeg) Allow(_ context.Context, _ uint64) (bool, error) { } func TestMiddlewareRecover(t *testing.T) { + if !*unit { + t.Skip() + } t.Run("Positive", func(t *testing.T) { fn := func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain; charset=utf-8") @@ -60,6 +61,9 @@ func TestMiddlewareRecover(t *testing.T) { } func TestMiddlewareLimit(t *testing.T) { + if !*unit { + t.Skip() + } t.Run("Positive", func(t *testing.T) { fn := func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain; charset=utf-8") @@ -95,6 +99,9 @@ func TestMiddlewareLimit(t *testing.T) { } func TestIP(t *testing.T) { + if !*unit { + t.Skip() + } type args struct { xff string remoteAddr string diff --git a/delivery/http/server_test.go b/delivery/http/server_test.go index 0bdbc91..eceae59 100644 --- a/delivery/http/server_test.go +++ b/delivery/http/server_test.go @@ -1,8 +1,7 @@ -//go:build unit - package http import ( + "flag" "net/http" "net/http/httptest" "testing" @@ -19,7 +18,16 @@ import ( "github.com/zitryss/aye-and-nay/internal/client" ) +var ( + unit = flag.Bool("unit", false, "") + integration = flag.Bool("int", false, "") + ci = flag.Bool("ci", false, "") +) + func TestServer(t *testing.T) { + if !*unit { + t.Skip() + } comp := compressor.NewMock() stor := storage.NewMock() data := database.NewMem(database.DefaultMemConfig) diff --git a/domain/service/queue_integration_test.go b/domain/service/queue_integration_test.go index 2b71313..e26a5ba 100644 --- a/domain/service/queue_integration_test.go +++ b/domain/service/queue_integration_test.go @@ -1,5 +1,3 @@ -//go:build integration - package service import ( @@ -15,6 +13,9 @@ import ( ) func TestPQueueIntegration(t *testing.T) { + if !*integration { + t.Skip() + } id, _ := GenId() redis, err := cache.NewRedis(context.Background(), cache.DefaultRedisConfig) require.NoError(t, err) diff --git a/domain/service/queue_test.go b/domain/service/queue_test.go index 0eaf6fc..94e72c7 100644 --- a/domain/service/queue_test.go +++ b/domain/service/queue_test.go @@ -1,5 +1,3 @@ -//go:build unit - package service import ( @@ -14,6 +12,9 @@ import ( ) func TestPQueue(t *testing.T) { + if !*unit { + t.Skip() + } id, _ := GenId() mem := cache.NewMem(cache.DefaultMemConfig) pqueue := id() diff --git a/domain/service/service_integration_test.go b/domain/service/service_integration_test.go index c16cd50..3f39b24 100644 --- a/domain/service/service_integration_test.go +++ b/domain/service/service_integration_test.go @@ -1,11 +1,7 @@ -//go:build integration - package service import ( "context" - "io" - "os" "testing" "time" @@ -19,42 +15,10 @@ import ( "github.com/zitryss/aye-and-nay/infrastructure/compressor" "github.com/zitryss/aye-and-nay/infrastructure/database" "github.com/zitryss/aye-and-nay/infrastructure/storage" - "github.com/zitryss/aye-and-nay/internal/dockertest" . "github.com/zitryss/aye-and-nay/internal/generator" . "github.com/zitryss/aye-and-nay/internal/testing" - "github.com/zitryss/aye-and-nay/pkg/env" - "github.com/zitryss/aye-and-nay/pkg/log" ) -func TestMain(m *testing.M) { - _, err := env.Lookup("CONTINUOUS_INTEGRATION") - if err != nil { - log.SetOutput(os.Stderr) - log.SetLevel(log.CRITICAL) - docker := dockertest.New() - host := &cache.DefaultRedisConfig.Host - port := &cache.DefaultRedisConfig.Port - docker.RunRedis(host, port) - host = &compressor.DefaultImaginaryConfig.Host - port = &compressor.DefaultImaginaryConfig.Port - docker.RunImaginary(host, port) - host = &database.DefaultMongoConfig.Host - port = &database.DefaultMongoConfig.Port - docker.RunMongo(host, port) - host = &storage.DefaultMinioConfig.Host - port = &storage.DefaultMinioConfig.Port - accessKey := storage.DefaultMinioConfig.AccessKey - secretKey := storage.DefaultMinioConfig.SecretKey - docker.RunMinio(host, port, accessKey, secretKey) - log.SetOutput(io.Discard) - code := m.Run() - docker.Purge() - os.Exit(code) - } - code := m.Run() - os.Exit(code) -} - func TestServiceIntegrationAlbum(t *testing.T) { t.Run("Positive", func(t *testing.T) { id, _ := GenId() diff --git a/internal/dockertest/dockertest.go b/internal/dockertest/dockertest.go index 2f78ab6..69c1447 100644 --- a/internal/dockertest/dockertest.go +++ b/internal/dockertest/dockertest.go @@ -6,14 +6,13 @@ import ( "github.com/ory/dockertest/v3" - "github.com/zitryss/aye-and-nay/pkg/env" "github.com/zitryss/aye-and-nay/pkg/errors" "github.com/zitryss/aye-and-nay/pkg/log" ) func New() docker { - host, err := env.Lookup("DOCKER_HOST") - if err != nil { + host, ok := os.LookupEnv("DOCKER_HOST") + if !ok || host == "" { host = "tcp://localhost:2375" } u, err := url.Parse(host) diff --git a/internal/generator/generator_test.go b/internal/generator/generator_test.go index 1bb036a..79d0d30 100644 --- a/internal/generator/generator_test.go +++ b/internal/generator/generator_test.go @@ -1,15 +1,23 @@ -//go:build unit - package generator import ( + "flag" "sync" "testing" "github.com/stretchr/testify/assert" ) +var ( + unit = flag.Bool("unit", false, "") + integration = flag.Bool("int", false, "") + ci = flag.Bool("ci", false, "") +) + func TestGenId(t *testing.T) { + if !*unit { + t.Skip() + } id, ids := GenId() id, ids = GenId() wg := sync.WaitGroup{} diff --git a/pkg/env/env.go b/pkg/env/env.go deleted file mode 100644 index fc2d867..0000000 --- a/pkg/env/env.go +++ /dev/null @@ -1,17 +0,0 @@ -package env - -import ( - "errors" - "os" -) - -func Lookup(key string) (string, error) { - val, ok := os.LookupEnv(key) - if !ok { - return "", errors.New("environment variable " + key + " not found") - } - if val == "" { - return "", errors.New("environment variable " + key + " is empty") - } - return val, nil -} diff --git a/pkg/errors/errors_test.go b/pkg/errors/errors_test.go index f42fc44..3338975 100644 --- a/pkg/errors/errors_test.go +++ b/pkg/errors/errors_test.go @@ -1,8 +1,7 @@ -//go:build unit - package errors_test import ( + "flag" "fmt" "testing" @@ -11,7 +10,16 @@ import ( "github.com/zitryss/aye-and-nay/pkg/errors" ) +var ( + unit = flag.Bool("unit", false, "") + integration = flag.Bool("int", false, "") + ci = flag.Bool("ci", false, "") +) + func TestCause(t *testing.T) { + if !*unit { + t.Skip() + } tests := []struct { give error want error diff --git a/pkg/linalg/linalg_test.go b/pkg/linalg/linalg_test.go index eb91f0c..2a61d56 100644 --- a/pkg/linalg/linalg_test.go +++ b/pkg/linalg/linalg_test.go @@ -1,8 +1,7 @@ -//go:build unit - package linalg_test import ( + "flag" "fmt" "math/rand" "testing" @@ -13,7 +12,16 @@ import ( "github.com/zitryss/aye-and-nay/pkg/linalg" ) +var ( + unit = flag.Bool("unit", false, "") + integration = flag.Bool("int", false, "") + ci = flag.Bool("ci", false, "") +) + func TestPageRank(t *testing.T) { + if !*unit { + t.Skip() + } edgs := map[uint64]map[uint64]int{} edgs[0x5B92] = map[uint64]int{} edgs[0x804F] = map[uint64]int{} diff --git a/pkg/log/log_test.go b/pkg/log/log_test.go index 40412b0..817775f 100644 --- a/pkg/log/log_test.go +++ b/pkg/log/log_test.go @@ -1,8 +1,7 @@ -//go:build unit - package log_test import ( + "flag" "strings" "testing" @@ -11,7 +10,16 @@ import ( "github.com/zitryss/aye-and-nay/pkg/log" ) +var ( + unit = flag.Bool("unit", false, "") + integration = flag.Bool("int", false, "") + ci = flag.Bool("ci", false, "") +) + func TestLogLevelPositive(t *testing.T) { + if !*unit { + t.Skip() + } tests := []struct { level interface{} want string @@ -71,6 +79,9 @@ func TestLogLevelPositive(t *testing.T) { } func TestLogLevelNegative(t *testing.T) { + if !*unit { + t.Skip() + } tests := []struct { level interface{} want string diff --git a/pkg/retry/retry_test.go b/pkg/retry/retry_test.go index 66c47f9..c1ee40e 100644 --- a/pkg/retry/retry_test.go +++ b/pkg/retry/retry_test.go @@ -1,8 +1,7 @@ -//go:build unit - package retry_test import ( + "flag" "testing" "time" @@ -12,7 +11,16 @@ import ( "github.com/zitryss/aye-and-nay/pkg/retry" ) +var ( + unit = flag.Bool("unit", false, "") + integration = flag.Bool("int", false, "") + ci = flag.Bool("ci", false, "") +) + func TestDo1(t *testing.T) { + if !*unit { + t.Skip() + } type give struct { times int pause time.Duration @@ -69,6 +77,9 @@ func TestDo1(t *testing.T) { } func TestDo2(t *testing.T) { + if !*unit { + t.Skip() + } type give struct { times int pause time.Duration @@ -125,6 +136,9 @@ func TestDo2(t *testing.T) { } func TestDo3(t *testing.T) { + if !*unit { + t.Skip() + } type give struct { times int pause time.Duration From 322fc54d049372343b02316b24e41db4650805ce Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Wed, 23 Feb 2022 09:49:27 +0100 Subject: [PATCH 58/92] Minor improvements --- delivery/http/config.go | 7 ++-- delivery/http/controller.go | 22 +++++++----- domain/domain/error.go | 54 ++++++++++++++-------------- infrastructure/cache/mem_test.go | 3 -- infrastructure/database/mem_test.go | 2 +- internal/generator/generator.go | 34 ++++++++++++------ internal/generator/generator_test.go | 10 +++--- internal/testing/testing.go | 2 +- main.go | 6 ++-- pkg/unit/unit.go | 8 ----- 10 files changed, 79 insertions(+), 69 deletions(-) delete mode 100644 pkg/unit/unit.go diff --git a/delivery/http/config.go b/delivery/http/config.go index ec753c3..0879753 100644 --- a/delivery/http/config.go +++ b/delivery/http/config.go @@ -2,8 +2,11 @@ package http import ( "time" +) - "github.com/zitryss/aye-and-nay/pkg/unit" +const ( + _ int64 = 1 << (10 * iota) + kb ) type ServerConfig struct { @@ -44,6 +47,6 @@ var ( } DefaultControllerConfig = ControllerConfig{ MaxNumberOfFiles: 3, - MaxFileSize: 512 * unit.KB, + MaxFileSize: 512 * kb, } ) diff --git a/delivery/http/controller.go b/delivery/http/controller.go index 84fdc42..9cae6fc 100644 --- a/delivery/http/controller.go +++ b/delivery/http/controller.go @@ -83,19 +83,25 @@ func (c *controller) handleAlbum() httprouter.Handle { _ = f.Close() return nil, albumRequest{}, errors.Wrap(domain.ErrNotImage) } - closeFn := func() error { - switch v := f.(type) { - case *os.File: + F := model.File{} + switch v := f.(type) { + case *os.File: + closeFn := func() error { _ = v.Close() _ = os.Remove(v.Name()) - case multipart.File: + return nil + } + F = model.NewFile(v, closeFn, fh.Size) + case multipart.File: + closeFn := func() error { _ = v.Close() - default: - panic(errors.Wrap(domain.ErrUnknown)) + return nil } - return nil + F = model.NewFile(v, closeFn, fh.Size) + default: + return nil, albumRequest{}, errors.Wrap(domain.ErrUnknown) } - req.ff = append(req.ff, model.NewFile(f, closeFn, fh.Size)) + req.ff = append(req.ff, F) } vals := r.MultipartForm.Value["duration"] if len(vals) == 0 { diff --git a/domain/domain/error.go b/domain/domain/error.go index af1b3b9..974d570 100644 --- a/domain/domain/error.go +++ b/domain/domain/error.go @@ -6,11 +6,11 @@ import ( ) const ( - ldisabled int = iota - ldebug - linfo - lerror - lcritical + logDisabled int = iota + logDebug + logInfo + logError + logCritical ) var ( @@ -21,7 +21,7 @@ var ( UserMsg: "too many requests", }, innerError: innerError{ - Level: ldebug, + Level: logDebug, DevMsg: "too many requests", }, } @@ -32,7 +32,7 @@ var ( UserMsg: "body too large", }, innerError: innerError{ - Level: ldebug, + Level: logDebug, DevMsg: "body too large", }, } @@ -43,7 +43,7 @@ var ( UserMsg: "unsupported media type", }, innerError: innerError{ - Level: ldebug, + Level: logDebug, DevMsg: "wrong content type", }, } @@ -54,7 +54,7 @@ var ( UserMsg: "not enough images", }, innerError: innerError{ - Level: ldebug, + Level: logDebug, DevMsg: "not enough images", }, } @@ -65,7 +65,7 @@ var ( UserMsg: "too many images", }, innerError: innerError{ - Level: ldebug, + Level: logDebug, DevMsg: "too many images", }, } @@ -76,7 +76,7 @@ var ( UserMsg: "image too large", }, innerError: innerError{ - Level: ldebug, + Level: logDebug, DevMsg: "image too large", }, } @@ -87,7 +87,7 @@ var ( UserMsg: "unsupported media type", }, innerError: innerError{ - Level: ldebug, + Level: logDebug, DevMsg: "not an image", }, } @@ -98,7 +98,7 @@ var ( UserMsg: "duration not set", }, innerError: innerError{ - Level: ldebug, + Level: logDebug, DevMsg: "duration not set", }, } @@ -109,7 +109,7 @@ var ( UserMsg: "duration invalid", }, innerError: innerError{ - Level: ldebug, + Level: logDebug, DevMsg: "duration invalid", }, } @@ -120,7 +120,7 @@ var ( UserMsg: "album not found", }, innerError: innerError{ - Level: ldebug, + Level: logDebug, DevMsg: "album not found", }, } @@ -131,7 +131,7 @@ var ( UserMsg: "internal server error", }, innerError: innerError{ - Level: lerror, + Level: logError, DevMsg: "pair not found", }, } @@ -142,7 +142,7 @@ var ( UserMsg: "token not found", }, innerError: innerError{ - Level: ldebug, + Level: logDebug, DevMsg: "token not found", }, } @@ -153,7 +153,7 @@ var ( UserMsg: "internal server error", }, innerError: innerError{ - Level: lerror, + Level: logError, DevMsg: "image not found", }, } @@ -164,7 +164,7 @@ var ( UserMsg: "internal server error", }, innerError: innerError{ - Level: lerror, + Level: logError, DevMsg: "album already exists", }, } @@ -175,7 +175,7 @@ var ( UserMsg: "internal server error", }, innerError: innerError{ - Level: lerror, + Level: logError, DevMsg: "token already exists", }, } @@ -186,7 +186,7 @@ var ( UserMsg: "unsupported media type", }, innerError: innerError{ - Level: lerror, + Level: logError, DevMsg: "image rejected by third party", }, } @@ -197,7 +197,7 @@ var ( UserMsg: "internal server error", }, innerError: innerError{ - Level: lcritical, + Level: logCritical, DevMsg: "third party is unavailable", }, } @@ -208,7 +208,7 @@ var ( UserMsg: "internal server error", }, innerError: innerError{ - Level: lcritical, + Level: logCritical, DevMsg: "compressor is unavailable", }, } @@ -219,7 +219,7 @@ var ( UserMsg: "internal server error", }, innerError: innerError{ - Level: lcritical, + Level: logCritical, DevMsg: "storage is unavailable", }, } @@ -230,7 +230,7 @@ var ( UserMsg: "internal server error", }, innerError: innerError{ - Level: lcritical, + Level: logCritical, DevMsg: "database is unavailable", }, } @@ -241,7 +241,7 @@ var ( UserMsg: "internal server error", }, innerError: innerError{ - Level: lcritical, + Level: logCritical, DevMsg: "cache is unavailable", }, } @@ -252,7 +252,7 @@ var ( UserMsg: "internal server error", }, innerError: innerError{ - Level: lerror, + Level: logError, DevMsg: "unknown", }, } diff --git a/infrastructure/cache/mem_test.go b/infrastructure/cache/mem_test.go index 3e19f3d..7e623d3 100644 --- a/infrastructure/cache/mem_test.go +++ b/infrastructure/cache/mem_test.go @@ -61,9 +61,6 @@ func (suite *MemTestSuite) TearDownTest() { func (suite *MemTestSuite) TearDownSuite() { err := suite.cache.(*Mem).Reset() require.NoError(suite.T(), err) - close(suite.heartbeatCleanup) - close(suite.heartbeatPair) - close(suite.heartbeatToken) suite.cancel() } diff --git a/infrastructure/database/mem_test.go b/infrastructure/database/mem_test.go index e1310e4..ea5a74d 100644 --- a/infrastructure/database/mem_test.go +++ b/infrastructure/database/mem_test.go @@ -53,7 +53,7 @@ func (suite *MemTestSuite) TearDownSuite() { suite.cancel() } -func (suite *MemTestSuite) saveAlbum(id func() uint64, ids Ids) model.Album { +func (suite *MemTestSuite) saveAlbum(id IdGenFunc, ids Ids) model.Album { suite.T().Helper() alb := AlbumFactory(id, ids) err := suite.db.SaveAlbum(suite.ctx, alb) diff --git a/internal/generator/generator.go b/internal/generator/generator.go index c3bdcf2..fdf39e7 100644 --- a/internal/generator/generator.go +++ b/internal/generator/generator.go @@ -8,7 +8,7 @@ import ( ) const ( - IDS_SPAN = 100 + span = 100 ) var ( @@ -16,22 +16,24 @@ var ( indexId uint64 ) +type IdGenFunc func() uint64 + type Ids interface { Uint64(i int) uint64 Base64(i int) string } -func GenId() (func() uint64, *syncLogBook) { - lb := syncLogBook{m: sync.Mutex{}, logBook: map[int]uint64{}} - fn := func() func() uint64 { +func GenId() (IdGenFunc, *IdLogBook) { + lb := IdLogBook{m: sync.Mutex{}, logBook: map[int]uint64{}, valid: true} + fn := func() IdGenFunc { m.Lock() firstId := indexId - indexId += IDS_SPAN + indexId += span m.Unlock() mFn := sync.Mutex{} i := -1 curId := firstId - 1 - lastId := firstId + IDS_SPAN - 1 + lastId := firstId + span - 1 return func() uint64 { mFn.Lock() i++ @@ -48,18 +50,28 @@ func GenId() (func() uint64, *syncLogBook) { return fn(), &lb } -type syncLogBook struct { +type IdLogBook struct { m sync.Mutex logBook map[int]uint64 + valid bool } -func (lb *syncLogBook) set(i int, id uint64) { +func (lb *IdLogBook) set(i int, id uint64) { + if lb == nil || !lb.valid { + return + } lb.m.Lock() defer lb.m.Unlock() - lb.logBook[i] = id + _, ok := lb.logBook[i] + if ok { + lb.logBook[i] = id + } } -func (lb *syncLogBook) Uint64(i int) uint64 { +func (lb *IdLogBook) Uint64(i int) uint64 { + if lb == nil || !lb.valid { + return 0x0 + } lb.m.Lock() defer lb.m.Unlock() id, ok := lb.logBook[i] @@ -69,6 +81,6 @@ func (lb *syncLogBook) Uint64(i int) uint64 { return id } -func (lb *syncLogBook) Base64(i int) string { +func (lb *IdLogBook) Base64(i int) string { return base64.FromUint64(lb.Uint64(i)) } diff --git a/internal/generator/generator_test.go b/internal/generator/generator_test.go index 79d0d30..b53af77 100644 --- a/internal/generator/generator_test.go +++ b/internal/generator/generator_test.go @@ -27,29 +27,29 @@ func TestGenId(t *testing.T) { assert.NotPanics(t, func() { go func() { defer wg.Done() - for i := 0; i < IDS_SPAN/2; i++ { + for i := 0; i < span/2; i++ { _ = id() } ch1 <- struct{}{} <-ch2 - for i := 0; i < IDS_SPAN/2; i++ { + for i := 0; i < span/2; i++ { _ = ids.Uint64(i) } }() go func() { defer wg.Done() - for i := IDS_SPAN / 2; i < IDS_SPAN; i++ { + for i := span / 2; i < span; i++ { _ = id() } ch2 <- struct{}{} <-ch1 - for i := IDS_SPAN / 2; i < IDS_SPAN; i++ { + for i := span / 2; i < span; i++ { _ = ids.Uint64(i) } }() }) wg.Wait() - assert.Len(t, ids.logBook, IDS_SPAN) + assert.Len(t, ids.logBook, span) assert.Equal(t, ids.logBook[0], uint64(100)) assert.Equal(t, ids.logBook[len(ids.logBook)-1], uint64(199)) assert.Panics(t, func() { id() }) diff --git a/internal/testing/testing.go b/internal/testing/testing.go index bfb071a..0656af1 100644 --- a/internal/testing/testing.go +++ b/internal/testing/testing.go @@ -27,7 +27,7 @@ func Png() model.File { return model.File{Reader: buf, Size: int64(buf.Len())} } -func AlbumFactory(id func() uint64, ids Ids) model.Album { +func AlbumFactory(id IdGenFunc, ids Ids) model.Album { album := id() img1 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.48954984} img2 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.19186324} diff --git a/main.go b/main.go index 39188b5..89aeb52 100644 --- a/main.go +++ b/main.go @@ -94,7 +94,7 @@ func main() { qCalc.Monitor(ctx) qComp := &service.QueueComp{} - if conf.Compressor.IsMock() { + if !conf.Compressor.IsMock() { qComp = service.NewQueueComp(cach) qComp.Monitor(ctx) } @@ -117,7 +117,7 @@ func main() { gComp := (*errgroup.Group)(nil) ctxComp := context.Context(nil) - if conf.Compressor.IsMock() { + if !conf.Compressor.IsMock() { gComp, ctxComp = errgroup.WithContext(ctx) log.Info("starting compression worker pool") serv.StartWorkingPoolComp(ctxComp, gComp) @@ -155,7 +155,7 @@ func main() { log.Error(err) } - if conf.Compressor.IsMock() { + if !conf.Compressor.IsMock() { log.Info("stopping compression worker pool") err = gComp.Wait() if err != nil { diff --git a/pkg/unit/unit.go b/pkg/unit/unit.go deleted file mode 100644 index 10877a5..0000000 --- a/pkg/unit/unit.go +++ /dev/null @@ -1,8 +0,0 @@ -package unit - -const ( - _ int64 = 1 << (10 * iota) - KB - MB - GB -) From 6b4b14d7e9b8cbf0172024e891cc3023a6efc771 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Wed, 16 Mar 2022 16:20:38 +0100 Subject: [PATCH 59/92] Various small changes --- delivery/http/config.go | 3 +-- ulimit.go => internal/ulimit/ulimit.go | 18 +++++------------- internal/ulimit/ulimit_windows.go | 5 +++++ main.go | 7 +++++++ 4 files changed, 18 insertions(+), 15 deletions(-) rename ulimit.go => internal/ulimit/ulimit.go (58%) create mode 100644 internal/ulimit/ulimit_windows.go diff --git a/delivery/http/config.go b/delivery/http/config.go index 0879753..6ef5a4a 100644 --- a/delivery/http/config.go +++ b/delivery/http/config.go @@ -5,8 +5,7 @@ import ( ) const ( - _ int64 = 1 << (10 * iota) - kb + kb = 1 << (10 * 1) ) type ServerConfig struct { diff --git a/ulimit.go b/internal/ulimit/ulimit.go similarity index 58% rename from ulimit.go rename to internal/ulimit/ulimit.go index da5748e..93ca06e 100644 --- a/ulimit.go +++ b/internal/ulimit/ulimit.go @@ -1,22 +1,14 @@ -//go:build !windows - -package main +package ulimit import ( - "fmt" - "os" "syscall" ) -func init() { - err := setUlimit() - if err != nil { - _, _ = fmt.Fprintln(os.Stderr, "critical:", err) - os.Exit(1) - } -} +var ( + SetMax = setMax +) -func setUlimit() error { +func setMax() error { rLimit := syscall.Rlimit{} err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit) if err != nil { diff --git a/internal/ulimit/ulimit_windows.go b/internal/ulimit/ulimit_windows.go new file mode 100644 index 0000000..1a17c4c --- /dev/null +++ b/internal/ulimit/ulimit_windows.go @@ -0,0 +1,5 @@ +package ulimit + +func init() { + SetMax = func() error {} +} diff --git a/main.go b/main.go index 89aeb52..0527202 100644 --- a/main.go +++ b/main.go @@ -17,6 +17,7 @@ import ( "github.com/zitryss/aye-and-nay/infrastructure/database" "github.com/zitryss/aye-and-nay/infrastructure/storage" "github.com/zitryss/aye-and-nay/internal/config" + "github.com/zitryss/aye-and-nay/internal/ulimit" "github.com/zitryss/aye-and-nay/pkg/errors" "github.com/zitryss/aye-and-nay/pkg/log" ) @@ -26,6 +27,12 @@ var ( ) func main() { + err := ulimit.SetMax() + if err != nil { + _, _ = fmt.Fprintln(os.Stderr, "critical:", err) + os.Exit(1) + } + path := "" flag.StringVar(&path, "config", "./config.env", "filepath to a config file") flag.Parse() From 1ca093b2269d8ab58875addc59632c6d497f5e3e Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Thu, 17 Mar 2022 17:18:12 +0100 Subject: [PATCH 60/92] Various test related improvements --- .github/workflows/integration.yml | 8 +- .github/workflows/loadtest.yml | 4 +- .github/workflows/unit.yml | 8 +- Makefile | 8 +- domain/service/service_integration_test.go | 747 +++--------------- domain/service/service_test.go | 697 ++++++---------- infrastructure/cache/mem_test.go | 12 + .../cache/redis_integration_test.go | 7 +- .../database/badger_integration_test.go | 1 + infrastructure/database/mem_test.go | 30 +- .../database/mongo_integration_test.go | 1 + .../storage/minio_integration_test.go | 10 +- internal/generator/generator.go | 3 +- internal/generator/generator_test.go | 2 - 14 files changed, 423 insertions(+), 1115 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 1d601a0..f21aa08 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -7,8 +7,8 @@ jobs: integration: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 with: go-version: 1.17 - uses: actions/cache@v2 @@ -21,7 +21,7 @@ jobs: CONTINUOUS_INTEGRATION: "true" run: make test-int-ci - run: make dev-down - - uses: codecov/codecov-action@v1 + - uses: codecov/codecov-action@v2 with: token: ${{ secrets.CODECOV_TOKEN }} - file: ./coverage.txt + files: ./coverage.txt diff --git a/.github/workflows/loadtest.yml b/.github/workflows/loadtest.yml index abf525b..c92566e 100644 --- a/.github/workflows/loadtest.yml +++ b/.github/workflows/loadtest.yml @@ -7,8 +7,8 @@ jobs: loadtest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 with: go-version: 1.17 - uses: actions/cache@v2 diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index dba8e0a..b9fbfb4 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -7,8 +7,8 @@ jobs: unit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 with: go-version: 1.17 - uses: actions/cache@v2 @@ -17,7 +17,7 @@ jobs: key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-go- - run: make test-unit-ci - - uses: codecov/codecov-action@v1 + - uses: codecov/codecov-action@v2 with: token: ${{ secrets.CODECOV_TOKEN }} - file: ./coverage.txt + files: ./coverage.txt diff --git a/Makefile b/Makefile index 37715f8..4bcc54a 100644 --- a/Makefile +++ b/Makefile @@ -12,16 +12,16 @@ compile-health: CGO_ENABLED=0 go build -ldflags="-s -w" -o healthcheck ./cmd/healthcheck/main.go test-unit: gen - go test -v -race -shuffle=on -count=1 -short -tags=unit -cover ./... + go test -v -race -shuffle=on -count=2 -short -cover ./... -args -unit test-int: gen - go test -v -race -shuffle=on -count=1 -short -tags=integration -cover ./... + go test -v -race -shuffle=on -count=2 -short -cover ./... -args -int test-unit-ci: gen - go test -v -race -shuffle=on -count=1 -tags=unit -failfast -coverprofile=coverage.txt -covermode=atomic ./... + go test -v -race -shuffle=on -count=2 -failfast -coverprofile=coverage.txt -covermode=atomic ./... -args -unit -ci test-int-ci: gen - go test -v -race -shuffle=on -count=1 -tags=integration -failfast -coverprofile=coverage.txt -covermode=atomic ./... + go test -v -race -shuffle=on -count=2 -failfast -coverprofile=coverage.txt -covermode=atomic ./... -args -int -ci dev-up: docker compose --file ./build/docker-compose-dev.yml up -d --build diff --git a/domain/service/service_integration_test.go b/domain/service/service_integration_test.go index 3f39b24..577d101 100644 --- a/domain/service/service_integration_test.go +++ b/domain/service/service_integration_test.go @@ -3,665 +3,136 @@ package service import ( "context" "testing" - "time" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" "golang.org/x/sync/errgroup" - "github.com/zitryss/aye-and-nay/domain/domain" - "github.com/zitryss/aye-and-nay/domain/model" "github.com/zitryss/aye-and-nay/infrastructure/cache" "github.com/zitryss/aye-and-nay/infrastructure/compressor" "github.com/zitryss/aye-and-nay/infrastructure/database" "github.com/zitryss/aye-and-nay/infrastructure/storage" . "github.com/zitryss/aye-and-nay/internal/generator" - . "github.com/zitryss/aye-and-nay/internal/testing" ) -func TestServiceIntegrationAlbum(t *testing.T) { - t.Run("Positive", func(t *testing.T) { - id, _ := GenId() - idQ, _ := GenId() - fnId := func() func() (uint64, error) { - return func() (uint64, error) { - return id(), nil - } - }() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - require.NoError(t, err) - minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - require.NoError(t, err) - mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - require.NoError(t, err) - redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - require.NoError(t, err) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{newQueue(idQ(), redis)} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - heartbeatComp := make(chan interface{}) - serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fnId), WithHeartbeatComp(heartbeatComp)) - gComp, ctxComp := errgroup.WithContext(ctx) - serv.StartWorkingPoolComp(ctxComp, gComp) - files := []model.File{Png(), Png()} - _, err = serv.Album(ctx, files, 0*time.Millisecond) - assert.NoError(t, err) - v := AssertChannel(t, heartbeatComp) - p, ok := v.(float64) - assert.True(t, ok) - assert.InDelta(t, 0.5, p, TOLERANCE) - v = AssertChannel(t, heartbeatComp) - p, ok = v.(float64) - assert.True(t, ok) - assert.InDelta(t, 1, p, TOLERANCE) - }) - t.Run("Negative", func(t *testing.T) { - id, _ := GenId() - idQ, _ := GenId() - fnId := func() func() (uint64, error) { - return func() (uint64, error) { - return id(), nil - } - }() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - heartbeatRestart := make(chan interface{}) - comp := compressor.NewShortpixel(compressor.DefaultShortpixelConfig, compressor.WithHeartbeatRestart(heartbeatRestart)) - comp.Monitor(ctx) - minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - require.NoError(t, err) - mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - require.NoError(t, err) - redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - require.NoError(t, err) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{newQueue(idQ(), redis)} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - heartbeatComp := make(chan interface{}) - serv := New(DefaultServiceConfig, comp, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fnId), WithHeartbeatComp(heartbeatComp)) - gComp, ctxComp := errgroup.WithContext(ctx) - serv.StartWorkingPoolComp(ctxComp, gComp) - files := []model.File{Png(), Png()} - _, err = serv.Album(ctx, files, 0*time.Millisecond) - assert.NoError(t, err) - v := AssertChannel(t, heartbeatComp) - _ = AssertChannel(t, heartbeatComp) - err, ok := v.(error) - assert.True(t, ok) - assert.ErrorIs(t, err, domain.ErrThirdPartyUnavailable) - files = []model.File{Png(), Png()} - _, err = serv.Album(ctx, files, 0*time.Millisecond) - assert.NoError(t, err) - v = AssertChannel(t, heartbeatComp) - p, ok := v.(float64) - assert.True(t, ok) - assert.InDelta(t, 0.5, p, TOLERANCE) - v = AssertChannel(t, heartbeatComp) - p, ok = v.(float64) - assert.True(t, ok) - assert.InDelta(t, 1, p, TOLERANCE) - AssertChannel(t, heartbeatRestart) - AssertChannel(t, heartbeatRestart) - files = []model.File{Png(), Png()} - _, err = serv.Album(ctx, files, 0*time.Millisecond) - assert.NoError(t, err) - v = AssertChannel(t, heartbeatComp) - _ = AssertChannel(t, heartbeatComp) - err, ok = v.(error) - assert.True(t, ok) - assert.ErrorIs(t, err, domain.ErrThirdPartyUnavailable) - files = []model.File{Png(), Png()} - _, err = serv.Album(ctx, files, 0*time.Millisecond) - assert.NoError(t, err) - v = AssertChannel(t, heartbeatComp) - p, ok = v.(float64) - assert.True(t, ok) - assert.InDelta(t, 0.5, p, TOLERANCE) - v = AssertChannel(t, heartbeatComp) - p, ok = v.(float64) - assert.True(t, ok) - assert.InDelta(t, 1, p, TOLERANCE) - }) +func TestServiceIntegrationTestSuite(t *testing.T) { + suite.Run(t, &ServiceIntegrationTestSuite{}) } -func TestServiceIntegrationPair(t *testing.T) { - t.Run("Positive1", func(t *testing.T) { - id, ids := GenId() - fnId := func() func() (uint64, error) { - return func() (uint64, error) { - return id(), nil - } - }() - fnS := func(n int, swap func(i int, j int)) {} - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - require.NoError(t, err) - minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - require.NoError(t, err) - mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - require.NoError(t, err) - redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - require.NoError(t, err) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) - files := []model.File{Png(), Png()} - album, err := serv.Album(ctx, files, 0*time.Millisecond) - assert.NoError(t, err) - img7, img8, err := serv.Pair(ctx, album) - assert.NoError(t, err) - img1 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(3), Src: "/api/images/" + ids.Base64(3) + "/"} - img2 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(4), Src: "/api/images/" + ids.Base64(4) + "/"} - imgs1 := []model.Image{img1, img2} - assert.NotEqual(t, img7, img8) - assert.Contains(t, imgs1, img7) - assert.Contains(t, imgs1, img8) - img9, img10, err := serv.Pair(ctx, album) - assert.NoError(t, err) - img3 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(5), Src: "/api/images/" + ids.Base64(5) + "/"} - img4 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(6), Src: "/api/images/" + ids.Base64(6) + "/"} - imgs2 := []model.Image{img3, img4} - assert.NotEqual(t, img9, img10) - assert.Contains(t, imgs2, img9) - assert.Contains(t, imgs2, img10) - img11, img12, err := serv.Pair(ctx, album) - assert.NoError(t, err) - img5 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(7), Src: "/api/images/" + ids.Base64(7) + "/"} - img6 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(8), Src: "/api/images/" + ids.Base64(8) + "/"} - imgs3 := []model.Image{img5, img6} - assert.NotEqual(t, img11, img12) - assert.Contains(t, imgs3, img11) - assert.Contains(t, imgs3, img12) - }) - t.Run("Positive2", func(t *testing.T) { - id, ids := GenId() - fnId := func() func() (uint64, error) { - return func() (uint64, error) { - return id(), nil - } - }() - fnS := func(n int, swap func(i int, j int)) {} - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - require.NoError(t, err) - minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - require.NoError(t, err) - mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - require.NoError(t, err) - redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - require.NoError(t, err) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - conf := DefaultServiceConfig - conf.TempLinks = false - serv := New(conf, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) - files := []model.File{Png(), Png()} - album, err := serv.Album(ctx, files, 0*time.Millisecond) - assert.NoError(t, err) - img7, img8, err := serv.Pair(ctx, album) - assert.NoError(t, err) - img1 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1)} - img2 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2)} - imgs1 := []model.Image{img1, img2} - assert.NotEqual(t, img7, img8) - assert.Contains(t, imgs1, img7) - assert.Contains(t, imgs1, img8) - img9, img10, err := serv.Pair(ctx, album) - assert.NoError(t, err) - img3 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2)} - img4 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1)} - imgs2 := []model.Image{img3, img4} - assert.NotEqual(t, img9, img10) - assert.Contains(t, imgs2, img9) - assert.Contains(t, imgs2, img10) - img11, img12, err := serv.Pair(ctx, album) - assert.NoError(t, err) - img5 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1)} - img6 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2)} - imgs3 := []model.Image{img5, img6} - assert.NotEqual(t, img11, img12) - assert.Contains(t, imgs3, img11) - assert.Contains(t, imgs3, img12) - }) - t.Run("Negative", func(t *testing.T) { - id, _ := GenId() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - require.NoError(t, err) - minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - require.NoError(t, err) - mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - require.NoError(t, err) - redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - require.NoError(t, err) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel) - _, _, err = serv.Pair(ctx, id()) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) +type ServiceIntegrationTestSuite struct { + suite.Suite + base ServiceTestSuite } -func TestServiceIntegrationImage(t *testing.T) { - t.Run("Positive", func(t *testing.T) { - id, _ := GenId() - fnId := func() func() (uint64, error) { - return func() (uint64, error) { - return id(), nil - } - }() - fnS := func(n int, swap func(i int, j int)) {} - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - require.NoError(t, err) - minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - require.NoError(t, err) - mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - require.NoError(t, err) - redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - require.NoError(t, err) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) - files := []model.File{Png(), Png()} - album, err := serv.Album(ctx, files, 0*time.Millisecond) - assert.NoError(t, err) - img1, img2, err := serv.Pair(ctx, album) - assert.NoError(t, err) - f, err := serv.Image(ctx, img1.Token) - assert.NoError(t, err) - assert.NotNil(t, f.Reader) - f, err = serv.Image(ctx, img2.Token) - assert.NoError(t, err) - assert.NotNil(t, f.Reader) - }) - t.Run("Negative", func(t *testing.T) { - id, _ := GenId() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - require.NoError(t, err) - minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - require.NoError(t, err) - mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - require.NoError(t, err) - redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - require.NoError(t, err) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel) - _, err = serv.Image(ctx, id()) - assert.ErrorIs(t, err, domain.ErrTokenNotFound) - }) +func (suite *ServiceIntegrationTestSuite) SetupSuite() { + if !*integration { + suite.T().Skip() + } + suite.base = ServiceTestSuite{} + suite.base.SetT(suite.T()) + ctx, cancel := context.WithCancel(context.Background()) + comp, err := compressor.New(ctx, compressor.CompressorConfig{Compressor: "mock"}) + require.NoError(suite.T(), err) + stor, err := storage.New(ctx, storage.StorageConfig{Storage: "minio", Minio: storage.DefaultMinioConfig}) + require.NoError(suite.T(), err) + data, err := database.New(ctx, database.DatabaseConfig{Database: "mongo", Mongo: database.DefaultMongoConfig}) + require.NoError(suite.T(), err) + cach, err := cache.New(ctx, cache.CacheConfig{Cache: "redis", Redis: cache.DefaultRedisConfig}) + require.NoError(suite.T(), err) + qCalc := NewQueueCalc(cach) + qCalc.Monitor(ctx) + qComp := NewQueueComp(cach) + qComp.Monitor(ctx) + qDel := NewQueueDel(cach) + qDel.Monitor(ctx) + fnShuffle := func(n int, swap func(i int, j int)) {} + heartbeatComp := make(chan interface{}) + heartbeatCalc := make(chan interface{}) + heartbeatDel := make(chan interface{}) + serv := New(DefaultServiceConfig, comp, stor, data, cach, qCalc, qComp, qDel, + WithRandShuffle(fnShuffle), + WithHeartbeatComp(heartbeatComp), + WithHeartbeatCalc(heartbeatCalc), + WithHeartbeatDel(heartbeatDel), + ) + gComp, ctxComp := errgroup.WithContext(ctx) + serv.StartWorkingPoolComp(ctxComp, gComp) + gCalc, ctxCalc := errgroup.WithContext(ctx) + serv.StartWorkingPoolCalc(ctxCalc, gCalc) + gDel, ctxDel := errgroup.WithContext(ctx) + serv.StartWorkingPoolDel(ctxDel, gDel) + suite.base.ctx = ctx + suite.base.cancel = cancel + suite.base.heartbeatComp = heartbeatComp + suite.base.heartbeatCalc = heartbeatCalc + suite.base.heartbeatDel = heartbeatDel + suite.base.serv = serv + suite.base.gComp = gComp + suite.base.gCalc = gComp + suite.base.gDel = gComp + suite.base.setupTestFn = suite.SetupTest } -func TestServiceIntegrationVote(t *testing.T) { - t.Run("Positive1", func(t *testing.T) { - id, _ := GenId() - fnId := func() func() (uint64, error) { - return func() (uint64, error) { - return id(), nil - } - }() - fnS := func(n int, swap func(i int, j int)) {} - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - require.NoError(t, err) - minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - require.NoError(t, err) - mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - require.NoError(t, err) - redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - require.NoError(t, err) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) - files := []model.File{Png(), Png()} - album, err := serv.Album(ctx, files, 0*time.Millisecond) - assert.NoError(t, err) - img1, img2, err := serv.Pair(ctx, album) - assert.NoError(t, err) - err = serv.Vote(ctx, album, img1.Token, img2.Token) - assert.NoError(t, err) - }) - t.Run("Positive2", func(t *testing.T) { - id, _ := GenId() - fnId := func() func() (uint64, error) { - return func() (uint64, error) { - return id(), nil - } - }() - fnS := func(n int, swap func(i int, j int)) {} - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - require.NoError(t, err) - minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - require.NoError(t, err) - mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - require.NoError(t, err) - redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - require.NoError(t, err) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - conf := DefaultServiceConfig - conf.TempLinks = false - serv := New(conf, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) - files := []model.File{Png(), Png()} - album, err := serv.Album(ctx, files, 0*time.Millisecond) - assert.NoError(t, err) - img1, img2, err := serv.Pair(ctx, album) - assert.NoError(t, err) - err = serv.Vote(ctx, album, img1.Token, img2.Token) - assert.NoError(t, err) - }) - t.Run("Negative1", func(t *testing.T) { - id, _ := GenId() - fnId := func() func() (uint64, error) { - return func() (uint64, error) { - return id(), nil - } - }() - fnS := func(n int, swap func(i int, j int)) {} - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - require.NoError(t, err) - minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - require.NoError(t, err) - mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - require.NoError(t, err) - redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - require.NoError(t, err) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) - files := []model.File{Png(), Png()} - album, err := serv.Album(ctx, files, 0*time.Millisecond) - assert.NoError(t, err) - img1, img2, err := serv.Pair(ctx, album) - assert.NoError(t, err) - err = serv.Vote(ctx, id(), img1.Token, img2.Token) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) - t.Run("Negative2", func(t *testing.T) { - id, _ := GenId() - fnId := func() func() (uint64, error) { - return func() (uint64, error) { - return id(), nil - } - }() - fnS := func(n int, swap func(i int, j int)) {} - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - require.NoError(t, err) - minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - require.NoError(t, err) - mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - require.NoError(t, err) - redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - require.NoError(t, err) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) - files := []model.File{Png(), Png()} - album, err := serv.Album(ctx, files, 0*time.Millisecond) - assert.NoError(t, err) - _, _, err = serv.Pair(ctx, album) - assert.NoError(t, err) - err = serv.Vote(ctx, album, id(), id()) - assert.ErrorIs(t, err, domain.ErrTokenNotFound) - }) +func (suite *ServiceIntegrationTestSuite) SetupTest() { + id, ids := GenId() + fnId := func() func() (uint64, error) { + return func() (uint64, error) { + return id(), nil + } + }() + suite.base.id = id + suite.base.ids = ids + suite.base.serv.rand.id = fnId + err := suite.base.serv.stor.(*storage.Minio).Reset() + require.NoError(suite.T(), err) + err = suite.base.serv.pers.(*database.Mongo).Reset() + require.NoError(suite.T(), err) + err = suite.base.serv.cache.(*cache.Redis).Reset() + require.NoError(suite.T(), err) } -func TestServiceIntegrationTop(t *testing.T) { - t.Run("Positive", func(t *testing.T) { - id, ids := GenId() - idQ, _ := GenId() - fnId := func() func() (uint64, error) { - return func() (uint64, error) { - return id(), nil - } - }() - fnS := func(n int, swap func(i int, j int)) {} - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - require.NoError(t, err) - minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - require.NoError(t, err) - mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - require.NoError(t, err) - redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - require.NoError(t, err) - qCalc := &QueueCalc{newQueue(idQ(), redis)} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - heartbeatCalc := make(chan interface{}) - serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS), WithHeartbeatCalc(heartbeatCalc)) - gCalc, ctxCalc := errgroup.WithContext(ctx) - serv.StartWorkingPoolCalc(ctxCalc, gCalc) - files := []model.File{Png(), Png()} - album, err := serv.Album(ctx, files, 0*time.Millisecond) - assert.NoError(t, err) - img1, img2, err := serv.Pair(ctx, album) - assert.NoError(t, err) - err = serv.Vote(ctx, album, img1.Token, img2.Token) - assert.NoError(t, err) - AssertChannel(t, heartbeatCalc) - img3, img4, err := serv.Pair(ctx, album) - assert.NoError(t, err) - err = serv.Vote(ctx, album, img3.Token, img4.Token) - assert.NoError(t, err) - AssertChannel(t, heartbeatCalc) - imgs1, err := serv.Top(ctx, album) - assert.NoError(t, err) - img5 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.5, Compressed: false} - img6 := model.Image{Id: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.5, Compressed: false} - imgs2 := []model.Image{img5, img6} - assert.Equal(t, imgs2, imgs1) - }) - t.Run("Negative", func(t *testing.T) { - id, _ := GenId() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - require.NoError(t, err) - minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - require.NoError(t, err) - mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - require.NoError(t, err) - redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - require.NoError(t, err) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel) - _, err = serv.Top(ctx, id()) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) +func (suite *ServiceIntegrationTestSuite) TearDownTest() { + } -func TestServiceIntegrationDelete(t *testing.T) { - t.Run("Positive1", func(t *testing.T) { - id1, ids1 := GenId() - id2, ids2 := GenId() - idPQ, _ := GenId() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - require.NoError(t, err) - minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - require.NoError(t, err) - mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - require.NoError(t, err) - redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - require.NoError(t, err) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{newPQueue(idPQ(), redis)} - qDel.Monitor(ctx) - alb1 := AlbumFactory(id1, ids1) - alb1.Expires = time.Now().Add(-1 * time.Hour) - err = mongo.SaveAlbum(ctx, alb1) - assert.NoError(t, err) - alb2 := AlbumFactory(id2, ids2) - alb2.Expires = time.Now().Add(1 * time.Hour) - err = mongo.SaveAlbum(ctx, alb2) - assert.NoError(t, err) - heartbeatDel := make(chan interface{}) - serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) - err = serv.CleanUp(ctx) - assert.NoError(t, err) - gDel, ctxDel := errgroup.WithContext(ctx) - serv.StartWorkingPoolDel(ctxDel, gDel) - v := AssertChannel(t, heartbeatDel) - album, ok := v.(uint64) - assert.True(t, ok) - assert.Equal(t, ids1.Uint64(0), album) - t.Cleanup(func() { - _ = mongo.DeleteAlbum(context.Background(), ids1.Uint64(0)) - _ = mongo.DeleteAlbum(context.Background(), ids2.Uint64(0)) - }) - }) - t.Run("Positive2", func(t *testing.T) { - idPQ, _ := GenId() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - require.NoError(t, err) - minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - require.NoError(t, err) - mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - require.NoError(t, err) - redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - require.NoError(t, err) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{newPQueue(idPQ(), redis)} - qDel.Monitor(ctx) - heartbeatDel := make(chan interface{}) - serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) - gDel, ctxDel := errgroup.WithContext(ctx) - serv.StartWorkingPoolDel(ctxDel, gDel) - files := []model.File{Png(), Png()} - dur := 100 * time.Millisecond - album, err := serv.Album(ctx, files, dur) - assert.NoError(t, err) - AssertChannel(t, heartbeatDel) - _, err = serv.Top(ctx, album) - assert.ErrorIs(t, err, domain.ErrAlbumNotFound) - }) - t.Run("Negative", func(t *testing.T) { - idPQ, _ := GenId() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - require.NoError(t, err) - minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - require.NoError(t, err) - mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - require.NoError(t, err) - redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - require.NoError(t, err) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{newPQueue(idPQ(), redis)} - qDel.Monitor(ctx) - heartbeatDel := make(chan interface{}) - serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) - gDel, ctxDel := errgroup.WithContext(ctx) - serv.StartWorkingPoolDel(ctxDel, gDel) - files := []model.File{Png(), Png()} - dur := 0 * time.Second - album, err := serv.Album(ctx, files, dur) - assert.NoError(t, err) - AssertNotChannel(t, heartbeatDel) - _, err = serv.Top(ctx, album) - assert.NoError(t, err) - }) +func (suite *ServiceIntegrationTestSuite) TearDownSuite() { + suite.base.cancel() + err := suite.base.gDel.Wait() + require.NoError(suite.T(), err) + err = suite.base.gCalc.Wait() + require.NoError(suite.T(), err) + err = suite.base.gComp.Wait() + require.NoError(suite.T(), err) + err = suite.base.serv.stor.(*storage.Minio).Reset() + require.NoError(suite.T(), err) + err = suite.base.serv.pers.(*database.Mongo).Reset() + require.NoError(suite.T(), err) + err = suite.base.serv.cache.(*cache.Redis).Reset() + require.NoError(suite.T(), err) + err = suite.base.serv.pers.(*database.Mongo).Close(suite.base.ctx) + require.NoError(suite.T(), err) + err = suite.base.serv.cache.(*cache.Redis).Close(suite.base.ctx) + require.NoError(suite.T(), err) } -func TestServiceIntegrationHealth(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - imaginary, err := compressor.NewImaginary(ctx, compressor.DefaultImaginaryConfig) - require.NoError(t, err) - minio, err := storage.NewMinio(ctx, storage.DefaultMinioConfig) - require.NoError(t, err) - mongo, err := database.NewMongo(ctx, database.DefaultMongoConfig) - require.NoError(t, err) - redis, err := cache.NewRedis(ctx, cache.DefaultRedisConfig) - require.NoError(t, err) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, imaginary, minio, mongo, redis, qCalc, qComp, qDel) - _, err = serv.Health(ctx) - assert.NoError(t, err) +func (suite *ServiceIntegrationTestSuite) TestServiceIntegrationAlbum() { + suite.base.TestServiceAlbum() +} +func (suite *ServiceIntegrationTestSuite) TestServiceIntegrationPair() { + suite.base.TestServicePair() +} +func (suite *ServiceIntegrationTestSuite) TestServiceIntegrationImage() { + suite.base.TestServiceImage() +} +func (suite *ServiceIntegrationTestSuite) TestServiceIntegrationVote() { + suite.base.TestServiceVote() +} +func (suite *ServiceIntegrationTestSuite) TestServiceIntegrationTop() { + suite.base.TestServiceTop() +} +func (suite *ServiceIntegrationTestSuite) TestServiceIntegrationDelete() { + suite.base.TestServiceDelete() +} +func (suite *ServiceIntegrationTestSuite) TestServiceIntegrationHealth() { + suite.base.TestServiceHealth() } diff --git a/domain/service/service_test.go b/domain/service/service_test.go index fa108d3..613c69a 100644 --- a/domain/service/service_test.go +++ b/domain/service/service_test.go @@ -1,13 +1,16 @@ -//go:build unit - package service import ( "context" + "flag" + "io" + "os" "testing" "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" "golang.org/x/sync/errgroup" "github.com/zitryss/aye-and-nay/domain/domain" @@ -16,582 +19,370 @@ import ( "github.com/zitryss/aye-and-nay/infrastructure/compressor" "github.com/zitryss/aye-and-nay/infrastructure/database" "github.com/zitryss/aye-and-nay/infrastructure/storage" + "github.com/zitryss/aye-and-nay/internal/dockertest" . "github.com/zitryss/aye-and-nay/internal/generator" . "github.com/zitryss/aye-and-nay/internal/testing" + "github.com/zitryss/aye-and-nay/pkg/log" ) -func TestServiceAlbum(t *testing.T) { - t.Run("Positive", func(t *testing.T) { - id, _ := GenId() - idQ, _ := GenId() - fnId := func() func() (uint64, error) { - return func() (uint64, error) { - return id(), nil - } - }() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - comp := compressor.NewMock() - stor := storage.NewMock() - mDb := database.NewMem(database.DefaultMemConfig) - mCache := cache.NewMem(cache.DefaultMemConfig) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{newQueue(idQ(), mCache)} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - heartbeatComp := make(chan interface{}) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fnId), WithHeartbeatComp(heartbeatComp)) - gComp, ctxComp := errgroup.WithContext(ctx) - serv.StartWorkingPoolComp(ctxComp, gComp) - files := []model.File{Png(), Png()} - _, err := serv.Album(ctx, files, 0*time.Millisecond) - assert.NoError(t, err) - v := AssertChannel(t, heartbeatComp) - p, ok := v.(float64) - assert.True(t, ok) - assert.InDelta(t, 0.5, p, TOLERANCE) - v = AssertChannel(t, heartbeatComp) - p, ok = v.(float64) - assert.True(t, ok) - assert.InDelta(t, 1, p, TOLERANCE) - }) - t.Run("Negative", func(t *testing.T) { - id, _ := GenId() - idQ, _ := GenId() - fnId := func() func() (uint64, error) { - return func() (uint64, error) { - return id(), nil - } - }() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - heartbeatRestart := make(chan interface{}) - comp := compressor.NewShortpixel(compressor.DefaultShortpixelConfig, compressor.WithHeartbeatRestart(heartbeatRestart)) - comp.Monitor(ctx) - stor := storage.NewMock() - mDb := database.NewMem(database.DefaultMemConfig) - mCache := cache.NewMem(cache.DefaultMemConfig) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{newQueue(idQ(), mCache)} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - heartbeatComp := make(chan interface{}) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fnId), WithHeartbeatComp(heartbeatComp)) - gComp, ctxComp := errgroup.WithContext(ctx) - serv.StartWorkingPoolComp(ctxComp, gComp) +var ( + unit = flag.Bool("unit", false, "") + integration = flag.Bool("int", false, "") + ci = flag.Bool("ci", false, "") +) + +func TestMain(m *testing.M) { + flag.Parse() + if *ci || !*integration { + code := m.Run() + os.Exit(code) + } + log.SetOutput(os.Stderr) + log.SetLevel(log.CRITICAL) + docker := dockertest.New() + host := &cache.DefaultRedisConfig.Host + port := &cache.DefaultRedisConfig.Port + docker.RunRedis(host, port) + host = &compressor.DefaultImaginaryConfig.Host + port = &compressor.DefaultImaginaryConfig.Port + docker.RunImaginary(host, port) + host = &database.DefaultMongoConfig.Host + port = &database.DefaultMongoConfig.Port + docker.RunMongo(host, port) + host = &storage.DefaultMinioConfig.Host + port = &storage.DefaultMinioConfig.Port + accessKey := storage.DefaultMinioConfig.AccessKey + secretKey := storage.DefaultMinioConfig.SecretKey + docker.RunMinio(host, port, accessKey, secretKey) + log.SetOutput(io.Discard) + code := m.Run() + docker.Purge() + os.Exit(code) +} + +func TestServiceTestSuite(t *testing.T) { + suite.Run(t, &ServiceTestSuite{}) +} + +type ServiceTestSuite struct { + suite.Suite + ctx context.Context + cancel context.CancelFunc + id IdGenFunc + ids *IdLogBook + heartbeatComp chan interface{} + heartbeatCalc chan interface{} + heartbeatDel chan interface{} + serv *Service + gComp *errgroup.Group + gCalc *errgroup.Group + gDel *errgroup.Group + setupTestFn func() +} + +func (suite *ServiceTestSuite) SetupSuite() { + ctx, cancel := context.WithCancel(context.Background()) + comp := compressor.NewMock() + stor := storage.NewMock() + data := database.NewMem(database.DefaultMemConfig) + cach := cache.NewMem(cache.DefaultMemConfig) + qCalc := NewQueueCalc(cach) + qCalc.Monitor(ctx) + qComp := NewQueueComp(cach) + qComp.Monitor(ctx) + qDel := NewQueueDel(cach) + qDel.Monitor(ctx) + fnShuffle := func(n int, swap func(i int, j int)) {} + heartbeatComp := make(chan interface{}) + heartbeatCalc := make(chan interface{}) + heartbeatDel := make(chan interface{}) + serv := New(DefaultServiceConfig, comp, stor, data, cach, qCalc, qComp, qDel, + WithRandShuffle(fnShuffle), + WithHeartbeatComp(heartbeatComp), + WithHeartbeatCalc(heartbeatCalc), + WithHeartbeatDel(heartbeatDel), + ) + gComp, ctxComp := errgroup.WithContext(ctx) + serv.StartWorkingPoolComp(ctxComp, gComp) + gCalc, ctxCalc := errgroup.WithContext(ctx) + serv.StartWorkingPoolCalc(ctxCalc, gCalc) + gDel, ctxDel := errgroup.WithContext(ctx) + serv.StartWorkingPoolDel(ctxDel, gDel) + suite.ctx = ctx + suite.cancel = cancel + suite.heartbeatComp = heartbeatComp + suite.heartbeatCalc = heartbeatCalc + suite.heartbeatDel = heartbeatDel + suite.serv = serv + suite.gComp = gComp + suite.gCalc = gComp + suite.gDel = gComp + suite.setupTestFn = suite.SetupTest +} + +func (suite *ServiceTestSuite) SetupTest() { + id, ids := GenId() + fnId := func() func() (uint64, error) { + return func() (uint64, error) { + return id(), nil + } + }() + suite.id = id + suite.ids = ids + suite.serv.rand.id = fnId + err := suite.serv.pers.(*database.Mem).Reset() + require.NoError(suite.T(), err) + err = suite.serv.cache.(*cache.Mem).Reset() + require.NoError(suite.T(), err) +} + +func (suite *ServiceTestSuite) TearDownTest() { + +} + +func (suite *ServiceTestSuite) TearDownSuite() { + suite.cancel() + err := suite.gDel.Wait() + require.NoError(suite.T(), err) + err = suite.gCalc.Wait() + require.NoError(suite.T(), err) + err = suite.gComp.Wait() + require.NoError(suite.T(), err) + err = suite.serv.pers.(*database.Mem).Reset() + require.NoError(suite.T(), err) + err = suite.serv.cache.(*cache.Mem).Reset() + require.NoError(suite.T(), err) +} + +func (suite *ServiceTestSuite) TestServiceAlbum() { + suite.T().Run("Positive", func(t *testing.T) { + suite.setupTestFn() files := []model.File{Png(), Png()} - _, err := serv.Album(ctx, files, 0*time.Millisecond) + _, err := suite.serv.Album(suite.ctx, files, 0*time.Millisecond) assert.NoError(t, err) - v := AssertChannel(t, heartbeatComp) - _ = AssertChannel(t, heartbeatComp) - err, ok := v.(error) - assert.True(t, ok) - assert.ErrorIs(t, err, domain.ErrThirdPartyUnavailable) - files = []model.File{Png(), Png()} - _, err = serv.Album(ctx, files, 0*time.Millisecond) - assert.NoError(t, err) - v = AssertChannel(t, heartbeatComp) + v := AssertChannel(t, suite.heartbeatComp) p, ok := v.(float64) assert.True(t, ok) assert.InDelta(t, 0.5, p, TOLERANCE) - v = AssertChannel(t, heartbeatComp) - p, ok = v.(float64) - assert.True(t, ok) - assert.InDelta(t, 1, p, TOLERANCE) - AssertChannel(t, heartbeatRestart) - AssertChannel(t, heartbeatRestart) - files = []model.File{Png(), Png()} - _, err = serv.Album(ctx, files, 0*time.Millisecond) - assert.NoError(t, err) - v = AssertChannel(t, heartbeatComp) - _ = AssertChannel(t, heartbeatComp) - err, ok = v.(error) - assert.True(t, ok) - assert.ErrorIs(t, err, domain.ErrThirdPartyUnavailable) - files = []model.File{Png(), Png()} - _, err = serv.Album(ctx, files, 0*time.Millisecond) - assert.NoError(t, err) - v = AssertChannel(t, heartbeatComp) - p, ok = v.(float64) - assert.True(t, ok) - assert.InDelta(t, 0.5, p, TOLERANCE) - v = AssertChannel(t, heartbeatComp) + v = AssertChannel(t, suite.heartbeatComp) p, ok = v.(float64) assert.True(t, ok) assert.InDelta(t, 1, p, TOLERANCE) }) } -func TestServicePair(t *testing.T) { - t.Run("Positive1", func(t *testing.T) { - id, ids := GenId() - fnId := func() func() (uint64, error) { - return func() (uint64, error) { - return id(), nil - } - }() - fnS := func(n int, swap func(i int, j int)) {} - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - comp := compressor.NewMock() - stor := storage.NewMock() - mDb := database.NewMem(database.DefaultMemConfig) - mCache := cache.NewMem(cache.DefaultMemConfig) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) +func (suite *ServiceTestSuite) TestServicePair() { + suite.T().Run("Positive1", func(t *testing.T) { + suite.setupTestFn() files := []model.File{Png(), Png()} - album, err := serv.Album(ctx, files, 0*time.Millisecond) + album, err := suite.serv.Album(suite.ctx, files, 0*time.Millisecond) assert.NoError(t, err) - img7, img8, err := serv.Pair(ctx, album) + img7, img8, err := suite.serv.Pair(suite.ctx, album) assert.NoError(t, err) - img1 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(3), Src: "/api/images/" + ids.Base64(3) + "/"} - img2 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(4), Src: "/api/images/" + ids.Base64(4) + "/"} + img1 := model.Image{Id: suite.ids.Uint64(1), Token: suite.ids.Uint64(3), Src: "/api/images/" + suite.ids.Base64(3) + "/"} + img2 := model.Image{Id: suite.ids.Uint64(2), Token: suite.ids.Uint64(4), Src: "/api/images/" + suite.ids.Base64(4) + "/"} imgs1 := []model.Image{img1, img2} assert.NotEqual(t, img7, img8) assert.Contains(t, imgs1, img7) assert.Contains(t, imgs1, img8) - img9, img10, err := serv.Pair(ctx, album) + img9, img10, err := suite.serv.Pair(suite.ctx, album) assert.NoError(t, err) - img3 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(5), Src: "/api/images/" + ids.Base64(5) + "/"} - img4 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(6), Src: "/api/images/" + ids.Base64(6) + "/"} + img3 := model.Image{Id: suite.ids.Uint64(2), Token: suite.ids.Uint64(5), Src: "/api/images/" + suite.ids.Base64(5) + "/"} + img4 := model.Image{Id: suite.ids.Uint64(1), Token: suite.ids.Uint64(6), Src: "/api/images/" + suite.ids.Base64(6) + "/"} imgs2 := []model.Image{img3, img4} assert.NotEqual(t, img9, img10) assert.Contains(t, imgs2, img9) assert.Contains(t, imgs2, img10) - img11, img12, err := serv.Pair(ctx, album) + img11, img12, err := suite.serv.Pair(suite.ctx, album) assert.NoError(t, err) - img5 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(7), Src: "/api/images/" + ids.Base64(7) + "/"} - img6 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(8), Src: "/api/images/" + ids.Base64(8) + "/"} + img5 := model.Image{Id: suite.ids.Uint64(1), Token: suite.ids.Uint64(7), Src: "/api/images/" + suite.ids.Base64(7) + "/"} + img6 := model.Image{Id: suite.ids.Uint64(2), Token: suite.ids.Uint64(8), Src: "/api/images/" + suite.ids.Base64(8) + "/"} imgs3 := []model.Image{img5, img6} assert.NotEqual(t, img11, img12) assert.Contains(t, imgs3, img11) assert.Contains(t, imgs3, img12) }) - t.Run("Positive2", func(t *testing.T) { - id, ids := GenId() - fnId := func() func() (uint64, error) { - return func() (uint64, error) { - return id(), nil - } - }() - fnS := func(n int, swap func(i int, j int)) {} - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - comp := compressor.NewMock() - stor := storage.NewMock() - mDb := database.NewMem(database.DefaultMemConfig) - mCache := cache.NewMem(cache.DefaultMemConfig) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - conf := DefaultServiceConfig - conf.TempLinks = false - serv := New(conf, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) + suite.T().Run("Positive2", func(t *testing.T) { + suite.setupTestFn() + oldTempLinks := suite.serv.conf.TempLinks + suite.serv.conf.TempLinks = false + defer func() { suite.serv.conf.TempLinks = oldTempLinks }() files := []model.File{Png(), Png()} - album, err := serv.Album(ctx, files, 0*time.Millisecond) + album, err := suite.serv.Album(suite.ctx, files, 0*time.Millisecond) assert.NoError(t, err) - img7, img8, err := serv.Pair(ctx, album) + img7, img8, err := suite.serv.Pair(suite.ctx, album) assert.NoError(t, err) - img1 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1)} - img2 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2)} + img1 := model.Image{Id: suite.ids.Uint64(1), Token: suite.ids.Uint64(1), Src: "/aye-and-nay/albums/" + suite.ids.Base64(0) + "/images/" + suite.ids.Base64(1)} + img2 := model.Image{Id: suite.ids.Uint64(2), Token: suite.ids.Uint64(2), Src: "/aye-and-nay/albums/" + suite.ids.Base64(0) + "/images/" + suite.ids.Base64(2)} imgs1 := []model.Image{img1, img2} assert.NotEqual(t, img7, img8) assert.Contains(t, imgs1, img7) assert.Contains(t, imgs1, img8) - img9, img10, err := serv.Pair(ctx, album) + img9, img10, err := suite.serv.Pair(suite.ctx, album) assert.NoError(t, err) - img3 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2)} - img4 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1)} + img3 := model.Image{Id: suite.ids.Uint64(2), Token: suite.ids.Uint64(2), Src: "/aye-and-nay/albums/" + suite.ids.Base64(0) + "/images/" + suite.ids.Base64(2)} + img4 := model.Image{Id: suite.ids.Uint64(1), Token: suite.ids.Uint64(1), Src: "/aye-and-nay/albums/" + suite.ids.Base64(0) + "/images/" + suite.ids.Base64(1)} imgs2 := []model.Image{img3, img4} assert.NotEqual(t, img9, img10) assert.Contains(t, imgs2, img9) assert.Contains(t, imgs2, img10) - img11, img12, err := serv.Pair(ctx, album) + img11, img12, err := suite.serv.Pair(suite.ctx, album) assert.NoError(t, err) - img5 := model.Image{Id: ids.Uint64(1), Token: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1)} - img6 := model.Image{Id: ids.Uint64(2), Token: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2)} + img5 := model.Image{Id: suite.ids.Uint64(1), Token: suite.ids.Uint64(1), Src: "/aye-and-nay/albums/" + suite.ids.Base64(0) + "/images/" + suite.ids.Base64(1)} + img6 := model.Image{Id: suite.ids.Uint64(2), Token: suite.ids.Uint64(2), Src: "/aye-and-nay/albums/" + suite.ids.Base64(0) + "/images/" + suite.ids.Base64(2)} imgs3 := []model.Image{img5, img6} assert.NotEqual(t, img11, img12) assert.Contains(t, imgs3, img11) assert.Contains(t, imgs3, img12) }) - t.Run("Negative", func(t *testing.T) { - id, _ := GenId() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - comp := compressor.NewMock() - stor := storage.NewMock() - mDb := database.NewMem(database.DefaultMemConfig) - mCache := cache.NewMem(cache.DefaultMemConfig) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel) - _, _, err := serv.Pair(ctx, id()) + suite.T().Run("Negative", func(t *testing.T) { + suite.setupTestFn() + _, _, err := suite.serv.Pair(suite.ctx, suite.id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } -func TestServiceImage(t *testing.T) { - t.Run("Positive", func(t *testing.T) { - id, _ := GenId() - fnId := func() func() (uint64, error) { - return func() (uint64, error) { - return id(), nil - } - }() - fnS := func(n int, swap func(i int, j int)) {} - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - comp := compressor.NewMock() - stor := storage.NewMock() - mDb := database.NewMem(database.DefaultMemConfig) - mCache := cache.NewMem(cache.DefaultMemConfig) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) +func (suite *ServiceTestSuite) TestServiceImage() { + suite.T().Run("Positive", func(t *testing.T) { + suite.setupTestFn() files := []model.File{Png(), Png()} - album, err := serv.Album(ctx, files, 0*time.Millisecond) + album, err := suite.serv.Album(suite.ctx, files, 0*time.Millisecond) assert.NoError(t, err) - img1, img2, err := serv.Pair(ctx, album) + img1, img2, err := suite.serv.Pair(suite.ctx, album) assert.NoError(t, err) - f, err := serv.Image(ctx, img1.Token) + f, err := suite.serv.Image(suite.ctx, img1.Token) assert.NoError(t, err) assert.NotNil(t, f.Reader) - f, err = serv.Image(ctx, img2.Token) + f, err = suite.serv.Image(suite.ctx, img2.Token) assert.NoError(t, err) assert.NotNil(t, f.Reader) }) - t.Run("Negative", func(t *testing.T) { - id, _ := GenId() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - comp := compressor.NewMock() - stor := storage.NewMock() - mDb := database.NewMem(database.DefaultMemConfig) - mCache := cache.NewMem(cache.DefaultMemConfig) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel) - _, err := serv.Image(ctx, id()) + suite.T().Run("Negative", func(t *testing.T) { + suite.setupTestFn() + _, err := suite.serv.Image(suite.ctx, suite.id()) assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) } -func TestServiceVote(t *testing.T) { - t.Run("Positive1", func(t *testing.T) { - id, _ := GenId() - fnId := func() func() (uint64, error) { - return func() (uint64, error) { - return id(), nil - } - }() - fnS := func(n int, swap func(i int, j int)) {} - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - comp := compressor.NewMock() - stor := storage.NewMock() - mDb := database.NewMem(database.DefaultMemConfig) - mCache := cache.NewMem(cache.DefaultMemConfig) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) +func (suite *ServiceTestSuite) TestServiceVote() { + suite.T().Run("Positive1", func(t *testing.T) { + suite.setupTestFn() files := []model.File{Png(), Png()} - album, err := serv.Album(ctx, files, 0*time.Millisecond) + album, err := suite.serv.Album(suite.ctx, files, 0*time.Millisecond) assert.NoError(t, err) - img1, img2, err := serv.Pair(ctx, album) + img1, img2, err := suite.serv.Pair(suite.ctx, album) assert.NoError(t, err) - err = serv.Vote(ctx, album, img1.Token, img2.Token) + err = suite.serv.Vote(suite.ctx, album, img1.Token, img2.Token) assert.NoError(t, err) }) - t.Run("Positive2", func(t *testing.T) { - id, _ := GenId() - fnId := func() func() (uint64, error) { - return func() (uint64, error) { - return id(), nil - } - }() - fnS := func(n int, swap func(i int, j int)) {} - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - comp := compressor.NewMock() - stor := storage.NewMock() - mDb := database.NewMem(database.DefaultMemConfig) - mCache := cache.NewMem(cache.DefaultMemConfig) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - conf := DefaultServiceConfig - conf.TempLinks = false - serv := New(conf, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) + suite.T().Run("Positive2", func(t *testing.T) { + suite.setupTestFn() + oldTempLinks := suite.serv.conf.TempLinks + suite.serv.conf.TempLinks = false + defer func() { suite.serv.conf.TempLinks = oldTempLinks }() files := []model.File{Png(), Png()} - album, err := serv.Album(ctx, files, 0*time.Millisecond) + album, err := suite.serv.Album(suite.ctx, files, 0*time.Millisecond) assert.NoError(t, err) - img1, img2, err := serv.Pair(ctx, album) + img1, img2, err := suite.serv.Pair(suite.ctx, album) assert.NoError(t, err) - err = serv.Vote(ctx, album, img1.Token, img2.Token) + err = suite.serv.Vote(suite.ctx, album, img1.Token, img2.Token) assert.NoError(t, err) }) - t.Run("Negative1", func(t *testing.T) { - id, _ := GenId() - fnId := func() func() (uint64, error) { - return func() (uint64, error) { - return id(), nil - } - }() - fnS := func(n int, swap func(i int, j int)) {} - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - comp := compressor.NewMock() - stor := storage.NewMock() - mDb := database.NewMem(database.DefaultMemConfig) - mCache := cache.NewMem(cache.DefaultMemConfig) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) + suite.T().Run("Negative1", func(t *testing.T) { + suite.setupTestFn() files := []model.File{Png(), Png()} - album, err := serv.Album(ctx, files, 0*time.Millisecond) + album, err := suite.serv.Album(suite.ctx, files, 0*time.Millisecond) assert.NoError(t, err) - img1, img2, err := serv.Pair(ctx, album) + img1, img2, err := suite.serv.Pair(suite.ctx, album) assert.NoError(t, err) - err = serv.Vote(ctx, id(), img1.Token, img2.Token) + err = suite.serv.Vote(suite.ctx, suite.id(), img1.Token, img2.Token) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) - t.Run("Negative2", func(t *testing.T) { - id, _ := GenId() - fnId := func() func() (uint64, error) { - return func() (uint64, error) { - return id(), nil - } - }() - fnS := func(n int, swap func(i int, j int)) {} - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - comp := compressor.NewMock() - stor := storage.NewMock() - mDb := database.NewMem(database.DefaultMemConfig) - mCache := cache.NewMem(cache.DefaultMemConfig) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS)) + suite.T().Run("Negative2", func(t *testing.T) { + suite.setupTestFn() files := []model.File{Png(), Png()} - album, err := serv.Album(ctx, files, 0*time.Millisecond) + album, err := suite.serv.Album(suite.ctx, files, 0*time.Millisecond) assert.NoError(t, err) - _, _, err = serv.Pair(ctx, album) + _, _, err = suite.serv.Pair(suite.ctx, album) assert.NoError(t, err) - err = serv.Vote(ctx, album, id(), id()) + err = suite.serv.Vote(suite.ctx, album, suite.id(), suite.id()) assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) } -func TestServiceTop(t *testing.T) { - t.Run("Positive", func(t *testing.T) { - id, ids := GenId() - idQ, _ := GenId() - fnId := func() func() (uint64, error) { - return func() (uint64, error) { - return id(), nil - } - }() - fnS := func(n int, swap func(i int, j int)) {} - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - comp := compressor.NewMock() - stor := storage.NewMock() - mDb := database.NewMem(database.DefaultMemConfig) - mCache := cache.NewMem(cache.DefaultMemConfig) - qCalc := &QueueCalc{newQueue(idQ(), mCache)} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - heartbeatCalc := make(chan interface{}) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithRandId(fnId), WithRandShuffle(fnS), WithHeartbeatCalc(heartbeatCalc)) - gCalc, ctxCalc := errgroup.WithContext(ctx) - serv.StartWorkingPoolCalc(ctxCalc, gCalc) +func (suite *ServiceTestSuite) TestServiceTop() { + suite.T().Run("Positive", func(t *testing.T) { + suite.setupTestFn() files := []model.File{Png(), Png()} - album, err := serv.Album(ctx, files, 0*time.Millisecond) + album, err := suite.serv.Album(suite.ctx, files, 0*time.Millisecond) assert.NoError(t, err) - img1, img2, err := serv.Pair(ctx, album) + img1, img2, err := suite.serv.Pair(suite.ctx, album) assert.NoError(t, err) - err = serv.Vote(ctx, album, img1.Token, img2.Token) + err = suite.serv.Vote(suite.ctx, album, img1.Token, img2.Token) assert.NoError(t, err) - AssertChannel(t, heartbeatCalc) - img3, img4, err := serv.Pair(ctx, album) + AssertChannel(t, suite.heartbeatCalc) + img3, img4, err := suite.serv.Pair(suite.ctx, album) assert.NoError(t, err) - err = serv.Vote(ctx, album, img3.Token, img4.Token) + err = suite.serv.Vote(suite.ctx, album, img3.Token, img4.Token) assert.NoError(t, err) - AssertChannel(t, heartbeatCalc) - imgs1, err := serv.Top(ctx, album) + AssertChannel(t, suite.heartbeatCalc) + imgs1, err := suite.serv.Top(suite.ctx, album) assert.NoError(t, err) - img5 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.5, Compressed: false} - img6 := model.Image{Id: ids.Uint64(2), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(2), Rating: 0.5, Compressed: false} + img5 := model.Image{Id: suite.ids.Uint64(1), Src: "/aye-and-nay/albums/" + suite.ids.Base64(0) + "/images/" + suite.ids.Base64(1), Rating: 0.5, Compressed: false} + img6 := model.Image{Id: suite.ids.Uint64(2), Src: "/aye-and-nay/albums/" + suite.ids.Base64(0) + "/images/" + suite.ids.Base64(2), Rating: 0.5, Compressed: false} imgs2 := []model.Image{img5, img6} assert.Equal(t, imgs2, imgs1) }) - t.Run("Negative", func(t *testing.T) { - id, _ := GenId() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - comp := compressor.NewMock() - stor := storage.NewMock() - mDb := database.NewMem(database.DefaultMemConfig) - mCache := cache.NewMem(cache.DefaultMemConfig) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel) - _, err := serv.Top(ctx, id()) + suite.T().Run("Negative", func(t *testing.T) { + suite.setupTestFn() + _, err := suite.serv.Top(suite.ctx, suite.id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) } -func TestServiceDelete(t *testing.T) { - t.Run("Positive1", func(t *testing.T) { +func (suite *ServiceTestSuite) TestServiceDelete() { + suite.T().Run("Positive1", func(t *testing.T) { + suite.setupTestFn() id1, ids1 := GenId() - id2, ids2 := GenId() - idPQ, _ := GenId() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - comp := compressor.NewMock() - stor := storage.NewMock() - mDb := database.NewMem(database.DefaultMemConfig) - mCache := cache.NewMem(cache.DefaultMemConfig) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{newPQueue(idPQ(), mCache)} - qDel.Monitor(ctx) alb1 := AlbumFactory(id1, ids1) alb1.Expires = time.Now().Add(-1 * time.Hour) - err := mDb.SaveAlbum(ctx, alb1) + err := suite.serv.pers.SaveAlbum(suite.ctx, alb1) assert.NoError(t, err) + id2, ids2 := GenId() alb2 := AlbumFactory(id2, ids2) alb2.Expires = time.Now().Add(1 * time.Hour) - err = mDb.SaveAlbum(ctx, alb2) + err = suite.serv.pers.SaveAlbum(suite.ctx, alb2) assert.NoError(t, err) - heartbeatDel := make(chan interface{}) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) - err = serv.CleanUp(ctx) + err = suite.serv.CleanUp(suite.ctx) assert.NoError(t, err) - gDel, ctxDel := errgroup.WithContext(ctx) - serv.StartWorkingPoolDel(ctxDel, gDel) - v := AssertChannel(t, heartbeatDel) + v := AssertChannel(t, suite.heartbeatDel) album, ok := v.(uint64) assert.True(t, ok) assert.Equal(t, ids1.Uint64(0), album) }) - t.Run("Positive2", func(t *testing.T) { - idPQ, _ := GenId() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - comp := compressor.NewMock() - stor := storage.NewMock() - mDb := database.NewMem(database.DefaultMemConfig) - mCache := cache.NewMem(cache.DefaultMemConfig) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{newPQueue(idPQ(), mCache)} - qDel.Monitor(ctx) - heartbeatDel := make(chan interface{}) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) - gDel, ctxDel := errgroup.WithContext(ctx) - serv.StartWorkingPoolDel(ctxDel, gDel) + suite.T().Run("Positive2", func(t *testing.T) { + suite.setupTestFn() files := []model.File{Png(), Png()} dur := 100 * time.Millisecond - album, err := serv.Album(ctx, files, dur) + album, err := suite.serv.Album(suite.ctx, files, dur) assert.NoError(t, err) - AssertChannel(t, heartbeatDel) - _, err = serv.Top(ctx, album) + AssertChannel(t, suite.heartbeatDel) + _, err = suite.serv.Top(suite.ctx, album) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) - t.Run("Negative", func(t *testing.T) { - idPQ, _ := GenId() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - comp := compressor.NewMock() - stor := storage.NewMock() - mDb := database.NewMem(database.DefaultMemConfig) - mCache := cache.NewMem(cache.DefaultMemConfig) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{newPQueue(idPQ(), mCache)} - qDel.Monitor(ctx) - heartbeatDel := make(chan interface{}) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel, WithHeartbeatDel(heartbeatDel)) - gDel, ctxDel := errgroup.WithContext(ctx) - serv.StartWorkingPoolDel(ctxDel, gDel) + suite.T().Run("Negative", func(t *testing.T) { + suite.setupTestFn() files := []model.File{Png(), Png()} dur := 0 * time.Second - album, err := serv.Album(ctx, files, dur) + album, err := suite.serv.Album(suite.ctx, files, dur) assert.NoError(t, err) - AssertNotChannel(t, heartbeatDel) - _, err = serv.Top(ctx, album) + AssertNotChannel(t, suite.heartbeatDel) + _, err = suite.serv.Top(suite.ctx, album) assert.NoError(t, err) }) } -func TestServiceHealth(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - comp := compressor.NewMock() - stor := storage.NewMock() - mDb := database.NewMem(database.DefaultMemConfig) - mCache := cache.NewMem(cache.DefaultMemConfig) - qCalc := &QueueCalc{} - qCalc.Monitor(ctx) - qComp := &QueueComp{} - qComp.Monitor(ctx) - qDel := &QueueDel{} - qDel.Monitor(ctx) - serv := New(DefaultServiceConfig, comp, stor, mDb, mCache, qCalc, qComp, qDel) - _, err := serv.Health(ctx) - assert.NoError(t, err) +func (suite *ServiceTestSuite) TestServiceHealth() { + _, err := suite.serv.Health(suite.ctx) + assert.NoError(suite.T(), err) } diff --git a/infrastructure/cache/mem_test.go b/infrastructure/cache/mem_test.go index 7e623d3..d24c873 100644 --- a/infrastructure/cache/mem_test.go +++ b/infrastructure/cache/mem_test.go @@ -27,6 +27,7 @@ type MemTestSuite struct { heartbeatPair chan interface{} heartbeatToken chan interface{} cache domain.Cacher + setupTestFn func() } func (suite *MemTestSuite) SetupSuite() { @@ -47,6 +48,7 @@ func (suite *MemTestSuite) SetupSuite() { suite.heartbeatPair = hp suite.heartbeatToken = ht suite.cache = mem + suite.setupTestFn = suite.SetupTest } func (suite *MemTestSuite) SetupTest() { @@ -66,6 +68,7 @@ func (suite *MemTestSuite) TearDownSuite() { func (suite *MemTestSuite) TestPair() { suite.T().Run("Positive", func(t *testing.T) { + suite.setupTestFn() id, ids := GenId() album := id() pairs := [][2]uint64{{id(), id()}} @@ -77,12 +80,14 @@ func (suite *MemTestSuite) TestPair() { assert.Equal(t, ids.Uint64(2), image2) }) suite.T().Run("Negative1", func(t *testing.T) { + suite.setupTestFn() id, _ := GenId() album := id() _, _, err := suite.cache.Pop(suite.ctx, album) assert.ErrorIs(t, err, domain.ErrPairNotFound) }) suite.T().Run("Negative2", func(t *testing.T) { + suite.setupTestFn() id, _ := GenId() album := id() pairs := [][2]uint64{{id(), id()}} @@ -94,6 +99,7 @@ func (suite *MemTestSuite) TestPair() { assert.ErrorIs(t, err, domain.ErrPairNotFound) }) suite.T().Run("Negative3", func(t *testing.T) { + suite.setupTestFn() _, ok := suite.cache.(*Redis) if testing.Short() && ok { t.Skip("short flag is set") @@ -113,6 +119,7 @@ func (suite *MemTestSuite) TestPair() { func (suite *MemTestSuite) TestToken() { suite.T().Run("Positive", func(t *testing.T) { + suite.setupTestFn() id, _ := GenId() token := id() album1 := id() @@ -125,6 +132,7 @@ func (suite *MemTestSuite) TestToken() { assert.Equal(t, image1, image2) }) suite.T().Run("Negative1", func(t *testing.T) { + suite.setupTestFn() id, _ := GenId() token := id() album := id() @@ -135,12 +143,14 @@ func (suite *MemTestSuite) TestToken() { assert.ErrorIs(t, err, domain.ErrTokenAlreadyExists) }) suite.T().Run("Negative2", func(t *testing.T) { + suite.setupTestFn() id, _ := GenId() token := id() _, _, err := suite.cache.Get(suite.ctx, token) assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) suite.T().Run("Negative3", func(t *testing.T) { + suite.setupTestFn() id, _ := GenId() token := id() album := id() @@ -157,12 +167,14 @@ func (suite *MemTestSuite) TestToken() { assert.ErrorIs(t, err, domain.ErrTokenNotFound) }) suite.T().Run("Negative4", func(t *testing.T) { + suite.setupTestFn() id, _ := GenId() token := id() err := suite.cache.Del(suite.ctx, token) assert.NoError(t, err) }) suite.T().Run("Negative5", func(t *testing.T) { + suite.setupTestFn() _, ok := suite.cache.(*Redis) if testing.Short() && ok { t.Skip("short flag is set") diff --git a/infrastructure/cache/redis_integration_test.go b/infrastructure/cache/redis_integration_test.go index 1a68f16..74a2fa4 100644 --- a/infrastructure/cache/redis_integration_test.go +++ b/infrastructure/cache/redis_integration_test.go @@ -19,7 +19,8 @@ func TestRedisTestSuite(t *testing.T) { type RedisTestSuite struct { suite.Suite - base MemTestSuite + base MemTestSuite + setupTestFn func() } func (suite *RedisTestSuite) SetupSuite() { @@ -37,6 +38,8 @@ func (suite *RedisTestSuite) SetupSuite() { suite.base.conf.LimiterRequestsPerSecond = float64(conf.LimiterRequestsPerSecond) suite.base.conf.TimeToLive = conf.TimeToLive suite.base.cache = redis + suite.base.setupTestFn = suite.SetupTest + suite.setupTestFn = suite.SetupTest } func (suite *RedisTestSuite) SetupTest() { @@ -58,6 +61,7 @@ func (suite *RedisTestSuite) TearDownSuite() { func (suite *RedisTestSuite) TestRedisAllow() { suite.T().Run("Positive", func(t *testing.T) { + suite.setupTestFn() id, _ := GenId() rpm := suite.base.conf.LimiterRequestsPerSecond ip := id() @@ -74,6 +78,7 @@ func (suite *RedisTestSuite) TestRedisAllow() { } }) suite.T().Run("Negative", func(t *testing.T) { + suite.setupTestFn() id, _ := GenId() rps := suite.base.conf.LimiterRequestsPerSecond ip := id() diff --git a/infrastructure/database/badger_integration_test.go b/infrastructure/database/badger_integration_test.go index 368864d..e9a635b 100644 --- a/infrastructure/database/badger_integration_test.go +++ b/infrastructure/database/badger_integration_test.go @@ -32,6 +32,7 @@ func (suite *BadgerTestSuite) SetupSuite() { suite.base.ctx = ctx suite.base.cancel = cancel suite.base.db = badger + suite.base.setupTestFn = suite.SetupTest } func (suite *BadgerTestSuite) SetupTest() { diff --git a/infrastructure/database/mem_test.go b/infrastructure/database/mem_test.go index ea5a74d..5f81b77 100644 --- a/infrastructure/database/mem_test.go +++ b/infrastructure/database/mem_test.go @@ -22,9 +22,10 @@ func TestMemTestSuite(t *testing.T) { type MemTestSuite struct { suite.Suite - ctx context.Context - cancel context.CancelFunc - db domain.Databaser + ctx context.Context + cancel context.CancelFunc + db domain.Databaser + setupTestFn func() } func (suite *MemTestSuite) SetupSuite() { @@ -36,6 +37,7 @@ func (suite *MemTestSuite) SetupSuite() { suite.ctx = ctx suite.cancel = cancel suite.db = mem + suite.setupTestFn = suite.SetupTest } func (suite *MemTestSuite) SetupTest() { @@ -63,6 +65,7 @@ func (suite *MemTestSuite) saveAlbum(id IdGenFunc, ids Ids) model.Album { func (suite *MemTestSuite) TestAlbum() { suite.T().Run("Positive", func(t *testing.T) { + suite.setupTestFn() id, ids := GenId() alb := suite.saveAlbum(id, ids) edgs, err := suite.db.GetEdges(suite.ctx, ids.Uint64(0)) @@ -70,17 +73,20 @@ func (suite *MemTestSuite) TestAlbum() { assert.Equal(t, alb.Edges, edgs) }) suite.T().Run("Negative1", func(t *testing.T) { + suite.setupTestFn() id, ids := GenId() alb := suite.saveAlbum(id, ids) err := suite.db.SaveAlbum(suite.ctx, alb) assert.ErrorIs(t, err, domain.ErrAlbumAlreadyExists) }) suite.T().Run("Negative2", func(t *testing.T) { + suite.setupTestFn() id, _ := GenId() _, err := suite.db.GetImagesIds(suite.ctx, id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) suite.T().Run("Negative3", func(t *testing.T) { + suite.setupTestFn() id, _ := GenId() _, err := suite.db.GetEdges(suite.ctx, id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) @@ -89,6 +95,7 @@ func (suite *MemTestSuite) TestAlbum() { func (suite *MemTestSuite) TestCount() { suite.T().Run("Positive", func(t *testing.T) { + suite.setupTestFn() id, ids := GenId() _ = suite.saveAlbum(id, ids) n, err := suite.db.CountImages(suite.ctx, ids.Uint64(0)) @@ -112,6 +119,7 @@ func (suite *MemTestSuite) TestCount() { assert.Equal(t, 2, n) }) suite.T().Run("Negative1", func(t *testing.T) { + suite.setupTestFn() id, ids := GenId() _ = suite.saveAlbum(id, ids) err := suite.db.UpdateCompressionStatus(suite.ctx, ids.Uint64(0), ids.Uint64(1)) @@ -123,21 +131,25 @@ func (suite *MemTestSuite) TestCount() { assert.Equal(t, 1, n) }) suite.T().Run("Negative2", func(t *testing.T) { + suite.setupTestFn() id, _ := GenId() _, err := suite.db.CountImages(suite.ctx, id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) suite.T().Run("Negative3", func(t *testing.T) { + suite.setupTestFn() id, _ := GenId() _, err := suite.db.CountImagesCompressed(suite.ctx, id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) suite.T().Run("Negative4", func(t *testing.T) { + suite.setupTestFn() id, ids := GenId() err := suite.db.UpdateCompressionStatus(suite.ctx, id(), ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) suite.T().Run("Negative5", func(t *testing.T) { + suite.setupTestFn() id, ids := GenId() _ = suite.saveAlbum(id, ids) err := suite.db.UpdateCompressionStatus(suite.ctx, ids.Uint64(0), id()) @@ -147,6 +159,7 @@ func (suite *MemTestSuite) TestCount() { func (suite *MemTestSuite) TestImage() { suite.T().Run("Positive", func(t *testing.T) { + suite.setupTestFn() id, ids := GenId() _ = suite.saveAlbum(id, ids) src, err := suite.db.GetImageSrc(suite.ctx, ids.Uint64(0), ids.Uint64(4)) @@ -154,11 +167,13 @@ func (suite *MemTestSuite) TestImage() { assert.Equal(t, "/aye-and-nay/albums/"+ids.Base64(0)+"/images/"+ids.Base64(4), src) }) suite.T().Run("Negative1", func(t *testing.T) { + suite.setupTestFn() id, ids := GenId() _, err := suite.db.GetImageSrc(suite.ctx, id(), ids.Uint64(0)) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) suite.T().Run("Negative2", func(t *testing.T) { + suite.setupTestFn() id, ids := GenId() _ = suite.saveAlbum(id, ids) _, err := suite.db.GetImageSrc(suite.ctx, ids.Uint64(0), id()) @@ -168,6 +183,7 @@ func (suite *MemTestSuite) TestImage() { func (suite *MemTestSuite) TestVote() { suite.T().Run("Positive", func(t *testing.T) { + suite.setupTestFn() id, ids := GenId() _ = suite.saveAlbum(id, ids) err := suite.db.SaveVote(suite.ctx, ids.Uint64(0), ids.Uint64(3), ids.Uint64(5)) @@ -179,6 +195,7 @@ func (suite *MemTestSuite) TestVote() { assert.Equal(t, 2, edgs[ids.Uint64(3)][ids.Uint64(5)]) }) suite.T().Run("Negative", func(t *testing.T) { + suite.setupTestFn() id, _ := GenId() err := suite.db.SaveVote(suite.ctx, id(), id(), id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) @@ -187,6 +204,7 @@ func (suite *MemTestSuite) TestVote() { func (suite *MemTestSuite) TestSort() { suite.T().Run("Positive", func(t *testing.T) { + suite.setupTestFn() id, ids := GenId() _ = suite.saveAlbum(id, ids) imgs1, err := suite.db.GetImagesOrdered(suite.ctx, ids.Uint64(0)) @@ -200,6 +218,7 @@ func (suite *MemTestSuite) TestSort() { assert.Equal(t, imgs2, imgs1) }) suite.T().Run("Negative", func(t *testing.T) { + suite.setupTestFn() id, _ := GenId() _, err := suite.db.GetImagesOrdered(suite.ctx, id()) assert.ErrorIs(t, err, domain.ErrAlbumNotFound) @@ -208,6 +227,7 @@ func (suite *MemTestSuite) TestSort() { func (suite *MemTestSuite) TestRatings() { suite.T().Run("Positive", func(t *testing.T) { + suite.setupTestFn() id, ids := GenId() _ = suite.saveAlbum(id, ids) img1 := model.Image{Id: ids.Uint64(1), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} @@ -230,6 +250,7 @@ func (suite *MemTestSuite) TestRatings() { assert.Equal(t, imgs1, imgs2) }) suite.T().Run("Negative", func(t *testing.T) { + suite.setupTestFn() id, ids := GenId() album := id() img1 := model.Image{Id: id(), Src: "/aye-and-nay/albums/" + ids.Base64(0) + "/images/" + ids.Base64(1), Rating: 0.54412788} @@ -250,6 +271,7 @@ func (suite *MemTestSuite) TestRatings() { func (suite *MemTestSuite) TestDelete() { suite.T().Run("Positive1", func(t *testing.T) { + suite.setupTestFn() id, ids := GenId() alb := AlbumFactory(id, ids) _, err := suite.db.CountImages(suite.ctx, ids.Uint64(0)) @@ -268,6 +290,7 @@ func (suite *MemTestSuite) TestDelete() { assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) suite.T().Run("Positive2", func(t *testing.T) { + suite.setupTestFn() id, ids := GenId() alb := AlbumFactory(id, ids) alb.Expires = time.Now().Add(-1 * time.Hour) @@ -282,6 +305,7 @@ func (suite *MemTestSuite) TestDelete() { assert.ErrorIs(t, err, domain.ErrAlbumNotFound) }) suite.T().Run("Negative", func(t *testing.T) { + suite.setupTestFn() id, ids := GenId() _ = suite.saveAlbum(id, ids) err := suite.db.DeleteAlbum(suite.ctx, id()) diff --git a/infrastructure/database/mongo_integration_test.go b/infrastructure/database/mongo_integration_test.go index 057c5cc..8dc741e 100644 --- a/infrastructure/database/mongo_integration_test.go +++ b/infrastructure/database/mongo_integration_test.go @@ -32,6 +32,7 @@ func (suite *MongoTestSuite) SetupSuite() { suite.base.ctx = ctx suite.base.cancel = cancel suite.base.db = mongo + suite.base.setupTestFn = suite.SetupTest } func (suite *MongoTestSuite) SetupTest() { diff --git a/infrastructure/storage/minio_integration_test.go b/infrastructure/storage/minio_integration_test.go index 5a32636..bc9de09 100644 --- a/infrastructure/storage/minio_integration_test.go +++ b/infrastructure/storage/minio_integration_test.go @@ -20,9 +20,10 @@ func TestMinioTestSuite(t *testing.T) { type MinioTestSuite struct { suite.Suite - ctx context.Context - cancel context.CancelFunc - storage domain.Storager + ctx context.Context + cancel context.CancelFunc + storage domain.Storager + setupTestFn func() } func (suite *MinioTestSuite) SetupSuite() { @@ -35,6 +36,7 @@ func (suite *MinioTestSuite) SetupSuite() { suite.ctx = ctx suite.cancel = cancel suite.storage = minio + suite.setupTestFn = suite.SetupTest } func (suite *MinioTestSuite) SetupTest() { @@ -54,6 +56,7 @@ func (suite *MinioTestSuite) TearDownSuite() { func (suite *MinioTestSuite) TestMinio() { suite.T().Run("", func(t *testing.T) { + suite.setupTestFn() id, ids := GenId() album := id() image := id() @@ -75,6 +78,7 @@ func (suite *MinioTestSuite) TestMinio() { assert.Nil(t, f.Reader) }) suite.T().Run("", func(t *testing.T) { + suite.setupTestFn() id, ids := GenId() album := id() image := id() diff --git a/internal/generator/generator.go b/internal/generator/generator.go index fdf39e7..874b3e3 100644 --- a/internal/generator/generator.go +++ b/internal/generator/generator.go @@ -64,8 +64,9 @@ func (lb *IdLogBook) set(i int, id uint64) { defer lb.m.Unlock() _, ok := lb.logBook[i] if ok { - lb.logBook[i] = id + panic(fmt.Sprintf("id #%d already used", i)) } + lb.logBook[i] = id } func (lb *IdLogBook) Uint64(i int) uint64 { diff --git a/internal/generator/generator_test.go b/internal/generator/generator_test.go index b53af77..2747ab6 100644 --- a/internal/generator/generator_test.go +++ b/internal/generator/generator_test.go @@ -50,8 +50,6 @@ func TestGenId(t *testing.T) { }) wg.Wait() assert.Len(t, ids.logBook, span) - assert.Equal(t, ids.logBook[0], uint64(100)) - assert.Equal(t, ids.logBook[len(ids.logBook)-1], uint64(199)) assert.Panics(t, func() { id() }) assert.Panics(t, func() { _, ids := GenId() From 390ec559f319cea64c43d1d07d4a31ae453e8746 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Thu, 17 Mar 2022 17:30:32 +0100 Subject: [PATCH 61/92] Parallelize tests --- delivery/http/middleware_test.go | 6 ++++++ delivery/http/server_test.go | 1 + internal/generator/generator_test.go | 1 + pkg/errors/errors_test.go | 2 ++ pkg/linalg/linalg_test.go | 1 + pkg/retry/retry_test.go | 6 ++++++ 6 files changed, 17 insertions(+) diff --git a/delivery/http/middleware_test.go b/delivery/http/middleware_test.go index 18632fa..01579e3 100644 --- a/delivery/http/middleware_test.go +++ b/delivery/http/middleware_test.go @@ -29,6 +29,7 @@ func TestMiddlewareRecover(t *testing.T) { t.Skip() } t.Run("Positive", func(t *testing.T) { + t.Parallel() fn := func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.WriteHeader(418) @@ -45,6 +46,7 @@ func TestMiddlewareRecover(t *testing.T) { AssertBody(t, w, `I'm a teapot`) }) t.Run("Negative", func(t *testing.T) { + t.Parallel() fn := func(w http.ResponseWriter, r *http.Request) { panic("don't") } @@ -65,6 +67,7 @@ func TestMiddlewareLimit(t *testing.T) { t.Skip() } t.Run("Positive", func(t *testing.T) { + t.Parallel() fn := func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.WriteHeader(418) @@ -81,6 +84,7 @@ func TestMiddlewareLimit(t *testing.T) { AssertBody(t, w, `I'm a teapot`) }) t.Run("Negative", func(t *testing.T) { + t.Parallel() fn := func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.WriteHeader(418) @@ -147,10 +151,12 @@ func TestIP(t *testing.T) { }, } for _, tt := range tests { + tt := tt r := httptest.NewRequest(http.MethodGet, "/api/health/", http.NoBody) r.Header.Set("X-Forwarded-For", tt.args.xff) r.RemoteAddr = tt.args.remoteAddr t.Run("", func(t *testing.T) { + t.Parallel() assert.Equal(t, tt.want, ip(r)) }) } diff --git a/delivery/http/server_test.go b/delivery/http/server_test.go index eceae59..3bec7ad 100644 --- a/delivery/http/server_test.go +++ b/delivery/http/server_test.go @@ -28,6 +28,7 @@ func TestServer(t *testing.T) { if !*unit { t.Skip() } + t.Parallel() comp := compressor.NewMock() stor := storage.NewMock() data := database.NewMem(database.DefaultMemConfig) diff --git a/internal/generator/generator_test.go b/internal/generator/generator_test.go index 2747ab6..6b4bf37 100644 --- a/internal/generator/generator_test.go +++ b/internal/generator/generator_test.go @@ -18,6 +18,7 @@ func TestGenId(t *testing.T) { if !*unit { t.Skip() } + t.Parallel() id, ids := GenId() id, ids = GenId() wg := sync.WaitGroup{} diff --git a/pkg/errors/errors_test.go b/pkg/errors/errors_test.go index 3338975..f4ca847 100644 --- a/pkg/errors/errors_test.go +++ b/pkg/errors/errors_test.go @@ -66,7 +66,9 @@ func TestCause(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run("", func(t *testing.T) { + t.Parallel() got := errors.Cause(tt.give) assert.Equal(t, tt.want, got) }) diff --git a/pkg/linalg/linalg_test.go b/pkg/linalg/linalg_test.go index 2a61d56..6181735 100644 --- a/pkg/linalg/linalg_test.go +++ b/pkg/linalg/linalg_test.go @@ -22,6 +22,7 @@ func TestPageRank(t *testing.T) { if !*unit { t.Skip() } + t.Parallel() edgs := map[uint64]map[uint64]int{} edgs[0x5B92] = map[uint64]int{} edgs[0x804F] = map[uint64]int{} diff --git a/pkg/retry/retry_test.go b/pkg/retry/retry_test.go index c1ee40e..f877805 100644 --- a/pkg/retry/retry_test.go +++ b/pkg/retry/retry_test.go @@ -63,7 +63,9 @@ func TestDo1(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run("", func(t *testing.T) { + t.Parallel() c := 0 err := retry.Do(tt.times, tt.pause, func() error { c++ @@ -122,7 +124,9 @@ func TestDo2(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run("", func(t *testing.T) { + t.Parallel() c := 0 err := retry.Do(tt.times, tt.pause, func() error { c++ @@ -181,7 +185,9 @@ func TestDo3(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run("", func(t *testing.T) { + t.Parallel() c := 0 err := retry.Do(tt.times, tt.pause, func() error { c++ From 56304ff9bf4bcf89a384961448f08286c2ea72f8 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Tue, 22 Mar 2022 23:00:07 +0100 Subject: [PATCH 62/92] Tune GOGC in runtime --- Makefile | 4 +- build/config-dev.env | 6 +- build/config-embed.env | 4 +- build/config-prod.env | 6 +- build/docker-compose-embed.yml | 9 ++ build/docker-compose-prod.yml | 9 ++ cmd/loadtest/main.go | 9 +- config.env | 4 +- go.mod | 9 +- go.sum | 15 +++- internal/config/config.go | 8 +- internal/gctuner/gctuner.go | 152 +++++++++++++++++++++++++++++++++ main.go | 26 ++++-- 13 files changed, 236 insertions(+), 25 deletions(-) create mode 100644 internal/gctuner/gctuner.go diff --git a/Makefile b/Makefile index 4bcc54a..a99355c 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ dev-down: docker compose --file ./build/docker-compose-dev.yml down --rmi all -v prod-loadtest: - go run ./cmd/loadtest/main.go -verbose=false + go run ./cmd/loadtest/* -verbose=false prod-up: docker compose --file ./build/docker-compose-prod.yml up -d --build @@ -39,7 +39,7 @@ prod-down: docker compose --file ./build/docker-compose-prod.yml down --rmi all -v embed-loadtest: - go run ./cmd/loadtest/main.go -verbose=false -api-address "http://localhost:8001" -minio-address "http://localhost:9000" -html-address "" + go run ./cmd/loadtest/* -verbose=false -api-address "http://localhost:8001" -minio-address "http://localhost:9000" -html-address "" embed-up: docker compose --file ./build/docker-compose-embed.yml up -d --build diff --git a/build/config-dev.env b/build/config-dev.env index 264be8e..1f75152 100644 --- a/build/config-dev.env +++ b/build/config-dev.env @@ -4,8 +4,10 @@ CONFIG_RELOAD_INTERVAL=1s # APP APP_NAME=config-dev -APP_BALLAST=0 APP_LOG=info +APP_GC_TUNER=true +APP_MEM_TOTAL=2147483648 # 2 GB +APP_MEM_LIMIT_RATIO=0.7 # SERVER SERVER_DOMAIN= @@ -43,7 +45,7 @@ CACHE_REDIS_TIMEOUT=30s CACHE_REDIS_TIME_TO_LIVE=15m # COMPRESSOR: [mock, shortpixel, imaginary] -APP_COMPRESSOR=imaginary +APP_COMPRESSOR=mock COMPRESSOR_SHORTPIXEL_URL=https://api.shortpixel.com/v2/post-reducer.php COMPRESSOR_SHORTPIXEL_URL2=https://api.shortpixel.com/v2/reducer.php COMPRESSOR_SHORTPIXEL_API_KEY=abcdefghijklmnopqrst diff --git a/build/config-embed.env b/build/config-embed.env index 9b89ecf..2d79bd6 100644 --- a/build/config-embed.env +++ b/build/config-embed.env @@ -4,8 +4,10 @@ CONFIG_RELOAD_INTERVAL=1s # APP APP_NAME=config-embed -APP_BALLAST=0 APP_LOG=info +APP_GC_TUNER=true +APP_MEM_TOTAL=2147483648 # 2 GB +APP_MEM_LIMIT_RATIO=0.7 # SERVER SERVER_DOMAIN= diff --git a/build/config-prod.env b/build/config-prod.env index a4b1f38..a6a2bc5 100644 --- a/build/config-prod.env +++ b/build/config-prod.env @@ -4,8 +4,10 @@ CONFIG_RELOAD_INTERVAL=1s # APP APP_NAME=config-prod -APP_BALLAST=0 APP_LOG=info +APP_GC_TUNER=true +APP_MEM_TOTAL=2147483648 # 2 GB +APP_MEM_LIMIT_RATIO=0.7 # SERVER SERVER_DOMAIN= @@ -43,7 +45,7 @@ CACHE_REDIS_TIMEOUT=30s CACHE_REDIS_TIME_TO_LIVE=15m # COMPRESSOR: [mock, shortpixel, imaginary] -APP_COMPRESSOR=imaginary +APP_COMPRESSOR=mock COMPRESSOR_SHORTPIXEL_URL=https://api.shortpixel.com/v2/post-reducer.php COMPRESSOR_SHORTPIXEL_URL2=https://api.shortpixel.com/v2/reducer.php COMPRESSOR_SHORTPIXEL_API_KEY=abcdefghijklmnopqrst diff --git a/build/docker-compose-embed.yml b/build/docker-compose-embed.yml index 0d91530..b75c1c4 100644 --- a/build/docker-compose-embed.yml +++ b/build/docker-compose-embed.yml @@ -5,6 +5,15 @@ services: context: ./../ dockerfile: ./build/Dockerfile-app container_name: embed-app + env_file: config-embed.env + deploy: + resources: + limits: + memory: ${APP_MEM_TOTAL} + restart_policy: + condition: on-failure + max_attempts: 3 + window: 120s ports: - "8001:8001" volumes: diff --git a/build/docker-compose-prod.yml b/build/docker-compose-prod.yml index 57ca656..d18d176 100644 --- a/build/docker-compose-prod.yml +++ b/build/docker-compose-prod.yml @@ -21,6 +21,15 @@ services: context: ./../ dockerfile: ./build/Dockerfile-app container_name: prod-app + env_file: config-prod.env + deploy: + resources: + limits: + memory: ${APP_MEM_TOTAL} + restart_policy: + condition: on-failure + max_attempts: 3 + window: 120s volumes: - "./config-prod.env:/config.env" depends_on: diff --git a/cmd/loadtest/main.go b/cmd/loadtest/main.go index 6ba53e5..d75ff59 100644 --- a/cmd/loadtest/main.go +++ b/cmd/loadtest/main.go @@ -3,7 +3,6 @@ package main import ( "context" "flag" - "fmt" "os" "os/signal" "sync" @@ -38,7 +37,7 @@ func main() { if verbose { log.SetOutput(os.Stderr) - log.SetLevel(log.ERROR) + log.SetLevel(log.INFO) } ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) @@ -60,9 +59,9 @@ func main() { return case <-time.After(1 * time.Second): passed, failed := c.Stats() - fmt.Printf("%d rps, ", passed-passed1sAgo) - fmt.Printf("%d passed (%.2f%%), ", passed, float64(passed)/float64(passed+failed)*100) - fmt.Printf("%d failed (%.2f%%)\n", failed, float64(failed)/float64(passed+failed)*100) + log.Infof("%d rps, ", passed-passed1sAgo) + log.Infof("%d passed (%.2f%%), ", passed, float64(passed)/float64(passed+failed)*100) + log.Infof("%d failed (%.2f%%)\n", failed, float64(failed)/float64(passed+failed)*100) passed1sAgo = passed } } diff --git a/config.env b/config.env index 36eed06..c08f4aa 100644 --- a/config.env +++ b/config.env @@ -4,8 +4,10 @@ CONFIG_RELOAD_INTERVAL=1s # APP APP_NAME=config -APP_BALLAST=0 APP_LOG=info +APP_GC_TUNER=true +APP_MEM_TOTAL=2147483648 # 2 GB +APP_MEM_LIMIT_RATIO=0.7 # SERVER SERVER_DOMAIN= diff --git a/go.mod b/go.mod index 87befbc..a80ddb5 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( github.com/radovskyb/watcher v1.0.7 github.com/rs/cors v1.8.0 github.com/segmentio/asm v1.1.3 + github.com/shirou/gopsutil v3.21.11+incompatible github.com/spf13/viper v1.9.0 github.com/stretchr/testify v1.7.0 go.mongodb.org/mongo-driver v1.8.0 @@ -41,6 +42,7 @@ require ( github.com/docker/go-units v0.4.0 // indirect github.com/dustin/go-humanize v1.0.0 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-playground/locales v0.12.1 // indirect github.com/go-playground/universal-translator v0.16.0 // indirect github.com/go-stack/stack v1.8.1 // indirect @@ -85,17 +87,20 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.2.0 // indirect github.com/tidwall/pretty v1.0.2 // indirect + github.com/tklauser/go-sysconf v0.3.10 // indirect + github.com/tklauser/numcpus v0.4.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.0.2 // indirect github.com/xdg-go/stringprep v1.0.2 // indirect github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect + github.com/yusufpapurcu/wmi v1.2.2 // indirect go.opencensus.io v0.23.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.7.0 // indirect go.uber.org/zap v1.19.1 // indirect golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 // indirect golang.org/x/mod v0.5.1 // indirect - golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 // indirect + golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/protobuf v1.27.1 // indirect @@ -104,3 +109,5 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) + +replace github.com/zitryss/aye-and-nay => ./pkg diff --git a/go.sum b/go.sum index 32ab776..f38e086 100644 --- a/go.sum +++ b/go.sum @@ -154,6 +154,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc= github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= @@ -456,6 +458,8 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/segmentio/asm v1.1.3 h1:WM03sfUOENvvKexOLp+pCqgb/WDjsi7EK8gIsICtzhc= github.com/segmentio/asm v1.1.3/go.mod h1:Ld3L4ZXGNcSLRg4JBsZ3//1+f/TjYl0Mzen/DQy1EJg= +github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= +github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= @@ -502,6 +506,10 @@ github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU= github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw= +github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= +github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o= +github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= @@ -528,6 +536,8 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= +github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= @@ -712,6 +722,7 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -767,8 +778,8 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 h1:TyHqChC80pFkXWraUUf6RuB5IqFdQieMLwwCJokV2pc= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 h1:XDXtA5hveEEV8JB2l7nhMTp3t3cHp9ZpwcdjqyEWLlo= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/internal/config/config.go b/internal/config/config.go index a1ef131..34c34fc 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -51,9 +51,11 @@ type Config struct { } type AppConfig struct { - Name string `mapstructure:"APP_NAME" validate:"required"` - Ballast int64 `mapstructure:"APP_BALLAST"` - Log string `mapstructure:"APP_LOG" validate:"required"` + Name string `mapstructure:"APP_NAME" validate:"required"` + Log string `mapstructure:"APP_LOG" validate:"required"` + GcTuner bool `mapstructure:"APP_GC_TUNER"` + MemTotal int `mapstructure:"APP_MEM_TOTAL"` + MemLimitRatio float64 `mapstructure:"APP_MEM_LIMIT_RATIO"` } func (c *Config) OnChange(ctx context.Context, fn func()) { diff --git a/internal/gctuner/gctuner.go b/internal/gctuner/gctuner.go new file mode 100644 index 0000000..998d306 --- /dev/null +++ b/internal/gctuner/gctuner.go @@ -0,0 +1,152 @@ +package gctuner + +import ( + "context" + "io" + "os" + "runtime" + "runtime/debug" + "strconv" + "strings" + + "github.com/shirou/gopsutil/mem" + "github.com/shirou/gopsutil/process" + + "github.com/zitryss/aye-and-nay/pkg/errors" + "github.com/zitryss/aye-and-nay/pkg/log" +) + +const ( + cgroupMemTotalPathV1 = "/sys/fs/cgroup/memory/memory.limit_in_bytes" + cgroupMemTotalPathV2 = "/sys/fs/cgroup/memory.max" +) + +var ( + lastGOGC float64 + memTotal float64 + memLimitRatio = 0.7 +) + +func Start(ctx context.Context, total int, ratio float64) error { + if lastGOGC == 0.0 { + gogc, ok := os.LookupEnv("GOGC") + if !ok || gogc == "" { + gogc = "100" + } + err := error(nil) + lastGOGC, err = strconv.ParseFloat(gogc, 64) + if err != nil { + return errors.Wrap(err) + } + } + if total >= 0.0 { + memTotal = float64(total) + } + if ratio > 0.0 && ratio <= 1.0 { + memLimitRatio = ratio + } + err := checkMemTotal() + if err != nil { + return errors.Wrap(err) + } + err = checkCgroup() + if err != nil { + return errors.Wrap(err) + } + fin := &finalizer{} + fin.ref = &finalizerRef{parent: fin} + runtime.SetFinalizer(fin.ref, finalizerHandler(ctx)) + fin.ref = nil + return nil +} + +func checkMemTotal() error { + if memTotal > 0.0 { + return nil + } + memVirtual, err := mem.VirtualMemory() + if err != nil { + return errors.Wrap(err) + } + memTotal = float64(memVirtual.Total) + return nil +} + +func checkCgroup() error { + for _, path := range []string{cgroupMemTotalPathV1, cgroupMemTotalPathV2} { + f, err := os.Open(path) + if err != nil { + continue + } + defer f.Close() + err = readCgroupMemTotal(f) + if err != nil { + return errors.Wrap(err) + } + } + return nil +} + +func readCgroupMemTotal(f io.Reader) error { + b, err := io.ReadAll(f) + if err != nil { + return errors.Wrap(err) + } + s := strings.TrimSpace(string(b)) + if s == "max" { + return nil + } + cgroupMemTotal, err := strconv.ParseFloat(s, 64) + if err != nil { + return errors.Wrap(err) + } + if cgroupMemTotal > 0.0 && cgroupMemTotal < memTotal { + memTotal = cgroupMemTotal + } + return nil +} + +type finalizer struct { + ref *finalizerRef +} + +type finalizerRef struct { + parent *finalizer +} + +func finalizerHandler(ctx context.Context) func(fin *finalizerRef) { + return func(fin *finalizerRef) { + err := updateGOGC() + if err != nil { + log.Error("update GOGC:", err) + } + select { + case <-ctx.Done(): + return + default: + runtime.SetFinalizer(fin, finalizerHandler(ctx)) + } + } +} + +func updateGOGC() error { + p, err := process.NewProcess(int32(os.Getpid())) + if err != nil { + return errors.Wrap(err) + } + processMemory, err := p.MemoryInfo() + if err != nil { + return errors.Wrap(err) + } + memUsed := float64(processMemory.RSS) + memUsedRatio := memUsed / memTotal + newGOGC := (memLimitRatio - memUsedRatio) / memUsedRatio * 100.0 + if newGOGC < 0.0 { + newGOGC = lastGOGC * memLimitRatio / memUsedRatio + } + lastGOGC = float64(debug.SetGCPercent(int(newGOGC))) + log.Debugf("mem used: %.0f\n", memUsed) + log.Debugf("mem used ratio: %.2f\n", memUsedRatio) + log.Debugf("new GOGC: %.0f\n", newGOGC) + return nil +} diff --git a/main.go b/main.go index 0527202..e91a25f 100644 --- a/main.go +++ b/main.go @@ -7,6 +7,7 @@ import ( "os" "os/signal" "syscall" + "time" "golang.org/x/sync/errgroup" @@ -17,15 +18,12 @@ import ( "github.com/zitryss/aye-and-nay/infrastructure/database" "github.com/zitryss/aye-and-nay/infrastructure/storage" "github.com/zitryss/aye-and-nay/internal/config" + "github.com/zitryss/aye-and-nay/internal/gctuner" "github.com/zitryss/aye-and-nay/internal/ulimit" "github.com/zitryss/aye-and-nay/pkg/errors" "github.com/zitryss/aye-and-nay/pkg/log" ) -var ( - ballast []byte -) - func main() { err := ulimit.SetMax() if err != nil { @@ -48,6 +46,7 @@ func main() { _, _ = fmt.Fprintln(os.Stderr, "critical:", err) reload = true stop() + time.Sleep(2 * time.Second) continue } @@ -58,18 +57,28 @@ func main() { }) } - ballast = make([]byte, conf.App.Ballast) - log.SetOutput(os.Stderr) log.SetPrefix(conf.App.Name) log.SetLevel(conf.App.Log) log.Info("logging initialized:", "log level:", conf.App.Log) + if conf.App.GcTuner { + err = gctuner.Start(ctx, conf.App.MemTotal, conf.App.MemLimitRatio) + if err != nil { + log.Critical(err) + reload = true + stop() + time.Sleep(2 * time.Second) + continue + } + } + cach, err := cache.New(ctx, conf.Cache) if err != nil { log.Critical(err) reload = true stop() + time.Sleep(2 * time.Second) continue } @@ -78,6 +87,7 @@ func main() { log.Critical(err) reload = true stop() + time.Sleep(2 * time.Second) continue } @@ -86,6 +96,7 @@ func main() { log.Critical(err) reload = true stop() + time.Sleep(2 * time.Second) continue } @@ -94,6 +105,7 @@ func main() { log.Critical(err) reload = true stop() + time.Sleep(2 * time.Second) continue } @@ -115,6 +127,7 @@ func main() { log.Critical(err) reload = true stop() + time.Sleep(2 * time.Second) continue } @@ -141,6 +154,7 @@ func main() { log.Critical(err) reload = true stop() + time.Sleep(2 * time.Second) continue } srv.Monitor(ctx) From 355b5f5cdf9d6b4472947185c127e375f3cfc18e Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Thu, 24 Mar 2022 19:14:43 +0100 Subject: [PATCH 63/92] Deploy --- .dockerignore | 2 +- .gitignore | 2 +- Makefile | 10 +++---- build/config-dev.env | 2 +- build/config-embed.env | 4 +-- build/config-prod.env | 6 ++-- build/docker-compose-embed.yml | 1 - build/docker-compose-prod.yml | 1 - cmd/loadtest/loadtest.go | 21 ++++++++----- cmd/loadtest/main.go | 31 ++++++++++--------- main.go | 54 +++++++++++++++++++--------------- 11 files changed, 73 insertions(+), 61 deletions(-) diff --git a/.dockerignore b/.dockerignore index bd6a53f..69a1767 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,5 @@ /.git/ -main +healthcheck aye-and-nay coverage.txt /badger/ diff --git a/.gitignore b/.gitignore index 4aa0a88..da553cd 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,7 @@ *.test # aye-and-nay -main +healthcheck aye-and-nay coverage.txt /badger/ diff --git a/Makefile b/Makefile index a99355c..df00949 100644 --- a/Makefile +++ b/Makefile @@ -33,16 +33,16 @@ prod-loadtest: go run ./cmd/loadtest/* -verbose=false prod-up: - docker compose --file ./build/docker-compose-prod.yml up -d --build + docker compose --file ./build/docker-compose-prod.yml --env-file ./build/config-prod.env up -d --build prod-down: - docker compose --file ./build/docker-compose-prod.yml down --rmi all -v + docker compose --file ./build/docker-compose-prod.yml --env-file ./build/config-prod.env down --rmi all -v embed-loadtest: - go run ./cmd/loadtest/* -verbose=false -api-address "http://localhost:8001" -minio-address "http://localhost:9000" -html-address "" + go run ./cmd/loadtest/* -verbose=false -api-address="http://localhost:8001" -html=false embed-up: - docker compose --file ./build/docker-compose-embed.yml up -d --build + docker compose --file ./build/docker-compose-embed.yml --env-file ./build/config-embed.env up -d --build embed-down: - docker compose --file ./build/docker-compose-embed.yml down --rmi all -v + docker compose --file ./build/docker-compose-embed.yml --env-file ./build/config-embed.env down --rmi all -v diff --git a/build/config-dev.env b/build/config-dev.env index 1f75152..7cc7caf 100644 --- a/build/config-dev.env +++ b/build/config-dev.env @@ -88,4 +88,4 @@ STORAGE_MINIO_RETRY_TIMES=4 STORAGE_MINIO_RETRY_PAUSE=5s STORAGE_MINIO_TIMEOUT=30s STORAGE_MINIO_LOCATION=eu-central-1 -STORAGE_MINIO_PREFIX=http://localhost:9000 +STORAGE_MINIO_PREFIX= diff --git a/build/config-embed.env b/build/config-embed.env index 2d79bd6..e910283 100644 --- a/build/config-embed.env +++ b/build/config-embed.env @@ -6,7 +6,7 @@ CONFIG_RELOAD_INTERVAL=1s APP_NAME=config-embed APP_LOG=info APP_GC_TUNER=true -APP_MEM_TOTAL=2147483648 # 2 GB +APP_MEM_TOTAL=2147483648 APP_MEM_LIMIT_RATIO=0.7 # SERVER @@ -29,7 +29,7 @@ CONTROLLER_MAX_NUMBER_OF_FILES=100 CONTROLLER_MAX_FILE_SIZE=5242880 # 5 MB # SERVICE -SERVICE_TEMP_LINKS=false +SERVICE_TEMP_LINKS=true SERVICE_NUMBER_OF_WORKERS_CALC=8 SERVICE_NUMBER_OF_WORKERS_COMP=8 SERVICE_ACCURACY=0.625 diff --git a/build/config-prod.env b/build/config-prod.env index a6a2bc5..550a2e0 100644 --- a/build/config-prod.env +++ b/build/config-prod.env @@ -6,7 +6,7 @@ CONFIG_RELOAD_INTERVAL=1s APP_NAME=config-prod APP_LOG=info APP_GC_TUNER=true -APP_MEM_TOTAL=2147483648 # 2 GB +APP_MEM_TOTAL=2147483648 APP_MEM_LIMIT_RATIO=0.7 # SERVER @@ -29,7 +29,7 @@ CONTROLLER_MAX_NUMBER_OF_FILES=100 CONTROLLER_MAX_FILE_SIZE=5242880 # 5 MB # SERVICE -SERVICE_TEMP_LINKS=false +SERVICE_TEMP_LINKS=true SERVICE_NUMBER_OF_WORKERS_CALC=8 SERVICE_NUMBER_OF_WORKERS_COMP=8 SERVICE_ACCURACY=0.625 @@ -88,4 +88,4 @@ STORAGE_MINIO_RETRY_TIMES=4 STORAGE_MINIO_RETRY_PAUSE=5s STORAGE_MINIO_TIMEOUT=30s STORAGE_MINIO_LOCATION=eu-central-1 -STORAGE_MINIO_PREFIX=/s3 +STORAGE_MINIO_PREFIX= diff --git a/build/docker-compose-embed.yml b/build/docker-compose-embed.yml index b75c1c4..c842e31 100644 --- a/build/docker-compose-embed.yml +++ b/build/docker-compose-embed.yml @@ -5,7 +5,6 @@ services: context: ./../ dockerfile: ./build/Dockerfile-app container_name: embed-app - env_file: config-embed.env deploy: resources: limits: diff --git a/build/docker-compose-prod.yml b/build/docker-compose-prod.yml index d18d176..76fe66d 100644 --- a/build/docker-compose-prod.yml +++ b/build/docker-compose-prod.yml @@ -21,7 +21,6 @@ services: context: ./../ dockerfile: ./build/Dockerfile-app container_name: prod-app - env_file: config-prod.env deploy: resources: limits: diff --git a/cmd/loadtest/loadtest.go b/cmd/loadtest/loadtest.go index 2e1c080..83dbc3b 100644 --- a/cmd/loadtest/loadtest.go +++ b/cmd/loadtest/loadtest.go @@ -105,10 +105,10 @@ func (l *loadtest) html(page string) { if l.err != nil { return } - if htmlAddress == "" { + if !html { return } - err := l.client.Do(http.MethodGet, htmlAddress+page, http.NoBody) + err := l.client.Do(http.MethodGet, apiAddress+page, http.NoBody) if err != nil { l.err = errors.Wrap(err) log.Error(l.err) @@ -131,14 +131,19 @@ func (l *loadtest) minio(src string) { if l.err != nil { return } - address := minioAddress - if strings.HasPrefix(src, "/api/images/") { - address = apiAddress - } - if minioAddress == "" && address == "" { + if !minio { return } - err := l.client.Do(http.MethodGet, address+src, http.NoBody) + address := "" + if strings.HasPrefix(src, "http://") || strings.HasPrefix(src, "https://") { + address = src + } else { + address = apiAddress + src + } + if !strings.HasPrefix(src, "/api/images/") { + return // FIXME + } + err := l.client.Do(http.MethodGet, address, http.NoBody) if err != nil { l.err = errors.Wrap(err) log.Error(l.err) diff --git a/cmd/loadtest/main.go b/cmd/loadtest/main.go index d75ff59..cdf769b 100644 --- a/cmd/loadtest/main.go +++ b/cmd/loadtest/main.go @@ -14,14 +14,14 @@ import ( ) var ( - duration time.Duration - connections int - timeout time.Duration - testdata string - apiAddress string - htmlAddress string - minioAddress string - verbose bool + duration time.Duration + connections int + timeout time.Duration + testdata string + apiAddress string + html bool + minio bool + verbose bool ) func main() { @@ -30,8 +30,8 @@ func main() { flag.DurationVar(&timeout, "timeout", 5*time.Second, "in seconds") flag.StringVar(&testdata, "testdata", "./testdata", "") flag.StringVar(&apiAddress, "api-address", "https://localhost", "") - flag.StringVar(&htmlAddress, "html-address", "https://localhost", "") - flag.StringVar(&minioAddress, "minio-address", "https://localhost", "") + flag.BoolVar(&html, "html", true, "") + flag.BoolVar(&minio, "minio", true, "") flag.BoolVar(&verbose, "verbose", true, "") flag.Parse() @@ -59,9 +59,12 @@ func main() { return case <-time.After(1 * time.Second): passed, failed := c.Stats() - log.Infof("%d rps, ", passed-passed1sAgo) - log.Infof("%d passed (%.2f%%), ", passed, float64(passed)/float64(passed+failed)*100) - log.Infof("%d failed (%.2f%%)\n", failed, float64(failed)/float64(passed+failed)*100) + log.Infof( + "%d rps, %d passed (%.2f%%), %d failed (%.2f%%)\n", + passed-passed1sAgo, + passed, float64(passed)/float64(passed+failed)*100, + failed, float64(failed)/float64(passed+failed)*100, + ) passed1sAgo = passed } } @@ -71,7 +74,7 @@ func main() { defer wg.Done() start := time.Now() sem := make(chan struct{}, connections) - for time.Since(start) < duration*time.Second { + for time.Since(start) < duration { select { case sem <- struct{}{}: case <-ctx.Done(): diff --git a/main.go b/main.go index e91a25f..c3fc713 100644 --- a/main.go +++ b/main.go @@ -12,6 +12,7 @@ import ( "golang.org/x/sync/errgroup" "github.com/zitryss/aye-and-nay/delivery/http" + "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/service" "github.com/zitryss/aye-and-nay/infrastructure/cache" "github.com/zitryss/aye-and-nay/infrastructure/compressor" @@ -35,6 +36,11 @@ func main() { flag.StringVar(&path, "config", "./config.env", "filepath to a config file") flag.Parse() + cach := domain.Cacher(nil) + comp := domain.Compresser(nil) + data := domain.Databaser(nil) + stor := domain.Storager(nil) + reload := true for reload { reload = false @@ -73,7 +79,7 @@ func main() { } } - cach, err := cache.New(ctx, conf.Cache) + cach, err = cache.New(ctx, conf.Cache) if err != nil { log.Critical(err) reload = true @@ -82,7 +88,7 @@ func main() { continue } - comp, err := compressor.New(ctx, conf.Compressor) + comp, err = compressor.New(ctx, conf.Compressor) if err != nil { log.Critical(err) reload = true @@ -91,7 +97,7 @@ func main() { continue } - data, err := database.New(ctx, conf.Database) + data, err = database.New(ctx, conf.Database) if err != nil { log.Critical(err) reload = true @@ -100,7 +106,7 @@ func main() { continue } - stor, err := storage.New(ctx, conf.Storage) + stor, err = storage.New(ctx, conf.Storage) if err != nil { log.Critical(err) reload = true @@ -190,30 +196,30 @@ func main() { log.Error(err) } - r, ok := cach.(*cache.Redis) - if ok { - err = r.Close(ctx) - if err != nil { - log.Error(err) - } - } + stop() + } - m, ok := data.(*database.Mongo) - if ok { - err = m.Close(ctx) - if err != nil { - log.Error(err) - } + r, ok := cach.(*cache.Redis) + if ok { + err = r.Close(context.Background()) + if err != nil { + log.Error(err) } + } - b, ok := data.(*database.Badger) - if ok { - err = b.Close(ctx) - if err != nil { - log.Error(err) - } + m, ok := data.(*database.Mongo) + if ok { + err = m.Close(context.Background()) + if err != nil { + log.Error(err) } + } - stop() + b, ok := data.(*database.Badger) + if ok { + err = b.Close(context.Background()) + if err != nil { + log.Error(err) + } } } From e2cb2ecd27a5669278f0e6007e7a855b520b177b Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Fri, 25 Mar 2022 11:38:09 +0100 Subject: [PATCH 64/92] Check key for existence --- infrastructure/cache/redis.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/infrastructure/cache/redis.go b/infrastructure/cache/redis.go index b5a6c48..1dce842 100644 --- a/infrastructure/cache/redis.go +++ b/infrastructure/cache/redis.go @@ -168,14 +168,10 @@ func (r *Redis) Push(ctx context.Context, album uint64, pairs [][2]uint64) error func (r *Redis) Pop(ctx context.Context, album uint64) (uint64, uint64, error) { albumB64 := base64.FromUint64(album) key := "album:" + albumB64 + ":pairs" - n, err := r.client.LLen(ctx, key).Result() - if err != nil { - return 0x0, 0x0, errors.Wrap(err) - } - if n == 0 { + val, err := r.client.LPop(ctx, key).Result() + if errors.Is(err, redisdb.Nil) { return 0x0, 0x0, errors.Wrap(domain.ErrPairNotFound) } - val, err := r.client.LPop(ctx, key).Result() if err != nil { return 0x0, 0x0, errors.Wrap(err) } From f5b52a6dba07923ee48deb55bc18d7c37507deb2 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Fri, 25 Mar 2022 13:28:21 +0100 Subject: [PATCH 65/92] Use transactions --- infrastructure/cache/redis.go | 73 +++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 20 deletions(-) diff --git a/infrastructure/cache/redis.go b/infrastructure/cache/redis.go index 1dce842..bcc326e 100644 --- a/infrastructure/cache/redis.go +++ b/infrastructure/cache/redis.go @@ -14,6 +14,10 @@ import ( "github.com/zitryss/aye-and-nay/pkg/retry" ) +const ( + retries = 5 +) + var ( _ domain.Cacher = (*Redis)(nil) ) @@ -59,21 +63,35 @@ func (r *Redis) Allow(ctx context.Context, ip uint64) (bool, error) { func (r *Redis) Add(ctx context.Context, queue uint64, album uint64) error { queueB64 := base64.FromUint64(queue) - albumB64 := base64.FromUint64(album) key1 := "queue:" + queueB64 + ":set" - ok, err := r.client.SIsMember(ctx, key1, albumB64).Result() - if err != nil { - return errors.Wrap(err) - } - if ok { + key2 := "queue:" + queueB64 + ":list" + txFn := func(tx *redisdb.Tx) error { + albumB64 := base64.FromUint64(album) + ok, err := tx.SIsMember(ctx, key1, albumB64).Result() + if err != nil { + return errors.Wrap(err) + } + if ok { + return nil + } + _, err = tx.SAdd(ctx, key1, albumB64).Result() + if err != nil { + return errors.Wrap(err) + } + _, err = tx.RPush(ctx, key2, albumB64).Result() + if err != nil { + return errors.Wrap(err) + } return nil } - _, err = r.client.SAdd(ctx, key1, albumB64).Result() - if err != nil { - return errors.Wrap(err) + err := error(nil) + for i := 0; i < retries; i++ { + err = r.client.Watch(ctx, txFn, key1, key2) + if err != nil { + continue + } + break } - key2 := "queue:" + queueB64 + ":list" - _, err = r.client.RPush(ctx, key2, albumB64).Result() if err != nil { return errors.Wrap(err) } @@ -83,16 +101,31 @@ func (r *Redis) Add(ctx context.Context, queue uint64, album uint64) error { func (r *Redis) Poll(ctx context.Context, queue uint64) (uint64, error) { queueB64 := base64.FromUint64(queue) key1 := "queue:" + queueB64 + ":list" - albumB64, err := r.client.LPop(ctx, key1).Result() - if errors.Is(err, redisdb.Nil) { - return 0x0, errors.Wrap(domain.ErrUnknown) - } key2 := "queue:" + queueB64 + ":set" - _, err = r.client.SRem(ctx, key2, albumB64).Result() - if err != nil { - return 0x0, errors.Wrap(err) + album := uint64(0x0) + txFn := func(tx *redisdb.Tx) error { + albumB64, err := tx.LPop(ctx, key1).Result() + if errors.Is(err, redisdb.Nil) { + return errors.Wrap(domain.ErrUnknown) + } + _, err = tx.SRem(ctx, key2, albumB64).Result() + if err != nil { + return errors.Wrap(err) + } + album, err = base64.ToUint64(albumB64) + if err != nil { + return errors.Wrap(err) + } + return nil + } + err := error(nil) + for i := 0; i < retries; i++ { + err = r.client.Watch(ctx, txFn, key1, key2) + if err != nil { + continue + } + break } - album, err := base64.ToUint64(albumB64) if err != nil { return 0x0, errors.Wrap(err) } @@ -149,9 +182,9 @@ func (r *Redis) PSize(ctx context.Context, pqueue uint64) (int, error) { } func (r *Redis) Push(ctx context.Context, album uint64, pairs [][2]uint64) error { + pipe := r.client.Pipeline() albumB64 := base64.FromUint64(album) key := "album:" + albumB64 + ":pairs" - pipe := r.client.Pipeline() for _, images := range pairs { image0B64 := base64.FromUint64(images[0]) image1B64 := base64.FromUint64(images[1]) From 804e038fde7ec0b73846b1108929f97156df52de Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Fri, 25 Mar 2022 14:45:17 +0100 Subject: [PATCH 66/92] Add Tx parameter --- build/config-dev.env | 1 + build/config-embed.env | 1 + build/config-prod.env | 1 + config.env | 1 + infrastructure/cache/config.go | 2 ++ infrastructure/cache/redis.go | 38 ++++++++++++++++++++++++++-------- main.go | 16 +++++++------- 7 files changed, 43 insertions(+), 17 deletions(-) diff --git a/build/config-dev.env b/build/config-dev.env index 7cc7caf..57f5c5f 100644 --- a/build/config-dev.env +++ b/build/config-dev.env @@ -43,6 +43,7 @@ CACHE_REDIS_RETRY_TIMES=4 CACHE_REDIS_RETRY_PAUSE=5s CACHE_REDIS_TIMEOUT=30s CACHE_REDIS_TIME_TO_LIVE=15m +CACHE_REDIS_TX_RETRIES=5 # COMPRESSOR: [mock, shortpixel, imaginary] APP_COMPRESSOR=mock diff --git a/build/config-embed.env b/build/config-embed.env index e910283..71f1d57 100644 --- a/build/config-embed.env +++ b/build/config-embed.env @@ -43,6 +43,7 @@ CACHE_REDIS_RETRY_TIMES=4 CACHE_REDIS_RETRY_PAUSE=5s CACHE_REDIS_TIMEOUT=30s CACHE_REDIS_TIME_TO_LIVE=15m +CACHE_REDIS_TX_RETRIES=5 # COMPRESSOR: [mock, shortpixel, imaginary] APP_COMPRESSOR=mock diff --git a/build/config-prod.env b/build/config-prod.env index 550a2e0..dbc9d5e 100644 --- a/build/config-prod.env +++ b/build/config-prod.env @@ -43,6 +43,7 @@ CACHE_REDIS_RETRY_TIMES=4 CACHE_REDIS_RETRY_PAUSE=5s CACHE_REDIS_TIMEOUT=30s CACHE_REDIS_TIME_TO_LIVE=15m +CACHE_REDIS_TX_RETRIES=5 # COMPRESSOR: [mock, shortpixel, imaginary] APP_COMPRESSOR=mock diff --git a/config.env b/config.env index c08f4aa..e901747 100644 --- a/config.env +++ b/config.env @@ -43,6 +43,7 @@ CACHE_REDIS_RETRY_TIMES=4 CACHE_REDIS_RETRY_PAUSE=5s CACHE_REDIS_TIMEOUT=30s CACHE_REDIS_TIME_TO_LIVE=15m +CACHE_REDIS_TX_RETRIES=5 # COMPRESSOR: [mock, shortpixel, imaginary] APP_COMPRESSOR=mock diff --git a/infrastructure/cache/config.go b/infrastructure/cache/config.go index c4ad289..a1efd4a 100644 --- a/infrastructure/cache/config.go +++ b/infrastructure/cache/config.go @@ -26,6 +26,7 @@ type RedisConfig struct { LimiterRequestsPerSecond int `mapstructure:"MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND" validate:"required"` LimiterBurst int64 `mapstructure:"MIDDLEWARE_LIMITER_BURST" validate:"required"` TimeToLive time.Duration `mapstructure:"CACHE_REDIS_TIME_TO_LIVE" validate:"required"` + TxRetries int `mapstructure:"CACHE_REDIS_TX_RETRIES" validate:"required"` } var ( @@ -44,5 +45,6 @@ var ( LimiterRequestsPerSecond: 1, LimiterBurst: 1, TimeToLive: 3 * time.Second, + TxRetries: 1, } ) diff --git a/infrastructure/cache/redis.go b/infrastructure/cache/redis.go index bcc326e..ab9abf9 100644 --- a/infrastructure/cache/redis.go +++ b/infrastructure/cache/redis.go @@ -14,10 +14,6 @@ import ( "github.com/zitryss/aye-and-nay/pkg/retry" ) -const ( - retries = 5 -) - var ( _ domain.Cacher = (*Redis)(nil) ) @@ -85,7 +81,7 @@ func (r *Redis) Add(ctx context.Context, queue uint64, album uint64) error { return nil } err := error(nil) - for i := 0; i < retries; i++ { + for i := 0; i < r.conf.TxRetries; i++ { err = r.client.Watch(ctx, txFn, key1, key2) if err != nil { continue @@ -119,7 +115,7 @@ func (r *Redis) Poll(ctx context.Context, queue uint64) (uint64, error) { return nil } err := error(nil) - for i := 0; i < retries; i++ { + for i := 0; i < r.conf.TxRetries; i++ { err = r.client.Watch(ctx, txFn, key1, key2) if err != nil { continue @@ -134,12 +130,36 @@ func (r *Redis) Poll(ctx context.Context, queue uint64) (uint64, error) { func (r *Redis) Size(ctx context.Context, queue uint64) (int, error) { queueB64 := base64.FromUint64(queue) - key := "queue:" + queueB64 + ":set" - n, err := r.client.SCard(ctx, key).Result() + key1 := "queue:" + queueB64 + ":set" + key2 := "queue:" + queueB64 + ":list" + n := 0 + txFn := func(tx *redisdb.Tx) error { + n1, err := r.client.SCard(ctx, key1).Result() + if err != nil { + return errors.Wrap(err) + } + n2, err := r.client.LLen(ctx, key2).Result() + if err != nil { + return errors.Wrap(err) + } + if n1 != n2 { + return errors.Wrap(domain.ErrUnknown) + } + n = int(n1) + return nil + } + err := error(nil) + for i := 0; i < r.conf.TxRetries; i++ { + err = r.client.Watch(ctx, txFn, key1, key2) + if err != nil { + continue + } + break + } if err != nil { return 0, errors.Wrap(err) } - return int(n), nil + return n, nil } func (r *Redis) PAdd(ctx context.Context, pqueue uint64, album uint64, expires time.Time) error { diff --git a/main.go b/main.go index c3fc713..148e84b 100644 --- a/main.go +++ b/main.go @@ -197,6 +197,14 @@ func main() { } stop() + + b, ok := data.(*database.Badger) + if ok { + err = b.Close(context.Background()) + if err != nil { + log.Error(err) + } + } } r, ok := cach.(*cache.Redis) @@ -214,12 +222,4 @@ func main() { log.Error(err) } } - - b, ok := data.(*database.Badger) - if ok { - err = b.Close(context.Background()) - if err != nil { - log.Error(err) - } - } } From 519195eeb20ed1097726b055df7d5fc23b15daa7 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Fri, 25 Mar 2022 15:24:29 +0100 Subject: [PATCH 67/92] Upgrade to 1.18 --- .github/workflows/integration.yml | 2 +- .github/workflows/loadtest.yml | 2 +- .github/workflows/unit.yml | 2 +- build/Dockerfile-app | 2 +- go.mod | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index f21aa08..466a3f4 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -10,7 +10,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: - go-version: 1.17 + go-version: 1.18 - uses: actions/cache@v2 with: path: ~/go/pkg/mod diff --git a/.github/workflows/loadtest.yml b/.github/workflows/loadtest.yml index c92566e..fb1c4a6 100644 --- a/.github/workflows/loadtest.yml +++ b/.github/workflows/loadtest.yml @@ -10,7 +10,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: - go-version: 1.17 + go-version: 1.18 - uses: actions/cache@v2 with: path: ~/go/pkg/mod diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index b9fbfb4..40985ef 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -10,7 +10,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: - go-version: 1.17 + go-version: 1.18 - uses: actions/cache@v2 with: path: ~/go/pkg/mod diff --git a/build/Dockerfile-app b/build/Dockerfile-app index e6d4f08..34164d6 100644 --- a/build/Dockerfile-app +++ b/build/Dockerfile-app @@ -1,4 +1,4 @@ -FROM golang:1.17-alpine AS builder +FROM golang:1.18-alpine AS builder RUN apk add --no-cache make RUN addgroup -S appgroup && adduser -S appuser -G appgroup WORKDIR /app/ diff --git a/go.mod b/go.mod index a80ddb5..3324945 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/zitryss/aye-and-nay -go 1.17 +go 1.18 require ( github.com/caddyserver/certmagic v0.15.2 From 9e2e87107d6b9eeb658580e12cfa8c6b8b9a25c9 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Fri, 25 Mar 2022 15:27:23 +0100 Subject: [PATCH 68/92] Update go mod --- go.mod | 40 ++-- go.sum | 593 ++++++--------------------------------------------------- 2 files changed, 78 insertions(+), 555 deletions(-) diff --git a/go.mod b/go.mod index 3324945..01b9dfa 100644 --- a/go.mod +++ b/go.mod @@ -3,41 +3,43 @@ module github.com/zitryss/aye-and-nay go 1.18 require ( - github.com/caddyserver/certmagic v0.15.2 + github.com/caddyserver/certmagic v0.15.4 github.com/dgraph-io/badger/v3 v3.2103.2 github.com/emirpasic/gods v1.12.0 github.com/go-playground/validator v9.31.0+incompatible - github.com/go-redis/redis/v8 v8.11.4 + github.com/go-redis/redis/v8 v8.11.5 github.com/go-redis/redis_rate/v9 v9.1.2 github.com/hashicorp/golang-lru v0.5.4 github.com/julienschmidt/httprouter v1.3.0 github.com/mailru/easyjson v0.7.7 - github.com/minio/minio-go/v7 v7.0.16 - github.com/ory/dockertest/v3 v3.6.5 + github.com/minio/minio-go/v7 v7.0.23 + github.com/ory/dockertest/v3 v3.8.1 github.com/radovskyb/watcher v1.0.7 - github.com/rs/cors v1.8.0 + github.com/rs/cors v1.8.2 github.com/segmentio/asm v1.1.3 github.com/shirou/gopsutil v3.21.11+incompatible - github.com/spf13/viper v1.9.0 - github.com/stretchr/testify v1.7.0 - go.mongodb.org/mongo-driver v1.8.0 - golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c + github.com/spf13/viper v1.10.1 + github.com/stretchr/testify v1.7.1 + go.mongodb.org/mongo-driver v1.8.4 + golang.org/x/net v0.0.0-20220225172249-27dd8689420f golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 - golang.org/x/tools v0.1.7 + golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 + golang.org/x/tools v0.1.10 ) require ( github.com/Azure/go-ansiterm v0.0.0-20210608035416-43c61cb656b4 // indirect - github.com/Microsoft/go-winio v0.5.0 // indirect + github.com/Microsoft/go-winio v0.5.1 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect - github.com/cenkalti/backoff/v4 v4.1.1 // indirect + github.com/cenkalti/backoff/v4 v4.1.2 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/containerd/continuity v0.1.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgraph-io/ristretto v0.1.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/docker/cli v20.10.11+incompatible // indirect + github.com/docker/docker v20.10.7+incompatible // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.4.0 // indirect github.com/dustin/go-humanize v1.0.0 // indirect @@ -52,8 +54,10 @@ require ( github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/flatbuffers v2.0.0+incompatible // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.3.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect + github.com/imdario/mergo v0.3.12 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.13.6 // indirect @@ -74,8 +78,8 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.0.1 // indirect - github.com/opencontainers/runc v1.0.0-rc95 // indirect + github.com/opencontainers/image-spec v1.0.2 // indirect + github.com/opencontainers/runc v1.0.2 // indirect github.com/pelletier/go-toml v1.9.4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -92,6 +96,9 @@ require ( github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.0.2 // indirect github.com/xdg-go/stringprep v1.0.2 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect go.opencensus.io v0.23.0 // indirect @@ -99,12 +106,13 @@ require ( go.uber.org/multierr v1.7.0 // indirect go.uber.org/zap v1.19.1 // indirect golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 // indirect - golang.org/x/mod v0.5.1 // indirect + golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/protobuf v1.27.1 // indirect gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect + gopkg.in/go-playground/assert.v1 v1.2.1 // indirect gopkg.in/ini.v1 v1.66.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect diff --git a/go.sum b/go.sum index f38e086..9ad7848 100644 --- a/go.sum +++ b/go.sum @@ -1,78 +1,27 @@ bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/firestore v1.6.0/go.mod h1:afJwI0vaXwAG54kI7A//lP/lSPDkQORQuMkv56TxEPU= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210608035416-43c61cb656b4 h1:poX3j1kSFMgZhtUGrKSAwjh/FKVYrzvoXzwyXPHkAv0= github.com/Azure/go-ansiterm v0.0.0-20210608035416-43c61cb656b4/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= -github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU= -github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= +github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/caddyserver/certmagic v0.15.2 h1:OMTakTsLM1ZfzMDjwvYprfUgFzpVPh3u87oxMPwmeBc= -github.com/caddyserver/certmagic v0.15.2/go.mod h1:qhkAOthf72ufAcp3Y5jF2RaGE96oip3UbEQRIzwe3/8= -github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= -github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ= -github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/caddyserver/certmagic v0.15.4 h1:kz//9+Z/xw197jtIBxxUDub8pQi9gcYvhXk5Ouw2EkM= +github.com/caddyserver/certmagic v0.15.4/go.mod h1:qhkAOthf72ufAcp3Y5jF2RaGE96oip3UbEQRIzwe3/8= +github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= +github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= @@ -80,15 +29,9 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.1.0 h1:UFRRY5JemiAhPZrr/uE0n8fMTLcZsUvySPr1+D7pgr8= @@ -97,9 +40,7 @@ github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkE github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.3.1/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= @@ -122,6 +63,10 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUn github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/docker/cli v20.10.11+incompatible h1:tXU1ezXcruZQRrMP8RN2z9N91h+6egZTS1gsPsKantc= +github.com/docker/cli v20.10.11+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/docker v20.10.7+incompatible h1:Z6O9Nhsjv+ayUEeI1IojKbYcsGdgYSNqxe1s2MYzUhQ= +github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= @@ -133,24 +78,12 @@ github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= @@ -162,14 +95,13 @@ github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rm github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-playground/validator v9.31.0+incompatible h1:UA72EPEogEnq76ehGdEDp4Mit+3FDh548oRqwVgNsHA= github.com/go-playground/validator v9.31.0+incompatible/go.mod h1:yrEkQXlcI+PugkyDjY2bRrL/UBU4f3rvrgkN3V8JEig= -github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg= -github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-redis/redis_rate/v9 v9.1.2 h1:H0l5VzoAtOE6ydd38j8MCq3ABlGLnvvbA1xDSVVCHgQ= github.com/go-redis/redis_rate/v9 v9.1.2/go.mod h1:oam2de2apSgRG8aJzwJddXbNu91Iyz1m8IKJE2vpvlQ= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= @@ -180,24 +112,13 @@ github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -205,17 +126,14 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/flatbuffers v2.0.0+incompatible h1:dicJ2oXwypfwUGnB2/TYWYEKiuk9eYQlQO/AnOHl5mI= @@ -224,87 +142,35 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= -github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= -github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= @@ -312,22 +178,16 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s= -github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -345,37 +205,21 @@ github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaW github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mholt/acmez v1.0.1 h1:J7uquHOKEmo71UDnVApy1sSLA0oF/r+NtVrNzMKKA9I= github.com/mholt/acmez v1.0.1/go.mod h1:8qnn8QA/Ewx8E3ZSsmscqsIjhhpxuy9vqdgbX2ceceM= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg= github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= -github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= -github.com/minio/minio-go/v7 v7.0.16 h1:GspaSBS8lOuEUCAqMe0W3UxSoyOA4b4F8PTspRVI+k4= -github.com/minio/minio-go/v7 v7.0.16/go.mod h1:pUV0Pc+hPd1nccgmzQF/EXh48l/Z/yps6QPF1aaie4g= -github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/minio-go/v7 v7.0.23 h1:NleyGQvAn9VQMU+YHVrgV4CX+EPtxPt/78lHOOTncy4= +github.com/minio/minio-go/v7 v7.0.23/go.mod h1:ei5JjmxwHaMrgsMrn4U/+Nmg+d8MKS1U2DAn1ou4+Do= github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= -github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= @@ -384,8 +228,6 @@ github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXy github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= @@ -393,31 +235,21 @@ github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= -github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= -github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runc v1.0.0-rc95 h1:RMuWVfY3E1ILlVsC3RhIq38n4sJtlOFwU9gfFZSqrd0= -github.com/opencontainers/runc v1.0.0-rc95/go.mod h1:z+bZxa/+Tz/FmYVWkhUajJdzFeOqjc5vrqskhVyHGUM= +github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v1.0.2 h1:opHZMaswlyxz1OuGpBE53Dwe4/xF7EZTY0A2L/FpCOg= +github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= -github.com/ory/dockertest/v3 v3.6.5 h1:mhNKFeVEHuvaYW+/u+59mLzM/6XXGjpaet/yApgv+yc= -github.com/ory/dockertest/v3 v3.6.5/go.mod h1:iYKQSRlYrt/2s5fJWYdB98kCQG6g/LjBMvzEYii63vg= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= +github.com/ory/dockertest/v3 v3.8.1 h1:vU/8d1We4qIad2YM0kOwRVtnyue7ExvacPiw1yDm17g= +github.com/ory/dockertest/v3 v3.8.1/go.mod h1:wSRQ3wmkz+uSARYMk7kVJFDBGm8x5gSxIhI7NDc+BAQ= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= @@ -428,8 +260,6 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= 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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -443,18 +273,13 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T github.com/radovskyb/watcher v1.0.7 h1:AYePLih6dpmS32vlHfhCeli8127LzkIgwJGcwwe8tUE= github.com/radovskyb/watcher v1.0.7/go.mod h1:78okwvY5wPdzcb1UYnip1pvrZNIVEIh/Cm+ZuvsUYIg= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rs/cors v1.8.0 h1:P2KMzcFwrPoSjkF1WLRPsp3UMLyql8L4v9hQpVeK5so= -github.com/rs/cors v1.8.0/go.mod h1:EBwu+T5AvHOcXwvZIkQFjUN6s8Czyqw12GL/Y0tUyRM= -github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= +github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sagikazarmark/crypt v0.1.0/go.mod h1:B/mN0msZuINBtQ1zZLEQcegFJJf9vnYIR88KRMEuODE= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/segmentio/asm v1.1.3 h1:WM03sfUOENvvKexOLp+pCqgb/WDjsi7EK8gIsICtzhc= github.com/segmentio/asm v1.1.3/go.mod h1:Ld3L4ZXGNcSLRg4JBsZ3//1+f/TjYl0Mzen/DQy1EJg= @@ -462,13 +287,9 @@ github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKl github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= @@ -489,17 +310,17 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.9.0 h1:yR6EXjTp0y0cLN8OZg1CRZmOBdI88UcGkhgyJhu6nZk= -github.com/spf13/viper v1.9.0/go.mod h1:+i6ajR7OX2XaiBkrcZJFK21htRk7eDeLg7+O6bhUPP4= +github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk= +github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= @@ -512,47 +333,38 @@ github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq// github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= -github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc= github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk= github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.mongodb.org/mongo-driver v1.8.0 h1:R/P/JJzu8LJvJ1lDfph9GLNIKQxEtIHFfnUUUve35zY= -go.mongodb.org/mongo-driver v1.8.0/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.mongodb.org/mongo-driver v1.8.4 h1:NruvZPPL0PBcRJKmbswoWSrmHeUvzdxA3GCPfD/NEOA= +go.mongodb.org/mongo-driver v1.8.4/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -572,412 +384,130 @@ go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 h1:/pEO3GD/ABYAjuakUS6xSEmmlyVS4kxBNkeA9tLJiTI= golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c h1:WtYZ93XtWSO5KlOMgPZu7hXY9WhMZpprvlm5VwvAl8c= -golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 h1:XDXtA5hveEEV8JB2l7nhMTp3t3cHp9ZpwcdjqyEWLlo= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M= -golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs= +golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -986,7 +516,6 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= @@ -999,23 +528,15 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= -gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -1023,15 +544,9 @@ 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.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= From 5863402a5b2fd46e68ced309add8e1157b7fb10f Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sun, 27 Mar 2022 03:00:09 +0200 Subject: [PATCH 69/92] Fix scope --- delivery/http/error.go | 3 +-- domain/service/error.go | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/delivery/http/error.go b/delivery/http/error.go index a65136a..985bb37 100644 --- a/delivery/http/error.go +++ b/delivery/http/error.go @@ -45,8 +45,7 @@ func handleOuterError(w http.ResponseWriter, err error) { _ = json.NewEncoder(w).Encode(resp) }() cause := errors.Cause(err) - e := domain.Error(nil) - if errors.As(cause, &e) { + if e := domain.Error(nil); errors.As(cause, &e) { out := e.Outer() resp.Error.statusCode = out.StatusCode resp.Error.AppCode = out.AppCode diff --git a/domain/service/error.go b/domain/service/error.go index 570afc9..5adf3d5 100644 --- a/domain/service/error.go +++ b/domain/service/error.go @@ -14,8 +14,7 @@ func handleError(err error) { func HandleInnerError(err error) { cause := errors.Cause(err) - e := domain.Error(nil) - if errors.As(cause, &e) { + if e := domain.Error(nil); errors.As(cause, &e) { log.Println(log.Level(e.Inner().Level), err) return } From b0a0809f731623ad17e2a8693a76baab7f63ab13 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Mon, 28 Mar 2022 23:55:15 +0200 Subject: [PATCH 70/92] Test improvements --- delivery/http/controller.go | 14 +-- domain/domain/error.go | 11 ++ internal/gctuner/gctuner.go | 65 +++++++---- internal/gctuner/gctuner_test.go | 188 +++++++++++++++++++++++++++++++ pkg/base64/base64.go | 4 + pkg/base64/base64_test.go | 27 +++++ 6 files changed, 283 insertions(+), 26 deletions(-) create mode 100644 internal/gctuner/gctuner_test.go create mode 100644 pkg/base64/base64_test.go diff --git a/delivery/http/controller.go b/delivery/http/controller.go index 9cae6fc..a62a66f 100644 --- a/delivery/http/controller.go +++ b/delivery/http/controller.go @@ -168,7 +168,7 @@ func (c *controller) handleStatus() httprouter.Handle { process := func(ctx context.Context, req statusRequest) (statusResponse, error) { album, err := base64.ToUint64(req.album.id) if err != nil { - return statusResponse{}, errors.Wrap(err) + return statusResponse{}, errors.Wrap(domain.ErrInvalidId) } p, err := c.serv.Progress(ctx, album) if err != nil { @@ -215,7 +215,7 @@ func (c *controller) handlePair() httprouter.Handle { process := func(ctx context.Context, req pairRequest) (pairResponse, error) { album, err := base64.ToUint64(req.album.id) if err != nil { - return pairResponse{}, errors.Wrap(err) + return pairResponse{}, errors.Wrap(domain.ErrInvalidId) } img1, img2, err := c.serv.Pair(ctx, album) if err != nil { @@ -267,7 +267,7 @@ func (c *controller) handleImage() httprouter.Handle { process := func(ctx context.Context, req imageRequest) (imageResponse, error) { token, err := base64.ToUint64(req.image.token) if err != nil { - return imageResponse{}, errors.Wrap(err) + return imageResponse{}, errors.Wrap(domain.ErrInvalidId) } f, err := c.serv.Image(ctx, token) if err != nil { @@ -321,15 +321,15 @@ func (c *controller) handleVote() httprouter.Handle { process := func(ctx context.Context, req voteRequest) (voteResponse, error) { album, err := base64.ToUint64(req.Album.id) if err != nil { - return voteResponse{}, errors.Wrap(err) + return voteResponse{}, errors.Wrap(domain.ErrInvalidId) } imgFromToken, err := base64.ToUint64(req.Album.ImgFrom.Token) if err != nil { - return voteResponse{}, errors.Wrap(err) + return voteResponse{}, errors.Wrap(domain.ErrInvalidId) } imgToToken, err := base64.ToUint64(req.Album.ImgTo.Token) if err != nil { - return voteResponse{}, errors.Wrap(err) + return voteResponse{}, errors.Wrap(domain.ErrInvalidId) } err = c.serv.Vote(ctx, album, imgFromToken, imgToToken) if err != nil { @@ -370,7 +370,7 @@ func (c *controller) handleTop() httprouter.Handle { process := func(ctx context.Context, req topRequest) (topResponse, error) { album, err := base64.ToUint64(req.album.id) if err != nil { - return topResponse{}, errors.Wrap(err) + return topResponse{}, errors.Wrap(domain.ErrInvalidId) } imgs, err := c.serv.Top(ctx, album) if err != nil { diff --git a/domain/domain/error.go b/domain/domain/error.go index 974d570..2e9f897 100644 --- a/domain/domain/error.go +++ b/domain/domain/error.go @@ -113,6 +113,17 @@ var ( DevMsg: "duration invalid", }, } + ErrInvalidId = &domainError{ + outerError: outerError{ + StatusCode: http.StatusBadRequest, + AppCode: 0x17, + UserMsg: "id invalid", + }, + innerError: innerError{ + Level: logDebug, + DevMsg: "id invalid", + }, + } ErrAlbumNotFound = &domainError{ outerError: outerError{ StatusCode: http.StatusNotFound, diff --git a/internal/gctuner/gctuner.go b/internal/gctuner/gctuner.go index 998d306..d0c72f0 100644 --- a/internal/gctuner/gctuner.go +++ b/internal/gctuner/gctuner.go @@ -11,6 +11,7 @@ import ( "github.com/shirou/gopsutil/mem" "github.com/shirou/gopsutil/process" + "github.com/spf13/afero" "github.com/zitryss/aye-and-nay/pkg/errors" "github.com/zitryss/aye-and-nay/pkg/log" @@ -25,6 +26,7 @@ var ( lastGOGC float64 memTotal float64 memLimitRatio = 0.7 + appFs = afero.NewOsFs() ) func Start(ctx context.Context, total int, ratio float64) error { @@ -39,7 +41,7 @@ func Start(ctx context.Context, total int, ratio float64) error { return errors.Wrap(err) } } - if total >= 0.0 { + if total > 0.0 { memTotal = float64(total) } if ratio > 0.0 && ratio <= 1.0 { @@ -73,37 +75,62 @@ func checkMemTotal() error { } func checkCgroup() error { - for _, path := range []string{cgroupMemTotalPathV1, cgroupMemTotalPathV2} { - f, err := os.Open(path) - if err != nil { - continue - } - defer f.Close() - err = readCgroupMemTotal(f) - if err != nil { - return errors.Wrap(err) - } + var ( + f io.ReadCloser + err error + e error + mt float64 + ) + f, err = appFs.Open(cgroupMemTotalPathV1) + if err != nil { + e = errors.Wrap(err) + goto second_file + } + defer f.Close() + mt, err = readCgroupMemTotal(f) + if err != nil { + e = errors.Wrap(err) + goto second_file + } + if mt > 0.0 && mt < memTotal { + memTotal = mt + } +second_file: + f, err = appFs.Open(cgroupMemTotalPathV2) + if err != nil { + return nil + } + defer f.Close() + mt, err = readCgroupMemTotal(f) + if err != nil && e != nil { + return errors.Wrapf(err, "%s", e) + } + if err != nil && e == nil { + return nil + } + if mt > 0.0 && mt < memTotal { + memTotal = mt } return nil } -func readCgroupMemTotal(f io.Reader) error { +func readCgroupMemTotal(f io.Reader) (float64, error) { b, err := io.ReadAll(f) if err != nil { - return errors.Wrap(err) + return 0.0, errors.Wrap(err) } s := strings.TrimSpace(string(b)) - if s == "max" { - return nil + if s == "" || s == "max" { + return 0.0, nil } cgroupMemTotal, err := strconv.ParseFloat(s, 64) if err != nil { - return errors.Wrap(err) + return 0.0, errors.Wrap(err) } - if cgroupMemTotal > 0.0 && cgroupMemTotal < memTotal { - memTotal = cgroupMemTotal + if cgroupMemTotal <= 0.0 { + return 0.0, nil } - return nil + return cgroupMemTotal, nil } type finalizer struct { diff --git a/internal/gctuner/gctuner_test.go b/internal/gctuner/gctuner_test.go new file mode 100644 index 0000000..f157028 --- /dev/null +++ b/internal/gctuner/gctuner_test.go @@ -0,0 +1,188 @@ +package gctuner + +import ( + "io" + "strings" + "testing" + + "github.com/spf13/afero" + "github.com/stretchr/testify/assert" +) + +func TestReadCgroupMemTotal(t *testing.T) { + tests := []struct { + f io.Reader + want float64 + wantErr bool + }{ + { + f: strings.NewReader(""), + want: 0, + wantErr: true, + }, + { + f: strings.NewReader("0"), + want: 0, + wantErr: false, + }, + { + f: strings.NewReader("1"), + want: 1, + wantErr: false, + }, + { + f: strings.NewReader("\r1\n"), + want: 1, + wantErr: false, + }, + { + f: strings.NewReader("-1"), + want: 0, + wantErr: false, + }, + { + f: strings.NewReader("9223372036854775807"), + want: 9223372036854775807, + wantErr: false, + }, + { + f: strings.NewReader("-9223372036854775808"), + want: 0, + wantErr: false, + }, + { + f: strings.NewReader("max"), + want: 0, + wantErr: false, + }, + { + f: strings.NewReader("abc"), + want: 0, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run("", func(t *testing.T) { + got, err := readCgroupMemTotal(tt.f) + if (err != nil) != tt.wantErr { + assert.Error(t, err) + return + } + assert.Equal(t, tt.want, got) + }) + } +} + +func TestMemTotal(t *testing.T) { + tests := []struct { + total float64 + cgroupMemTotalV1 []byte + cgroupMemTotalV2 []byte + want float64 + }{ + { + total: 1073741824, + cgroupMemTotalV1: []byte(""), + cgroupMemTotalV2: []byte("-1"), + want: 1073741824, + }, + { + total: 1073741824, + cgroupMemTotalV1: []byte("$%^&"), + cgroupMemTotalV2: []byte("0"), + want: 1073741824, + }, + { + total: 1073741824, + cgroupMemTotalV1: []byte("max"), + cgroupMemTotalV2: []byte("$%^&"), + want: 1073741824, + }, + { + total: 0, + cgroupMemTotalV1: []byte("943718400\n"), + cgroupMemTotalV2: nil, + want: 943718400, + }, + { + total: 0, + cgroupMemTotalV1: nil, + cgroupMemTotalV2: []byte("734003200\n"), + want: 734003200, + }, + + { + total: 1073741824, + cgroupMemTotalV1: []byte("943718400\n"), + cgroupMemTotalV2: nil, + want: 943718400, + }, + { + total: 943718400, + cgroupMemTotalV1: []byte("1073741824\n"), + cgroupMemTotalV2: nil, + want: 943718400, + }, + { + total: 1073741824, + cgroupMemTotalV1: nil, + cgroupMemTotalV2: []byte("943718400\n"), + want: 943718400, + }, + { + total: 943718400, + cgroupMemTotalV1: nil, + cgroupMemTotalV2: []byte("1073741824\n"), + want: 943718400, + }, + { + total: 0, + cgroupMemTotalV1: []byte("943718400\n"), + cgroupMemTotalV2: []byte("1073741824\n"), + want: 943718400, + }, + { + total: 0, + cgroupMemTotalV1: []byte("1073741824\n"), + cgroupMemTotalV2: []byte("943718400\n"), + want: 943718400, + }, + { + total: 734003200, + cgroupMemTotalV1: []byte("1073741824\n"), + cgroupMemTotalV2: []byte("943718400\n"), + want: 734003200, + }, + { + total: 943718400, + cgroupMemTotalV1: []byte("1073741824\n"), + cgroupMemTotalV2: []byte("734003200\n"), + want: 734003200, + }, + { + total: 1073741824, + cgroupMemTotalV1: []byte("734003200\n"), + cgroupMemTotalV2: []byte("943718400\n"), + want: 734003200, + }, + } + for _, tt := range tests { + t.Run("", func(t *testing.T) { + appFs = afero.NewMemMapFs() + if tt.cgroupMemTotalV1 != nil { + err := afero.WriteFile(appFs, cgroupMemTotalPathV1, tt.cgroupMemTotalV1, 0644) + assert.NoError(t, err) + } + if tt.cgroupMemTotalV2 != nil { + err := afero.WriteFile(appFs, cgroupMemTotalPathV2, tt.cgroupMemTotalV2, 0644) + assert.NoError(t, err) + } + memTotal = tt.total + err := checkMemTotal() + assert.NoError(t, err) + err = checkCgroup() + assert.NoError(t, err) + assert.Equal(t, tt.want, memTotal) + }) + } +} diff --git a/pkg/base64/base64.go b/pkg/base64/base64.go index 859082c..bee0414 100644 --- a/pkg/base64/base64.go +++ b/pkg/base64/base64.go @@ -2,6 +2,7 @@ package base64 import ( "encoding/binary" + "errors" "github.com/segmentio/asm/base64" ) @@ -17,5 +18,8 @@ func ToUint64(s string) (uint64, error) { if err != nil { return 0x0, err } + if len(b) != 8 { + return 0x0, errors.New("invalid input") + } return binary.LittleEndian.Uint64(b), nil } diff --git a/pkg/base64/base64_test.go b/pkg/base64/base64_test.go new file mode 100644 index 0000000..aa4cd33 --- /dev/null +++ b/pkg/base64/base64_test.go @@ -0,0 +1,27 @@ +package base64 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func FuzzFromUint64(f *testing.F) { + f.Add(uint64(0)) + f.Fuzz(func(t *testing.T, u1 uint64) { + b64 := FromUint64(u1) + u2, err := ToUint64(b64) + assert.NoError(t, err) + assert.Equal(t, u1, u2) + }) +} + +func FuzzToUint64(f *testing.F) { + f.Add("AAAAAAAAAAA") + f.Fuzz(func(t *testing.T, s string) { + _, err := ToUint64(s) + if err != nil { + t.Skip() + } + }) +} From 273ce8ac1b7562a772c6f89054e01142e7eeaacd Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Tue, 29 Mar 2022 12:18:23 +0200 Subject: [PATCH 71/92] Replace interface{} with any --- domain/service/service.go | 12 +++---- domain/service/service_integration_test.go | 6 ++-- domain/service/service_test.go | 12 +++---- infrastructure/cache/mem.go | 14 ++++---- infrastructure/cache/mem_test.go | 12 +++---- infrastructure/compressor/shortpixel.go | 8 ++--- infrastructure/compressor/shortpixel_test.go | 36 ++++++++++---------- infrastructure/database/mongo.go | 2 +- internal/testing/testing.go | 6 ++-- pkg/errors/errors.go | 4 +-- pkg/log/log.go | 26 +++++++------- pkg/log/log_test.go | 4 +-- pkg/pool/pool.go | 2 +- 13 files changed, 72 insertions(+), 72 deletions(-) diff --git a/domain/service/service.go b/domain/service/service.go index db89b3b..8feebb4 100644 --- a/domain/service/service.go +++ b/domain/service/service.go @@ -96,19 +96,19 @@ func WithRandShuffle(fn func(int, func(int, int))) options { } } -func WithHeartbeatCalc(ch chan<- interface{}) options { +func WithHeartbeatCalc(ch chan<- any) options { return func(s *Service) { s.heartbeat.calc = ch } } -func WithHeartbeatComp(ch chan<- interface{}) options { +func WithHeartbeatComp(ch chan<- any) options { return func(s *Service) { s.heartbeat.comp = ch } } -func WithHeartbeatDel(ch chan<- interface{}) options { +func WithHeartbeatDel(ch chan<- any) options { return func(s *Service) { s.heartbeat.del = ch } @@ -132,9 +132,9 @@ type Service struct { shuffle func(n int, swap func(i, j int)) } heartbeat struct { - calc chan<- interface{} - comp chan<- interface{} - del chan<- interface{} + calc chan<- any + comp chan<- any + del chan<- any } } diff --git a/domain/service/service_integration_test.go b/domain/service/service_integration_test.go index 577d101..6b38484 100644 --- a/domain/service/service_integration_test.go +++ b/domain/service/service_integration_test.go @@ -46,9 +46,9 @@ func (suite *ServiceIntegrationTestSuite) SetupSuite() { qDel := NewQueueDel(cach) qDel.Monitor(ctx) fnShuffle := func(n int, swap func(i int, j int)) {} - heartbeatComp := make(chan interface{}) - heartbeatCalc := make(chan interface{}) - heartbeatDel := make(chan interface{}) + heartbeatComp := make(chan any) + heartbeatCalc := make(chan any) + heartbeatDel := make(chan any) serv := New(DefaultServiceConfig, comp, stor, data, cach, qCalc, qComp, qDel, WithRandShuffle(fnShuffle), WithHeartbeatComp(heartbeatComp), diff --git a/domain/service/service_test.go b/domain/service/service_test.go index 613c69a..0f52bc0 100644 --- a/domain/service/service_test.go +++ b/domain/service/service_test.go @@ -70,9 +70,9 @@ type ServiceTestSuite struct { cancel context.CancelFunc id IdGenFunc ids *IdLogBook - heartbeatComp chan interface{} - heartbeatCalc chan interface{} - heartbeatDel chan interface{} + heartbeatComp chan any + heartbeatCalc chan any + heartbeatDel chan any serv *Service gComp *errgroup.Group gCalc *errgroup.Group @@ -93,9 +93,9 @@ func (suite *ServiceTestSuite) SetupSuite() { qDel := NewQueueDel(cach) qDel.Monitor(ctx) fnShuffle := func(n int, swap func(i int, j int)) {} - heartbeatComp := make(chan interface{}) - heartbeatCalc := make(chan interface{}) - heartbeatDel := make(chan interface{}) + heartbeatComp := make(chan any) + heartbeatCalc := make(chan any) + heartbeatDel := make(chan any) serv := New(DefaultServiceConfig, comp, stor, data, cach, qCalc, qComp, qDel, WithRandShuffle(fnShuffle), WithHeartbeatComp(heartbeatComp), diff --git a/infrastructure/cache/mem.go b/infrastructure/cache/mem.go index 1d821bd..e895d92 100644 --- a/infrastructure/cache/mem.go +++ b/infrastructure/cache/mem.go @@ -34,19 +34,19 @@ func NewMem(conf MemConfig, opts ...options) *Mem { type options func(*Mem) -func WithHeartbeatCleanup(ch chan<- interface{}) options { +func WithHeartbeatCleanup(ch chan<- any) options { return func(m *Mem) { m.heartbeat.cleanup = ch } } -func WithHeartbeatPair(ch chan<- interface{}) options { +func WithHeartbeatPair(ch chan<- any) options { return func(m *Mem) { m.heartbeat.pair = ch } } -func WithHeartbeatToken(ch chan<- interface{}) options { +func WithHeartbeatToken(ch chan<- any) options { return func(m *Mem) { m.heartbeat.token = ch } @@ -60,9 +60,9 @@ type Mem struct { syncPairs syncTokens heartbeat struct { - cleanup chan<- interface{} - pair chan<- interface{} - token chan<- interface{} + cleanup chan<- any + pair chan<- any + token chan<- any } } @@ -112,7 +112,7 @@ type elem struct { expires time.Time } -func timeComparator(a, b interface{}) int { +func timeComparator(a, b any) int { tA := a.(elem).expires tB := b.(elem).expires switch { diff --git a/infrastructure/cache/mem_test.go b/infrastructure/cache/mem_test.go index d24c873..bd00d84 100644 --- a/infrastructure/cache/mem_test.go +++ b/infrastructure/cache/mem_test.go @@ -23,9 +23,9 @@ type MemTestSuite struct { ctx context.Context cancel context.CancelFunc conf MemConfig - heartbeatCleanup chan interface{} - heartbeatPair chan interface{} - heartbeatToken chan interface{} + heartbeatCleanup chan any + heartbeatPair chan any + heartbeatToken chan any cache domain.Cacher setupTestFn func() } @@ -36,9 +36,9 @@ func (suite *MemTestSuite) SetupSuite() { } ctx, cancel := context.WithCancel(context.Background()) conf := DefaultMemConfig - hc := make(chan interface{}) - hp := make(chan interface{}) - ht := make(chan interface{}) + hc := make(chan any) + hp := make(chan any) + ht := make(chan any) mem := NewMem(conf, WithHeartbeatCleanup(hc), WithHeartbeatPair(hp), WithHeartbeatToken(ht)) mem.Monitor(ctx) suite.ctx = ctx diff --git a/infrastructure/compressor/shortpixel.go b/infrastructure/compressor/shortpixel.go index 48ce503..a8f56af 100644 --- a/infrastructure/compressor/shortpixel.go +++ b/infrastructure/compressor/shortpixel.go @@ -34,7 +34,7 @@ func NewShortpixel(conf ShortpixelConfig, opts ...options) *Shortpixel { type options func(*Shortpixel) -func WithHeartbeatRestart(ch chan<- interface{}) options { +func WithHeartbeatRestart(ch chan<- any) options { return func(sp *Shortpixel) { sp.heartbeat.restart = ch } @@ -45,7 +45,7 @@ type Shortpixel struct { done uint32 ch chan struct{} heartbeat struct { - restart chan<- interface{} + restart chan<- any } } @@ -220,7 +220,7 @@ func (sp *Shortpixel) upload(ctx context.Context, f model.File) (string, error) buf.Write(bb) response := struct { Status struct { - Code interface{} + Code any Message string } OriginalUrl string @@ -314,7 +314,7 @@ func (sp *Shortpixel) repeat(ctx context.Context, src string) (string, error) { buf.Write(b) response := struct { Status struct { - Code interface{} + Code any Message string } LossyUrl string diff --git a/infrastructure/compressor/shortpixel_test.go b/infrastructure/compressor/shortpixel_test.go index ea8f396..8e27330 100644 --- a/infrastructure/compressor/shortpixel_test.go +++ b/infrastructure/compressor/shortpixel_test.go @@ -17,7 +17,7 @@ import ( type response []struct { Status struct { - Code interface{} + Code any Message string } OriginalURL string `json:"OriginalURL,omitempty"` @@ -53,7 +53,7 @@ func TestShortpixel(t *testing.T) { resp := response{ { Status: struct { - Code interface{} + Code any Message string }{ Code: "2", @@ -151,7 +151,7 @@ func TestShortpixel(t *testing.T) { resp := response{ { Status: struct { - Code interface{} + Code any Message string }{ Code: "2", @@ -209,7 +209,7 @@ func TestShortpixel(t *testing.T) { resp := response{ { Status: struct { - Code interface{} + Code any Message string }{ Code: "2", @@ -265,7 +265,7 @@ func TestShortpixel(t *testing.T) { resp := response{ { Status: struct { - Code interface{} + Code any Message string }{ Code: "2", @@ -341,7 +341,7 @@ func TestShortpixel(t *testing.T) { resp := response{ { Status: struct { - Code interface{} + Code any Message string }{ Code: -110, @@ -365,7 +365,7 @@ func TestShortpixel(t *testing.T) { resp := response{ { Status: struct { - Code interface{} + Code any Message string }{ Code: -201, @@ -389,7 +389,7 @@ func TestShortpixel(t *testing.T) { resp := response{ { Status: struct { - Code interface{} + Code any Message string }{ Code: -202, @@ -419,7 +419,7 @@ func TestShortpixel(t *testing.T) { resp := response{ { Status: struct { - Code interface{} + Code any Message string }{ Code: "2", @@ -452,7 +452,7 @@ func TestShortpixel(t *testing.T) { resp := response{ { Status: struct { - Code interface{} + Code any Message string }{ Code: "1", @@ -545,7 +545,7 @@ func TestShortpixel(t *testing.T) { resp := response{ { Status: struct { - Code interface{} + Code any Message string }{ Code: "1", @@ -579,7 +579,7 @@ func TestShortpixel(t *testing.T) { resp := response{ { Status: struct { - Code interface{} + Code any Message string }{ Code: "1", @@ -611,7 +611,7 @@ func TestShortpixel(t *testing.T) { resp := response{ { Status: struct { - Code interface{} + Code any Message string }{ Code: "1", @@ -668,7 +668,7 @@ func TestShortpixel(t *testing.T) { resp := response{ { Status: struct { - Code interface{} + Code any Message string }{ Code: "1", @@ -696,7 +696,7 @@ func TestShortpixel(t *testing.T) { resp := response{ { Status: struct { - Code interface{} + Code any Message string }{ Code: -110, @@ -713,7 +713,7 @@ func TestShortpixel(t *testing.T) { resp := response{ { Status: struct { - Code interface{} + Code any Message string }{ Code: "1", @@ -741,7 +741,7 @@ func TestShortpixel(t *testing.T) { resp := response{ { Status: struct { - Code interface{} + Code any Message string }{ Code: "1", @@ -761,7 +761,7 @@ func TestShortpixel(t *testing.T) { resp := response{ { Status: struct { - Code interface{} + Code any Message string }{ Code: "1", diff --git a/infrastructure/database/mongo.go b/infrastructure/database/mongo.go index 8a7a8d9..843ae9c 100644 --- a/infrastructure/database/mongo.go +++ b/infrastructure/database/mongo.go @@ -86,7 +86,7 @@ func (m *Mongo) SaveAlbum(ctx context.Context, alb model.Album) error { if n > 0 { return errors.Wrap(domain.ErrAlbumAlreadyExists) } - imgsDao := make([]interface{}, 0, len(alb.Images)) + imgsDao := make([]any, 0, len(alb.Images)) albLru := make(albumLru, len(alb.Images)) for _, img := range alb.Images { imgDao := imageDao{int64(alb.Id), int64(img.Id), img.Src, img.Rating, m.conf.Compressed, alb.Expires} diff --git a/internal/testing/testing.go b/internal/testing/testing.go index 0656af1..4ed2c64 100644 --- a/internal/testing/testing.go +++ b/internal/testing/testing.go @@ -73,12 +73,12 @@ func AssertBody(t *testing.T, w *httptest.ResponseRecorder, body string) { } } -func AssertChannel(t *testing.T, heartbeat <-chan interface{}) interface{} { +func AssertChannel(t *testing.T, heartbeat <-chan any) any { t.Helper() if heartbeat == nil { return nil } - v := interface{}(nil) + v := any(nil) select { case v = <-heartbeat: case <-time.After(1 * time.Second): @@ -87,7 +87,7 @@ func AssertChannel(t *testing.T, heartbeat <-chan interface{}) interface{} { return v } -func AssertNotChannel(t *testing.T, heartbeat <-chan interface{}) { +func AssertNotChannel(t *testing.T, heartbeat <-chan any) { t.Helper() if heartbeat == nil { return diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go index 4a9db63..4401192 100644 --- a/pkg/errors/errors.go +++ b/pkg/errors/errors.go @@ -22,7 +22,7 @@ func Wrap(err error) error { return fmt.Errorf("%s:%d: %w", funcName, line, err) } -func Wrapf(err error, format string, args ...interface{}) error { +func Wrapf(err error, format string, args ...any) error { if err == nil { return err } @@ -43,7 +43,7 @@ func Is(err error, target error) bool { return errors.Is(err, target) } -func As(err error, target interface{}) bool { +func As(err error, target any) bool { return errors.As(err, target) } diff --git a/pkg/log/log.go b/pkg/log/log.go index d5c18d5..5147463 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -41,7 +41,7 @@ func SetFlags(flag int) { l.SetFlags(flag) } -func SetLevel(lvl interface{}) { +func SetLevel(lvl any) { oldLevel := l.lvl newLevel := disabled switch v := lvl.(type) { @@ -71,46 +71,46 @@ func SetLevel(lvl interface{}) { l.lvl = newLevel } -func Println(level Level, v ...interface{}) { +func Println(level Level, v ...any) { if DEBUG <= level && level <= CRITICAL && l.lvl <= level { - l.Println(append([]interface{}{fmt.Sprint(level) + ":"}, v...)...) + l.Println(append([]any{fmt.Sprint(level) + ":"}, v...)...) } } -func Printf(level Level, format string, v ...interface{}) { +func Printf(level Level, format string, v ...any) { if DEBUG <= level && level <= CRITICAL && l.lvl <= level { - l.Printf("%s: "+format, append([]interface{}{level}, v...)...) + l.Printf("%s: "+format, append([]any{level}, v...)...) } } -func Debug(v ...interface{}) { +func Debug(v ...any) { Println(DEBUG, v...) } -func Debugf(format string, v ...interface{}) { +func Debugf(format string, v ...any) { Printf(DEBUG, format, v...) } -func Info(v ...interface{}) { +func Info(v ...any) { Println(INFO, v...) } -func Infof(format string, v ...interface{}) { +func Infof(format string, v ...any) { Printf(INFO, format, v...) } -func Error(v ...interface{}) { +func Error(v ...any) { Println(ERROR, v...) } -func Errorf(format string, v ...interface{}) { +func Errorf(format string, v ...any) { Printf(ERROR, format, v...) } -func Critical(v ...interface{}) { +func Critical(v ...any) { Println(CRITICAL, v...) } -func Criticalf(format string, v ...interface{}) { +func Criticalf(format string, v ...any) { Printf(CRITICAL, format, v...) } diff --git a/pkg/log/log_test.go b/pkg/log/log_test.go index 817775f..485e950 100644 --- a/pkg/log/log_test.go +++ b/pkg/log/log_test.go @@ -21,7 +21,7 @@ func TestLogLevelPositive(t *testing.T) { t.Skip() } tests := []struct { - level interface{} + level any want string }{ { @@ -83,7 +83,7 @@ func TestLogLevelNegative(t *testing.T) { t.Skip() } tests := []struct { - level interface{} + level any want string }{ { diff --git a/pkg/pool/pool.go b/pkg/pool/pool.go index d606f7c..eb45695 100644 --- a/pkg/pool/pool.go +++ b/pkg/pool/pool.go @@ -7,7 +7,7 @@ import ( var ( p = &sync.Pool{ - New: func() interface{} { + New: func() any { return &bytes.Buffer{} }, } From 06682a44a565af834b76ae20d56dd3676425b5f0 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Tue, 29 Mar 2022 17:41:42 +0200 Subject: [PATCH 72/92] Update GcTuner tests --- internal/gctuner/gctuner.go | 27 +++++++--- internal/gctuner/gctuner_test.go | 93 ++++++++++++++++++++++++++++++-- 2 files changed, 111 insertions(+), 9 deletions(-) diff --git a/internal/gctuner/gctuner.go b/internal/gctuner/gctuner.go index d0c72f0..52af6b9 100644 --- a/internal/gctuner/gctuner.go +++ b/internal/gctuner/gctuner.go @@ -23,10 +23,12 @@ const ( ) var ( + newGOGC float64 lastGOGC float64 memTotal float64 memLimitRatio = 0.7 appFs = afero.NewOsFs() + memUsedFn = memProcess ) func Start(ctx context.Context, total int, ratio float64) error { @@ -157,17 +159,18 @@ func finalizerHandler(ctx context.Context) func(fin *finalizerRef) { } func updateGOGC() error { - p, err := process.NewProcess(int32(os.Getpid())) + memUsed, err := memUsedFn() if err != nil { return errors.Wrap(err) } - processMemory, err := p.MemoryInfo() - if err != nil { - return errors.Wrap(err) + if memTotal == 0 { + return errors.New("division by zero") } - memUsed := float64(processMemory.RSS) memUsedRatio := memUsed / memTotal - newGOGC := (memLimitRatio - memUsedRatio) / memUsedRatio * 100.0 + if memUsedRatio == 0 { + return errors.New("division by zero") + } + newGOGC = (memLimitRatio - memUsedRatio) / memUsedRatio * 100.0 if newGOGC < 0.0 { newGOGC = lastGOGC * memLimitRatio / memUsedRatio } @@ -177,3 +180,15 @@ func updateGOGC() error { log.Debugf("new GOGC: %.0f\n", newGOGC) return nil } + +func memProcess() (float64, error) { + p, err := process.NewProcess(int32(os.Getpid())) + if err != nil { + return 0.0, errors.Wrap(err) + } + processMemory, err := p.MemoryInfo() + if err != nil { + return 0.0, errors.Wrap(err) + } + return float64(processMemory.RSS), nil +} diff --git a/internal/gctuner/gctuner_test.go b/internal/gctuner/gctuner_test.go index f157028..9b00127 100644 --- a/internal/gctuner/gctuner_test.go +++ b/internal/gctuner/gctuner_test.go @@ -7,6 +7,8 @@ import ( "github.com/spf13/afero" "github.com/stretchr/testify/assert" + + . "github.com/zitryss/aye-and-nay/internal/testing" ) func TestReadCgroupMemTotal(t *testing.T) { @@ -18,7 +20,7 @@ func TestReadCgroupMemTotal(t *testing.T) { { f: strings.NewReader(""), want: 0, - wantErr: true, + wantErr: false, }, { f: strings.NewReader("0"), @@ -64,10 +66,11 @@ func TestReadCgroupMemTotal(t *testing.T) { for _, tt := range tests { t.Run("", func(t *testing.T) { got, err := readCgroupMemTotal(tt.f) - if (err != nil) != tt.wantErr { + if tt.wantErr { assert.Error(t, err) return } + assert.NoError(t, err) assert.Equal(t, tt.want, got) }) } @@ -79,91 +82,112 @@ func TestMemTotal(t *testing.T) { cgroupMemTotalV1 []byte cgroupMemTotalV2 []byte want float64 + wantErr bool }{ { total: 1073741824, cgroupMemTotalV1: []byte(""), cgroupMemTotalV2: []byte("-1"), want: 1073741824, + wantErr: false, }, { total: 1073741824, cgroupMemTotalV1: []byte("$%^&"), cgroupMemTotalV2: []byte("0"), want: 1073741824, + wantErr: false, }, { total: 1073741824, cgroupMemTotalV1: []byte("max"), cgroupMemTotalV2: []byte("$%^&"), want: 1073741824, + wantErr: false, }, { total: 0, cgroupMemTotalV1: []byte("943718400\n"), cgroupMemTotalV2: nil, want: 943718400, + wantErr: false, }, { total: 0, cgroupMemTotalV1: nil, cgroupMemTotalV2: []byte("734003200\n"), want: 734003200, + wantErr: false, }, - { total: 1073741824, cgroupMemTotalV1: []byte("943718400\n"), cgroupMemTotalV2: nil, want: 943718400, + wantErr: false, }, { total: 943718400, cgroupMemTotalV1: []byte("1073741824\n"), cgroupMemTotalV2: nil, want: 943718400, + wantErr: false, }, { total: 1073741824, cgroupMemTotalV1: nil, cgroupMemTotalV2: []byte("943718400\n"), want: 943718400, + wantErr: false, }, { total: 943718400, cgroupMemTotalV1: nil, cgroupMemTotalV2: []byte("1073741824\n"), want: 943718400, + wantErr: false, }, { total: 0, cgroupMemTotalV1: []byte("943718400\n"), cgroupMemTotalV2: []byte("1073741824\n"), want: 943718400, + wantErr: false, }, { total: 0, cgroupMemTotalV1: []byte("1073741824\n"), cgroupMemTotalV2: []byte("943718400\n"), want: 943718400, + wantErr: false, }, { total: 734003200, cgroupMemTotalV1: []byte("1073741824\n"), cgroupMemTotalV2: []byte("943718400\n"), want: 734003200, + wantErr: false, }, { total: 943718400, cgroupMemTotalV1: []byte("1073741824\n"), cgroupMemTotalV2: []byte("734003200\n"), want: 734003200, + wantErr: false, }, { total: 1073741824, cgroupMemTotalV1: []byte("734003200\n"), cgroupMemTotalV2: []byte("943718400\n"), want: 734003200, + wantErr: false, + }, + { + total: 1073741824, + cgroupMemTotalV1: []byte("$%^&"), + cgroupMemTotalV2: []byte("$%^&"), + want: 0.0, + wantErr: true, }, } for _, tt := range tests { @@ -181,8 +205,71 @@ func TestMemTotal(t *testing.T) { err := checkMemTotal() assert.NoError(t, err) err = checkCgroup() + if tt.wantErr { + assert.Error(t, err) + return + } assert.NoError(t, err) assert.Equal(t, tt.want, memTotal) }) } } + +func TestUpdateGOGC(t *testing.T) { + memTestFn := func(memUsed float64) func() (float64, error) { + return func() (float64, error) { + return memUsed, nil + } + } + tests := []struct { + memTotal float64 + memUsed float64 + memLimitRatio float64 + want float64 + wantErr bool + }{ + { + memTotal: 100.0, + memUsed: 20.0, + memLimitRatio: 0.6, + want: 199.99999999999997, + wantErr: false, + }, + { + memTotal: 100.0, + memUsed: 99.9, + memLimitRatio: 0.5, + want: 50.05005005005005, + wantErr: false, + }, + { + memTotal: 0.0, + memUsed: 20.0, + memLimitRatio: 0.7, + want: 0.0, + wantErr: true, + }, + { + memTotal: 100.0, + memUsed: 0.0, + memLimitRatio: 0.7, + want: 0.0, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run("", func(t *testing.T) { + memTotal = tt.memTotal + memUsedFn = memTestFn(tt.memUsed) + memLimitRatio = tt.memLimitRatio + err := updateGOGC() + if tt.wantErr { + assert.Error(t, err) + return + } + assert.NoError(t, err) + got := newGOGC + assert.InDelta(t, tt.want, got, TOLERANCE) + }) + } +} From 59f75ec20a1ff4e0d78db3fae18b7ad55f7fd2e3 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Wed, 30 Mar 2022 17:37:39 +0200 Subject: [PATCH 73/92] Random improvements --- delivery/http/config.go | 2 + delivery/http/middleware.go | 8 ++- domain/service/service_test.go | 3 + go.mod | 2 - infrastructure/cache/redis.go | 16 ++--- internal/gctuner/gctuner_test.go | 20 +++++- pkg/base64/base64_test.go | 106 +++++++++++++++++++++++++++++++ pkg/debug/debug_test.go | 39 ++++++++++++ pkg/pool/pool_test.go | 27 ++++++++ pkg/rand/rand_test.go | 23 +++++++ 10 files changed, 232 insertions(+), 14 deletions(-) create mode 100644 pkg/debug/debug_test.go create mode 100644 pkg/pool/pool_test.go create mode 100644 pkg/rand/rand_test.go diff --git a/delivery/http/config.go b/delivery/http/config.go index 6ef5a4a..632fe65 100644 --- a/delivery/http/config.go +++ b/delivery/http/config.go @@ -22,6 +22,7 @@ type ServerConfig struct { type MiddlewareConfig struct { CorsAllowOrigin string `mapstructure:"MIDDLEWARE_CORS_ALLOW_ORIGIN" validate:"required"` + MaxFileSize int64 `mapstructure:"CONTROLLER_MAX_FILE_SIZE" validate:"required"` } type ControllerConfig struct { @@ -43,6 +44,7 @@ var ( } DefaultMiddlewareConfig = MiddlewareConfig{ CorsAllowOrigin: "", + MaxFileSize: 512 * kb, } DefaultControllerConfig = ControllerConfig{ MaxNumberOfFiles: 3, diff --git a/delivery/http/middleware.go b/delivery/http/middleware.go index 016380b..217a3fd 100644 --- a/delivery/http/middleware.go +++ b/delivery/http/middleware.go @@ -29,7 +29,7 @@ func (m *Middleware) Chain(h http.Handler) http.Handler { AllowedOrigins: []string{m.conf.CorsAllowOrigin}, AllowedMethods: []string{http.MethodGet, http.MethodPost, http.MethodPatch}, }) - return m.recover(m.limit(c.Handler(m.headers(h)))) + return m.recover(m.limit(c.Handler(http.MaxBytesHandler(m.headers(h), m.conf.MaxFileSize)))) } func (m *Middleware) recover(h http.Handler) http.Handler { @@ -87,7 +87,9 @@ func (m *Middleware) headers(h http.Handler) http.Handler { func ip(r *http.Request) string { xff := r.Header.Get("X-Forwarded-For") if xff != "" { - return strings.Split(xff, ", ")[0] + before, _, _ := strings.Cut(xff, ", ") + return before } - return strings.Split(r.RemoteAddr, ":")[0] + before, _, _ := strings.Cut(r.RemoteAddr, ":") + return before } diff --git a/domain/service/service_test.go b/domain/service/service_test.go index 0f52bc0..625d7f7 100644 --- a/domain/service/service_test.go +++ b/domain/service/service_test.go @@ -81,6 +81,9 @@ type ServiceTestSuite struct { } func (suite *ServiceTestSuite) SetupSuite() { + if !*unit { + suite.T().Skip() + } ctx, cancel := context.WithCancel(context.Background()) comp := compressor.NewMock() stor := storage.NewMock() diff --git a/go.mod b/go.mod index 01b9dfa..6b1804a 100644 --- a/go.mod +++ b/go.mod @@ -117,5 +117,3 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) - -replace github.com/zitryss/aye-and-nay => ./pkg diff --git a/infrastructure/cache/redis.go b/infrastructure/cache/redis.go index ab9abf9..995424e 100644 --- a/infrastructure/cache/redis.go +++ b/infrastructure/cache/redis.go @@ -229,15 +229,15 @@ func (r *Redis) Pop(ctx context.Context, album uint64) (uint64, uint64, error) { return 0x0, 0x0, errors.Wrap(err) } _ = r.client.Expire(ctx, key, r.conf.TimeToLive) - imagesB64 := strings.Split(val, ":") - if len(imagesB64) != 2 { + image1B64, image2B64, found := strings.Cut(val, ":") + if !found { return 0x0, 0x0, errors.Wrap(domain.ErrUnknown) } - image0, err := base64.ToUint64(imagesB64[0]) + image0, err := base64.ToUint64(image1B64) if err != nil { return 0x0, 0x0, errors.Wrap(err) } - image1, err := base64.ToUint64(imagesB64[1]) + image1, err := base64.ToUint64(image2B64) if err != nil { return 0x0, 0x0, errors.Wrap(err) } @@ -273,15 +273,15 @@ func (r *Redis) Get(ctx context.Context, token uint64) (uint64, uint64, error) { if err != nil { return 0x0, 0x0, errors.Wrap(err) } - ss := strings.Split(s, ":") - if len(ss) != 2 { + albumB64, imageB64, found := strings.Cut(s, ":") + if !found { return 0x0, 0x0, errors.Wrap(domain.ErrUnknown) } - album, err := base64.ToUint64(ss[0]) + album, err := base64.ToUint64(albumB64) if err != nil { return 0x0, 0x0, errors.Wrap(err) } - image, err := base64.ToUint64(ss[1]) + image, err := base64.ToUint64(imageB64) if err != nil { return 0x0, 0x0, errors.Wrap(err) } diff --git a/internal/gctuner/gctuner_test.go b/internal/gctuner/gctuner_test.go index 9b00127..d43496f 100644 --- a/internal/gctuner/gctuner_test.go +++ b/internal/gctuner/gctuner_test.go @@ -1,7 +1,9 @@ package gctuner import ( + "flag" "io" + "runtime/debug" "strings" "testing" @@ -11,7 +13,16 @@ import ( . "github.com/zitryss/aye-and-nay/internal/testing" ) +var ( + unit = flag.Bool("unit", false, "") + integration = flag.Bool("int", false, "") + ci = flag.Bool("ci", false, "") +) + func TestReadCgroupMemTotal(t *testing.T) { + if !*unit { + t.Skip() + } tests := []struct { f io.Reader want float64 @@ -77,6 +88,9 @@ func TestReadCgroupMemTotal(t *testing.T) { } func TestMemTotal(t *testing.T) { + if !*unit { + t.Skip() + } tests := []struct { total float64 cgroupMemTotalV1 []byte @@ -216,6 +230,9 @@ func TestMemTotal(t *testing.T) { } func TestUpdateGOGC(t *testing.T) { + if !*unit { + t.Skip() + } memTestFn := func(memUsed float64) func() (float64, error) { return func() (float64, error) { return memUsed, nil @@ -239,7 +256,7 @@ func TestUpdateGOGC(t *testing.T) { memTotal: 100.0, memUsed: 99.9, memLimitRatio: 0.5, - want: 50.05005005005005, + want: 99.59959959959959, wantErr: false, }, { @@ -262,6 +279,7 @@ func TestUpdateGOGC(t *testing.T) { memTotal = tt.memTotal memUsedFn = memTestFn(tt.memUsed) memLimitRatio = tt.memLimitRatio + lastGOGC = float64(debug.SetGCPercent(100)) err := updateGOGC() if tt.wantErr { assert.Error(t, err) diff --git a/pkg/base64/base64_test.go b/pkg/base64/base64_test.go index aa4cd33..77706ac 100644 --- a/pkg/base64/base64_test.go +++ b/pkg/base64/base64_test.go @@ -1,14 +1,117 @@ package base64 import ( + "flag" + "math" "testing" "github.com/stretchr/testify/assert" ) +var ( + unit = flag.Bool("unit", false, "") + integration = flag.Bool("int", false, "") + ci = flag.Bool("ci", false, "") +) + +func TestFromUint64(t *testing.T) { + if !*unit { + t.Skip() + } + tests := []struct { + u uint64 + want string + }{ + { + u: 0x0, + want: "AAAAAAAAAAA", + }, + { + u: 0x1, + want: "AQAAAAAAAAA", + }, + { + u: math.MaxUint64, + want: "__________8", + }, + } + for _, tt := range tests { + t.Run("", func(t *testing.T) { + got := FromUint64(tt.u) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestToUint64(t *testing.T) { + if !*unit { + t.Skip() + } + tests := []struct { + s string + want uint64 + wantErr bool + }{ + { + s: "AAAAAAAAAAA", + want: 0x0, + wantErr: false, + }, + { + s: "AQAAAAAAAAA", + want: 0x1, + wantErr: false, + }, + { + s: "__________8", + want: math.MaxUint64, + wantErr: false, + }, + { + s: "00000000000", + want: 0x4dd3344dd3344dd3, + wantErr: false, + }, + { + s: "00000000001", + want: 0x4dd3344dd3344dd3, + wantErr: false, + }, + { + s: "", + want: 0x0, + wantErr: true, + }, + { + s: "A", + want: 0x0, + wantErr: true, + }, + { + s: "!@#$%^&*()_", + want: 0x0, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run("", func(t *testing.T) { + got, err := ToUint64(tt.s) + if tt.wantErr { + assert.Error(t, err) + return + } + assert.NoError(t, err) + assert.Equal(t, tt.want, got) + }) + } +} + func FuzzFromUint64(f *testing.F) { f.Add(uint64(0)) f.Fuzz(func(t *testing.T, u1 uint64) { + if !*unit { + t.Skip() + } b64 := FromUint64(u1) u2, err := ToUint64(b64) assert.NoError(t, err) @@ -19,6 +122,9 @@ func FuzzFromUint64(f *testing.F) { func FuzzToUint64(f *testing.F) { f.Add("AAAAAAAAAAA") f.Fuzz(func(t *testing.T, s string) { + if !*unit { + t.Skip() + } _, err := ToUint64(s) if err != nil { t.Skip() diff --git a/pkg/debug/debug_test.go b/pkg/debug/debug_test.go new file mode 100644 index 0000000..f460920 --- /dev/null +++ b/pkg/debug/debug_test.go @@ -0,0 +1,39 @@ +package debug + +import ( + "errors" + "flag" + "testing" + + "github.com/stretchr/testify/assert" +) + +var ( + unit = flag.Bool("unit", false, "") + integration = flag.Bool("int", false, "") + ci = flag.Bool("ci", false, "") +) + +func TestAssert(t *testing.T) { + if !*unit { + t.Skip() + } + assert.NotPanics(t, func() { + Assert(true) + }) + assert.Panics(t, func() { + Assert(false) + }) +} + +func TestCheck(t *testing.T) { + if !*unit { + t.Skip() + } + assert.NotPanics(t, func() { + Check(nil) + }) + assert.Panics(t, func() { + Check(errors.New("")) + }) +} diff --git a/pkg/pool/pool_test.go b/pkg/pool/pool_test.go new file mode 100644 index 0000000..c197618 --- /dev/null +++ b/pkg/pool/pool_test.go @@ -0,0 +1,27 @@ +package pool + +import ( + "flag" + "testing" + + "github.com/stretchr/testify/assert" +) + +var ( + unit = flag.Bool("unit", false, "") + integration = flag.Bool("int", false, "") + ci = flag.Bool("ci", false, "") +) + +func TestBuffer(t *testing.T) { + if !*unit { + t.Skip() + } + buf1 := GetBuffer() + assert.NotNil(t, buf1) + PutBuffer(buf1) + buf2 := GetBufferN(100) + assert.NotNil(t, buf2) + assert.GreaterOrEqual(t, buf2.Cap(), 100) + PutBuffer(buf2) +} diff --git a/pkg/rand/rand_test.go b/pkg/rand/rand_test.go new file mode 100644 index 0000000..1cd4206 --- /dev/null +++ b/pkg/rand/rand_test.go @@ -0,0 +1,23 @@ +package rand + +import ( + "flag" + "testing" + + "github.com/stretchr/testify/assert" +) + +var ( + unit = flag.Bool("unit", false, "") + integration = flag.Bool("int", false, "") + ci = flag.Bool("ci", false, "") +) + +func TestId(t *testing.T) { + if !*unit { + t.Skip() + } + got, err := Id() + assert.NoError(t, err) + assert.Positive(t, got) +} From 3d043c85843387289aeca9bb1ffb7a2c11be39f9 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Wed, 30 Mar 2022 18:35:26 +0200 Subject: [PATCH 74/92] Refactor middleware --- delivery/http/config.go | 6 ++++-- delivery/http/middleware.go | 17 ++++++++++++++++- delivery/http/server.go | 2 +- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/delivery/http/config.go b/delivery/http/config.go index 632fe65..1adf0da 100644 --- a/delivery/http/config.go +++ b/delivery/http/config.go @@ -21,8 +21,9 @@ type ServerConfig struct { } type MiddlewareConfig struct { - CorsAllowOrigin string `mapstructure:"MIDDLEWARE_CORS_ALLOW_ORIGIN" validate:"required"` - MaxFileSize int64 `mapstructure:"CONTROLLER_MAX_FILE_SIZE" validate:"required"` + CorsAllowOrigin string `mapstructure:"MIDDLEWARE_CORS_ALLOW_ORIGIN" validate:"required"` + WriteTimeout time.Duration `mapstructure:"SERVER_WRITE_TIMEOUT" validate:"required"` + MaxFileSize int64 `mapstructure:"CONTROLLER_MAX_FILE_SIZE" validate:"required"` } type ControllerConfig struct { @@ -44,6 +45,7 @@ var ( } DefaultMiddlewareConfig = MiddlewareConfig{ CorsAllowOrigin: "", + WriteTimeout: 10 * time.Second, MaxFileSize: 512 * kb, } DefaultControllerConfig = ControllerConfig{ diff --git a/delivery/http/middleware.go b/delivery/http/middleware.go index 217a3fd..277f699 100644 --- a/delivery/http/middleware.go +++ b/delivery/http/middleware.go @@ -29,7 +29,22 @@ func (m *Middleware) Chain(h http.Handler) http.Handler { AllowedOrigins: []string{m.conf.CorsAllowOrigin}, AllowedMethods: []string{http.MethodGet, http.MethodPost, http.MethodPatch}, }) - return m.recover(m.limit(c.Handler(http.MaxBytesHandler(m.headers(h), m.conf.MaxFileSize)))) + handler := + m.recover( + m.limit( + c.Handler( + http.TimeoutHandler( + http.MaxBytesHandler( + m.headers(h), + m.conf.MaxFileSize, + ), + m.conf.WriteTimeout, + "", + ), + ), + ), + ) + return handler } func (m *Middleware) recover(h http.Handler) http.Handler { diff --git a/delivery/http/server.go b/delivery/http/server.go index 935c444..629bbef 100644 --- a/delivery/http/server.go +++ b/delivery/http/server.go @@ -36,7 +36,7 @@ func NewServer( func newServer(conf ServerConfig, handler http.Handler) (*http.Server, error) { srv := &http.Server{ Addr: conf.Host + ":" + conf.Port, - Handler: http.TimeoutHandler(handler, conf.WriteTimeout, ""), + Handler: handler, ReadTimeout: conf.ReadTimeout, WriteTimeout: conf.WriteTimeout + 1*time.Second, IdleTimeout: conf.IdleTimeout, From 9b4cdd8743552e0155182d2fd09235b264392eea Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Mon, 4 Apr 2022 17:56:31 +0200 Subject: [PATCH 75/92] Assign request id --- delivery/http/controller_test.go | 4 +- delivery/http/middleware.go | 33 +++++++++++----- delivery/http/middleware_test.go | 65 ++++++++++++++++++++++++++++++-- internal/context/context.go | 29 ++++++++++++++ internal/testing/testing.go | 8 ++-- 5 files changed, 119 insertions(+), 20 deletions(-) create mode 100644 internal/context/context.go diff --git a/delivery/http/controller_test.go b/delivery/http/controller_test.go index fd1ff1c..e0b6500 100644 --- a/delivery/http/controller_test.go +++ b/delivery/http/controller_test.go @@ -247,7 +247,7 @@ func TestControllerHandle(t *testing.T) { } fn(w, r, tt.give.params) AssertStatusCode(t, w, tt.want.code) - AssertContentType(t, w, tt.want.typ) + AssertHeader(t, w, "Content-Type", tt.want.typ) AssertBody(t, w, tt.want.respBody) }) } @@ -550,7 +550,7 @@ func TestControllerError(t *testing.T) { r := httptest.NewRequest(http.MethodGet, "/api/health/", http.NoBody) fn(w, r, nil) AssertStatusCode(t, w, tt.want.code) - AssertContentType(t, w, tt.want.typ) + AssertHeader(t, w, "Content-Type", tt.want.typ) AssertBody(t, w, tt.want.respBody) }) } diff --git a/delivery/http/middleware.go b/delivery/http/middleware.go index 277f699..f2ed062 100644 --- a/delivery/http/middleware.go +++ b/delivery/http/middleware.go @@ -9,6 +9,7 @@ import ( "github.com/rs/cors" "github.com/zitryss/aye-and-nay/domain/domain" + "github.com/zitryss/aye-and-nay/internal/context" "github.com/zitryss/aye-and-nay/pkg/errors" ) @@ -35,7 +36,9 @@ func (m *Middleware) Chain(h http.Handler) http.Handler { c.Handler( http.TimeoutHandler( http.MaxBytesHandler( - m.headers(h), + m.requestId( + m.headers(h), + ), m.conf.MaxFileSize, ), m.conf.WriteTimeout, @@ -90,15 +93,6 @@ func (m *Middleware) limit(h http.Handler) http.Handler { ) } -func (m *Middleware) headers(h http.Handler) http.Handler { - return http.HandlerFunc( - func(w http.ResponseWriter, r *http.Request) { - h.ServeHTTP(w, r) - w.Header().Set("X-Content-Type-Options", "nosniff") - }, - ) -} - func ip(r *http.Request) string { xff := r.Header.Get("X-Forwarded-For") if xff != "" { @@ -108,3 +102,22 @@ func ip(r *http.Request) string { before, _, _ := strings.Cut(r.RemoteAddr, ":") return before } + +func (m *Middleware) requestId(h http.Handler) http.Handler { + return http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + ctx := context.WithRequestId(r.Context()) + r = r.WithContext(ctx) + h.ServeHTTP(w, r) + }, + ) +} + +func (m *Middleware) headers(h http.Handler) http.Handler { + return http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("X-Content-Type-Options", "nosniff") + h.ServeHTTP(w, r) + }, + ) +} diff --git a/delivery/http/middleware_test.go b/delivery/http/middleware_test.go index 01579e3..8e9ad89 100644 --- a/delivery/http/middleware_test.go +++ b/delivery/http/middleware_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/assert" + . "github.com/zitryss/aye-and-nay/internal/context" . "github.com/zitryss/aye-and-nay/internal/testing" ) @@ -42,7 +43,7 @@ func TestMiddlewareRecover(t *testing.T) { r := httptest.NewRequest(http.MethodGet, "/", http.NoBody) handler.ServeHTTP(w, r) AssertStatusCode(t, w, 418) - AssertContentType(t, w, "text/plain; charset=utf-8") + AssertHeader(t, w, "Content-Type", "text/plain; charset=utf-8") AssertBody(t, w, `I'm a teapot`) }) t.Run("Negative", func(t *testing.T) { @@ -57,7 +58,7 @@ func TestMiddlewareRecover(t *testing.T) { r := httptest.NewRequest(http.MethodGet, "/", http.NoBody) handler.ServeHTTP(w, r) AssertStatusCode(t, w, 500) - AssertContentType(t, w, "application/json; charset=utf-8") + AssertHeader(t, w, "Content-Type", "application/json; charset=utf-8") AssertBody(t, w, `{"error":{"code":22,"msg":"internal server error"}}`+"\n") }) } @@ -80,7 +81,7 @@ func TestMiddlewareLimit(t *testing.T) { r := httptest.NewRequest(http.MethodGet, "/", http.NoBody) handler.ServeHTTP(w, r) AssertStatusCode(t, w, 418) - AssertContentType(t, w, "text/plain; charset=utf-8") + AssertHeader(t, w, "Content-Type", "text/plain; charset=utf-8") AssertBody(t, w, `I'm a teapot`) }) t.Run("Negative", func(t *testing.T) { @@ -97,7 +98,7 @@ func TestMiddlewareLimit(t *testing.T) { r := httptest.NewRequest(http.MethodGet, "/", http.NoBody) handler.ServeHTTP(w, r) AssertStatusCode(t, w, 429) - AssertContentType(t, w, "application/json; charset=utf-8") + AssertHeader(t, w, "Content-Type", "application/json; charset=utf-8") AssertBody(t, w, `{"error":{"code":1,"msg":"too many requests"}}`+"\n") }) } @@ -161,3 +162,59 @@ func TestIP(t *testing.T) { }) } } + +func TestMiddlewareRequestId(t *testing.T) { + if !*unit { + t.Skip() + } + t.Parallel() + ids := []uint64{0} + fn := func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + id := GetRequestId(ctx) + assert.NotZero(t, id) + assert.Positive(t, id) + assert.Greater(t, id, ids[len(ids)-1]) + ids = append(ids, id) + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.WriteHeader(418) + _, _ = io.WriteString(w, "I'm a teapot") + } + lim := limiterMockPos{} + middle := NewMiddleware(DefaultMiddlewareConfig, lim) + handler := middle.requestId(http.HandlerFunc(fn)) + w := httptest.NewRecorder() + r := httptest.NewRequest(http.MethodGet, "/", http.NoBody) + handler.ServeHTTP(w, r) + AssertStatusCode(t, w, 418) + AssertHeader(t, w, "Content-Type", "text/plain; charset=utf-8") + AssertBody(t, w, `I'm a teapot`) + w = httptest.NewRecorder() + r = httptest.NewRequest(http.MethodGet, "/", http.NoBody) + handler.ServeHTTP(w, r) + AssertStatusCode(t, w, 418) + AssertHeader(t, w, "Content-Type", "text/plain; charset=utf-8") + AssertBody(t, w, `I'm a teapot`) +} + +func TestMiddlewareHeaders(t *testing.T) { + if !*unit { + t.Skip() + } + t.Parallel() + fn := func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.WriteHeader(418) + _, _ = io.WriteString(w, "I'm a teapot") + } + lim := limiterMockPos{} + middle := NewMiddleware(DefaultMiddlewareConfig, lim) + handler := middle.headers(http.HandlerFunc(fn)) + w := httptest.NewRecorder() + r := httptest.NewRequest(http.MethodGet, "/", http.NoBody) + handler.ServeHTTP(w, r) + AssertStatusCode(t, w, 418) + AssertHeader(t, w, "Content-Type", "text/plain; charset=utf-8") + AssertHeader(t, w, "X-Content-Type-Options", "nosniff") + AssertBody(t, w, `I'm a teapot`) +} diff --git a/internal/context/context.go b/internal/context/context.go new file mode 100644 index 0000000..6039b57 --- /dev/null +++ b/internal/context/context.go @@ -0,0 +1,29 @@ +package context + +import ( + "context" + + "go.uber.org/atomic" +) + +type ctxKey int + +const ( + ctxRequestId ctxKey = iota +) + +var ( + requestID atomic.Uint64 +) + +func WithRequestId(ctx context.Context) context.Context { + return context.WithValue(ctx, ctxRequestId, requestID.Inc()) +} + +func GetRequestId(ctx context.Context) uint64 { + reqId, ok := ctx.Value(ctxRequestId).(uint64) + if !ok { + return 0 + } + return reqId +} diff --git a/internal/testing/testing.go b/internal/testing/testing.go index 4ed2c64..26121e1 100644 --- a/internal/testing/testing.go +++ b/internal/testing/testing.go @@ -55,12 +55,12 @@ func AssertStatusCode(t *testing.T, w *httptest.ResponseRecorder, code int) { } } -func AssertContentType(t *testing.T, w *httptest.ResponseRecorder, content string) { +func AssertHeader(t *testing.T, w *httptest.ResponseRecorder, header string, value string) { t.Helper() - got := w.Result().Header.Get("Content-Type") - want := content + got := w.Result().Header.Get(header) + want := value if got != want { - t.Errorf("Content-Type = %v; want %v", got, want) + t.Errorf("%v = %v; want %v", header, got, want) } } From 3383d0a0905bb2c29e5363bdd0a6c1d68bd0deb6 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Mon, 4 Apr 2022 18:23:44 +0200 Subject: [PATCH 76/92] Test context --- internal/context/context_test.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 internal/context/context_test.go diff --git a/internal/context/context_test.go b/internal/context/context_test.go new file mode 100644 index 0000000..310ad65 --- /dev/null +++ b/internal/context/context_test.go @@ -0,0 +1,28 @@ +package context + +import ( + "context" + "flag" + "testing" + + "github.com/stretchr/testify/assert" +) + +var ( + unit = flag.Bool("unit", false, "") + integration = flag.Bool("int", false, "") + ci = flag.Bool("ci", false, "") +) + +func TestContext(t *testing.T) { + t.Run("Positive", func(t *testing.T) { + ctx := WithRequestId(context.Background()) + assert.Equal(t, uint64(1), GetRequestId(ctx)) + ctx = WithRequestId(ctx) + assert.Equal(t, uint64(2), GetRequestId(ctx)) + }) + t.Run("Negative", func(t *testing.T) { + ctx := context.Background() + assert.Equal(t, uint64(0), GetRequestId(ctx)) + }) +} From 24b258bd4b5af066b2ee688d05202f8f4d8b9c71 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sun, 12 Jun 2022 01:01:00 +0200 Subject: [PATCH 77/92] Jsonify logs --- Makefile | 4 +- build/config-dev.env | 1 + build/config-embed.env | 1 + build/config-prod.env | 1 + config.env | 1 + delivery/http/config.go | 2 + delivery/http/controller.go | 69 +++++----- delivery/http/error.go | 16 +-- delivery/http/middleware.go | 44 ++++-- delivery/http/middleware_test.go | 4 +- domain/service/error.go | 14 +- go.mod | 7 +- go.sum | 2 + infrastructure/cache/cache.go | 4 +- infrastructure/compressor/compressor.go | 6 +- infrastructure/database/badger.go | 4 +- infrastructure/database/database.go | 6 +- infrastructure/database/mem.go | 5 +- infrastructure/storage/storage.go | 4 +- internal/config/config.go | 12 +- internal/gctuner/gctuner.go | 12 +- internal/log/log.go | 127 ++++++++++++++++++ .../context.go => requestid/requestid.go} | 6 +- .../requestid_test.go} | 21 ++- main.go | 62 +++++---- 25 files changed, 309 insertions(+), 126 deletions(-) create mode 100644 internal/log/log.go rename internal/{context/context.go => requestid/requestid.go} (70%) rename internal/{context/context_test.go => requestid/requestid_test.go} (52%) diff --git a/Makefile b/Makefile index df00949..207269e 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ .PHONY: gen compile compile-health test-unit test-int test-unit-ci test-int-ci dev-up dev-down prod-loadtest prod-up prod-down embed-loadtest embed-up embed-down gen: - go install github.com/mailru/easyjson/easyjson@latest - go install golang.org/x/tools/cmd/stringer@latest + go install github.com/mailru/easyjson/easyjson + go install golang.org/x/tools/cmd/stringer go generate ./... compile: gen diff --git a/build/config-dev.env b/build/config-dev.env index 57f5c5f..e78f8b4 100644 --- a/build/config-dev.env +++ b/build/config-dev.env @@ -23,6 +23,7 @@ SERVER_SHUTDOWN_TIMEOUT=10s MIDDLEWARE_CORS_ALLOW_ORIGIN=* MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=30000 MIDDLEWARE_LIMITER_BURST=300 +MIDDLEWARE_DEBUG=true # CONTROLLER CONTROLLER_MAX_NUMBER_OF_FILES=100 diff --git a/build/config-embed.env b/build/config-embed.env index 71f1d57..c31e823 100644 --- a/build/config-embed.env +++ b/build/config-embed.env @@ -23,6 +23,7 @@ SERVER_SHUTDOWN_TIMEOUT=10s MIDDLEWARE_CORS_ALLOW_ORIGIN=* MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=30000 MIDDLEWARE_LIMITER_BURST=300 +MIDDLEWARE_DEBUG=false # CONTROLLER CONTROLLER_MAX_NUMBER_OF_FILES=100 diff --git a/build/config-prod.env b/build/config-prod.env index dbc9d5e..c91ea13 100644 --- a/build/config-prod.env +++ b/build/config-prod.env @@ -23,6 +23,7 @@ SERVER_SHUTDOWN_TIMEOUT=10s MIDDLEWARE_CORS_ALLOW_ORIGIN=* MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=30000 MIDDLEWARE_LIMITER_BURST=300 +MIDDLEWARE_DEBUG=false # CONTROLLER CONTROLLER_MAX_NUMBER_OF_FILES=100 diff --git a/config.env b/config.env index e901747..6f3ae5d 100644 --- a/config.env +++ b/config.env @@ -23,6 +23,7 @@ SERVER_SHUTDOWN_TIMEOUT=10s MIDDLEWARE_CORS_ALLOW_ORIGIN=* MIDDLEWARE_LIMITER_REQUESTS_PER_SECOND=30000 MIDDLEWARE_LIMITER_BURST=300 +MIDDLEWARE_DEBUG=true # CONTROLLER CONTROLLER_MAX_NUMBER_OF_FILES=100 diff --git a/delivery/http/config.go b/delivery/http/config.go index 1adf0da..fad0acd 100644 --- a/delivery/http/config.go +++ b/delivery/http/config.go @@ -24,6 +24,7 @@ type MiddlewareConfig struct { CorsAllowOrigin string `mapstructure:"MIDDLEWARE_CORS_ALLOW_ORIGIN" validate:"required"` WriteTimeout time.Duration `mapstructure:"SERVER_WRITE_TIMEOUT" validate:"required"` MaxFileSize int64 `mapstructure:"CONTROLLER_MAX_FILE_SIZE" validate:"required"` + Debug bool `mapstructure:"MIDDLEWARE_DEBUG"` } type ControllerConfig struct { @@ -47,6 +48,7 @@ var ( CorsAllowOrigin: "", WriteTimeout: 10 * time.Second, MaxFileSize: 512 * kb, + Debug: false, } DefaultControllerConfig = ControllerConfig{ MaxNumberOfFiles: 3, diff --git a/delivery/http/controller.go b/delivery/http/controller.go index a62a66f..8519338 100644 --- a/delivery/http/controller.go +++ b/delivery/http/controller.go @@ -140,20 +140,20 @@ func (c *controller) handleAlbum() httprouter.Handle { return nil } return handleHttpRouterError( - func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) error { + func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) (context.Context, error) { ctx, req, err := input(r, ps) if err != nil { - return errors.Wrap(err) + return ctx, errors.Wrap(err) } resp, err := process(ctx, req) if err != nil { - return errors.Wrap(err) + return ctx, errors.Wrap(err) } err = output(ctx, w, resp) if err != nil { - return errors.Wrap(err) + return ctx, errors.Wrap(err) } - return nil + return ctx, nil }, ) } @@ -187,20 +187,20 @@ func (c *controller) handleStatus() httprouter.Handle { return nil } return handleHttpRouterError( - func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) error { + func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) (context.Context, error) { ctx, req, err := input(r, ps) if err != nil { - return errors.Wrap(err) + return ctx, errors.Wrap(err) } resp, err := process(ctx, req) if err != nil { - return errors.Wrap(err) + return ctx, errors.Wrap(err) } err = output(ctx, w, resp) if err != nil { - return errors.Wrap(err) + return ctx, errors.Wrap(err) } - return nil + return ctx, nil }, ) } @@ -239,20 +239,20 @@ func (c *controller) handlePair() httprouter.Handle { return nil } return handleHttpRouterError( - func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) error { + func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) (context.Context, error) { ctx, req, err := input(r, ps) if err != nil { - return errors.Wrap(err) + return ctx, errors.Wrap(err) } resp, err := process(ctx, req) if err != nil { - return errors.Wrap(err) + return ctx, errors.Wrap(err) } err = output(ctx, w, resp) if err != nil { - return errors.Wrap(err) + return ctx, errors.Wrap(err) } - return nil + return ctx, nil }, ) } @@ -285,20 +285,20 @@ func (c *controller) handleImage() httprouter.Handle { return nil } return handleHttpRouterError( - func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) error { + func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) (context.Context, error) { ctx, req, err := input(r, ps) if err != nil { - return errors.Wrap(err) + return ctx, errors.Wrap(err) } resp, err := process(ctx, req) if err != nil { - return errors.Wrap(err) + return ctx, errors.Wrap(err) } err = output(ctx, w, resp) if err != nil { - return errors.Wrap(err) + return ctx, errors.Wrap(err) } - return nil + return ctx, nil }, ) } @@ -342,20 +342,20 @@ func (c *controller) handleVote() httprouter.Handle { return nil } return handleHttpRouterError( - func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) error { + func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) (context.Context, error) { ctx, req, err := input(r, ps) if err != nil { - return errors.Wrap(err) + return ctx, errors.Wrap(err) } resp, err := process(ctx, req) if err != nil { - return errors.Wrap(err) + return ctx, errors.Wrap(err) } err = output(ctx, w, resp) if err != nil { - return errors.Wrap(err) + return ctx, errors.Wrap(err) } - return nil + return ctx, nil }, ) } @@ -393,32 +393,33 @@ func (c *controller) handleTop() httprouter.Handle { return nil } return handleHttpRouterError( - func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) error { + func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) (context.Context, error) { ctx, req, err := input(r, ps) if err != nil { - return errors.Wrap(err) + return ctx, errors.Wrap(err) } resp, err := process(ctx, req) if err != nil { - return errors.Wrap(err) + return ctx, errors.Wrap(err) } err = output(ctx, w, resp) if err != nil { - return errors.Wrap(err) + return ctx, errors.Wrap(err) } - return nil + return ctx, nil }, ) } func (c *controller) handleHealth() httprouter.Handle { return handleHttpRouterError( - func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) error { - _, err := c.serv.Health(r.Context()) + func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) (context.Context, error) { + ctx := r.Context() + _, err := c.serv.Health(ctx) if err != nil { - return errors.Wrap(err) + return ctx, errors.Wrap(err) } - return nil + return ctx, nil }, ) } diff --git a/delivery/http/error.go b/delivery/http/error.go index 985bb37..6cbdef1 100644 --- a/delivery/http/error.go +++ b/delivery/http/error.go @@ -12,28 +12,28 @@ import ( "github.com/zitryss/aye-and-nay/pkg/errors" ) -func handleHttpRouterError(fn func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) error) httprouter.Handle { +func handleHttpRouterError(fn func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) (context.Context, error)) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - err := fn(w, r, ps) + ctx, err := fn(w, r, ps) if err == nil { return } - handleError(w, err) + handleError(ctx, w, err) } } -func handleHttpError(fn func(w http.ResponseWriter, r *http.Request) error) http.HandlerFunc { +func handleHttpError(fn func(w http.ResponseWriter, r *http.Request) (context.Context, error)) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - err := fn(w, r) + ctx, err := fn(w, r) if err == nil { return } - handleError(w, err) + handleError(ctx, w, err) } } -func handleError(w http.ResponseWriter, err error) { - service.HandleInnerError(err) +func handleError(ctx context.Context, w http.ResponseWriter, err error) { + service.HandleInnerError(ctx, err) handleOuterError(w, err) } diff --git a/delivery/http/middleware.go b/delivery/http/middleware.go index f2ed062..d0804eb 100644 --- a/delivery/http/middleware.go +++ b/delivery/http/middleware.go @@ -1,15 +1,18 @@ package http import ( + "context" "hash/fnv" "io" "net/http" "strings" + "time" "github.com/rs/cors" "github.com/zitryss/aye-and-nay/domain/domain" - "github.com/zitryss/aye-and-nay/internal/context" + "github.com/zitryss/aye-and-nay/internal/log" + "github.com/zitryss/aye-and-nay/internal/requestid" "github.com/zitryss/aye-and-nay/pkg/errors" ) @@ -30,6 +33,9 @@ func (m *Middleware) Chain(h http.Handler) http.Handler { AllowedOrigins: []string{m.conf.CorsAllowOrigin}, AllowedMethods: []string{http.MethodGet, http.MethodPost, http.MethodPatch}, }) + if m.conf.Debug { + h = m.debug(h) + } handler := m.recover( m.limit( @@ -52,7 +58,8 @@ func (m *Middleware) Chain(h http.Handler) http.Handler { func (m *Middleware) recover(h http.Handler) http.Handler { return handleHttpError( - func(w http.ResponseWriter, r *http.Request) (e error) { + func(w http.ResponseWriter, r *http.Request) (ctx context.Context, e error) { + ctx = r.Context() defer func() { v := recover() if v == nil { @@ -73,22 +80,22 @@ func (m *Middleware) recover(h http.Handler) http.Handler { func (m *Middleware) limit(h http.Handler) http.Handler { return handleHttpError( - func(w http.ResponseWriter, r *http.Request) error { + func(w http.ResponseWriter, r *http.Request) (context.Context, error) { ctx := r.Context() hash := fnv.New64a() _, err := io.WriteString(hash, ip(r)) if err != nil { - return errors.Wrap(err) + return ctx, errors.Wrap(err) } allowed, err := m.lim.Allow(ctx, hash.Sum64()) if err != nil { - return errors.Wrap(err) + return ctx, errors.Wrap(err) } if !allowed { - return errors.Wrap(domain.ErrTooManyRequests) + return ctx, errors.Wrap(domain.ErrTooManyRequests) } h.ServeHTTP(w, r) - return nil + return ctx, nil }, ) } @@ -106,7 +113,7 @@ func ip(r *http.Request) string { func (m *Middleware) requestId(h http.Handler) http.Handler { return http.HandlerFunc( func(w http.ResponseWriter, r *http.Request) { - ctx := context.WithRequestId(r.Context()) + ctx := requestid.Set(r.Context()) r = r.WithContext(ctx) h.ServeHTTP(w, r) }, @@ -121,3 +128,24 @@ func (m *Middleware) headers(h http.Handler) http.Handler { }, ) } + +func (m *Middleware) debug(h http.Handler) http.Handler { + return http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + log.Debug(ctx, + "time", time.Now(), + "r.RemoteAddr", r.RemoteAddr, + "r.Host", r.Host, + "r.Proto", r.Proto, + "r.TLS", r.TLS != nil, + "r.Method", r.Method, + "r.RequestURI", r.RequestURI, + "r.URL.Path", r.URL.Path, + "r.URL.RawQuery", r.URL.RawQuery, + "req.Header", r.Header, + ) + h.ServeHTTP(w, r) + }, + ) +} diff --git a/delivery/http/middleware_test.go b/delivery/http/middleware_test.go index 8e9ad89..ff91ae8 100644 --- a/delivery/http/middleware_test.go +++ b/delivery/http/middleware_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" - . "github.com/zitryss/aye-and-nay/internal/context" + "github.com/zitryss/aye-and-nay/internal/requestid" . "github.com/zitryss/aye-and-nay/internal/testing" ) @@ -171,7 +171,7 @@ func TestMiddlewareRequestId(t *testing.T) { ids := []uint64{0} fn := func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - id := GetRequestId(ctx) + id := requestid.Get(ctx) assert.NotZero(t, id) assert.Positive(t, id) assert.Greater(t, id, ids[len(ids)-1]) diff --git a/domain/service/error.go b/domain/service/error.go index 5adf3d5..0ded78e 100644 --- a/domain/service/error.go +++ b/domain/service/error.go @@ -4,26 +4,26 @@ import ( "context" "github.com/zitryss/aye-and-nay/domain/domain" + "github.com/zitryss/aye-and-nay/internal/log" "github.com/zitryss/aye-and-nay/pkg/errors" - "github.com/zitryss/aye-and-nay/pkg/log" ) func handleError(err error) { - HandleInnerError(err) + HandleInnerError(context.Background(), err) } -func HandleInnerError(err error) { +func HandleInnerError(ctx context.Context, err error) { cause := errors.Cause(err) if e := domain.Error(nil); errors.As(cause, &e) { - log.Println(log.Level(e.Inner().Level), err) + log.Print(ctx, e.Inner().Level, "err", err) return } switch cause { case context.Canceled: - log.Debug(err) + log.Debug(ctx, "err", err) case context.DeadlineExceeded: - log.Debug(err) + log.Debug(ctx, "err", err) default: - log.Errorf("%T %v", err, err) + log.Error(ctx, "err", err) } } diff --git a/go.mod b/go.mod index 6b1804a..0cf4372 100644 --- a/go.mod +++ b/go.mod @@ -18,9 +18,13 @@ require ( github.com/rs/cors v1.8.2 github.com/segmentio/asm v1.1.3 github.com/shirou/gopsutil v3.21.11+incompatible + github.com/spf13/afero v1.6.0 github.com/spf13/viper v1.10.1 github.com/stretchr/testify v1.7.1 go.mongodb.org/mongo-driver v1.8.4 + go.uber.org/atomic v1.9.0 + go.uber.org/zap v1.19.1 + golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 golang.org/x/net v0.0.0-20220225172249-27dd8689420f golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 @@ -85,7 +89,6 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rs/xid v1.3.0 // indirect github.com/sirupsen/logrus v1.8.1 // indirect - github.com/spf13/afero v1.6.0 // indirect github.com/spf13/cast v1.4.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect @@ -102,9 +105,7 @@ require ( github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect go.opencensus.io v0.23.0 // indirect - go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.7.0 // indirect - go.uber.org/zap v1.19.1 // indirect golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 // indirect golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 // indirect diff --git a/go.sum b/go.sum index 9ad7848..67bc871 100644 --- a/go.sum +++ b/go.sum @@ -396,6 +396,8 @@ golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5 golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 h1:/pEO3GD/ABYAjuakUS6xSEmmlyVS4kxBNkeA9tLJiTI= golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= diff --git a/infrastructure/cache/cache.go b/infrastructure/cache/cache.go index a368190..011c9d8 100644 --- a/infrastructure/cache/cache.go +++ b/infrastructure/cache/cache.go @@ -4,13 +4,13 @@ import ( "context" "github.com/zitryss/aye-and-nay/domain/domain" - "github.com/zitryss/aye-and-nay/pkg/log" + "github.com/zitryss/aye-and-nay/internal/log" ) func New(ctx context.Context, conf CacheConfig) (domain.Cacher, error) { switch conf.Cache { case "redis": - log.Info("connecting to cache") + log.Info(context.Background(), "msg", "connecting to cache") return NewRedis(ctx, conf.Redis) case "mem": mem := NewMem(conf.Mem) diff --git a/infrastructure/compressor/compressor.go b/infrastructure/compressor/compressor.go index 97a67e8..e4b3811 100644 --- a/infrastructure/compressor/compressor.go +++ b/infrastructure/compressor/compressor.go @@ -4,13 +4,13 @@ import ( "context" "github.com/zitryss/aye-and-nay/domain/domain" - "github.com/zitryss/aye-and-nay/pkg/log" + "github.com/zitryss/aye-and-nay/internal/log" ) func New(ctx context.Context, conf CompressorConfig) (domain.Compresser, error) { switch conf.Compressor { case "shortpixel": - log.Info("connecting to compressor") + log.Info(context.Background(), "msg", "connecting to compressor") sp := NewShortpixel(conf.Shortpixel) err := sp.Ping(ctx) if err != nil { @@ -19,7 +19,7 @@ func New(ctx context.Context, conf CompressorConfig) (domain.Compresser, error) sp.Monitor(ctx) return sp, nil case "imaginary": - log.Info("connecting to imaginary") + log.Info(context.Background(), "msg", "connecting to imaginary") return NewImaginary(ctx, conf.Imaginary) case "mock": return NewMock(), nil diff --git a/infrastructure/database/badger.go b/infrastructure/database/badger.go index 26273a8..37e9300 100644 --- a/infrastructure/database/badger.go +++ b/infrastructure/database/badger.go @@ -5,12 +5,12 @@ import ( "encoding/binary" "encoding/gob" "runtime" - "sort" "time" "github.com/dgraph-io/badger/v3" "github.com/dgraph-io/badger/v3/options" lru "github.com/hashicorp/golang-lru" + "golang.org/x/exp/slices" "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/model" @@ -199,7 +199,7 @@ func (b *Badger) GetImagesOrdered(_ context.Context, album uint64) ([]model.Imag if errors.Is(err, badger.ErrKeyNotFound) { return nil, errors.Wrap(domain.ErrAlbumNotFound) } - sort.Slice(alb.Images, func(i, j int) bool { return alb.Images[i].Rating > alb.Images[j].Rating }) + slices.SortFunc(alb.Images, func(a, b model.Image) bool { return a.Rating > b.Rating }) return alb.Images, nil } diff --git a/infrastructure/database/database.go b/infrastructure/database/database.go index 7ea8d8c..b6f8867 100644 --- a/infrastructure/database/database.go +++ b/infrastructure/database/database.go @@ -4,16 +4,16 @@ import ( "context" "github.com/zitryss/aye-and-nay/domain/domain" - "github.com/zitryss/aye-and-nay/pkg/log" + "github.com/zitryss/aye-and-nay/internal/log" ) func New(ctx context.Context, conf DatabaseConfig) (domain.Databaser, error) { switch conf.Database { case "mongo": - log.Info("connecting to database") + log.Info(context.Background(), "msg", "connecting to database") return NewMongo(ctx, conf.Mongo) case "badger": - log.Info("connecting to embedded database") + log.Info(context.Background(), "msg", "connecting to embedded database") b, err := NewBadger(conf.Badger) if err != nil { return nil, err diff --git a/infrastructure/database/mem.go b/infrastructure/database/mem.go index 6324f8c..2dca703 100644 --- a/infrastructure/database/mem.go +++ b/infrastructure/database/mem.go @@ -2,9 +2,10 @@ package database import ( "context" - "sort" "sync" + "golang.org/x/exp/slices" + "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/domain/model" "github.com/zitryss/aye-and-nay/pkg/errors" @@ -192,7 +193,7 @@ func (m *Mem) GetImagesOrdered(_ context.Context, album uint64) ([]model.Image, } imgs := make([]model.Image, len(alb.Images)) copy(imgs, alb.Images) - sort.Slice(imgs, func(i, j int) bool { return imgs[i].Rating > imgs[j].Rating }) + slices.SortFunc(imgs, func(a, b model.Image) bool { return a.Rating > b.Rating }) return imgs, nil } diff --git a/infrastructure/storage/storage.go b/infrastructure/storage/storage.go index d867b72..706bbf1 100644 --- a/infrastructure/storage/storage.go +++ b/infrastructure/storage/storage.go @@ -4,13 +4,13 @@ import ( "context" "github.com/zitryss/aye-and-nay/domain/domain" - "github.com/zitryss/aye-and-nay/pkg/log" + "github.com/zitryss/aye-and-nay/internal/log" ) func New(ctx context.Context, conf StorageConfig) (domain.Storager, error) { switch conf.Storage { case "minio": - log.Info("connecting to storage") + log.Info(context.Background(), "msg", "connecting to storage") return NewMinio(ctx, conf.Minio) case "mock": return NewMock(), nil diff --git a/internal/config/config.go b/internal/config/config.go index 34c34fc..48e526a 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -16,8 +16,8 @@ import ( "github.com/zitryss/aye-and-nay/infrastructure/compressor" "github.com/zitryss/aye-and-nay/infrastructure/database" "github.com/zitryss/aye-and-nay/infrastructure/storage" + "github.com/zitryss/aye-and-nay/internal/log" "github.com/zitryss/aye-and-nay/pkg/errors" - "github.com/zitryss/aye-and-nay/pkg/log" ) func New(path string) (Config, error) { @@ -64,7 +64,7 @@ func (c *Config) OnChange(ctx context.Context, fn func()) { w.FilterOps(watcher.Write) err := w.Add(c.path) if err != nil { - log.Error(errors.Wrap(err)) + log.Error(context.Background(), "err", errors.Wrap(err)) } go func() { for { @@ -72,7 +72,7 @@ func (c *Config) OnChange(ctx context.Context, fn func()) { case <-w.Event: fn() case err := <-w.Error: - log.Error(errors.Wrap(err)) + log.Error(context.Background(), "err", errors.Wrap(err)) case <-w.Closed: return case <-ctx.Done(): @@ -85,7 +85,7 @@ func (c *Config) OnChange(ctx context.Context, fn func()) { go func() { err := w.Start(c.ReloadInterval) if err != nil { - log.Error(errors.Wrap(err)) + log.Error(context.Background(), "err", errors.Wrap(err)) } }() } @@ -95,7 +95,7 @@ func readConfig(path string, conf *Config) error { viper.AutomaticEnv() err := viper.ReadInConfig() if err != nil { - log.Error(errors.Wrap(err)) + log.Error(context.Background(), "err", errors.Wrap(err)) } if len(viper.AllSettings()) == 0 { bindEnv(reflect.TypeOf(*conf)) @@ -120,7 +120,7 @@ func bindEnv(t reflect.Type) { if field.IsExported() && tag != "" && tag != ",squash" { err := viper.BindEnv(strings.ToLower(tag), tag) if err != nil { - log.Error(errors.Wrap(err)) + log.Error(context.Background(), "err", errors.Wrap(err)) } } } diff --git a/internal/gctuner/gctuner.go b/internal/gctuner/gctuner.go index 52af6b9..4151a32 100644 --- a/internal/gctuner/gctuner.go +++ b/internal/gctuner/gctuner.go @@ -13,8 +13,8 @@ import ( "github.com/shirou/gopsutil/process" "github.com/spf13/afero" + "github.com/zitryss/aye-and-nay/internal/log" "github.com/zitryss/aye-and-nay/pkg/errors" - "github.com/zitryss/aye-and-nay/pkg/log" ) const ( @@ -147,7 +147,7 @@ func finalizerHandler(ctx context.Context) func(fin *finalizerRef) { return func(fin *finalizerRef) { err := updateGOGC() if err != nil { - log.Error("update GOGC:", err) + log.Error(context.Background(), "err", err) } select { case <-ctx.Done(): @@ -175,9 +175,11 @@ func updateGOGC() error { newGOGC = lastGOGC * memLimitRatio / memUsedRatio } lastGOGC = float64(debug.SetGCPercent(int(newGOGC))) - log.Debugf("mem used: %.0f\n", memUsed) - log.Debugf("mem used ratio: %.2f\n", memUsedRatio) - log.Debugf("new GOGC: %.0f\n", newGOGC) + log.Debug(context.Background(), + "mem used", memUsed, + "mem used ratio", memUsedRatio, + "new GOGC", newGOGC, + ) return nil } diff --git a/internal/log/log.go b/internal/log/log.go new file mode 100644 index 0000000..e331e74 --- /dev/null +++ b/internal/log/log.go @@ -0,0 +1,127 @@ +package log + +import ( + "context" + "strings" + + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + + "github.com/zitryss/aye-and-nay/internal/requestid" + "github.com/zitryss/aye-and-nay/pkg/errors" +) + +var ( + l logger +) + +type logger struct { + *zap.SugaredLogger + lvl zapcore.Level + prefix string +} + +func New(lvl string, prefix string) error { + zapConf := zap.NewProductionConfig() + switch strings.ToLower(lvl) { + case "debug": + l.lvl = zap.DebugLevel + zapConf.Level = zap.NewAtomicLevelAt(l.lvl) + case "info": + l.lvl = zap.InfoLevel + zapConf.Level = zap.NewAtomicLevelAt(l.lvl) + case "error": + l.lvl = zap.WarnLevel + zapConf.Level = zap.NewAtomicLevelAt(l.lvl) + case "critical": + l.lvl = zap.ErrorLevel + zapConf.Level = zap.NewAtomicLevelAt(l.lvl) + } + zapLog, err := zapConf.Build() + if err != nil { + return errors.Wrap(err) + } + l.SugaredLogger = zapLog.Sugar() + l.prefix = prefix + return nil +} + +func Print(ctx context.Context, level int, v ...any) { + if level < 1 || level > 4 || l.lvl > zapcore.Level(level-2) { + return + } + requestId := requestid.Get(ctx) + args := []any(nil) + args = append(args, "app-name", l.prefix) + if requestId != 0 { + args = append(args, "request-id", requestId) + } + args = append(args, v...) + + switch level { + case 1: + l.Debug(args...) + case 2: + l.Info(args...) + case 3: + l.Warn(args...) + case 4: + l.Error(args...) + } +} + +func Debug(ctx context.Context, v ...any) { + if l.lvl > zapcore.DebugLevel || l.SugaredLogger == nil { + return + } + requestId := requestid.Get(ctx) + args := []any(nil) + args = append(args, "app-name", l.prefix) + if requestId != 0 { + args = append(args, "request-id", requestId) + } + args = append(args, v...) + l.Debug(args...) +} + +func Info(ctx context.Context, v ...any) { + if l.lvl > zapcore.InfoLevel || l.SugaredLogger == nil { + return + } + requestId := requestid.Get(ctx) + args := []any(nil) + args = append(args, "app-name", l.prefix) + if requestId != 0 { + args = append(args, "request-id", requestId) + } + args = append(args, v...) + l.Info(args...) +} + +func Error(ctx context.Context, v ...any) { + if l.lvl > zapcore.WarnLevel || l.SugaredLogger == nil { + return + } + requestId := requestid.Get(ctx) + args := []any(nil) + args = append(args, "app-name", l.prefix) + if requestId != 0 { + args = append(args, "request-id", requestId) + } + args = append(args, v...) + l.Warn(args...) +} + +func Critical(ctx context.Context, v ...any) { + if l.lvl > zapcore.ErrorLevel || l.SugaredLogger == nil { + return + } + requestId := requestid.Get(ctx) + args := []any(nil) + args = append(args, "app-name", l.prefix) + if requestId != 0 { + args = append(args, "request-id", requestId) + } + args = append(args, v...) + l.Error(args...) +} diff --git a/internal/context/context.go b/internal/requestid/requestid.go similarity index 70% rename from internal/context/context.go rename to internal/requestid/requestid.go index 6039b57..6e3e10b 100644 --- a/internal/context/context.go +++ b/internal/requestid/requestid.go @@ -1,4 +1,4 @@ -package context +package requestid import ( "context" @@ -16,11 +16,11 @@ var ( requestID atomic.Uint64 ) -func WithRequestId(ctx context.Context) context.Context { +func Set(ctx context.Context) context.Context { return context.WithValue(ctx, ctxRequestId, requestID.Inc()) } -func GetRequestId(ctx context.Context) uint64 { +func Get(ctx context.Context) uint64 { reqId, ok := ctx.Value(ctxRequestId).(uint64) if !ok { return 0 diff --git a/internal/context/context_test.go b/internal/requestid/requestid_test.go similarity index 52% rename from internal/context/context_test.go rename to internal/requestid/requestid_test.go index 310ad65..708b359 100644 --- a/internal/context/context_test.go +++ b/internal/requestid/requestid_test.go @@ -1,4 +1,4 @@ -package context +package requestid import ( "context" @@ -15,14 +15,23 @@ var ( ) func TestContext(t *testing.T) { + if !*unit { + t.Skip() + } t.Run("Positive", func(t *testing.T) { - ctx := WithRequestId(context.Background()) - assert.Equal(t, uint64(1), GetRequestId(ctx)) - ctx = WithRequestId(ctx) - assert.Equal(t, uint64(2), GetRequestId(ctx)) + ctx := Set(context.Background()) + id1 := Get(ctx) + assert.NotZero(t, id1) + assert.Positive(t, id1) + assert.Greater(t, id1, uint64(0)) + ctx = Set(ctx) + id2 := Get(ctx) + assert.NotZero(t, id2) + assert.Positive(t, id2) + assert.Greater(t, id2, id1) }) t.Run("Negative", func(t *testing.T) { ctx := context.Background() - assert.Equal(t, uint64(0), GetRequestId(ctx)) + assert.Equal(t, uint64(0), Get(ctx)) }) } diff --git a/main.go b/main.go index 148e84b..28f0926 100644 --- a/main.go +++ b/main.go @@ -20,9 +20,9 @@ import ( "github.com/zitryss/aye-and-nay/infrastructure/storage" "github.com/zitryss/aye-and-nay/internal/config" "github.com/zitryss/aye-and-nay/internal/gctuner" + "github.com/zitryss/aye-and-nay/internal/log" "github.com/zitryss/aye-and-nay/internal/ulimit" "github.com/zitryss/aye-and-nay/pkg/errors" - "github.com/zitryss/aye-and-nay/pkg/log" ) func main() { @@ -63,15 +63,21 @@ func main() { }) } - log.SetOutput(os.Stderr) - log.SetPrefix(conf.App.Name) - log.SetLevel(conf.App.Log) - log.Info("logging initialized:", "log level:", conf.App.Log) + err = log.New(conf.App.Log, conf.App.Name) + if err != nil { + _, _ = fmt.Fprintln(os.Stderr, "critical:", err) + reload = true + stop() + time.Sleep(2 * time.Second) + continue + } + + log.Info(context.Background(), "msg", "logging initialized:", "log level:", conf.App.Log) if conf.App.GcTuner { err = gctuner.Start(ctx, conf.App.MemTotal, conf.App.MemLimitRatio) if err != nil { - log.Critical(err) + log.Critical(context.Background(), "err", err) reload = true stop() time.Sleep(2 * time.Second) @@ -81,7 +87,7 @@ func main() { cach, err = cache.New(ctx, conf.Cache) if err != nil { - log.Critical(err) + log.Critical(context.Background(), "err", err) reload = true stop() time.Sleep(2 * time.Second) @@ -90,7 +96,7 @@ func main() { comp, err = compressor.New(ctx, conf.Compressor) if err != nil { - log.Critical(err) + log.Critical(context.Background(), "err", err) reload = true stop() time.Sleep(2 * time.Second) @@ -99,7 +105,7 @@ func main() { data, err = database.New(ctx, conf.Database) if err != nil { - log.Critical(err) + log.Critical(context.Background(), "err", err) reload = true stop() time.Sleep(2 * time.Second) @@ -108,7 +114,7 @@ func main() { stor, err = storage.New(ctx, conf.Storage) if err != nil { - log.Critical(err) + log.Critical(context.Background(), "err", err) reload = true stop() time.Sleep(2 * time.Second) @@ -130,7 +136,7 @@ func main() { serv := service.New(conf.Service, comp, stor, data, cach, qCalc, qComp, qDel) err = serv.CleanUp(ctx) if err != nil { - log.Critical(err) + log.Critical(context.Background(), "err", err) reload = true stop() time.Sleep(2 * time.Second) @@ -138,62 +144,62 @@ func main() { } gCalc, ctxCalc := errgroup.WithContext(ctx) - log.Info("starting calculation worker pool") + log.Info(context.Background(), "msg", "starting calculation worker pool") serv.StartWorkingPoolCalc(ctxCalc, gCalc) gComp := (*errgroup.Group)(nil) ctxComp := context.Context(nil) if !conf.Compressor.IsMock() { gComp, ctxComp = errgroup.WithContext(ctx) - log.Info("starting compression worker pool") + log.Info(context.Background(), "msg", "starting compression worker pool") serv.StartWorkingPoolComp(ctxComp, gComp) } gDel, ctxDel := errgroup.WithContext(ctx) - log.Info("starting deletion worker pool") + log.Info(context.Background(), "msg", "starting deletion worker pool") serv.StartWorkingPoolDel(ctxDel, gDel) middle := http.NewMiddleware(conf.Middleware, cach) srvWait := make(chan error, 1) srv, err := http.NewServer(conf.Server, middle.Chain, serv, srvWait) if err != nil { - log.Critical(err) + log.Critical(context.Background(), "err", err) reload = true stop() time.Sleep(2 * time.Second) continue } srv.Monitor(ctx) - log.Info("starting web server") + log.Info(context.Background(), "msg", "starting web server") err = srv.Start() - log.Info("stopping web server") + log.Info(context.Background(), "msg", "stopping web server") if err != nil && !errors.Is(err, http.ErrServerClosed) { - log.Error(err) + log.Error(context.Background(), "err", err) } err = <-srvWait if err != nil { - log.Error(err) + log.Error(context.Background(), "err", err) } - log.Info("stopping deletion worker pool") + log.Info(context.Background(), "msg", "stopping deletion worker pool") err = gDel.Wait() if err != nil { - log.Error(err) + log.Error(context.Background(), "err", err) } if !conf.Compressor.IsMock() { - log.Info("stopping compression worker pool") + log.Info(context.Background(), "msg", "stopping compression worker pool") err = gComp.Wait() if err != nil { - log.Error(err) + log.Error(context.Background(), "err", err) } } - log.Info("stopping calculation worker pool") + log.Info(context.Background(), "msg", "stopping calculation worker pool") err = gCalc.Wait() if err != nil { - log.Error(err) + log.Error(context.Background(), "err", err) } stop() @@ -202,7 +208,7 @@ func main() { if ok { err = b.Close(context.Background()) if err != nil { - log.Error(err) + log.Error(context.Background(), "err", err) } } } @@ -211,7 +217,7 @@ func main() { if ok { err = r.Close(context.Background()) if err != nil { - log.Error(err) + log.Error(context.Background(), "err", err) } } @@ -219,7 +225,7 @@ func main() { if ok { err = m.Close(context.Background()) if err != nil { - log.Error(err) + log.Error(context.Background(), "err", err) } } } From 4c9b8478de85dcf17f7ece92d65e27735a872ed0 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Tue, 19 Jul 2022 10:38:42 +0200 Subject: [PATCH 78/92] Add comment on how to start a fuzz test --- pkg/base64/base64_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/base64/base64_test.go b/pkg/base64/base64_test.go index 77706ac..a3ac34d 100644 --- a/pkg/base64/base64_test.go +++ b/pkg/base64/base64_test.go @@ -106,6 +106,7 @@ func TestToUint64(t *testing.T) { } } +// go test -fuzz=FuzzFromUint64 -fuzztime 5s func FuzzFromUint64(f *testing.F) { f.Add(uint64(0)) f.Fuzz(func(t *testing.T, u1 uint64) { @@ -119,6 +120,7 @@ func FuzzFromUint64(f *testing.F) { }) } +// go test -fuzz=FuzzToUint64 -fuzztime 5s func FuzzToUint64(f *testing.F) { f.Add("AAAAAAAAAAA") f.Fuzz(func(t *testing.T, s string) { From 04f125b92c3194c9e91de317d4bec3858b63404d Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Tue, 19 Jul 2022 10:39:01 +0200 Subject: [PATCH 79/92] Check for the nil context --- internal/requestid/requestid.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/internal/requestid/requestid.go b/internal/requestid/requestid.go index 6e3e10b..edf2402 100644 --- a/internal/requestid/requestid.go +++ b/internal/requestid/requestid.go @@ -17,10 +17,16 @@ var ( ) func Set(ctx context.Context) context.Context { + if ctx == nil { + ctx = context.Background() + } return context.WithValue(ctx, ctxRequestId, requestID.Inc()) } func Get(ctx context.Context) uint64 { + if ctx == nil { + return 0 + } reqId, ok := ctx.Value(ctxRequestId).(uint64) if !ok { return 0 From 2f18ffbbfa8f29c879bc46b719609d085271f865 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Thu, 22 Sep 2022 18:11:32 +0200 Subject: [PATCH 80/92] Cache CORS --- delivery/http/middleware.go | 1 + 1 file changed, 1 insertion(+) diff --git a/delivery/http/middleware.go b/delivery/http/middleware.go index d0804eb..dc1151f 100644 --- a/delivery/http/middleware.go +++ b/delivery/http/middleware.go @@ -32,6 +32,7 @@ func (m *Middleware) Chain(h http.Handler) http.Handler { c := cors.New(cors.Options{ AllowedOrigins: []string{m.conf.CorsAllowOrigin}, AllowedMethods: []string{http.MethodGet, http.MethodPost, http.MethodPatch}, + MaxAge: 86400, // Firefox caps the value at 86400 (24 hours) while all Chromium-based browsers cap it at 7200 (2 hours) }) if m.conf.Debug { h = m.debug(h) From 88c8e1fd9abe8d111a5781038674098aeb584186 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sat, 8 Oct 2022 02:24:40 +0200 Subject: [PATCH 81/92] Structure logging --- delivery/http/middleware.go | 1 + domain/domain/error.go | 56 +++++++++--------- domain/service/error.go | 8 +-- infrastructure/cache/cache.go | 2 +- infrastructure/compressor/compressor.go | 4 +- infrastructure/database/database.go | 4 +- infrastructure/storage/storage.go | 2 +- internal/config/config.go | 10 ++-- internal/dockertest/dockertest.go | 2 +- internal/gctuner/gctuner.go | 3 +- internal/log/log.go | 76 +++++++++---------------- internal/log/log_test.go | 11 ++++ main.go | 48 ++++++++-------- 13 files changed, 110 insertions(+), 117 deletions(-) create mode 100644 internal/log/log_test.go diff --git a/delivery/http/middleware.go b/delivery/http/middleware.go index dc1151f..3171ed5 100644 --- a/delivery/http/middleware.go +++ b/delivery/http/middleware.go @@ -135,6 +135,7 @@ func (m *Middleware) debug(h http.Handler) http.Handler { func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() log.Debug(ctx, + "incoming request", "time", time.Now(), "r.RemoteAddr", r.RemoteAddr, "r.Host", r.Host, diff --git a/domain/domain/error.go b/domain/domain/error.go index 2e9f897..4083c80 100644 --- a/domain/domain/error.go +++ b/domain/domain/error.go @@ -6,11 +6,11 @@ import ( ) const ( - logDisabled int = iota - logDebug - logInfo - logError - logCritical + LogDisabled int = iota + LogDebug + LogInfo + LogError + LogCritical ) var ( @@ -21,7 +21,7 @@ var ( UserMsg: "too many requests", }, innerError: innerError{ - Level: logDebug, + Level: LogDebug, DevMsg: "too many requests", }, } @@ -32,7 +32,7 @@ var ( UserMsg: "body too large", }, innerError: innerError{ - Level: logDebug, + Level: LogDebug, DevMsg: "body too large", }, } @@ -43,7 +43,7 @@ var ( UserMsg: "unsupported media type", }, innerError: innerError{ - Level: logDebug, + Level: LogDebug, DevMsg: "wrong content type", }, } @@ -54,7 +54,7 @@ var ( UserMsg: "not enough images", }, innerError: innerError{ - Level: logDebug, + Level: LogDebug, DevMsg: "not enough images", }, } @@ -65,7 +65,7 @@ var ( UserMsg: "too many images", }, innerError: innerError{ - Level: logDebug, + Level: LogDebug, DevMsg: "too many images", }, } @@ -76,7 +76,7 @@ var ( UserMsg: "image too large", }, innerError: innerError{ - Level: logDebug, + Level: LogDebug, DevMsg: "image too large", }, } @@ -87,7 +87,7 @@ var ( UserMsg: "unsupported media type", }, innerError: innerError{ - Level: logDebug, + Level: LogDebug, DevMsg: "not an image", }, } @@ -98,7 +98,7 @@ var ( UserMsg: "duration not set", }, innerError: innerError{ - Level: logDebug, + Level: LogDebug, DevMsg: "duration not set", }, } @@ -109,7 +109,7 @@ var ( UserMsg: "duration invalid", }, innerError: innerError{ - Level: logDebug, + Level: LogDebug, DevMsg: "duration invalid", }, } @@ -120,7 +120,7 @@ var ( UserMsg: "id invalid", }, innerError: innerError{ - Level: logDebug, + Level: LogDebug, DevMsg: "id invalid", }, } @@ -131,7 +131,7 @@ var ( UserMsg: "album not found", }, innerError: innerError{ - Level: logDebug, + Level: LogDebug, DevMsg: "album not found", }, } @@ -142,7 +142,7 @@ var ( UserMsg: "internal server error", }, innerError: innerError{ - Level: logError, + Level: LogError, DevMsg: "pair not found", }, } @@ -153,7 +153,7 @@ var ( UserMsg: "token not found", }, innerError: innerError{ - Level: logDebug, + Level: LogDebug, DevMsg: "token not found", }, } @@ -164,7 +164,7 @@ var ( UserMsg: "internal server error", }, innerError: innerError{ - Level: logError, + Level: LogError, DevMsg: "image not found", }, } @@ -175,7 +175,7 @@ var ( UserMsg: "internal server error", }, innerError: innerError{ - Level: logError, + Level: LogError, DevMsg: "album already exists", }, } @@ -186,7 +186,7 @@ var ( UserMsg: "internal server error", }, innerError: innerError{ - Level: logError, + Level: LogError, DevMsg: "token already exists", }, } @@ -197,7 +197,7 @@ var ( UserMsg: "unsupported media type", }, innerError: innerError{ - Level: logError, + Level: LogError, DevMsg: "image rejected by third party", }, } @@ -208,7 +208,7 @@ var ( UserMsg: "internal server error", }, innerError: innerError{ - Level: logCritical, + Level: LogCritical, DevMsg: "third party is unavailable", }, } @@ -219,7 +219,7 @@ var ( UserMsg: "internal server error", }, innerError: innerError{ - Level: logCritical, + Level: LogCritical, DevMsg: "compressor is unavailable", }, } @@ -230,7 +230,7 @@ var ( UserMsg: "internal server error", }, innerError: innerError{ - Level: logCritical, + Level: LogCritical, DevMsg: "storage is unavailable", }, } @@ -241,7 +241,7 @@ var ( UserMsg: "internal server error", }, innerError: innerError{ - Level: logCritical, + Level: LogCritical, DevMsg: "database is unavailable", }, } @@ -252,7 +252,7 @@ var ( UserMsg: "internal server error", }, innerError: innerError{ - Level: logCritical, + Level: LogCritical, DevMsg: "cache is unavailable", }, } @@ -263,7 +263,7 @@ var ( UserMsg: "internal server error", }, innerError: innerError{ - Level: logError, + Level: LogError, DevMsg: "unknown", }, } diff --git a/domain/service/error.go b/domain/service/error.go index 0ded78e..8ee6085 100644 --- a/domain/service/error.go +++ b/domain/service/error.go @@ -15,15 +15,15 @@ func handleError(err error) { func HandleInnerError(ctx context.Context, err error) { cause := errors.Cause(err) if e := domain.Error(nil); errors.As(cause, &e) { - log.Print(ctx, e.Inner().Level, "err", err) + log.Print(ctx, e.Inner().Level, "err", "stacktrace", err) return } switch cause { case context.Canceled: - log.Debug(ctx, "err", err) + log.Debug(ctx, "err", "stacktrace", err) case context.DeadlineExceeded: - log.Debug(ctx, "err", err) + log.Debug(ctx, "err", "stacktrace", err) default: - log.Error(ctx, "err", err) + log.Error(ctx, "err", "stacktrace", err) } } diff --git a/infrastructure/cache/cache.go b/infrastructure/cache/cache.go index 011c9d8..5659c92 100644 --- a/infrastructure/cache/cache.go +++ b/infrastructure/cache/cache.go @@ -10,7 +10,7 @@ import ( func New(ctx context.Context, conf CacheConfig) (domain.Cacher, error) { switch conf.Cache { case "redis": - log.Info(context.Background(), "msg", "connecting to cache") + log.Info(context.Background(), "connecting to cache") return NewRedis(ctx, conf.Redis) case "mem": mem := NewMem(conf.Mem) diff --git a/infrastructure/compressor/compressor.go b/infrastructure/compressor/compressor.go index e4b3811..37e9ace 100644 --- a/infrastructure/compressor/compressor.go +++ b/infrastructure/compressor/compressor.go @@ -10,7 +10,7 @@ import ( func New(ctx context.Context, conf CompressorConfig) (domain.Compresser, error) { switch conf.Compressor { case "shortpixel": - log.Info(context.Background(), "msg", "connecting to compressor") + log.Info(context.Background(), "connecting to compressor") sp := NewShortpixel(conf.Shortpixel) err := sp.Ping(ctx) if err != nil { @@ -19,7 +19,7 @@ func New(ctx context.Context, conf CompressorConfig) (domain.Compresser, error) sp.Monitor(ctx) return sp, nil case "imaginary": - log.Info(context.Background(), "msg", "connecting to imaginary") + log.Info(context.Background(), "connecting to imaginary") return NewImaginary(ctx, conf.Imaginary) case "mock": return NewMock(), nil diff --git a/infrastructure/database/database.go b/infrastructure/database/database.go index b6f8867..9facaae 100644 --- a/infrastructure/database/database.go +++ b/infrastructure/database/database.go @@ -10,10 +10,10 @@ import ( func New(ctx context.Context, conf DatabaseConfig) (domain.Databaser, error) { switch conf.Database { case "mongo": - log.Info(context.Background(), "msg", "connecting to database") + log.Info(context.Background(), "connecting to database") return NewMongo(ctx, conf.Mongo) case "badger": - log.Info(context.Background(), "msg", "connecting to embedded database") + log.Info(context.Background(), "connecting to embedded database") b, err := NewBadger(conf.Badger) if err != nil { return nil, err diff --git a/infrastructure/storage/storage.go b/infrastructure/storage/storage.go index 706bbf1..84a1ad4 100644 --- a/infrastructure/storage/storage.go +++ b/infrastructure/storage/storage.go @@ -10,7 +10,7 @@ import ( func New(ctx context.Context, conf StorageConfig) (domain.Storager, error) { switch conf.Storage { case "minio": - log.Info(context.Background(), "msg", "connecting to storage") + log.Info(context.Background(), "connecting to storage") return NewMinio(ctx, conf.Minio) case "mock": return NewMock(), nil diff --git a/internal/config/config.go b/internal/config/config.go index 48e526a..547c690 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -64,7 +64,7 @@ func (c *Config) OnChange(ctx context.Context, fn func()) { w.FilterOps(watcher.Write) err := w.Add(c.path) if err != nil { - log.Error(context.Background(), "err", errors.Wrap(err)) + log.Error(context.Background(), "err", "stacktrace", errors.Wrap(err)) } go func() { for { @@ -72,7 +72,7 @@ func (c *Config) OnChange(ctx context.Context, fn func()) { case <-w.Event: fn() case err := <-w.Error: - log.Error(context.Background(), "err", errors.Wrap(err)) + log.Error(context.Background(), "err", "stacktrace", errors.Wrap(err)) case <-w.Closed: return case <-ctx.Done(): @@ -85,7 +85,7 @@ func (c *Config) OnChange(ctx context.Context, fn func()) { go func() { err := w.Start(c.ReloadInterval) if err != nil { - log.Error(context.Background(), "err", errors.Wrap(err)) + log.Error(context.Background(), "err", "stacktrace", errors.Wrap(err)) } }() } @@ -95,7 +95,7 @@ func readConfig(path string, conf *Config) error { viper.AutomaticEnv() err := viper.ReadInConfig() if err != nil { - log.Error(context.Background(), "err", errors.Wrap(err)) + log.Error(context.Background(), "err", "stacktrace", errors.Wrap(err)) } if len(viper.AllSettings()) == 0 { bindEnv(reflect.TypeOf(*conf)) @@ -120,7 +120,7 @@ func bindEnv(t reflect.Type) { if field.IsExported() && tag != "" && tag != ",squash" { err := viper.BindEnv(strings.ToLower(tag), tag) if err != nil { - log.Error(context.Background(), "err", errors.Wrap(err)) + log.Error(context.Background(), "err", "stacktrace", errors.Wrap(err)) } } } diff --git a/internal/dockertest/dockertest.go b/internal/dockertest/dockertest.go index 69c1447..9b323bb 100644 --- a/internal/dockertest/dockertest.go +++ b/internal/dockertest/dockertest.go @@ -18,7 +18,7 @@ func New() docker { u, err := url.Parse(host) if err != nil { err = errors.Wrap(err) - log.Critical("dockertest: ", err) + log.Critical("dockertest:", err) os.Exit(1) } hostname := u.Hostname() diff --git a/internal/gctuner/gctuner.go b/internal/gctuner/gctuner.go index 4151a32..e59ec0d 100644 --- a/internal/gctuner/gctuner.go +++ b/internal/gctuner/gctuner.go @@ -147,7 +147,7 @@ func finalizerHandler(ctx context.Context) func(fin *finalizerRef) { return func(fin *finalizerRef) { err := updateGOGC() if err != nil { - log.Error(context.Background(), "err", err) + log.Error(context.Background(), "err", "stacktrace", err) } select { case <-ctx.Done(): @@ -176,6 +176,7 @@ func updateGOGC() error { } lastGOGC = float64(debug.SetGCPercent(int(newGOGC))) log.Debug(context.Background(), + "gc", "mem used", memUsed, "mem used ratio", memUsedRatio, "new GOGC", newGOGC, diff --git a/internal/log/log.go b/internal/log/log.go index e331e74..6d07383 100644 --- a/internal/log/log.go +++ b/internal/log/log.go @@ -7,6 +7,7 @@ import ( "go.uber.org/zap" "go.uber.org/zap/zapcore" + "github.com/zitryss/aye-and-nay/domain/domain" "github.com/zitryss/aye-and-nay/internal/requestid" "github.com/zitryss/aye-and-nay/pkg/errors" ) @@ -17,12 +18,12 @@ var ( type logger struct { *zap.SugaredLogger - lvl zapcore.Level - prefix string + lvl zapcore.Level } func New(lvl string, prefix string) error { zapConf := zap.NewProductionConfig() + zapConf.EncoderConfig.EncodeTime = zapcore.RFC3339TimeEncoder switch strings.ToLower(lvl) { case "debug": l.lvl = zap.DebugLevel @@ -36,92 +37,71 @@ func New(lvl string, prefix string) error { case "critical": l.lvl = zap.ErrorLevel zapConf.Level = zap.NewAtomicLevelAt(l.lvl) + default: + return errors.Wrap(errors.New("wrong log level")) } - zapLog, err := zapConf.Build() + zapLog, err := zapConf.Build(zap.WithCaller(false)) if err != nil { return errors.Wrap(err) } l.SugaredLogger = zapLog.Sugar() - l.prefix = prefix + l.With("app-name", prefix) return nil } -func Print(ctx context.Context, level int, v ...any) { - if level < 1 || level > 4 || l.lvl > zapcore.Level(level-2) { - return - } - requestId := requestid.Get(ctx) - args := []any(nil) - args = append(args, "app-name", l.prefix) - if requestId != 0 { - args = append(args, "request-id", requestId) - } - args = append(args, v...) - +func Print(ctx context.Context, level int, msg string, v ...any) { switch level { - case 1: - l.Debug(args...) - case 2: - l.Info(args...) - case 3: - l.Warn(args...) - case 4: - l.Error(args...) + case domain.LogDebug: + Debug(ctx, msg, v...) + case domain.LogInfo: + Info(ctx, msg, v...) + case domain.LogError: + Error(ctx, msg, v...) + case domain.LogCritical: + Critical(ctx, msg, v...) } } -func Debug(ctx context.Context, v ...any) { +func Debug(ctx context.Context, msg string, v ...any) { if l.lvl > zapcore.DebugLevel || l.SugaredLogger == nil { return } requestId := requestid.Get(ctx) - args := []any(nil) - args = append(args, "app-name", l.prefix) if requestId != 0 { - args = append(args, "request-id", requestId) + v = append([]any{"request-id", requestId}, v...) } - args = append(args, v...) - l.Debug(args...) + l.Debugw(msg, v...) } -func Info(ctx context.Context, v ...any) { +func Info(ctx context.Context, msg string, v ...any) { if l.lvl > zapcore.InfoLevel || l.SugaredLogger == nil { return } requestId := requestid.Get(ctx) - args := []any(nil) - args = append(args, "app-name", l.prefix) if requestId != 0 { - args = append(args, "request-id", requestId) + v = append([]any{"request-id", requestId}, v...) } - args = append(args, v...) - l.Info(args...) + l.Infow(msg, v...) } -func Error(ctx context.Context, v ...any) { +func Error(ctx context.Context, msg string, v ...any) { if l.lvl > zapcore.WarnLevel || l.SugaredLogger == nil { return } requestId := requestid.Get(ctx) - args := []any(nil) - args = append(args, "app-name", l.prefix) if requestId != 0 { - args = append(args, "request-id", requestId) + v = append([]any{"request-id", requestId}, v...) } - args = append(args, v...) - l.Warn(args...) + l.Warnw(msg, v...) } -func Critical(ctx context.Context, v ...any) { +func Critical(ctx context.Context, msg string, v ...any) { if l.lvl > zapcore.ErrorLevel || l.SugaredLogger == nil { return } requestId := requestid.Get(ctx) - args := []any(nil) - args = append(args, "app-name", l.prefix) if requestId != 0 { - args = append(args, "request-id", requestId) + v = append([]any{"request-id", requestId}, v...) } - args = append(args, v...) - l.Error(args...) + l.Errorw(msg, v...) } diff --git a/internal/log/log_test.go b/internal/log/log_test.go new file mode 100644 index 0000000..c64852c --- /dev/null +++ b/internal/log/log_test.go @@ -0,0 +1,11 @@ +package log + +import ( + "flag" +) + +var ( + unit = flag.Bool("unit", false, "") + integration = flag.Bool("int", false, "") + ci = flag.Bool("ci", false, "") +) diff --git a/main.go b/main.go index 28f0926..f4e548f 100644 --- a/main.go +++ b/main.go @@ -72,12 +72,12 @@ func main() { continue } - log.Info(context.Background(), "msg", "logging initialized:", "log level:", conf.App.Log) + log.Info(context.Background(), "logging initialized", "log level", conf.App.Log) if conf.App.GcTuner { err = gctuner.Start(ctx, conf.App.MemTotal, conf.App.MemLimitRatio) if err != nil { - log.Critical(context.Background(), "err", err) + log.Critical(context.Background(), "err", "stacktrace", err) reload = true stop() time.Sleep(2 * time.Second) @@ -87,7 +87,7 @@ func main() { cach, err = cache.New(ctx, conf.Cache) if err != nil { - log.Critical(context.Background(), "err", err) + log.Critical(context.Background(), "err", "stacktrace", err) reload = true stop() time.Sleep(2 * time.Second) @@ -96,7 +96,7 @@ func main() { comp, err = compressor.New(ctx, conf.Compressor) if err != nil { - log.Critical(context.Background(), "err", err) + log.Critical(context.Background(), "err", "stacktrace", err) reload = true stop() time.Sleep(2 * time.Second) @@ -105,7 +105,7 @@ func main() { data, err = database.New(ctx, conf.Database) if err != nil { - log.Critical(context.Background(), "err", err) + log.Critical(context.Background(), "err", "stacktrace", err) reload = true stop() time.Sleep(2 * time.Second) @@ -114,7 +114,7 @@ func main() { stor, err = storage.New(ctx, conf.Storage) if err != nil { - log.Critical(context.Background(), "err", err) + log.Critical(context.Background(), "err", "stacktrace", err) reload = true stop() time.Sleep(2 * time.Second) @@ -136,7 +136,7 @@ func main() { serv := service.New(conf.Service, comp, stor, data, cach, qCalc, qComp, qDel) err = serv.CleanUp(ctx) if err != nil { - log.Critical(context.Background(), "err", err) + log.Critical(context.Background(), "err", "stacktrace", err) reload = true stop() time.Sleep(2 * time.Second) @@ -144,62 +144,62 @@ func main() { } gCalc, ctxCalc := errgroup.WithContext(ctx) - log.Info(context.Background(), "msg", "starting calculation worker pool") + log.Info(context.Background(), "starting calculation worker pool") serv.StartWorkingPoolCalc(ctxCalc, gCalc) gComp := (*errgroup.Group)(nil) ctxComp := context.Context(nil) if !conf.Compressor.IsMock() { gComp, ctxComp = errgroup.WithContext(ctx) - log.Info(context.Background(), "msg", "starting compression worker pool") + log.Info(context.Background(), "starting compression worker pool") serv.StartWorkingPoolComp(ctxComp, gComp) } gDel, ctxDel := errgroup.WithContext(ctx) - log.Info(context.Background(), "msg", "starting deletion worker pool") + log.Info(context.Background(), "starting deletion worker pool") serv.StartWorkingPoolDel(ctxDel, gDel) middle := http.NewMiddleware(conf.Middleware, cach) srvWait := make(chan error, 1) srv, err := http.NewServer(conf.Server, middle.Chain, serv, srvWait) if err != nil { - log.Critical(context.Background(), "err", err) + log.Critical(context.Background(), "err", "stacktrace", err) reload = true stop() time.Sleep(2 * time.Second) continue } srv.Monitor(ctx) - log.Info(context.Background(), "msg", "starting web server") + log.Info(context.Background(), "starting web server") err = srv.Start() - log.Info(context.Background(), "msg", "stopping web server") + log.Info(context.Background(), "stopping web server") if err != nil && !errors.Is(err, http.ErrServerClosed) { - log.Error(context.Background(), "err", err) + log.Error(context.Background(), "err", "stacktrace", err) } err = <-srvWait if err != nil { - log.Error(context.Background(), "err", err) + log.Error(context.Background(), "err", "stacktrace", err) } - log.Info(context.Background(), "msg", "stopping deletion worker pool") + log.Info(context.Background(), "stopping deletion worker pool") err = gDel.Wait() if err != nil { - log.Error(context.Background(), "err", err) + log.Error(context.Background(), "err", "stacktrace", err) } if !conf.Compressor.IsMock() { - log.Info(context.Background(), "msg", "stopping compression worker pool") + log.Info(context.Background(), "stopping compression worker pool") err = gComp.Wait() if err != nil { - log.Error(context.Background(), "err", err) + log.Error(context.Background(), "err", "stacktrace", err) } } - log.Info(context.Background(), "msg", "stopping calculation worker pool") + log.Info(context.Background(), "stopping calculation worker pool") err = gCalc.Wait() if err != nil { - log.Error(context.Background(), "err", err) + log.Error(context.Background(), "err", "stacktrace", err) } stop() @@ -208,7 +208,7 @@ func main() { if ok { err = b.Close(context.Background()) if err != nil { - log.Error(context.Background(), "err", err) + log.Error(context.Background(), "err", "stacktrace", err) } } } @@ -217,7 +217,7 @@ func main() { if ok { err = r.Close(context.Background()) if err != nil { - log.Error(context.Background(), "err", err) + log.Error(context.Background(), "err", "stacktrace", err) } } @@ -225,7 +225,7 @@ func main() { if ok { err = m.Close(context.Background()) if err != nil { - log.Error(context.Background(), "err", err) + log.Error(context.Background(), "err", "stacktrace", err) } } } From b691fe65483044879c3a0a5d79fec052142909f1 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sat, 8 Oct 2022 02:51:59 +0200 Subject: [PATCH 82/92] Update go version --- .github/workflows/integration.yml | 2 +- .github/workflows/loadtest.yml | 2 +- .github/workflows/unit.yml | 2 +- build/Dockerfile-app | 2 +- go.mod | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 466a3f4..8143926 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -10,7 +10,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: - go-version: 1.18 + go-version: 1.19 - uses: actions/cache@v2 with: path: ~/go/pkg/mod diff --git a/.github/workflows/loadtest.yml b/.github/workflows/loadtest.yml index fb1c4a6..1f0757b 100644 --- a/.github/workflows/loadtest.yml +++ b/.github/workflows/loadtest.yml @@ -10,7 +10,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: - go-version: 1.18 + go-version: 1.19 - uses: actions/cache@v2 with: path: ~/go/pkg/mod diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index 40985ef..f674c81 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -10,7 +10,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: - go-version: 1.18 + go-version: 1.19 - uses: actions/cache@v2 with: path: ~/go/pkg/mod diff --git a/build/Dockerfile-app b/build/Dockerfile-app index 34164d6..96c4fee 100644 --- a/build/Dockerfile-app +++ b/build/Dockerfile-app @@ -1,4 +1,4 @@ -FROM golang:1.18-alpine AS builder +FROM golang:1.19-alpine AS builder RUN apk add --no-cache make RUN addgroup -S appgroup && adduser -S appuser -G appgroup WORKDIR /app/ diff --git a/go.mod b/go.mod index 0cf4372..c0aef51 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/zitryss/aye-and-nay -go 1.18 +go 1.19 require ( github.com/caddyserver/certmagic v0.15.4 From a832609d3212c1f1fa6731a82f2bcc33d647435a Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Wed, 2 Nov 2022 10:51:09 +0100 Subject: [PATCH 83/92] Present Go GC tuner --- build/config-dev.env | 2 +- build/config-embed.env | 2 +- build/config-prod.env | 2 +- config.env | 2 +- internal/config/config.go | 2 +- main.go | 5 ++++- 6 files changed, 9 insertions(+), 6 deletions(-) diff --git a/build/config-dev.env b/build/config-dev.env index e78f8b4..c30218a 100644 --- a/build/config-dev.env +++ b/build/config-dev.env @@ -5,7 +5,7 @@ CONFIG_RELOAD_INTERVAL=1s # APP APP_NAME=config-dev APP_LOG=info -APP_GC_TUNER=true +APP_GC_TUNER=custom # [none, custom, go] APP_MEM_TOTAL=2147483648 # 2 GB APP_MEM_LIMIT_RATIO=0.7 diff --git a/build/config-embed.env b/build/config-embed.env index c31e823..f5d592f 100644 --- a/build/config-embed.env +++ b/build/config-embed.env @@ -5,7 +5,7 @@ CONFIG_RELOAD_INTERVAL=1s # APP APP_NAME=config-embed APP_LOG=info -APP_GC_TUNER=true +APP_GC_TUNER=custom # [none, custom, go] APP_MEM_TOTAL=2147483648 APP_MEM_LIMIT_RATIO=0.7 diff --git a/build/config-prod.env b/build/config-prod.env index c91ea13..63500d0 100644 --- a/build/config-prod.env +++ b/build/config-prod.env @@ -5,7 +5,7 @@ CONFIG_RELOAD_INTERVAL=1s # APP APP_NAME=config-prod APP_LOG=info -APP_GC_TUNER=true +APP_GC_TUNER=custom # [none, custom, go] APP_MEM_TOTAL=2147483648 APP_MEM_LIMIT_RATIO=0.7 diff --git a/config.env b/config.env index 6f3ae5d..eed8ec7 100644 --- a/config.env +++ b/config.env @@ -5,7 +5,7 @@ CONFIG_RELOAD_INTERVAL=1s # APP APP_NAME=config APP_LOG=info -APP_GC_TUNER=true +APP_GC_TUNER=custom # [none, custom, go] APP_MEM_TOTAL=2147483648 # 2 GB APP_MEM_LIMIT_RATIO=0.7 diff --git a/internal/config/config.go b/internal/config/config.go index 547c690..7f5bd27 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -53,7 +53,7 @@ type Config struct { type AppConfig struct { Name string `mapstructure:"APP_NAME" validate:"required"` Log string `mapstructure:"APP_LOG" validate:"required"` - GcTuner bool `mapstructure:"APP_GC_TUNER"` + GcTuner string `mapstructure:"APP_GC_TUNER" validate:"required"` MemTotal int `mapstructure:"APP_MEM_TOTAL"` MemLimitRatio float64 `mapstructure:"APP_MEM_LIMIT_RATIO"` } diff --git a/main.go b/main.go index f4e548f..527c942 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "os/signal" + "runtime/debug" "syscall" "time" @@ -74,7 +75,7 @@ func main() { log.Info(context.Background(), "logging initialized", "log level", conf.App.Log) - if conf.App.GcTuner { + if conf.App.GcTuner == "custom" { err = gctuner.Start(ctx, conf.App.MemTotal, conf.App.MemLimitRatio) if err != nil { log.Critical(context.Background(), "err", "stacktrace", err) @@ -83,6 +84,8 @@ func main() { time.Sleep(2 * time.Second) continue } + } else if conf.App.GcTuner == "go" { + debug.SetMemoryLimit(int64(float64(conf.App.MemTotal) * conf.App.MemLimitRatio)) } cach, err = cache.New(ctx, conf.Cache) From 8eee215b8d5d148eb222d20fd3def96847b91ff8 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Wed, 2 Nov 2022 10:51:37 +0100 Subject: [PATCH 84/92] Modify ulimit package --- internal/ulimit/ulimit.go | 22 +++------------------- internal/ulimit/ulimit_unix.go | 23 +++++++++++++++++++++++ internal/ulimit/ulimit_windows.go | 5 ----- 3 files changed, 26 insertions(+), 24 deletions(-) create mode 100644 internal/ulimit/ulimit_unix.go delete mode 100644 internal/ulimit/ulimit_windows.go diff --git a/internal/ulimit/ulimit.go b/internal/ulimit/ulimit.go index 93ca06e..4a37ee7 100644 --- a/internal/ulimit/ulimit.go +++ b/internal/ulimit/ulimit.go @@ -1,23 +1,7 @@ package ulimit -import ( - "syscall" -) - var ( - SetMax = setMax -) - -func setMax() error { - rLimit := syscall.Rlimit{} - err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit) - if err != nil { - return err - } - rLimit.Cur = rLimit.Max - err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit) - if err != nil { - return err + SetMax = func() error { + return nil } - return nil -} +) diff --git a/internal/ulimit/ulimit_unix.go b/internal/ulimit/ulimit_unix.go new file mode 100644 index 0000000..c911a44 --- /dev/null +++ b/internal/ulimit/ulimit_unix.go @@ -0,0 +1,23 @@ +package ulimit + +import ( + "syscall" +) + +func init() { + SetMax = setMax +} + +func setMax() error { + rLimit := syscall.Rlimit{} + err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit) + if err != nil { + return err + } + rLimit.Cur = rLimit.Max + err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit) + if err != nil { + return err + } + return nil +} diff --git a/internal/ulimit/ulimit_windows.go b/internal/ulimit/ulimit_windows.go deleted file mode 100644 index 1a17c4c..0000000 --- a/internal/ulimit/ulimit_windows.go +++ /dev/null @@ -1,5 +0,0 @@ -package ulimit - -func init() { - SetMax = func() error {} -} From b96b98f2fa2f36b685b73370db83113fa40fdb93 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Wed, 2 Nov 2022 10:52:04 +0100 Subject: [PATCH 85/92] Test logging --- internal/log/log.go | 5 ++++ internal/log/log_test.go | 57 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/internal/log/log.go b/internal/log/log.go index 6d07383..85a73e2 100644 --- a/internal/log/log.go +++ b/internal/log/log.go @@ -49,6 +49,11 @@ func New(lvl string, prefix string) error { return nil } +func newWithLogger(zapLog *zap.Logger, lvl zapcore.Level) { + l.SugaredLogger = zapLog.Sugar() + l.lvl = lvl +} + func Print(ctx context.Context, level int, msg string, v ...any) { switch level { case domain.LogDebug: diff --git a/internal/log/log_test.go b/internal/log/log_test.go index c64852c..9d02c95 100644 --- a/internal/log/log_test.go +++ b/internal/log/log_test.go @@ -1,11 +1,66 @@ package log import ( + "context" "flag" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" ) var ( - unit = flag.Bool("unit", false, "") + unit = flag.Bool("unit", true, "") integration = flag.Bool("int", false, "") ci = flag.Bool("ci", false, "") ) + +func testTimeEncoder(_ time.Time, enc zapcore.PrimitiveArrayEncoder) { + enc.AppendString("") +} + +func TestLogLevelPositive(t *testing.T) { + if !*unit { + t.Skip() + } + tests := []struct { + level zapcore.Level + want string + }{ + { + level: zapcore.DebugLevel, + want: "\tDEBUG\tmessage1\n\tINFO\tmessage3\n\tWARN\tmessage5\n\tERROR\tmessage7\n", + }, + { + level: zapcore.InfoLevel, + want: "\tINFO\tmessage3\n\tWARN\tmessage5\n\tERROR\tmessage7\n", + }, + { + level: zapcore.WarnLevel, + want: "\tWARN\tmessage5\n\tERROR\tmessage7\n", + }, + { + level: zapcore.ErrorLevel, + want: "\tERROR\tmessage7\n", + }, + } + for _, tt := range tests { + t.Run("", func(t *testing.T) { + encConf := zap.NewDevelopmentEncoderConfig() + encConf.EncodeTime = testTimeEncoder + enc := zapcore.NewConsoleEncoder(encConf) + w := strings.Builder{} + l := zap.New(zapcore.NewCore(enc, zapcore.AddSync(&w), tt.level)) + newWithLogger(l, tt.level) + Debug(context.Background(), "message1") + Info(context.Background(), "message3") + Error(context.Background(), "message5") + Critical(context.Background(), "message7") + got := w.String() + assert.Equal(t, tt.want, got) + }) + } +} From 4a0b8d5a88d7a0a2aab182eb1392487b1edcf9ab Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Wed, 2 Nov 2022 11:55:25 +0100 Subject: [PATCH 86/92] Update packages --- go.mod | 118 +++++----- go.sum | 689 ++++++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 539 insertions(+), 268 deletions(-) diff --git a/go.mod b/go.mod index c0aef51..e67a1d2 100644 --- a/go.mod +++ b/go.mod @@ -3,118 +3,116 @@ module github.com/zitryss/aye-and-nay go 1.19 require ( - github.com/caddyserver/certmagic v0.15.4 - github.com/dgraph-io/badger/v3 v3.2103.2 - github.com/emirpasic/gods v1.12.0 + github.com/caddyserver/certmagic v0.17.2 + github.com/dgraph-io/badger/v3 v3.2103.3 + github.com/emirpasic/gods v1.18.1 github.com/go-playground/validator v9.31.0+incompatible github.com/go-redis/redis/v8 v8.11.5 github.com/go-redis/redis_rate/v9 v9.1.2 github.com/hashicorp/golang-lru v0.5.4 github.com/julienschmidt/httprouter v1.3.0 github.com/mailru/easyjson v0.7.7 - github.com/minio/minio-go/v7 v7.0.23 - github.com/ory/dockertest/v3 v3.8.1 + github.com/minio/minio-go/v7 v7.0.43 + github.com/ory/dockertest/v3 v3.9.1 github.com/radovskyb/watcher v1.0.7 github.com/rs/cors v1.8.2 - github.com/segmentio/asm v1.1.3 + github.com/segmentio/asm v1.2.0 github.com/shirou/gopsutil v3.21.11+incompatible - github.com/spf13/afero v1.6.0 - github.com/spf13/viper v1.10.1 - github.com/stretchr/testify v1.7.1 - go.mongodb.org/mongo-driver v1.8.4 - go.uber.org/atomic v1.9.0 - go.uber.org/zap v1.19.1 - golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 - golang.org/x/net v0.0.0-20220225172249-27dd8689420f - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 - golang.org/x/tools v0.1.10 + github.com/spf13/afero v1.9.2 + github.com/spf13/viper v1.13.0 + github.com/stretchr/testify v1.8.1 + go.mongodb.org/mongo-driver v1.10.4 + go.uber.org/atomic v1.10.0 + go.uber.org/zap v1.23.0 + golang.org/x/exp v0.0.0-20221031165847-c99f073a8326 + golang.org/x/net v0.1.0 + golang.org/x/sync v0.1.0 + golang.org/x/time v0.1.0 + golang.org/x/tools v0.2.0 ) require ( - github.com/Azure/go-ansiterm v0.0.0-20210608035416-43c61cb656b4 // indirect - github.com/Microsoft/go-winio v0.5.1 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Microsoft/go-winio v0.6.0 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect - github.com/cenkalti/backoff/v4 v4.1.2 // indirect + github.com/cenkalti/backoff/v4 v4.1.3 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/containerd/continuity v0.1.0 // indirect + github.com/containerd/continuity v0.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dgraph-io/ristretto v0.1.0 // indirect + github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/docker/cli v20.10.11+incompatible // indirect - github.com/docker/docker v20.10.7+incompatible // indirect + github.com/docker/cli v20.10.21+incompatible // indirect + github.com/docker/docker v20.10.21+incompatible // indirect github.com/docker/go-connections v0.4.0 // indirect - github.com/docker/go-units v0.4.0 // indirect + github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.0 // indirect - github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-ole/go-ole v1.2.6 // indirect - github.com/go-playground/locales v0.12.1 // indirect - github.com/go-playground/universal-translator v0.16.0 // indirect - github.com/go-stack/stack v1.8.1 // indirect + github.com/go-playground/locales v0.14.0 // indirect + github.com/go-playground/universal-translator v0.18.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/glog v1.0.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/google/flatbuffers v2.0.0+incompatible // indirect + github.com/google/flatbuffers v22.10.26+incompatible // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.3.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/imdario/mergo v0.3.12 // indirect + github.com/imdario/mergo v0.3.13 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.13.6 // indirect - github.com/klauspost/cpuid/v2 v2.0.9 // indirect - github.com/kr/text v0.2.0 // indirect - github.com/leodido/go-urn v1.1.0 // indirect + github.com/klauspost/compress v1.15.12 // indirect + github.com/klauspost/cpuid/v2 v2.1.2 // indirect + github.com/leodido/go-urn v1.2.1 // indirect github.com/lib/pq v1.8.0 // indirect github.com/libdns/libdns v0.2.1 // indirect - github.com/magiconair/properties v1.8.5 // indirect - github.com/mholt/acmez v1.0.1 // indirect - github.com/miekg/dns v1.1.43 // indirect + github.com/magiconair/properties v1.8.6 // indirect + github.com/mholt/acmez v1.0.4 // indirect + github.com/miekg/dns v1.1.50 // indirect github.com/minio/md5-simd v1.1.2 // indirect github.com/minio/sha256-simd v1.0.0 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/mapstructure v1.4.3 // indirect - github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/montanaflynn/stats v0.6.6 // indirect github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect - github.com/opencontainers/runc v1.0.2 // indirect - github.com/pelletier/go-toml v1.9.4 // indirect + github.com/opencontainers/runc v1.1.4 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect + github.com/pelletier/go-toml/v2 v2.0.5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rs/xid v1.3.0 // indirect - github.com/sirupsen/logrus v1.8.1 // indirect - github.com/spf13/cast v1.4.1 // indirect + github.com/rs/xid v1.4.0 // indirect + github.com/sirupsen/logrus v1.9.0 // indirect + github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/subosito/gotenv v1.2.0 // indirect + github.com/subosito/gotenv v1.4.1 // indirect github.com/tidwall/pretty v1.0.2 // indirect github.com/tklauser/go-sysconf v0.3.10 // indirect - github.com/tklauser/numcpus v0.4.0 // indirect + github.com/tklauser/numcpus v0.5.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect - github.com/xdg-go/scram v1.0.2 // indirect - github.com/xdg-go/stringprep v1.0.2 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect + github.com/xdg-go/scram v1.1.1 // indirect + github.com/xdg-go/stringprep v1.0.3 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect go.opencensus.io v0.23.0 // indirect - go.uber.org/multierr v1.7.0 // indirect - golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 // indirect - golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect - golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 // indirect - golang.org/x/text v0.3.7 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect - google.golang.org/protobuf v1.27.1 // indirect + go.uber.org/multierr v1.8.0 // indirect + golang.org/x/crypto v0.1.0 // indirect + golang.org/x/mod v0.6.0 // indirect + golang.org/x/sys v0.1.0 // indirect + golang.org/x/text v0.4.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect gopkg.in/go-playground/assert.v1 v1.2.1 // indirect - gopkg.in/ini.v1 v1.66.2 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 67bc871..e4d253a 100644 --- a/go.sum +++ b/go.sum @@ -1,124 +1,170 @@ -bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-ansiterm v0.0.0-20210608035416-43c61cb656b4 h1:poX3j1kSFMgZhtUGrKSAwjh/FKVYrzvoXzwyXPHkAv0= -github.com/Azure/go-ansiterm v0.0.0-20210608035416-43c61cb656b4/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= -github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= +github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= -github.com/caddyserver/certmagic v0.15.4 h1:kz//9+Z/xw197jtIBxxUDub8pQi9gcYvhXk5Ouw2EkM= -github.com/caddyserver/certmagic v0.15.4/go.mod h1:qhkAOthf72ufAcp3Y5jF2RaGE96oip3UbEQRIzwe3/8= -github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= -github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/caddyserver/certmagic v0.17.2 h1:o30seC1T/dBqBCNNGNHWwj2i5/I/FMjBbTAhjADP3nE= +github.com/caddyserver/certmagic v0.17.2/go.mod h1:ouWUuC490GOLJzkyN35eXfV8bSbwMwSf4bdhkIxtdQE= +github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= +github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= -github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= -github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= -github.com/containerd/continuity v0.1.0 h1:UFRRY5JemiAhPZrr/uE0n8fMTLcZsUvySPr1+D7pgr8= -github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= +github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= 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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgraph-io/badger/v3 v3.2103.2 h1:dpyM5eCJAtQCBcMCZcT4UBZchuTJgCywerHHgmxfxM8= github.com/dgraph-io/badger/v3 v3.2103.2/go.mod h1:RHo4/GmYcKKh5Lxu63wLEMHJ70Pac2JqZRYGhlyAo2M= +github.com/dgraph-io/badger/v3 v3.2103.3 h1:s63J1pisDhKpzWslXFe+ChuthuZptpwTE6qEKoczPb4= +github.com/dgraph-io/badger/v3 v3.2103.3/go.mod h1:4MPiseMeDQ3FNCYwRbbcBOGJLf5jsE0PPFzRiKjtcdw= github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI= github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= +github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/docker/cli v20.10.11+incompatible h1:tXU1ezXcruZQRrMP8RN2z9N91h+6egZTS1gsPsKantc= -github.com/docker/cli v20.10.11+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/docker v20.10.7+incompatible h1:Z6O9Nhsjv+ayUEeI1IojKbYcsGdgYSNqxe1s2MYzUhQ= -github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/cli v20.10.18+incompatible h1:f/GQLsVpo10VvToRay2IraVA1wHz9KktZyjev3SIVDU= +github.com/docker/cli v20.10.18+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v20.10.21+incompatible h1:qVkgyYUnOLQ98LtXBrwd/duVqPT2X4SHndOuGsfwyhU= +github.com/docker/cli v20.10.21+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/docker v20.10.18+incompatible h1:SN84VYXTBNGn92T/QwIRPlum9zfemfitN7pbsp26WSc= +github.com/docker/docker v20.10.18+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.21+incompatible h1:UTLdBmHk3bEY+w8qeO5KttOhy6OmXWsl/FEet9Uswog= +github.com/docker/docker v20.10.21+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= -github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= -github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc= -github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= -github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= -github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= +github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/validator v9.31.0+incompatible h1:UA72EPEogEnq76ehGdEDp4Mit+3FDh548oRqwVgNsHA= github.com/go-playground/validator v9.31.0+incompatible/go.mod h1:yrEkQXlcI+PugkyDjY2bRrL/UBU4f3rvrgkN3V8JEig= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-redis/redis_rate/v9 v9.1.2 h1:H0l5VzoAtOE6ydd38j8MCq3ABlGLnvvbA1xDSVVCHgQ= github.com/go-redis/redis_rate/v9 v9.1.2/go.mod h1:oam2de2apSgRG8aJzwJddXbNu91Iyz1m8IKJE2vpvlQ= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= -github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -126,6 +172,7 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= @@ -134,174 +181,181 @@ github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/flatbuffers v2.0.0+incompatible h1:dicJ2oXwypfwUGnB2/TYWYEKiuk9eYQlQO/AnOHl5mI= -github.com/google/flatbuffers v2.0.0+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/flatbuffers v22.9.29+incompatible h1:3UBb679lq3V/O9rgzoJmnkP1jJzmC9OdFzITUBkLU/A= +github.com/google/flatbuffers v22.9.29+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/flatbuffers v22.10.26+incompatible h1:z1QiaMyPu1x3Z6xf2u1dsLj1ZxicdGSeaLpCuIsQNZM= +github.com/google/flatbuffers v22.10.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c= +github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM= +github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/klauspost/cpuid/v2 v2.1.2 h1:XhdX4fqAJUA0yj+kUwMavO0hHrSPAecYdYf1ZmxHvak= +github.com/klauspost/cpuid/v2 v2.1.2/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 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.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= -github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= -github.com/lib/pq v0.0.0-20180327071824-d34b9ff171c2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +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/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg= github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis= github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= -github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mholt/acmez v1.0.1 h1:J7uquHOKEmo71UDnVApy1sSLA0oF/r+NtVrNzMKKA9I= -github.com/mholt/acmez v1.0.1/go.mod h1:8qnn8QA/Ewx8E3ZSsmscqsIjhhpxuy9vqdgbX2ceceM= -github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg= -github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/mholt/acmez v1.0.4 h1:N3cE4Pek+dSolbsofIkAYz6H1d3pE+2G0os7QHslf80= +github.com/mholt/acmez v1.0.4/go.mod h1:qFGLZ4u+ehWINeJZjzPlsnjJBCPAADWTcIqE/7DAYQY= +github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= +github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= -github.com/minio/minio-go/v7 v7.0.23 h1:NleyGQvAn9VQMU+YHVrgV4CX+EPtxPt/78lHOOTncy4= -github.com/minio/minio-go/v7 v7.0.23/go.mod h1:ei5JjmxwHaMrgsMrn4U/+Nmg+d8MKS1U2DAn1ou4+Do= +github.com/minio/minio-go/v7 v7.0.40 h1:dgyyRKelGW1B/7spyDyvHv9LI3RK5AJDJUrIRllyLk4= +github.com/minio/minio-go/v7 v7.0.40/go.mod h1:nCrRzjoSUQh8hgKKtu3Y708OLvRLtuASMg2/nvmbarw= +github.com/minio/minio-go/v7 v7.0.43 h1:14Q4lwblqTdlAmba05oq5xL0VBLHi06zS4yLnIkz6hI= +github.com/minio/minio-go/v7 v7.0.43/go.mod h1:nCrRzjoSUQh8hgKKtu3Y708OLvRLtuASMg2/nvmbarw= github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= -github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= -github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk= -github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= +github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI= +github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/montanaflynn/stats v0.6.6 h1:Duep6KMIDpY4Yo11iFsvyqJDyfzLF9+sndUKT+v64GQ= +github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= -github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v1.0.2 h1:opHZMaswlyxz1OuGpBE53Dwe4/xF7EZTY0A2L/FpCOg= -github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= +github.com/opencontainers/runc v1.1.4 h1:nRCz/8sKg6K6jgYAFLDlXzPeITBZJyX28DBVhWD+5dg= +github.com/opencontainers/runc v1.1.4/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= -github.com/ory/dockertest/v3 v3.8.1 h1:vU/8d1We4qIad2YM0kOwRVtnyue7ExvacPiw1yDm17g= -github.com/ory/dockertest/v3 v3.8.1/go.mod h1:wSRQ3wmkz+uSARYMk7kVJFDBGm8x5gSxIhI7NDc+BAQ= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/ory/dockertest/v3 v3.9.1 h1:v4dkG+dlu76goxMiTT2j8zV7s4oPPEppKT8K8p2f1kY= +github.com/ory/dockertest/v3 v3.9.1/go.mod h1:42Ir9hmvaAPm0Mgibk6mBPi7SFvTXxEcnztDYOJ//uM= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= -github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= +github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= 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/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/radovskyb/watcher v1.0.7 h1:AYePLih6dpmS32vlHfhCeli8127LzkIgwJGcwwe8tUE= github.com/radovskyb/watcher v1.0.7/go.mod h1:78okwvY5wPdzcb1UYnip1pvrZNIVEIh/Cm+ZuvsUYIg= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4= -github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= -github.com/segmentio/asm v1.1.3 h1:WM03sfUOENvvKexOLp+pCqgb/WDjsi7EK8gIsICtzhc= -github.com/segmentio/asm v1.1.3/go.mod h1:Ld3L4ZXGNcSLRg4JBsZ3//1+f/TjYl0Mzen/DQy1EJg= +github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= +github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= -github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -309,207 +363,421 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk= -github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= +github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU= +github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= +github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU= github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw= github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= -github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o= github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/tklauser/numcpus v0.5.0 h1:ooe7gN0fg6myJ0EKoTAf5hebTZrH52px3New/D9iJ+A= +github.com/tklauser/numcpus v0.5.0/go.mod h1:OGzpTxpcIMNGYQdit2BYL1pvk/dSOaJWjKoflh+RQjo= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w= -github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= -github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc= -github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk= github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.mongodb.org/mongo-driver v1.8.4 h1:NruvZPPL0PBcRJKmbswoWSrmHeUvzdxA3GCPfD/NEOA= -go.mongodb.org/mongo-driver v1.8.4/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= +go.mongodb.org/mongo-driver v1.10.3 h1:XDQEvmh6z1EUsXuIkXE9TaVeqHw6SwS1uf93jFs0HBA= +go.mongodb.org/mongo-driver v1.10.3/go.mod h1:z4XpeoU6w+9Vht+jAFyLgVrD+jGSQQe0+CBWFHNiHt8= +go.mongodb.org/mongo-driver v1.10.4 h1:taPWsSsfn723M05lMyd/TAQe0kU9PsEYQ15WslnBtQw= +go.mongodb.org/mongo-driver v1.10.4/go.mod h1:z4XpeoU6w+9Vht+jAFyLgVrD+jGSQQe0+CBWFHNiHt8= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= -go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= -go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= +go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 h1:/pEO3GD/ABYAjuakUS6xSEmmlyVS4kxBNkeA9tLJiTI= -golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2 h1:x8vtB3zMecnlqZIwJNUUpwYKYSqCz5jXbiyv0ZJJZeI= +golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM= -golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20221011111909-0220f59fc3e4 h1:vJ72ext0XgGVpu8rmB7rsWFCFaSMeygqU5ewGUzYdNs= +golang.org/x/exp v0.0.0-20221011111909-0220f59fc3e4/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/exp v0.0.0-20221031165847-c99f073a8326 h1:QfTh0HpN6hlw6D3vu8DAwC8pBIwikq0AI1evdm+FksE= +golang.org/x/exp v0.0.0-20221031165847-c99f073a8326/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20221004154528-8021a29435af h1:wv66FM3rLZGPdxpYL+ApnDe2HzHcTFta3z5nsc13wI4= +golang.org/x/net v0.0.0-20221004154528-8021a29435af/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0 h1:cu5kTvlzcw1Q5S9f5ip1/cpiB4nXvw1XYzFPGgzLUOY= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 h1:XDXtA5hveEEV8JB2l7nhMTp3t3cHp9ZpwcdjqyEWLlo= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20221010170243-090e33056c14 h1:k5II8e6QD8mITdi+okbbmR/cIyEbeXLBhy5Ha4nevyc= +golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs= -golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= +golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= -golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -518,12 +786,13 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -532,23 +801,27 @@ gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= -gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= -gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= -gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +gotest.tools/v3 v3.2.0 h1:I0DwBVMGAx26dttAj1BtJLAkVGncrkkUXfJLC4Flt/I= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= From 143e1f6f3a06198949da1e723ca8014ae944da92 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Wed, 2 Nov 2022 13:54:15 +0100 Subject: [PATCH 87/92] Improve test parallelism --- delivery/http/middleware_test.go | 3 +++ pkg/errors/errors_test.go | 1 + pkg/retry/retry_test.go | 3 +++ 3 files changed, 7 insertions(+) diff --git a/delivery/http/middleware_test.go b/delivery/http/middleware_test.go index ff91ae8..b7f07ae 100644 --- a/delivery/http/middleware_test.go +++ b/delivery/http/middleware_test.go @@ -29,6 +29,7 @@ func TestMiddlewareRecover(t *testing.T) { if !*unit { t.Skip() } + t.Parallel() t.Run("Positive", func(t *testing.T) { t.Parallel() fn := func(w http.ResponseWriter, r *http.Request) { @@ -67,6 +68,7 @@ func TestMiddlewareLimit(t *testing.T) { if !*unit { t.Skip() } + t.Parallel() t.Run("Positive", func(t *testing.T) { t.Parallel() fn := func(w http.ResponseWriter, r *http.Request) { @@ -151,6 +153,7 @@ func TestIP(t *testing.T) { want: "", }, } + t.Parallel() for _, tt := range tests { tt := tt r := httptest.NewRequest(http.MethodGet, "/api/health/", http.NoBody) diff --git a/pkg/errors/errors_test.go b/pkg/errors/errors_test.go index f4ca847..112c0a5 100644 --- a/pkg/errors/errors_test.go +++ b/pkg/errors/errors_test.go @@ -65,6 +65,7 @@ func TestCause(t *testing.T) { want: errors.New("1"), }, } + t.Parallel() for _, tt := range tests { tt := tt t.Run("", func(t *testing.T) { diff --git a/pkg/retry/retry_test.go b/pkg/retry/retry_test.go index f877805..b39c445 100644 --- a/pkg/retry/retry_test.go +++ b/pkg/retry/retry_test.go @@ -62,6 +62,7 @@ func TestDo1(t *testing.T) { }, }, } + t.Parallel() for _, tt := range tests { tt := tt t.Run("", func(t *testing.T) { @@ -123,6 +124,7 @@ func TestDo2(t *testing.T) { }, }, } + t.Parallel() for _, tt := range tests { tt := tt t.Run("", func(t *testing.T) { @@ -184,6 +186,7 @@ func TestDo3(t *testing.T) { }, }, } + t.Parallel() for _, tt := range tests { tt := tt t.Run("", func(t *testing.T) { From 5b9208a2c5fcecae64e65e4ac882ac2143959ec6 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Thu, 8 Dec 2022 00:40:33 +0100 Subject: [PATCH 88/92] Update GitHub actions --- .github/workflows/integration.yml | 4 ++-- .github/workflows/loadtest.yml | 2 +- .github/workflows/unit.yml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 8143926..7187623 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -11,7 +11,7 @@ jobs: - uses: actions/setup-go@v3 with: go-version: 1.19 - - uses: actions/cache@v2 + - uses: actions/cache@v3 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} @@ -21,7 +21,7 @@ jobs: CONTINUOUS_INTEGRATION: "true" run: make test-int-ci - run: make dev-down - - uses: codecov/codecov-action@v2 + - uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./coverage.txt diff --git a/.github/workflows/loadtest.yml b/.github/workflows/loadtest.yml index 1f0757b..5ab65af 100644 --- a/.github/workflows/loadtest.yml +++ b/.github/workflows/loadtest.yml @@ -11,7 +11,7 @@ jobs: - uses: actions/setup-go@v3 with: go-version: 1.19 - - uses: actions/cache@v2 + - uses: actions/cache@v3 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index f674c81..d36767b 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -11,13 +11,13 @@ jobs: - uses: actions/setup-go@v3 with: go-version: 1.19 - - uses: actions/cache@v2 + - uses: actions/cache@v3 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-go- - run: make test-unit-ci - - uses: codecov/codecov-action@v2 + - uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./coverage.txt From a205dd6c730fcaa708c5b13b60e47c9af4360853 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Thu, 8 Dec 2022 00:44:30 +0100 Subject: [PATCH 89/92] Update GitHub cache action --- .github/workflows/integration.yml | 4 +++- .github/workflows/loadtest.yml | 4 +++- .github/workflows/unit.yml | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 7187623..2f889ca 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -13,7 +13,9 @@ jobs: go-version: 1.19 - uses: actions/cache@v3 with: - path: ~/go/pkg/mod + path: : | + ~/.cache/go-build + ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-go- - run: make dev-up diff --git a/.github/workflows/loadtest.yml b/.github/workflows/loadtest.yml index 5ab65af..644d7fc 100644 --- a/.github/workflows/loadtest.yml +++ b/.github/workflows/loadtest.yml @@ -13,7 +13,9 @@ jobs: go-version: 1.19 - uses: actions/cache@v3 with: - path: ~/go/pkg/mod + path: : | + ~/.cache/go-build + ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-go- - run: make prod-up diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index d36767b..5e8c52e 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -13,7 +13,9 @@ jobs: go-version: 1.19 - uses: actions/cache@v3 with: - path: ~/go/pkg/mod + path: : | + ~/.cache/go-build + ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-go- - run: make test-unit-ci From 010e38be21e9ca350e119c189fdc09177c6c7de0 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Thu, 8 Dec 2022 00:46:41 +0100 Subject: [PATCH 90/92] Fix GitHub cache action --- .github/workflows/integration.yml | 2 +- .github/workflows/loadtest.yml | 2 +- .github/workflows/unit.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 2f889ca..3cdf7c4 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -13,7 +13,7 @@ jobs: go-version: 1.19 - uses: actions/cache@v3 with: - path: : | + path: | ~/.cache/go-build ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} diff --git a/.github/workflows/loadtest.yml b/.github/workflows/loadtest.yml index 644d7fc..baf6c90 100644 --- a/.github/workflows/loadtest.yml +++ b/.github/workflows/loadtest.yml @@ -13,7 +13,7 @@ jobs: go-version: 1.19 - uses: actions/cache@v3 with: - path: : | + path: | ~/.cache/go-build ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index 5e8c52e..d442dca 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -13,7 +13,7 @@ jobs: go-version: 1.19 - uses: actions/cache@v3 with: - path: : | + path: | ~/.cache/go-build ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} From 4c059b4d0ee1b27ff2f4ea2df59cea1dcc1bc5d4 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Thu, 8 Dec 2022 12:02:45 +0100 Subject: [PATCH 91/92] Fix GitHub cache action --- .github/workflows/integration.yml | 4 +++- .github/workflows/loadtest.yml | 4 +++- .github/workflows/unit.yml | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 3cdf7c4..f614660 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -13,9 +13,11 @@ jobs: go-version: 1.19 - uses: actions/cache@v3 with: + # Module download cache + # Build cache (Linux) path: | - ~/.cache/go-build ~/go/pkg/mod + ~/.cache/go-build key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-go- - run: make dev-up diff --git a/.github/workflows/loadtest.yml b/.github/workflows/loadtest.yml index baf6c90..5971524 100644 --- a/.github/workflows/loadtest.yml +++ b/.github/workflows/loadtest.yml @@ -13,9 +13,11 @@ jobs: go-version: 1.19 - uses: actions/cache@v3 with: + # Module download cache + # Build cache (Linux) path: | - ~/.cache/go-build ~/go/pkg/mod + ~/.cache/go-build key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-go- - run: make prod-up diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index d442dca..fe8a813 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -13,9 +13,11 @@ jobs: go-version: 1.19 - uses: actions/cache@v3 with: + # Module download cache + # Build cache (Linux) path: | - ~/.cache/go-build ~/go/pkg/mod + ~/.cache/go-build key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-go- - run: make test-unit-ci From 32d7d0aef0b6e7cf029d8382254a6a44f2e68194 Mon Sep 17 00:00:00 2001 From: Eugene Russkikh Date: Sat, 14 Oct 2023 01:22:25 +0200 Subject: [PATCH 92/92] Extend vscode python features with continue --- .vscode/settings.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..882fc3d --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "python.analysis.extraPaths": [ + "/Users/mercury/.vscode/extensions/continue.continue-0.0.412-darwin-arm64" + ], + "python.autoComplete.extraPaths": [ + "/Users/mercury/.vscode/extensions/continue.continue-0.0.412-darwin-arm64" + ] +} \ No newline at end of file