feat: mock servvice

This commit is contained in:
Kirill 2023-06-19 22:04:55 +03:00
parent 2be49349f9
commit 63faacdd27
23 changed files with 373 additions and 508 deletions

@ -25,6 +25,9 @@ MONGO_DB_NAME - название базы данных для подключе
MONGO_PASSWORD - пароль пользователя MongoDB
MONGO_AUTH - имя базы данных Mongo, по которой будет производится авторизация
IS_MOCK - отвечает за инициализацию настроек моков в моковом сервисе (true | false)
MOCK_SERVICE_HOST - хост сервиса моков
YOOMONEY_STORE_ID - id магазина, зарегистрированного на yoomoney
YOOMONEY_SECRET_KEY - секретный ключ yoomoney
YOOMONEY_WEBHOOKS_URL - адрес к обработчику вебхуков yoomoney

@ -1,3 +0,0 @@
package main
func MockWebhooks() {}

@ -11,13 +11,18 @@ services:
environment:
- HTTP_HOST=0.0.0.0
- HTTP_PORT=8085
- HTTP_DOMEN=http://localhost:8080
- HTTP_DOMEN=http://localhost:8085
- GRPC_HOST=0.0.0.0
- GRPC_PORT=9085
- IS_MOCK=true
- MOCK_SERVICE_HOST=http://localhost:8080
- YOOMONEY_STORE_ID=id
- YOOMONEY_SECRET_KEY=secret
- YOOMONEY_WEBHOOKS_URL=http://localhost:8080/webhooks
- YOOMONEY_PAYMENTS_URL=http://localhost:8080/payments
- MONGO_HOST=mongo
- MONGO_PORT=27017

@ -10,6 +10,7 @@ import (
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/interface/swagger"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/models"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/server"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/worker"
"penahub.gitlab.yandexcloud.net/external/treasurer/pkg/closer"
"penahub.gitlab.yandexcloud.net/external/treasurer/pkg/mongo"
)
@ -60,6 +61,15 @@ func Run(ctx context.Context, config *models.Config, logger *zap.Logger) error {
return err.Wrap("failed to initialize services")
}
workers, err := initialize.NewWorkers(initialize.WorkersDeps{
Logger: logger,
Services: *services,
})
if err != nil {
return err.Wrap("failed to initialize workers")
}
controllers, err := initialize.NewControllers(initialize.ControllersDeps{
Logger: logger,
Services: *services,
@ -94,6 +104,7 @@ func Run(ctx context.Context, config *models.Config, logger *zap.Logger) error {
go httpServer.Run(&config.HTTP)
go grpcServer.Run(&config.GRPC)
go worker.Run(ctx, workers)
closer.Add(mongoDB.Client().Disconnect)
closer.Add(httpServer.Stop)

@ -5,6 +5,7 @@ import (
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/errors"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/models"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/service/callback"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/service/mock"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/service/payment"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/service/status"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/service/webhook"
@ -15,6 +16,7 @@ type ServicesDeps struct {
Repositories Repositories
Clients Clients
ConfigurationHTTP *models.ConfigurationHTTP
Configuration *models.ServiceConfiguration
}
type Services struct {
@ -23,6 +25,7 @@ type Services struct {
YandexPayment *payment.Yandex
Status *status.Service
YandexWebhook *webhook.Yandex
Mock *mock.Service
}
func NewServices(deps ServicesDeps) (*Services, errors.Error) {
@ -69,11 +72,29 @@ func NewServices(deps ServicesDeps) (*Services, errors.Error) {
return nil, err
}
yoomoneyMockService, err := mock.NewYoomoneyMockService(mock.YoomoneyMockServiceDeps{
Logger: deps.Logger,
YoomoneyURL: &deps.Configuration.MockConfiguration.YoomomeyURL,
})
if err != nil {
return nil, err
}
mockService, err := mock.New(mock.Deps{
Logger: deps.Logger,
MockServiceHost: deps.Configuration.MockConfiguration.Host,
YoomoneyMockService: yoomoneyMockService,
})
if err != nil {
return nil, err
}
return &Services{
Callback: callbackService,
Payment: paymentService,
YandexPayment: yandexPaymentService,
Status: statusService,
YandexWebhook: yandexWebhookService,
Mock: mockService,
}, nil
}

@ -0,0 +1,30 @@
package initialize
import (
"go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/errors"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/worker/mock"
)
type WorkersDeps struct {
Logger *zap.Logger
Services Services
}
type Workers struct {
Mock *mock.Worker
}
func NewWorkers(deps WorkersDeps) (*Workers, errors.Error) {
mockWorker, err := mock.New(mock.WorkerDeps{
Logger: deps.Logger,
MockService: deps.Services.Mock,
})
if err != nil {
return nil, err
}
return &Workers{
Mock: mockWorker,
}, nil
}

@ -24,6 +24,13 @@ type ConfigurationGRPC struct {
type ServiceConfiguration struct {
YoomomeyConfiguration YoomomeyConfiguration
MockConfiguration MockConfiguration
}
type MockConfiguration struct {
IsMock bool `env:"IS_MOCK,default=false"`
Host string `env:"MOCK_SERVICE_HOST,default=http://localhost:8080"`
YoomomeyURL YoomomeyURL
}
type YoomomeyConfiguration struct {

@ -0,0 +1,52 @@
package mock
import (
"go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/errors"
"penahub.gitlab.yandexcloud.net/external/treasurer/pkg/validate"
)
type MockStrategyService interface {
Register(host string) errors.Error
}
type Deps struct {
Logger *zap.Logger
MockServiceHost string
YoomoneyMockService MockStrategyService
}
type Service struct {
logger *zap.Logger
mockServiceHost string
yoomoneyMockService MockStrategyService
}
func New(deps Deps) (*Service, errors.Error) {
if deps.Logger == nil {
return nil, errors.NewWithMessage("logger is nil on <NewMockService>", errors.ErrInvalidArgs)
}
if deps.YoomoneyMockService == nil {
return nil, errors.NewWithMessage("YoomoneyMockService is nil on <NewMockService>", errors.ErrInvalidArgs)
}
if validate.IsStringEmpty(deps.MockServiceHost) {
return nil, errors.NewWithMessage("mock service host is empty on <NewMockService>", errors.ErrInvalidArgs)
}
return &Service{
logger: deps.Logger,
mockServiceHost: deps.MockServiceHost,
yoomoneyMockService: deps.YoomoneyMockService,
}, nil
}
func (receiver *Service) Register() bool {
if err := receiver.yoomoneyMockService.Register(receiver.mockServiceHost); err != nil {
receiver.logger.Error("failed to register yoomoney mocks", zap.Error(err), zap.String("host", receiver.mockServiceHost))
return false
}
return true
}

@ -0,0 +1,96 @@
package mock
import (
"fmt"
"net/url"
"github.com/walkerus/go-wiremock"
"go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/errors"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/models"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/models/yandex"
)
type YoomoneyMockServiceDeps struct {
Logger *zap.Logger
YoomoneyURL *models.YoomomeyURL
}
type YoomoneyMockService struct {
logger *zap.Logger
yoomoneyURL *models.YoomomeyURL
}
func NewYoomoneyMockService(deps YoomoneyMockServiceDeps) (*YoomoneyMockService, errors.Error) {
if deps.Logger == nil {
return nil, errors.NewWithMessage("logger is nil on <NewYoomoneyMockService>", errors.ErrInvalidArgs)
}
if deps.YoomoneyURL == nil {
return nil, errors.NewWithMessage("yoomoney urls is nil on <NewYoomoneyMockService>", errors.ErrInvalidArgs)
}
return &YoomoneyMockService{
logger: deps.Logger,
yoomoneyURL: deps.YoomoneyURL,
}, nil
}
func (receiver *YoomoneyMockService) Register(host string) errors.Error {
return receiver.RegisterPayments(host)
}
func (receiver *YoomoneyMockService) RegisterPayments(host string) errors.Error {
url, parseErr := url.Parse(receiver.yoomoneyURL.Payments)
if parseErr != nil {
receiver.logger.Error("failed to parse payment url on <RegisterPayment> of <YoomoneyMockService>",
zap.Error(parseErr),
zap.String("url", receiver.yoomoneyURL.Payments),
)
return errors.NewWithError(fmt.Errorf("failed to parse payment url: %w", parseErr), errors.ErrInternalError)
}
if url.Host != host {
return errors.NewWithMessage("yoomoney hosts not equal", errors.ErrInternalError)
}
mockClient := wiremock.NewClient(host)
rule := wiremock.
Post(wiremock.URLPathEqualTo(url.Path)).
WillReturnJSON(
&yandex.Payment{
ID: "f32d71f4-214b-464b-94bb-f7b4d5299af0",
Status: yandex.PaymentStatusPending,
Amount: yandex.Amount{
Value: "150.00",
Currency: "RUB",
},
Confirmation: &yandex.ConfirmationRedirect{
Type: yandex.ConfirmationTypeRedirect,
ConfirmationURL: "https://yandex-redirect-url.com",
},
},
map[string]string{"Content-Type": "application/json"},
200,
).
AtPriority(1)
if err := mockClient.StubFor(rule); err != nil {
receiver.logger.Error("failed to init payment mock handler on <RegisterPayment> of <YoomoneyMockService>", zap.Error(err))
return errors.NewWithError(fmt.Errorf("failed to init payment mock handler: %w", err), errors.ErrInternalError)
}
isVerified, err := mockClient.Verify(wiremock.NewRequest("post", wiremock.URLPathEqualTo(url.Path)), 0)
if err != nil {
receiver.logger.Error("failed to verify payment mock handler on <RegisterPayment> of <YoomoneyMockService>", zap.Error(err))
return errors.NewWithError(fmt.Errorf("failed to verify payment mock handler: %w", err), errors.ErrInternalError)
}
if !isVerified {
return errors.NewWithMessage("payment mock handler not verified", errors.ErrInternalError)
}
return nil
}

@ -1,224 +0,0 @@
// Package swagger provides primitives to interact with the openapi HTTP API.
//
// Code generated by github.com/deepmap/oapi-codegen version v1.12.4 DO NOT EDIT.
package swagger
import (
"bytes"
"compress/gzip"
"encoding/base64"
"fmt"
"net/url"
"path"
"strings"
"github.com/getkin/kin-openapi/openapi3"
"github.com/labstack/echo/v4"
)
// ServerInterface represents all server handlers.
type ServerInterface interface {
// (GET /available)
GetAvailablePayments(ctx echo.Context) error
// (POST /yandex/payment/status/canceled)
SetYandexPaymentStatusCanceled(ctx echo.Context) error
// (POST /yandex/payment/status/succeeded)
SetYandexPaymentStatusSucceeded(ctx echo.Context) error
// (POST /yandex/payment/status/waiting)
SetYandexPaymentStatusWaiting(ctx echo.Context) error
// (POST /yandex/refund/status/succeeded)
SetYandexRefundStatusSucceeded(ctx echo.Context) error
}
// ServerInterfaceWrapper converts echo contexts to parameters.
type ServerInterfaceWrapper struct {
Handler ServerInterface
}
// GetAvailablePayments converts echo context to params.
func (w *ServerInterfaceWrapper) GetAvailablePayments(ctx echo.Context) error {
var err error
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.GetAvailablePayments(ctx)
return err
}
// SetYandexPaymentStatusCanceled converts echo context to params.
func (w *ServerInterfaceWrapper) SetYandexPaymentStatusCanceled(ctx echo.Context) error {
var err error
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.SetYandexPaymentStatusCanceled(ctx)
return err
}
// SetYandexPaymentStatusSucceeded converts echo context to params.
func (w *ServerInterfaceWrapper) SetYandexPaymentStatusSucceeded(ctx echo.Context) error {
var err error
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.SetYandexPaymentStatusSucceeded(ctx)
return err
}
// SetYandexPaymentStatusWaiting converts echo context to params.
func (w *ServerInterfaceWrapper) SetYandexPaymentStatusWaiting(ctx echo.Context) error {
var err error
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.SetYandexPaymentStatusWaiting(ctx)
return err
}
// SetYandexRefundStatusSucceeded converts echo context to params.
func (w *ServerInterfaceWrapper) SetYandexRefundStatusSucceeded(ctx echo.Context) error {
var err error
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.SetYandexRefundStatusSucceeded(ctx)
return err
}
// This is a simple interface which specifies echo.Route addition functions which
// are present on both echo.Echo and echo.Group, since we want to allow using
// either of them for path registration
type EchoRouter interface {
CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
}
// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
RegisterHandlersWithBaseURL(router, si, "")
}
// Registers handlers, and prepends BaseURL to the paths, so that the paths
// can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
wrapper := ServerInterfaceWrapper{
Handler: si,
}
router.GET(baseURL+"/available", wrapper.GetAvailablePayments)
router.POST(baseURL+"/yandex/payment/status/canceled", wrapper.SetYandexPaymentStatusCanceled)
router.POST(baseURL+"/yandex/payment/status/succeeded", wrapper.SetYandexPaymentStatusSucceeded)
router.POST(baseURL+"/yandex/payment/status/waiting", wrapper.SetYandexPaymentStatusWaiting)
router.POST(baseURL+"/yandex/refund/status/succeeded", wrapper.SetYandexRefundStatusSucceeded)
}
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
"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",
}
// GetSwagger returns the content of the embedded swagger specification file
// or error if failed to decode
func decodeSpec() ([]byte, error) {
zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %s", err)
}
zr, err := gzip.NewReader(bytes.NewReader(zipped))
if err != nil {
return nil, fmt.Errorf("error decompressing spec: %s", err)
}
var buf bytes.Buffer
_, err = buf.ReadFrom(zr)
if err != nil {
return nil, fmt.Errorf("error decompressing spec: %s", err)
}
return buf.Bytes(), nil
}
var rawSpec = decodeSpecCached()
// a naive cached of a decoded swagger spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
return data, err
}
}
// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
var res = make(map[string]func() ([]byte, error))
if len(pathToFile) > 0 {
res[pathToFile] = rawSpec
}
return res
}
// GetSwagger returns the Swagger specification corresponding to the generated code
// in this file. The external references of Swagger specification are resolved.
// The logic of resolving external references is tightly connected to "import-mapping" feature.
// Externally referenced files must be embedded in the corresponding golang packages.
// Urls can be supported but this task was out of the scope.
func GetSwagger() (swagger *openapi3.T, err error) {
var resolvePath = PathToRawSpec("")
loader := openapi3.NewLoader()
loader.IsExternalRefsAllowed = true
loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
var pathToFile = url.String()
pathToFile = path.Clean(pathToFile)
getSpec, ok := resolvePath[pathToFile]
if !ok {
err1 := fmt.Errorf("path not found: %s", pathToFile)
return nil, err1
}
return getSpec()
}
var specData []byte
specData, err = rawSpec()
if err != nil {
return
}
swagger, err = loader.LoadFromData(specData)
if err != nil {
return
}
return
}

@ -1,77 +0,0 @@
package swagger
import (
"github.com/labstack/echo/v4"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/errors"
)
//go:generate oapi-codegen --config api.yaml ../../openapi.yaml
//go:generate oapi-codegen --config models.yaml ../../openapi.yaml
type commonController interface {
// (GET /available)
GetAvailablePayments(ctx echo.Context) error
}
type yandexStatusController interface {
// (POST /yandex/payment/status/canceled)
SetPaymentStatusCanceled(ctx echo.Context) error
// (POST /yandex/payment/status/succeeded)
SetPaymentStatusSucceeded(ctx echo.Context) error
// (POST /yandex/payment/status/waiting)
SetPaymentStatusWaiting(ctx echo.Context) error
// (POST /yandex/refund/status/succeeded)
SetRefundStatusSucceeded(ctx echo.Context) error
}
type Deps struct {
CommonController commonController
YandexStatusController yandexStatusController
}
type API struct {
commonController commonController
yandexStatusController yandexStatusController
}
func New(deps Deps) (*API, errors.Error) {
if deps.CommonController == nil {
return nil, errors.NewWithMessage("CommonController in nil on <NewSwaggerAPI>", errors.ErrInvalidArgs)
}
if deps.YandexStatusController == nil {
return nil, errors.NewWithMessage("YandexStatusController in nil on <NewSwaggerAPI>", errors.ErrInvalidArgs)
}
return &API{
commonController: deps.CommonController,
yandexStatusController: deps.YandexStatusController,
}, nil
}
// Common
func (receiver *API) GetAvailablePayments(ctx echo.Context) error {
return receiver.commonController.GetAvailablePayments(ctx)
}
// Status (Yandex)
func (receiver *API) SetYandexPaymentStatusCanceled(ctx echo.Context) error {
return receiver.yandexStatusController.SetPaymentStatusCanceled(ctx)
}
func (receiver *API) SetYandexPaymentStatusSucceeded(ctx echo.Context) error {
return receiver.yandexStatusController.SetPaymentStatusSucceeded(ctx)
}
func (receiver *API) SetYandexPaymentStatusWaiting(ctx echo.Context) error {
return receiver.yandexStatusController.SetPaymentStatusWaiting(ctx)
}
func (receiver *API) SetYandexRefundStatusSucceeded(ctx echo.Context) error {
return receiver.yandexStatusController.SetRefundStatusSucceeded(ctx)
}

@ -1,6 +0,0 @@
output: api.gen.go
package: swagger
generate:
echo-server: true
models: false
embedded-spec: true

@ -1,94 +0,0 @@
// Package swagger provides primitives to interact with the openapi HTTP API.
//
// Code generated by github.com/deepmap/oapi-codegen version v1.12.4 DO NOT EDIT.
package swagger
// Defines values for PaymentStatus.
const (
Canceled PaymentStatus = "canceled"
Pending PaymentStatus = "pending"
Succeeded PaymentStatus = "succeeded"
WaitingForCapture PaymentStatus = "waiting_for_capture"
)
// Amount defines model for Amount.
type Amount struct {
// Currency Трехбуквенный код валюты в формате ISO-4217
Currency string `json:"currency"`
// Value Сумма в выбранной валюте
Value string `json:"value"`
}
// PaymentStatus defines model for PaymentStatus.
type PaymentStatus string
// Recipient defines model for Recipient.
type Recipient struct {
// AccountId Идентификатор магазина в ЮKassa
AccountId string `json:"account_id"`
// GatewayId Идентификатор субаккаунта
GatewayId string `json:"gateway_id"`
}
// SetPaymentStatusRequest defines model for SetPaymentStatusRequest.
type SetPaymentStatusRequest struct {
// Event Событие, о котором уведомляет ЮKassa
Event string `json:"event"`
Object YandexPayment `json:"object"`
// Type Тип объекта. Фиксированное значение — notification (уведомление)
Type string `json:"type"`
}
// YandexPayment defines model for YandexPayment.
type YandexPayment struct {
Amount Amount `json:"amount"`
// CapturedAt Время подтверждения платежа
CapturedAt *string `json:"captured_at,omitempty"`
// Confirmation Выбранный способ подтверждения платежа
Confirmation *map[string]interface{} `json:"confirmation,omitempty"`
// CreatedAt Время создания заказа
CreatedAt string `json:"created_at"`
// Description Описание
Description *string `json:"description,omitempty"`
// ExpiresAt Время, до которого вы можете бесплатно отменить или подтвердить платеж
ExpiresAt *string `json:"expires_at,omitempty"`
// Id Идентификатор платежа в ЮKassa
Id string `json:"id"`
IncomeAmount *Amount `json:"income_amount,omitempty"`
// Paid Признак оплаты заказа
Paid bool `json:"paid"`
// PaymentMethod Структура метода платежа (может отличаться от способа платежа)
PaymentMethod *map[string]interface{} `json:"payment_method,omitempty"`
Recipient Recipient `json:"recipient"`
// Refundable Возможность провести возврат по API
Refundable bool `json:"refundable"`
RefundedAmount *Amount `json:"refunded_amount,omitempty"`
Status PaymentStatus `json:"status"`
// Test Признак тестовой операции
Test bool `json:"test"`
}
// SetYandexPaymentStatusCanceledJSONRequestBody defines body for SetYandexPaymentStatusCanceled for application/json ContentType.
type SetYandexPaymentStatusCanceledJSONRequestBody = SetPaymentStatusRequest
// SetYandexPaymentStatusSucceededJSONRequestBody defines body for SetYandexPaymentStatusSucceeded for application/json ContentType.
type SetYandexPaymentStatusSucceededJSONRequestBody = SetPaymentStatusRequest
// SetYandexPaymentStatusWaitingJSONRequestBody defines body for SetYandexPaymentStatusWaiting for application/json ContentType.
type SetYandexPaymentStatusWaitingJSONRequestBody = SetPaymentStatusRequest
// SetYandexRefundStatusSucceededJSONRequestBody defines body for SetYandexRefundStatusSucceeded for application/json ContentType.
type SetYandexRefundStatusSucceededJSONRequestBody = SetPaymentStatusRequest

@ -1,4 +0,0 @@
output: models.gen.go
package: swagger
generate:
models: true

@ -1,13 +0,0 @@
package echotools
import "github.com/labstack/echo/v4"
func Bind[T any](ctx echo.Context) (*T, error) {
item := new(T)
if err := ctx.Bind(item); err != nil {
return nil, err
}
return item, nil
}

@ -0,0 +1,60 @@
package mock
import (
"context"
"time"
"go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/errors"
)
type mockService interface {
Register() bool
}
type WorkerDeps struct {
Logger *zap.Logger
MockService mockService
}
type Worker struct {
logger *zap.Logger
mockService mockService
}
func New(deps WorkerDeps) (*Worker, errors.Error) {
if deps.Logger == nil {
return nil, errors.NewWithMessage("logger is nil on <NewMockWorker>", errors.ErrInvalidArgs)
}
if deps.MockService == nil {
return nil, errors.NewWithMessage("MockService urls is nil on <NewMockWorker>", errors.ErrInvalidArgs)
}
return &Worker{
logger: deps.Logger,
mockService: deps.MockService,
}, nil
}
func (receiver *Worker) Run(ctx context.Context) {
after := time.After(10 * time.Second)
select {
case <-ctx.Done():
receiver.logger.Info("register mocks operations canceled <mocks>")
return
case <-after:
receiver.logger.Info("register yoomoney mocks <mocks>")
isSuccess := receiver.mockService.Register()
if isSuccess {
receiver.logger.Info("register yoomoney mocks complete <mocks>")
}
if !isSuccess {
receiver.logger.Info("register yoomoney mocks failure <mocks>")
}
}
}

11
internal/worker/run.go Normal file

@ -0,0 +1,11 @@
package worker
import (
"context"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/initialize"
)
func Run(ctx context.Context, workers *initialize.Workers) {
go workers.Mock.Run(ctx)
}

@ -1 +0,0 @@
[{ "delete": "amocrm", "deletes": [{ "q": {} }] }]

@ -1,85 +0,0 @@
[
{
"insert": "amocrm",
"ordered": true,
"documents": [
{
"amocrmId": "1",
"userId": "1",
"information": {
"id": 30228997,
"name": "ООО ПЕНА",
"subdomain": "penadigital",
"created_at": 1683680509,
"created_by": 0,
"updated_at": 1683680509,
"updated_by": 0,
"current_user_id": 8110726,
"country": "RU",
"customers_mode": "disabled",
"is_unsorted_on": true,
"is_loss_reason_enabled": true,
"is_helpbot_enabled": false,
"is_technical_account": true,
"contact_name_display_order": 1,
"amojo_id": "",
"uuid": "",
"version": 0,
"_links": { "self": { "href": "https://penadigital.amocrm.ru/api/v4/account" } },
"_embedded": {
"amojo_rights": { "can_direct": false, "can_create_groups": false },
"users_groups": null,
"task_types": null,
"entity_names": {
"leads": {
"ru": {
"gender": "",
"plural_form": {
"dative": "",
"default": "",
"genitive": "",
"accusative": "",
"instrumental": "",
"prepositional": ""
},
"singular_form": {
"dative": "",
"default": "",
"genitive": "",
"accusative": "",
"instrumental": "",
"prepositional": ""
}
},
"en": {
"singular_form": { "default": "" },
"plural_form": { "default": "" },
"gender": ""
},
"es": {
"singular_form": { "default": "" },
"plural_form": { "default": "" },
"gender": ""
}
}
},
"datetime_settings": {
"date_pattern": "",
"short_date_pattern": "",
"short_time_pattern": "",
"date_formant": "",
"time_format": "",
"timezone": "",
"timezone_offset": ""
}
}
},
"audit": {
"createdAt": "2022-12-31T00:00:00.000Z",
"updatedAt": "2022-12-31T00:00:00.000Z",
"deleted": false
}
}
]
}
]

7
pkg/validate/string.go Normal file

@ -0,0 +1,7 @@
package validate
import "strings"
func IsStringEmpty(text string) bool {
return strings.TrimSpace(text) == ""
}

@ -0,0 +1,16 @@
package validate_test
import (
"testing"
"github.com/stretchr/testify/assert"
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/validate"
)
func TestIsStringEmpty(t *testing.T) {
assert.True(t, validate.IsStringEmpty(""))
assert.True(t, validate.IsStringEmpty(" "))
assert.True(t, validate.IsStringEmpty(" "))
assert.False(t, validate.IsStringEmpty("tett"))
assert.False(t, validate.IsStringEmpty(" t "))
}

28
pkg/validate/url.go Normal file

@ -0,0 +1,28 @@
package validate
import (
"net"
"net/url"
"regexp"
"strings"
)
func URL(text string) bool {
url, err := url.Parse(text)
if err != nil {
return false
}
address := net.ParseIP(url.Host)
if address == nil {
regex := regexp.MustCompile(`\b\w+:\d+\b`)
return strings.Contains(url.Host, ".") || regex.MatchString(url.Host)
}
if IsStringEmpty(url.Scheme) || IsStringEmpty(url.Host) {
return false
}
return true
}

25
pkg/validate/url_test.go Normal file

@ -0,0 +1,25 @@
package validate_test
import (
"testing"
"github.com/stretchr/testify/assert"
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/validate"
)
func TestValidateURL(t *testing.T) {
assert.True(t, validate.URL("http://google.com"))
assert.True(t, validate.URL("http://w.com/cn"))
assert.True(t, validate.URL("http://192.158.0.1:90"))
assert.False(t, validate.URL("192.158.0.1:9090"))
assert.False(t, validate.URL("http://w"))
assert.False(t, validate.URL("fsw"))
assert.True(t, validate.URL("http://192.158.1/1"))
assert.True(t, validate.URL("https://www.googleapis.com/oauth2/v3"))
assert.True(t, validate.URL("http://localhost:8080/google/callback"))
assert.True(t, validate.URL("https://oauth.pena.digital/amocrm/callback"))
assert.True(t, validate.URL("https://www.amocrm.ru/oauth"))
assert.True(t, validate.URL("https://www.amocrm.ru/oauth/access_token"))
assert.True(t, validate.URL("http://localhost:8080/vk/callback"))
assert.True(t, validate.URL("http://mock:8000/api/v4/account"))
}