diff --git a/Makefile b/Makefile index 9a64367046d3ac93fdf4ec05437cfb15ffc43777..b0b31e1dfe312e8ba8ae22c93fd17e5341d60079 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,9 @@ PROTOGOGRPCFILES=$(PROTOFILES:.proto=_grpc.pb.go) PKGDIR=pkg ACCESSLOGGING=$(shell find $(PKGDIR) -name "logging_middleware.go" -type f) ERRORLOGGING=$(shell find $(PKGDIR) -name "error_logging_middleware.go" -type f) +SERVICETELEMETRY=$(shell find $(PKGDIR) -name "telemetry_middleware.go" -type f) +SERVICEMIDDLEWARE=$(shell find $(PKGDIR) -name "middleware.go" -type f) +SERVICERECOVERING=$(shell find $(PKGDIR) -name "recovering_middleware.go" -type f) # Генерация grpc-клиентов для go proto: protoc-check protoc-gen-go-check $(PROTOGOFILES) @@ -54,6 +57,24 @@ logging: $(ERRORLOGGING) $(ACCESSLOGGING) @echo "$@" @go generate "$@" +telemetry: $(SERVICETELEMETRY) + +%/middleware/telemetry_middleware.go: % .FORCE + @echo "$@" + @go generate "$@" + +middleware: $(SERVICEMIDDLEWARE) + +%/middleware/middleware.go: % .FORCE + @echo "$@" + @go generate "$@" + +recovering: $(SERVICERECOVERING) + +%/middleware/recovering_middleware.go: % .FORCE + @echo "$@" + @go generate "$@" + # Генерация РјРѕРєРѕРІ для всех интерфейсов, найденных РІ директории. Выходные файлы СЃ моками сохраняются РІ `./mocks` MOCKSDIRS?=$(shell find . -name "service.go" -exec dirname {} \;) MOCKS=$(MOCKSDIRS:=/mocks) diff --git a/assets/templates/middleware/telemetry b/assets/templates/middleware/telemetry new file mode 100644 index 0000000000000000000000000000000000000000..3e893c09f161d2e832544f8bca625b6d63b3d990 --- /dev/null +++ b/assets/templates/middleware/telemetry @@ -0,0 +1,52 @@ +import ( + "context" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +{{ $decorator := (or .Vars.DecoratorName "telemetryMiddleware") }} +{{ $funcName := (or .Vars.FuncName ("TelemetryMiddleware")) }} + +// {{$decorator}} implements {{.Interface.Type}} interface instrumented with opentracing spans +type {{$decorator}} struct { + {{.Interface.Type}} + _instance string + _spanDecorator func(span trace.Span, params, results map[string]interface{}) +} + +// {{$funcName}} returns {{$decorator}} +func {{$funcName}} (base {{.Interface.Type}}, instance string, spanDecorator ...func(span trace.Span, params, results map[string]interface{})) {{$decorator}} { + d := {{$decorator}} { + {{.Interface.Name}}: base, + _instance: instance, + } + + if len(spanDecorator) > 0 && spanDecorator[0] != nil { + d._spanDecorator = spanDecorator[0] + } + + return d +} + +{{range $method := .Interface.Methods}} + {{if $method.AcceptsContext}} + // {{$method.Name}} implements {{$.Interface.Type}} +func (_d {{$decorator}}) {{$method.Declaration}} { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "{{$.Interface.Name}}.{{$method.Name}}") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, {{$method.ParamsMap}}, {{$method.ResultsMap}}) + }{{- if $method.ReturnsError}} else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + {{end}} + _span.End() + }() + {{$method.Pass (printf "_d.%s." $.Interface.Name) }} +} + {{end}} +{{end}} \ No newline at end of file diff --git a/pkg/clients/middleware/telemetry_middleware.go b/pkg/clients/middleware/telemetry_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..d8536b10fcac0a1f237c688fe9a8bde3db93fdcf --- /dev/null +++ b/pkg/clients/middleware/telemetry_middleware.go @@ -0,0 +1,186 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/telemetry +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/clients -i Clients -t ../../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l "" + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/clients" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +// telemetryMiddleware implements clients.Clients interface instrumented with opentracing spans +type telemetryMiddleware struct { + clients.Clients + _instance string + _spanDecorator func(span trace.Span, params, results map[string]interface{}) +} + +// TelemetryMiddleware returns telemetryMiddleware +func TelemetryMiddleware(base clients.Clients, instance string, spanDecorator ...func(span trace.Span, params, results map[string]interface{})) telemetryMiddleware { + d := telemetryMiddleware{ + Clients: base, + _instance: instance, + } + + if len(spanDecorator) > 0 && spanDecorator[0] != nil { + d._spanDecorator = spanDecorator[0] + } + + return d +} + +// Create implements clients.Clients +func (_d telemetryMiddleware) Create(ctx context.Context, client *clients.Client) (created *clients.Client, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Clients.Create") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "client": client}, map[string]interface{}{ + "created": created, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Clients.Create(ctx, client) +} + +// Delete implements clients.Clients +func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string, id string) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Clients.Delete") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "id": id}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Clients.Delete(ctx, spaceId, id) +} + +// Enable implements clients.Clients +func (_d telemetryMiddleware) Enable(ctx context.Context, spaceId string, id string, enable bool) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Clients.Enable") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "id": id, + "enable": enable}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Clients.Enable(ctx, spaceId, id, enable) +} + +// Get implements clients.Clients +func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, id string) (client *clients.Client, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Clients.Get") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "id": id}, map[string]interface{}{ + "client": client, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Clients.Get(ctx, spaceId, id) +} + +// GetBy implements clients.Clients +func (_d telemetryMiddleware) GetBy(ctx context.Context, spaceId string, params *clients.GetByParams) (client *clients.Client, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Clients.GetBy") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "params": params}, map[string]interface{}{ + "client": client, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Clients.GetBy(ctx, spaceId, params) +} + +// List implements clients.Clients +func (_d telemetryMiddleware) List(ctx context.Context, spaceId string) (clients []*clients.Client, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Clients.List") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId}, map[string]interface{}{ + "clients": clients, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Clients.List(ctx, spaceId) +} + +// Update implements clients.Clients +func (_d telemetryMiddleware) Update(ctx context.Context, client *clients.Client) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Clients.Update") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "client": client}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Clients.Update(ctx, client) +} diff --git a/pkg/clients/mocks/Storage.go b/pkg/clients/mocks/Storage.go new file mode 100644 index 0000000000000000000000000000000000000000..43166e0d3f4a21bb80d5179e23d0ee87596a565e --- /dev/null +++ b/pkg/clients/mocks/Storage.go @@ -0,0 +1,156 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + clients "git.perx.ru/perxis/perxis-go/pkg/clients" + + mock "github.com/stretchr/testify/mock" + + options "git.perx.ru/perxis/perxis-go/pkg/options" +) + +// Storage is an autogenerated mock type for the Storage type +type Storage struct { + mock.Mock +} + +// Create provides a mock function with given fields: ctx, client +func (_m *Storage) Create(ctx context.Context, client *clients.Client) (*clients.Client, error) { + ret := _m.Called(ctx, client) + + var r0 *clients.Client + if rf, ok := ret.Get(0).(func(context.Context, *clients.Client) *clients.Client); ok { + r0 = rf(ctx, client) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*clients.Client) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *clients.Client) error); ok { + r1 = rf(ctx, client) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Delete provides a mock function with given fields: ctx, spaceId, id +func (_m *Storage) Delete(ctx context.Context, spaceId string, id string) error { + ret := _m.Called(ctx, spaceId, id) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { + r0 = rf(ctx, spaceId, id) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Find provides a mock function with given fields: ctx, spaceId, filter, opts +func (_m *Storage) Find(ctx context.Context, spaceId string, filter *clients.Filter, opts *options.FindOptions) ([]*clients.Client, int, error) { + ret := _m.Called(ctx, spaceId, filter, opts) + + var r0 []*clients.Client + if rf, ok := ret.Get(0).(func(context.Context, string, *clients.Filter, *options.FindOptions) []*clients.Client); ok { + r0 = rf(ctx, spaceId, filter, opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*clients.Client) + } + } + + var r1 int + if rf, ok := ret.Get(1).(func(context.Context, string, *clients.Filter, *options.FindOptions) int); ok { + r1 = rf(ctx, spaceId, filter, opts) + } else { + r1 = ret.Get(1).(int) + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, string, *clients.Filter, *options.FindOptions) error); ok { + r2 = rf(ctx, spaceId, filter, opts) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// Init provides a mock function with given fields: ctx, spaceID +func (_m *Storage) Init(ctx context.Context, spaceID string) error { + ret := _m.Called(ctx, spaceID) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { + r0 = rf(ctx, spaceID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Reset provides a mock function with given fields: ctx, spaceId +func (_m *Storage) Reset(ctx context.Context, spaceId string) error { + ret := _m.Called(ctx, spaceId) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { + r0 = rf(ctx, spaceId) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Update provides a mock function with given fields: ctx, upd +func (_m *Storage) Update(ctx context.Context, upd *clients.Client) (int, int, error) { + ret := _m.Called(ctx, upd) + + var r0 int + if rf, ok := ret.Get(0).(func(context.Context, *clients.Client) int); ok { + r0 = rf(ctx, upd) + } else { + r0 = ret.Get(0).(int) + } + + var r1 int + if rf, ok := ret.Get(1).(func(context.Context, *clients.Client) int); ok { + r1 = rf(ctx, upd) + } else { + r1 = ret.Get(1).(int) + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, *clients.Client) error); ok { + r2 = rf(ctx, upd) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +type mockConstructorTestingTNewStorage interface { + mock.TestingT + Cleanup(func()) +} + +// NewStorage creates a new instance of Storage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewStorage(t mockConstructorTestingTNewStorage) *Storage { + mock := &Storage{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/clients/storage.go b/pkg/clients/storage.go new file mode 100644 index 0000000000000000000000000000000000000000..8b9d536a187145687fcfb3e4fc8b481eed77076f --- /dev/null +++ b/pkg/clients/storage.go @@ -0,0 +1,24 @@ +package clients + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/options" +) + +type Storage interface { + Create(ctx context.Context, client *Client) (*Client, error) + Find(ctx context.Context, spaceId string, filter *Filter, opts *options.FindOptions) ([]*Client, int, error) + Update(ctx context.Context, upd *Client) (updated, total int, err error) + Delete(ctx context.Context, spaceId, id string) error + + Reset(ctx context.Context, spaceId string) error + Init(ctx context.Context, spaceID string) error +} + +type Filter struct { + ID string + Name string + + GetByParams +} diff --git a/pkg/collaborators/middleware/telemetry_middleware.go b/pkg/collaborators/middleware/telemetry_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..6a824f1e0a31c585d07b7ebb1bbf391963b0ca63 --- /dev/null +++ b/pkg/collaborators/middleware/telemetry_middleware.go @@ -0,0 +1,144 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/telemetry +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/collaborators -i Collaborators -t ../../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l "" + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/collaborators" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +// telemetryMiddleware implements collaborators.Collaborators interface instrumented with opentracing spans +type telemetryMiddleware struct { + collaborators.Collaborators + _instance string + _spanDecorator func(span trace.Span, params, results map[string]interface{}) +} + +// TelemetryMiddleware returns telemetryMiddleware +func TelemetryMiddleware(base collaborators.Collaborators, instance string, spanDecorator ...func(span trace.Span, params, results map[string]interface{})) telemetryMiddleware { + d := telemetryMiddleware{ + Collaborators: base, + _instance: instance, + } + + if len(spanDecorator) > 0 && spanDecorator[0] != nil { + d._spanDecorator = spanDecorator[0] + } + + return d +} + +// Get implements collaborators.Collaborators +func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, subject string) (role string, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collaborators.Get") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "subject": subject}, map[string]interface{}{ + "role": role, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Collaborators.Get(ctx, spaceId, subject) +} + +// ListCollaborators implements collaborators.Collaborators +func (_d telemetryMiddleware) ListCollaborators(ctx context.Context, spaceId string) (collaborators []*collaborators.Collaborator, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collaborators.ListCollaborators") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId}, map[string]interface{}{ + "collaborators": collaborators, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Collaborators.ListCollaborators(ctx, spaceId) +} + +// ListSpaces implements collaborators.Collaborators +func (_d telemetryMiddleware) ListSpaces(ctx context.Context, subject string) (spaces []*collaborators.Collaborator, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collaborators.ListSpaces") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "subject": subject}, map[string]interface{}{ + "spaces": spaces, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Collaborators.ListSpaces(ctx, subject) +} + +// Remove implements collaborators.Collaborators +func (_d telemetryMiddleware) Remove(ctx context.Context, spaceId string, subject string) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collaborators.Remove") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "subject": subject}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Collaborators.Remove(ctx, spaceId, subject) +} + +// Set implements collaborators.Collaborators +func (_d telemetryMiddleware) Set(ctx context.Context, spaceId string, subject string, role string) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collaborators.Set") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "subject": subject, + "role": role}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Collaborators.Set(ctx, spaceId, subject, role) +} diff --git a/pkg/collaborators/mocks/CollaboratorObserver.go b/pkg/collaborators/mocks/CollaboratorObserver.go new file mode 100644 index 0000000000000000000000000000000000000000..c7f5aed4d5525f2d9136ea7645696dba9418e785 --- /dev/null +++ b/pkg/collaborators/mocks/CollaboratorObserver.go @@ -0,0 +1,25 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// CollaboratorObserver is an autogenerated mock type for the CollaboratorObserver type +type CollaboratorObserver struct { + mock.Mock +} + +type mockConstructorTestingTNewCollaboratorObserver interface { + mock.TestingT + Cleanup(func()) +} + +// NewCollaboratorObserver creates a new instance of CollaboratorObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewCollaboratorObserver(t mockConstructorTestingTNewCollaboratorObserver) *CollaboratorObserver { + mock := &CollaboratorObserver{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/collaborators/mocks/CollaboratorRemoveObserver.go b/pkg/collaborators/mocks/CollaboratorRemoveObserver.go new file mode 100644 index 0000000000000000000000000000000000000000..8733c7430a5b0a7b4c8b5d34a2a09bf90373a7c9 --- /dev/null +++ b/pkg/collaborators/mocks/CollaboratorRemoveObserver.go @@ -0,0 +1,52 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + collaborators "git.perx.ru/perxis/perxis-go/pkg/collaborators" + + mock "github.com/stretchr/testify/mock" +) + +// CollaboratorRemoveObserver is an autogenerated mock type for the CollaboratorRemoveObserver type +type CollaboratorRemoveObserver struct { + mock.Mock +} + +// OnCollaboratorRemove provides a mock function with given fields: ctx, collaborator +func (_m *CollaboratorRemoveObserver) OnCollaboratorRemove(ctx context.Context, collaborator *collaborators.Collaborator) (string, error) { + ret := _m.Called(ctx, collaborator) + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, *collaborators.Collaborator) string); ok { + r0 = rf(ctx, collaborator) + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *collaborators.Collaborator) error); ok { + r1 = rf(ctx, collaborator) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type mockConstructorTestingTNewCollaboratorRemoveObserver interface { + mock.TestingT + Cleanup(func()) +} + +// NewCollaboratorRemoveObserver creates a new instance of CollaboratorRemoveObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewCollaboratorRemoveObserver(t mockConstructorTestingTNewCollaboratorRemoveObserver) *CollaboratorRemoveObserver { + mock := &CollaboratorRemoveObserver{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/collaborators/mocks/CollaboratorSetObserver.go b/pkg/collaborators/mocks/CollaboratorSetObserver.go new file mode 100644 index 0000000000000000000000000000000000000000..296c37f12fd206923b904386a6a15924992fe3f7 --- /dev/null +++ b/pkg/collaborators/mocks/CollaboratorSetObserver.go @@ -0,0 +1,52 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + collaborators "git.perx.ru/perxis/perxis-go/pkg/collaborators" + + mock "github.com/stretchr/testify/mock" +) + +// CollaboratorSetObserver is an autogenerated mock type for the CollaboratorSetObserver type +type CollaboratorSetObserver struct { + mock.Mock +} + +// OnCollaboratorSet provides a mock function with given fields: ctx, collaborator +func (_m *CollaboratorSetObserver) OnCollaboratorSet(ctx context.Context, collaborator *collaborators.Collaborator) (string, error) { + ret := _m.Called(ctx, collaborator) + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, *collaborators.Collaborator) string); ok { + r0 = rf(ctx, collaborator) + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *collaborators.Collaborator) error); ok { + r1 = rf(ctx, collaborator) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type mockConstructorTestingTNewCollaboratorSetObserver interface { + mock.TestingT + Cleanup(func()) +} + +// NewCollaboratorSetObserver creates a new instance of CollaboratorSetObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewCollaboratorSetObserver(t mockConstructorTestingTNewCollaboratorSetObserver) *CollaboratorSetObserver { + mock := &CollaboratorSetObserver{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/collaborators/mocks/Storage.go b/pkg/collaborators/mocks/Storage.go new file mode 100644 index 0000000000000000000000000000000000000000..b2645f347aba5eeb418a5fb4228944bd051e46b0 --- /dev/null +++ b/pkg/collaborators/mocks/Storage.go @@ -0,0 +1,119 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + collaborators "git.perx.ru/perxis/perxis-go/pkg/collaborators" + + mock "github.com/stretchr/testify/mock" + + options "git.perx.ru/perxis/perxis-go/pkg/options" +) + +// Storage is an autogenerated mock type for the Storage type +type Storage struct { + mock.Mock +} + +// Delete provides a mock function with given fields: ctx, filter +func (_m *Storage) Delete(ctx context.Context, filter *collaborators.Filter) (int, error) { + ret := _m.Called(ctx, filter) + + var r0 int + if rf, ok := ret.Get(0).(func(context.Context, *collaborators.Filter) int); ok { + r0 = rf(ctx, filter) + } else { + r0 = ret.Get(0).(int) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *collaborators.Filter) error); ok { + r1 = rf(ctx, filter) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Find provides a mock function with given fields: ctx, filter, opts +func (_m *Storage) Find(ctx context.Context, filter *collaborators.Filter, opts *options.FindOptions) ([]*collaborators.Collaborator, error) { + ret := _m.Called(ctx, filter, opts) + + var r0 []*collaborators.Collaborator + if rf, ok := ret.Get(0).(func(context.Context, *collaborators.Filter, *options.FindOptions) []*collaborators.Collaborator); ok { + r0 = rf(ctx, filter, opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*collaborators.Collaborator) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *collaborators.Filter, *options.FindOptions) error); ok { + r1 = rf(ctx, filter, opts) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Init provides a mock function with given fields: ctx +func (_m *Storage) Init(ctx context.Context) error { + ret := _m.Called(ctx) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Reset provides a mock function with given fields: ctx +func (_m *Storage) Reset(ctx context.Context) error { + ret := _m.Called(ctx) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Set provides a mock function with given fields: ctx, collaborator +func (_m *Storage) Set(ctx context.Context, collaborator *collaborators.Collaborator) error { + ret := _m.Called(ctx, collaborator) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *collaborators.Collaborator) error); ok { + r0 = rf(ctx, collaborator) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +type mockConstructorTestingTNewStorage interface { + mock.TestingT + Cleanup(func()) +} + +// NewStorage creates a new instance of Storage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewStorage(t mockConstructorTestingTNewStorage) *Storage { + mock := &Storage{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/collaborators/storage.go b/pkg/collaborators/storage.go new file mode 100644 index 0000000000000000000000000000000000000000..7eb4bb7d3bf0ed2d3a657d874a2cddc87c4c9bb3 --- /dev/null +++ b/pkg/collaborators/storage.go @@ -0,0 +1,22 @@ +package collaborators + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/options" +) + +type Storage interface { + Set(ctx context.Context, collaborator *Collaborator) (err error) + Delete(ctx context.Context, filter *Filter) (total int, err error) + Find(ctx context.Context, filter *Filter, opts *options.FindOptions) (collaborators []*Collaborator, err error) + + Reset(ctx context.Context) error + Init(ctx context.Context) error +} + +type Filter struct { + SpaceID string `bson:"spaceId"` + Subject string `bson:"userId"` + Role string `bson:"role"` +} diff --git a/pkg/collections/middleware/telemetry_middleware.go b/pkg/collections/middleware/telemetry_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..74a0d685c37c6b6d8bdb0b6453f50cfea83e7f07 --- /dev/null +++ b/pkg/collections/middleware/telemetry_middleware.go @@ -0,0 +1,194 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/telemetry +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/collections -i Collections -t ../../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l "" + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/collections" + "git.perx.ru/perxis/perxis-go/pkg/schema" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +// telemetryMiddleware implements collections.Collections interface instrumented with opentracing spans +type telemetryMiddleware struct { + collections.Collections + _instance string + _spanDecorator func(span trace.Span, params, results map[string]interface{}) +} + +// TelemetryMiddleware returns telemetryMiddleware +func TelemetryMiddleware(base collections.Collections, instance string, spanDecorator ...func(span trace.Span, params, results map[string]interface{})) telemetryMiddleware { + d := telemetryMiddleware{ + Collections: base, + _instance: instance, + } + + if len(spanDecorator) > 0 && spanDecorator[0] != nil { + d._spanDecorator = spanDecorator[0] + } + + return d +} + +// Create implements collections.Collections +func (_d telemetryMiddleware) Create(ctx context.Context, collection *collections.Collection) (created *collections.Collection, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collections.Create") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "collection": collection}, map[string]interface{}{ + "created": created, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Collections.Create(ctx, collection) +} + +// Delete implements collections.Collections +func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string, envId string, collectionId string) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collections.Delete") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "collectionId": collectionId}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Collections.Delete(ctx, spaceId, envId, collectionId) +} + +// Get implements collections.Collections +func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, envId string, collectionId string, options ...*collections.GetOptions) (collection *collections.Collection, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collections.Get") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "collectionId": collectionId, + "options": options}, map[string]interface{}{ + "collection": collection, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Collections.Get(ctx, spaceId, envId, collectionId, options...) +} + +// List implements collections.Collections +func (_d telemetryMiddleware) List(ctx context.Context, spaceId string, envId string, filter *collections.Filter) (collections []*collections.Collection, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collections.List") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "filter": filter}, map[string]interface{}{ + "collections": collections, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Collections.List(ctx, spaceId, envId, filter) +} + +// SetSchema implements collections.Collections +func (_d telemetryMiddleware) SetSchema(ctx context.Context, spaceId string, envId string, collectionId string, schema *schema.Schema) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collections.SetSchema") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "collectionId": collectionId, + "schema": schema}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Collections.SetSchema(ctx, spaceId, envId, collectionId, schema) +} + +// SetState implements collections.Collections +func (_d telemetryMiddleware) SetState(ctx context.Context, spaceId string, envId string, collectionId string, state *collections.StateInfo) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collections.SetState") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "collectionId": collectionId, + "state": state}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Collections.SetState(ctx, spaceId, envId, collectionId, state) +} + +// Update implements collections.Collections +func (_d telemetryMiddleware) Update(ctx context.Context, coll *collections.Collection) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collections.Update") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "coll": coll}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Collections.Update(ctx, coll) +} diff --git a/pkg/collections/mocks/Storage.go b/pkg/collections/mocks/Storage.go new file mode 100644 index 0000000000000000000000000000000000000000..eb171b5884308f01753827496de9569a575ff818 --- /dev/null +++ b/pkg/collections/mocks/Storage.go @@ -0,0 +1,170 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + collections "git.perx.ru/perxis/perxis-go/pkg/collections" + + mock "github.com/stretchr/testify/mock" +) + +// Storage is an autogenerated mock type for the Storage type +type Storage struct { + mock.Mock +} + +// Create provides a mock function with given fields: ctx, coll +func (_m *Storage) Create(ctx context.Context, coll *collections.Collection) (*collections.Collection, error) { + ret := _m.Called(ctx, coll) + + var r0 *collections.Collection + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection) *collections.Collection); ok { + r0 = rf(ctx, coll) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*collections.Collection) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *collections.Collection) error); ok { + r1 = rf(ctx, coll) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Delete provides a mock function with given fields: ctx, spaceId, envId, collectionId +func (_m *Storage) Delete(ctx context.Context, spaceId string, envId string, collectionId string) error { + ret := _m.Called(ctx, spaceId, envId, collectionId) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) error); ok { + r0 = rf(ctx, spaceId, envId, collectionId) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Get provides a mock function with given fields: ctx, spaceId, envId, collectionId +func (_m *Storage) Get(ctx context.Context, spaceId string, envId string, collectionId string) (*collections.Collection, error) { + ret := _m.Called(ctx, spaceId, envId, collectionId) + + var r0 *collections.Collection + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) *collections.Collection); ok { + r0 = rf(ctx, spaceId, envId, collectionId) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*collections.Collection) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok { + r1 = rf(ctx, spaceId, envId, collectionId) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Init provides a mock function with given fields: ctx, spaceID, envID +func (_m *Storage) Init(ctx context.Context, spaceID string, envID string) error { + ret := _m.Called(ctx, spaceID, envID) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { + r0 = rf(ctx, spaceID, envID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// List provides a mock function with given fields: ctx, spaceId, envId, filter +func (_m *Storage) List(ctx context.Context, spaceId string, envId string, filter *collections.Filter) ([]*collections.Collection, error) { + ret := _m.Called(ctx, spaceId, envId, filter) + + var r0 []*collections.Collection + if rf, ok := ret.Get(0).(func(context.Context, string, string, *collections.Filter) []*collections.Collection); ok { + r0 = rf(ctx, spaceId, envId, filter) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*collections.Collection) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string, string, *collections.Filter) error); ok { + r1 = rf(ctx, spaceId, envId, filter) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Reset provides a mock function with given fields: ctx, spaceId, envId +func (_m *Storage) Reset(ctx context.Context, spaceId string, envId string) error { + ret := _m.Called(ctx, spaceId, envId) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { + r0 = rf(ctx, spaceId, envId) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Update provides a mock function with given fields: ctx, coll +func (_m *Storage) Update(ctx context.Context, coll *collections.Collection) (int, int, error) { + ret := _m.Called(ctx, coll) + + var r0 int + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection) int); ok { + r0 = rf(ctx, coll) + } else { + r0 = ret.Get(0).(int) + } + + var r1 int + if rf, ok := ret.Get(1).(func(context.Context, *collections.Collection) int); ok { + r1 = rf(ctx, coll) + } else { + r1 = ret.Get(1).(int) + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, *collections.Collection) error); ok { + r2 = rf(ctx, coll) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +type mockConstructorTestingTNewStorage interface { + mock.TestingT + Cleanup(func()) +} + +// NewStorage creates a new instance of Storage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewStorage(t mockConstructorTestingTNewStorage) *Storage { + mock := &Storage{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/collections/observer.go b/pkg/collections/observer.go new file mode 100644 index 0000000000000000000000000000000000000000..8d4a6b7d14ec687c97eec6b0406fcc32d515aca2 --- /dev/null +++ b/pkg/collections/observer.go @@ -0,0 +1,33 @@ +package collections + +import "context" + +// CollectionCreatedObserver интерфейс наблюдателя вызываемый РїСЂРё создании коллекции. +// Рнициировать оповещение наблюдателя может вызов метода `Collection.Create` +type CollectionCreatedObserver interface { + OnCollectionCreated(ctx context.Context, coll *Collection) (delayedTaskID string, err error) +} + +// CollectionUpdatedObserver интерфейс наблюдателя вызываемый РїСЂРё изменении коллекции. +// Рнициировать оповещение наблюдателя может вызов методов `Collection.Update` +type CollectionUpdatedObserver interface { + OnCollectionUpdated(ctx context.Context, before, after *Collection) (delayedTaskID string, err error) +} + +// CollectionSetSchemaObserver интерфейс наблюдателя вызываемый РїСЂРё изменении схемы коллекции. +// Рнициировать оповещение наблюдателя может вызов методов `Collection.Schema` +type CollectionSetSchemaObserver interface { + OnCollectionSetSchema(ctx context.Context, before, coll *Collection) (delayedTaskID string, err error) +} + +// CollectionDeletedObserver интерфейс наблюдателя вызываемый РїСЂРё удалении коллекции. +// Рнициировать оповещение наблюдателя может вызов метода `Collection.Delete` +type CollectionDeletedObserver interface { + OnCollectionDeleted(ctx context.Context, coll *Collection) (delayedTaskID string, err error) +} + +// CollectionPreUpdateObserver интерфейс наблюдателя вызываемый РїСЂРё перед обновлением коллекции. +// Рнициировать оповещение наблюдателя может вызов методов `Collection.Update` +type CollectionPreUpdateObserver interface { + OnCollectionPreUpdate(ctx context.Context, before, coll *Collection) (delayedTaskID string, err error) +} diff --git a/pkg/collections/storage.go b/pkg/collections/storage.go new file mode 100644 index 0000000000000000000000000000000000000000..37d35b38567e28057099e4edc13c2a1fd74a7817 --- /dev/null +++ b/pkg/collections/storage.go @@ -0,0 +1,16 @@ +package collections + +import ( + "context" +) + +type Storage interface { + Reset(ctx context.Context, spaceId, envId string) error + Init(ctx context.Context, spaceID, envID string) error + + Create(ctx context.Context, coll *Collection) (created *Collection, err error) + Get(ctx context.Context, spaceId, envId, collectionId string) (collection *Collection, err error) + List(ctx context.Context, spaceId, envId string, filter *Filter) (collections []*Collection, err error) + Update(ctx context.Context, coll *Collection) (updated, total int, err error) + Delete(ctx context.Context, spaceId, envId, collectionId string) (err error) +} diff --git a/pkg/delivery/middleware/telemetry_middleware.go b/pkg/delivery/middleware/telemetry_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..9468782004efd635902eea18b2a174e411a49be4 --- /dev/null +++ b/pkg/delivery/middleware/telemetry_middleware.go @@ -0,0 +1,226 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/telemetry +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/delivery -i Delivery -t ../../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l "" + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/collections" + "git.perx.ru/perxis/perxis-go/pkg/delivery" + "git.perx.ru/perxis/perxis-go/pkg/environments" + "git.perx.ru/perxis/perxis-go/pkg/items" + "git.perx.ru/perxis/perxis-go/pkg/locales" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +// telemetryMiddleware implements delivery.Delivery interface instrumented with opentracing spans +type telemetryMiddleware struct { + delivery.Delivery + _instance string + _spanDecorator func(span trace.Span, params, results map[string]interface{}) +} + +// TelemetryMiddleware returns telemetryMiddleware +func TelemetryMiddleware(base delivery.Delivery, instance string, spanDecorator ...func(span trace.Span, params, results map[string]interface{})) telemetryMiddleware { + d := telemetryMiddleware{ + Delivery: base, + _instance: instance, + } + + if len(spanDecorator) > 0 && spanDecorator[0] != nil { + d._spanDecorator = spanDecorator[0] + } + + return d +} + +// Aggregate implements delivery.Delivery +func (_d telemetryMiddleware) Aggregate(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.AggregatePublishedOptions) (result map[string]interface{}, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Delivery.Aggregate") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "collectionId": collectionId, + "filter": filter, + "options": options}, map[string]interface{}{ + "result": result, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Delivery.Aggregate(ctx, spaceId, envId, collectionId, filter, options...) +} + +// FindItems implements delivery.Delivery +func (_d telemetryMiddleware) FindItems(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.FindPublishedOptions) (items []*items.Item, total int, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Delivery.FindItems") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "collectionId": collectionId, + "filter": filter, + "options": options}, map[string]interface{}{ + "items": items, + "total": total, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Delivery.FindItems(ctx, spaceId, envId, collectionId, filter, options...) +} + +// GetCollection implements delivery.Delivery +func (_d telemetryMiddleware) GetCollection(ctx context.Context, spaceId string, envId string, collectionId string) (collection *collections.Collection, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Delivery.GetCollection") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "collectionId": collectionId}, map[string]interface{}{ + "collection": collection, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Delivery.GetCollection(ctx, spaceId, envId, collectionId) +} + +// GetEnvironment implements delivery.Delivery +func (_d telemetryMiddleware) GetEnvironment(ctx context.Context, spaceId string, envId string) (env *environments.Environment, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Delivery.GetEnvironment") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId}, map[string]interface{}{ + "env": env, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Delivery.GetEnvironment(ctx, spaceId, envId) +} + +// GetItem implements delivery.Delivery +func (_d telemetryMiddleware) GetItem(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, options ...*items.GetPublishedOptions) (item *items.Item, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Delivery.GetItem") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "collectionId": collectionId, + "itemId": itemId, + "options": options}, map[string]interface{}{ + "item": item, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Delivery.GetItem(ctx, spaceId, envId, collectionId, itemId, options...) +} + +// ListCollections implements delivery.Delivery +func (_d telemetryMiddleware) ListCollections(ctx context.Context, spaceId string, envId string) (collections []*collections.Collection, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Delivery.ListCollections") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId}, map[string]interface{}{ + "collections": collections, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Delivery.ListCollections(ctx, spaceId, envId) +} + +// ListEnvironments implements delivery.Delivery +func (_d telemetryMiddleware) ListEnvironments(ctx context.Context, spaceId string) (envs []*environments.Environment, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Delivery.ListEnvironments") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId}, map[string]interface{}{ + "envs": envs, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Delivery.ListEnvironments(ctx, spaceId) +} + +// ListLocales implements delivery.Delivery +func (_d telemetryMiddleware) ListLocales(ctx context.Context, spaceId string) (locales []*locales.Locale, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Delivery.ListLocales") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId}, map[string]interface{}{ + "locales": locales, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Delivery.ListLocales(ctx, spaceId) +} diff --git a/pkg/environments/middleware/telemetry_middleware.go b/pkg/environments/middleware/telemetry_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..3e27536fb5458dc05dd2f81bbd3ff85830f09c03 --- /dev/null +++ b/pkg/environments/middleware/telemetry_middleware.go @@ -0,0 +1,208 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/telemetry +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/environments -i Environments -t ../../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l "" + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/environments" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +// telemetryMiddleware implements environments.Environments interface instrumented with opentracing spans +type telemetryMiddleware struct { + environments.Environments + _instance string + _spanDecorator func(span trace.Span, params, results map[string]interface{}) +} + +// TelemetryMiddleware returns telemetryMiddleware +func TelemetryMiddleware(base environments.Environments, instance string, spanDecorator ...func(span trace.Span, params, results map[string]interface{})) telemetryMiddleware { + d := telemetryMiddleware{ + Environments: base, + _instance: instance, + } + + if len(spanDecorator) > 0 && spanDecorator[0] != nil { + d._spanDecorator = spanDecorator[0] + } + + return d +} + +// Create implements environments.Environments +func (_d telemetryMiddleware) Create(ctx context.Context, env *environments.Environment) (created *environments.Environment, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Environments.Create") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "env": env}, map[string]interface{}{ + "created": created, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Environments.Create(ctx, env) +} + +// Delete implements environments.Environments +func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string, envId string) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Environments.Delete") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Environments.Delete(ctx, spaceId, envId) +} + +// Get implements environments.Environments +func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, envId string) (env *environments.Environment, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Environments.Get") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId}, map[string]interface{}{ + "env": env, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Environments.Get(ctx, spaceId, envId) +} + +// List implements environments.Environments +func (_d telemetryMiddleware) List(ctx context.Context, spaceId string) (envs []*environments.Environment, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Environments.List") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId}, map[string]interface{}{ + "envs": envs, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Environments.List(ctx, spaceId) +} + +// Migrate implements environments.Environments +func (_d telemetryMiddleware) Migrate(ctx context.Context, spaceId string, envId string, options ...*environments.MigrateOptions) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Environments.Migrate") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "options": options}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Environments.Migrate(ctx, spaceId, envId, options...) +} + +// RemoveAlias implements environments.Environments +func (_d telemetryMiddleware) RemoveAlias(ctx context.Context, spaceId string, envId string, alias string) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Environments.RemoveAlias") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "alias": alias}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Environments.RemoveAlias(ctx, spaceId, envId, alias) +} + +// SetAlias implements environments.Environments +func (_d telemetryMiddleware) SetAlias(ctx context.Context, spaceId string, envId string, alias string) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Environments.SetAlias") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "alias": alias}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Environments.SetAlias(ctx, spaceId, envId, alias) +} + +// Update implements environments.Environments +func (_d telemetryMiddleware) Update(ctx context.Context, env *environments.Environment) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Environments.Update") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "env": env}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Environments.Update(ctx, env) +} diff --git a/pkg/environments/mocks/EnvironmentConfigurationObserver.go b/pkg/environments/mocks/EnvironmentConfigurationObserver.go new file mode 100644 index 0000000000000000000000000000000000000000..e5920c9de716195cbcc1efcd71fbcb75b91d5c40 --- /dev/null +++ b/pkg/environments/mocks/EnvironmentConfigurationObserver.go @@ -0,0 +1,44 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + environments "git.perx.ru/perxis/perxis-go/pkg/environments" + mock "github.com/stretchr/testify/mock" +) + +// EnvironmentConfigurationObserver is an autogenerated mock type for the EnvironmentConfigurationObserver type +type EnvironmentConfigurationObserver struct { + mock.Mock +} + +// OnEnvironmentConfiguration provides a mock function with given fields: ctx, before, after +func (_m *EnvironmentConfigurationObserver) OnEnvironmentConfiguration(ctx context.Context, before *environments.Environment, after *environments.Environment) error { + ret := _m.Called(ctx, before, after) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *environments.Environment, *environments.Environment) error); ok { + r0 = rf(ctx, before, after) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +type mockConstructorTestingTNewEnvironmentConfigurationObserver interface { + mock.TestingT + Cleanup(func()) +} + +// NewEnvironmentConfigurationObserver creates a new instance of EnvironmentConfigurationObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewEnvironmentConfigurationObserver(t mockConstructorTestingTNewEnvironmentConfigurationObserver) *EnvironmentConfigurationObserver { + mock := &EnvironmentConfigurationObserver{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/environments/mocks/EnvironmentCreatedObserver.go b/pkg/environments/mocks/EnvironmentCreatedObserver.go new file mode 100644 index 0000000000000000000000000000000000000000..a2a0eb73e40ef01d0e3732a6011facd3cd4b7abe --- /dev/null +++ b/pkg/environments/mocks/EnvironmentCreatedObserver.go @@ -0,0 +1,51 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + environments "git.perx.ru/perxis/perxis-go/pkg/environments" + mock "github.com/stretchr/testify/mock" +) + +// EnvironmentCreatedObserver is an autogenerated mock type for the EnvironmentCreatedObserver type +type EnvironmentCreatedObserver struct { + mock.Mock +} + +// OnEnvironmentCreated provides a mock function with given fields: ctx, env +func (_m *EnvironmentCreatedObserver) OnEnvironmentCreated(ctx context.Context, env *environments.Environment) (string, error) { + ret := _m.Called(ctx, env) + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, *environments.Environment) string); ok { + r0 = rf(ctx, env) + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *environments.Environment) error); ok { + r1 = rf(ctx, env) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type mockConstructorTestingTNewEnvironmentCreatedObserver interface { + mock.TestingT + Cleanup(func()) +} + +// NewEnvironmentCreatedObserver creates a new instance of EnvironmentCreatedObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewEnvironmentCreatedObserver(t mockConstructorTestingTNewEnvironmentCreatedObserver) *EnvironmentCreatedObserver { + mock := &EnvironmentCreatedObserver{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/environments/mocks/EnvironmentDeletedObserver.go b/pkg/environments/mocks/EnvironmentDeletedObserver.go new file mode 100644 index 0000000000000000000000000000000000000000..852cec94086338d53518afff08d18764b88e5170 --- /dev/null +++ b/pkg/environments/mocks/EnvironmentDeletedObserver.go @@ -0,0 +1,44 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + environments "git.perx.ru/perxis/perxis-go/pkg/environments" + mock "github.com/stretchr/testify/mock" +) + +// EnvironmentDeletedObserver is an autogenerated mock type for the EnvironmentDeletedObserver type +type EnvironmentDeletedObserver struct { + mock.Mock +} + +// OnEnvironmentDeleted provides a mock function with given fields: ctx, env +func (_m *EnvironmentDeletedObserver) OnEnvironmentDeleted(ctx context.Context, env *environments.Environment) error { + ret := _m.Called(ctx, env) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *environments.Environment) error); ok { + r0 = rf(ctx, env) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +type mockConstructorTestingTNewEnvironmentDeletedObserver interface { + mock.TestingT + Cleanup(func()) +} + +// NewEnvironmentDeletedObserver creates a new instance of EnvironmentDeletedObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewEnvironmentDeletedObserver(t mockConstructorTestingTNewEnvironmentDeletedObserver) *EnvironmentDeletedObserver { + mock := &EnvironmentDeletedObserver{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/environments/mocks/EnvironmentMigratedObserver.go b/pkg/environments/mocks/EnvironmentMigratedObserver.go new file mode 100644 index 0000000000000000000000000000000000000000..a2f042880ffe88d86187263d1688596d9a878507 --- /dev/null +++ b/pkg/environments/mocks/EnvironmentMigratedObserver.go @@ -0,0 +1,44 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + environments "git.perx.ru/perxis/perxis-go/pkg/environments" + mock "github.com/stretchr/testify/mock" +) + +// EnvironmentMigratedObserver is an autogenerated mock type for the EnvironmentMigratedObserver type +type EnvironmentMigratedObserver struct { + mock.Mock +} + +// OnEnvironmentMigrated provides a mock function with given fields: ctx, env +func (_m *EnvironmentMigratedObserver) OnEnvironmentMigrated(ctx context.Context, env *environments.Environment) error { + ret := _m.Called(ctx, env) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *environments.Environment) error); ok { + r0 = rf(ctx, env) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +type mockConstructorTestingTNewEnvironmentMigratedObserver interface { + mock.TestingT + Cleanup(func()) +} + +// NewEnvironmentMigratedObserver creates a new instance of EnvironmentMigratedObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewEnvironmentMigratedObserver(t mockConstructorTestingTNewEnvironmentMigratedObserver) *EnvironmentMigratedObserver { + mock := &EnvironmentMigratedObserver{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/environments/mocks/EnvironmentObserver.go b/pkg/environments/mocks/EnvironmentObserver.go new file mode 100644 index 0000000000000000000000000000000000000000..309d0ed217317c53be90e4f6a43afcddc3587eb4 --- /dev/null +++ b/pkg/environments/mocks/EnvironmentObserver.go @@ -0,0 +1,25 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// EnvironmentObserver is an autogenerated mock type for the EnvironmentObserver type +type EnvironmentObserver struct { + mock.Mock +} + +type mockConstructorTestingTNewEnvironmentObserver interface { + mock.TestingT + Cleanup(func()) +} + +// NewEnvironmentObserver creates a new instance of EnvironmentObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewEnvironmentObserver(t mockConstructorTestingTNewEnvironmentObserver) *EnvironmentObserver { + mock := &EnvironmentObserver{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/environments/mocks/EnvironmentUpdatedObserver.go b/pkg/environments/mocks/EnvironmentUpdatedObserver.go new file mode 100644 index 0000000000000000000000000000000000000000..4a7e76673439dcf09d9b3b52c461482e637960a3 --- /dev/null +++ b/pkg/environments/mocks/EnvironmentUpdatedObserver.go @@ -0,0 +1,44 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + environments "git.perx.ru/perxis/perxis-go/pkg/environments" + mock "github.com/stretchr/testify/mock" +) + +// EnvironmentUpdatedObserver is an autogenerated mock type for the EnvironmentUpdatedObserver type +type EnvironmentUpdatedObserver struct { + mock.Mock +} + +// OnEnvironmentUpdated provides a mock function with given fields: ctx, before, after +func (_m *EnvironmentUpdatedObserver) OnEnvironmentUpdated(ctx context.Context, before *environments.Environment, after *environments.Environment) error { + ret := _m.Called(ctx, before, after) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *environments.Environment, *environments.Environment) error); ok { + r0 = rf(ctx, before, after) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +type mockConstructorTestingTNewEnvironmentUpdatedObserver interface { + mock.TestingT + Cleanup(func()) +} + +// NewEnvironmentUpdatedObserver creates a new instance of EnvironmentUpdatedObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewEnvironmentUpdatedObserver(t mockConstructorTestingTNewEnvironmentUpdatedObserver) *EnvironmentUpdatedObserver { + mock := &EnvironmentUpdatedObserver{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/environments/mocks/Storage.go b/pkg/environments/mocks/Storage.go new file mode 100644 index 0000000000000000000000000000000000000000..68411694c5fc03e497e8c37e6a1ff0a1f1a68721 --- /dev/null +++ b/pkg/environments/mocks/Storage.go @@ -0,0 +1,195 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + environments "git.perx.ru/perxis/perxis-go/pkg/environments" + mock "github.com/stretchr/testify/mock" +) + +// Storage is an autogenerated mock type for the Storage type +type Storage struct { + mock.Mock +} + +// Create provides a mock function with given fields: ctx, create +func (_m *Storage) Create(ctx context.Context, create *environments.Environment) (*environments.Environment, error) { + ret := _m.Called(ctx, create) + + var r0 *environments.Environment + if rf, ok := ret.Get(0).(func(context.Context, *environments.Environment) *environments.Environment); ok { + r0 = rf(ctx, create) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*environments.Environment) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *environments.Environment) error); ok { + r1 = rf(ctx, create) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Delete provides a mock function with given fields: ctx, spaceId, envId +func (_m *Storage) Delete(ctx context.Context, spaceId string, envId string) error { + ret := _m.Called(ctx, spaceId, envId) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { + r0 = rf(ctx, spaceId, envId) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Get provides a mock function with given fields: ctx, spaceId, envId +func (_m *Storage) Get(ctx context.Context, spaceId string, envId string) (*environments.Environment, error) { + ret := _m.Called(ctx, spaceId, envId) + + var r0 *environments.Environment + if rf, ok := ret.Get(0).(func(context.Context, string, string) *environments.Environment); ok { + r0 = rf(ctx, spaceId, envId) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*environments.Environment) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { + r1 = rf(ctx, spaceId, envId) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Init provides a mock function with given fields: ctx, spaceID +func (_m *Storage) Init(ctx context.Context, spaceID string) error { + ret := _m.Called(ctx, spaceID) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { + r0 = rf(ctx, spaceID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// List provides a mock function with given fields: ctx, spaceId +func (_m *Storage) List(ctx context.Context, spaceId string) ([]*environments.Environment, error) { + ret := _m.Called(ctx, spaceId) + + var r0 []*environments.Environment + if rf, ok := ret.Get(0).(func(context.Context, string) []*environments.Environment); ok { + r0 = rf(ctx, spaceId) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*environments.Environment) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, spaceId) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RemoveAlias provides a mock function with given fields: ctx, spaceId, envId, alias +func (_m *Storage) RemoveAlias(ctx context.Context, spaceId string, envId string, alias string) error { + ret := _m.Called(ctx, spaceId, envId, alias) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) error); ok { + r0 = rf(ctx, spaceId, envId, alias) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Reset provides a mock function with given fields: ctx, spaceId +func (_m *Storage) Reset(ctx context.Context, spaceId string) { + _m.Called(ctx, spaceId) +} + +// SetAlias provides a mock function with given fields: ctx, spaceId, envId, alias +func (_m *Storage) SetAlias(ctx context.Context, spaceId string, envId string, alias string) error { + ret := _m.Called(ctx, spaceId, envId, alias) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) error); ok { + r0 = rf(ctx, spaceId, envId, alias) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Update provides a mock function with given fields: ctx, up, options +func (_m *Storage) Update(ctx context.Context, up *environments.Environment, options ...*environments.UpdateOptions) (int, int, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, up) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 int + if rf, ok := ret.Get(0).(func(context.Context, *environments.Environment, ...*environments.UpdateOptions) int); ok { + r0 = rf(ctx, up, options...) + } else { + r0 = ret.Get(0).(int) + } + + var r1 int + if rf, ok := ret.Get(1).(func(context.Context, *environments.Environment, ...*environments.UpdateOptions) int); ok { + r1 = rf(ctx, up, options...) + } else { + r1 = ret.Get(1).(int) + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, *environments.Environment, ...*environments.UpdateOptions) error); ok { + r2 = rf(ctx, up, options...) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +type mockConstructorTestingTNewStorage interface { + mock.TestingT + Cleanup(func()) +} + +// NewStorage creates a new instance of Storage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewStorage(t mockConstructorTestingTNewStorage) *Storage { + mock := &Storage{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/environments/observer.go b/pkg/environments/observer.go new file mode 100644 index 0000000000000000000000000000000000000000..0368d190acec46508eaa356b43da16791e0a780d --- /dev/null +++ b/pkg/environments/observer.go @@ -0,0 +1,41 @@ +package environments + +import "context" + +type EnvironmentObserver interface{} + +// EnvironmentCreatedObserver интерфейс наблюдателя вызываемый РїСЂРё создании окружения. +// Рнициировать оповещение наблюдателя может вызов метода `Environments.Create` +// Оповещение выполнятся РІ асинхронном режиме. +type EnvironmentCreatedObserver interface { + OnEnvironmentCreated(ctx context.Context, env *Environment) (delayedTaskID string, err error) +} + +// EnvironmentUpdatedObserver интерфейс наблюдателя вызываемый РїСЂРё изменении окружения. +// Рнициировать оповещение наблюдателя может вызов методов `Environments.Update`, +// `Environments.SetAlias`, `Environments.RemoveAlias` +// Оповещение выполнятся РІ асинхронном режиме. +type EnvironmentUpdatedObserver interface { + OnEnvironmentUpdated(ctx context.Context, before, after *Environment) error +} + +// EnvironmentDeletedObserver интерфейс наблюдателя вызываемый РїСЂРё удалении окружения. +// Рнициировать оповещение наблюдателя может вызов метода `Environments.Delete`. +// Оповещение выполнятся РІ асинхронном режиме. +type EnvironmentDeletedObserver interface { + OnEnvironmentDeleted(ctx context.Context, env *Environment) error +} + +// EnvironmentConfigurationObserver интерфейс наблюдателя вызываемый РїСЂРё изменении конфигурации +// окружения. +// Рнициировать оповещение наблюдателя может вызов методов `Environments.OnSpaceUpdate`, +// Оповещение выполнятся РІ асинхронном режиме. +type EnvironmentConfigurationObserver interface { + OnEnvironmentConfiguration(ctx context.Context, before, after *Environment) error +} + +// EnvironmentMigratedObserver интерфейс наблюдателя вызываемый РїСЂРё запуске миграции окружения. +// Рнициировать оповещение наблюдателя может вызов методов `Environments.Migrate`, +type EnvironmentMigratedObserver interface { + OnEnvironmentMigrated(ctx context.Context, env *Environment) error +} diff --git a/pkg/environments/storage.go b/pkg/environments/storage.go new file mode 100644 index 0000000000000000000000000000000000000000..675861e634b4e48cd6a17c77bf8c834fb7cd6e3a --- /dev/null +++ b/pkg/environments/storage.go @@ -0,0 +1,16 @@ +package environments + +import "context" + +type Storage interface { + Create(ctx context.Context, create *Environment) (environment *Environment, err error) + Get(ctx context.Context, spaceId, envId string) (env *Environment, err error) + List(ctx context.Context, spaceId string) (envs []*Environment, err error) + Update(ctx context.Context, up *Environment, options ...*UpdateOptions) (updated, total int, err error) + Delete(ctx context.Context, spaceId, envId string) (err error) + SetAlias(ctx context.Context, spaceId, envId, alias string) (err error) + RemoveAlias(ctx context.Context, spaceId, envId, alias string) (err error) + + Reset(ctx context.Context, spaceId string) + Init(ctx context.Context, spaceID string) error +} diff --git a/pkg/files/middleware/error_logging_middleware.go b/pkg/files/middleware/error_logging_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..18e9b65a502b6cacc1913a9c14cfe5ff0aac8a1c --- /dev/null +++ b/pkg/files/middleware/error_logging_middleware.go @@ -0,0 +1,100 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/error_log +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/files -i Files -t ../../../assets/templates/middleware/error_log -o error_logging_middleware.go -l "" + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/files" + "go.uber.org/zap" +) + +// errorLoggingMiddleware implements files.Files that is instrumented with logging +type errorLoggingMiddleware struct { + logger *zap.Logger + next files.Files +} + +// ErrorLoggingMiddleware instruments an implementation of the files.Files with simple logging +func ErrorLoggingMiddleware(logger *zap.Logger) Middleware { + return func(next files.Files) files.Files { + return &errorLoggingMiddleware{ + next: next, + logger: logger, + } + } +} + +func (m *errorLoggingMiddleware) AbortUpload(ctx context.Context, upload *files.MultipartUpload) (err error) { + logger := m.logger + defer func() { + if err != nil { + logger.Warn("response error", zap.Error(err)) + } + }() + return m.next.AbortUpload(ctx, upload) +} + +func (m *errorLoggingMiddleware) CompleteUpload(ctx context.Context, upload *files.MultipartUpload) (u *files.MultipartUpload, err error) { + logger := m.logger + defer func() { + if err != nil { + logger.Warn("response error", zap.Error(err)) + } + }() + return m.next.CompleteUpload(ctx, upload) +} + +func (m *errorLoggingMiddleware) DeleteFile(ctx context.Context, file *files.File) (err error) { + logger := m.logger + defer func() { + if err != nil { + logger.Warn("response error", zap.Error(err)) + } + }() + return m.next.DeleteFile(ctx, file) +} + +func (m *errorLoggingMiddleware) GetFile(ctx context.Context, file *files.File) (f *files.File, err error) { + logger := m.logger + defer func() { + if err != nil { + logger.Warn("response error", zap.Error(err)) + } + }() + return m.next.GetFile(ctx, file) +} + +func (m *errorLoggingMiddleware) MoveUpload(ctx context.Context, upload *files.MultipartUpload) (file *files.File, err error) { + logger := m.logger + defer func() { + if err != nil { + logger.Warn("response error", zap.Error(err)) + } + }() + return m.next.MoveUpload(ctx, upload) +} + +func (m *errorLoggingMiddleware) StartUpload(ctx context.Context, upload *files.MultipartUpload) (u *files.MultipartUpload, err error) { + logger := m.logger + defer func() { + if err != nil { + logger.Warn("response error", zap.Error(err)) + } + }() + return m.next.StartUpload(ctx, upload) +} + +func (m *errorLoggingMiddleware) Upload(ctx context.Context, file *files.File) (u *files.Upload, err error) { + logger := m.logger + defer func() { + if err != nil { + logger.Warn("response error", zap.Error(err)) + } + }() + return m.next.Upload(ctx, file) +} diff --git a/pkg/files/middleware/logging_middleware.go b/pkg/files/middleware/logging_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..b295fa68cc8367021d5fa5e00a0c850cc27c7cee --- /dev/null +++ b/pkg/files/middleware/logging_middleware.go @@ -0,0 +1,291 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/access_log +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/files -i Files -t ../../../assets/templates/middleware/access_log -o logging_middleware.go -l "" + +import ( + "context" + "fmt" + "time" + + "git.perx.ru/perxis/perxis-go/pkg/auth" + "git.perx.ru/perxis/perxis-go/pkg/files" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +// loggingMiddleware implements files.Files that is instrumented with logging +type loggingMiddleware struct { + logger *zap.Logger + next files.Files +} + +// LoggingMiddleware instruments an implementation of the files.Files with simple logging +func LoggingMiddleware(logger *zap.Logger) Middleware { + return func(next files.Files) files.Files { + return &loggingMiddleware{ + next: next, + logger: logger, + } + } +} + +func (m *loggingMiddleware) AbortUpload(ctx context.Context, upload *files.MultipartUpload) (err error) { + begin := time.Now() + var fields []zapcore.Field + for k, v := range map[string]interface{}{ + "ctx": ctx, + "upload": upload} { + if k == "ctx" { + fields = append(fields, zap.String("principal", fmt.Sprint(auth.GetPrincipal(ctx)))) + continue + } + fields = append(fields, zap.Reflect(k, v)) + } + + m.logger.Debug("AbortUpload.Request", fields...) + + err = m.next.AbortUpload(ctx, upload) + + fields = []zapcore.Field{ + zap.Duration("time", time.Since(begin)), + } + + for k, v := range map[string]interface{}{ + "err": err} { + if k == "err" { + err, _ := v.(error) + fields = append(fields, zap.Error(err)) + continue + } + fields = append(fields, zap.Reflect(k, v)) + } + + m.logger.Debug("AbortUpload.Response", fields...) + + return err +} + +func (m *loggingMiddleware) CompleteUpload(ctx context.Context, upload *files.MultipartUpload) (u *files.MultipartUpload, err error) { + begin := time.Now() + var fields []zapcore.Field + for k, v := range map[string]interface{}{ + "ctx": ctx, + "upload": upload} { + if k == "ctx" { + fields = append(fields, zap.String("principal", fmt.Sprint(auth.GetPrincipal(ctx)))) + continue + } + fields = append(fields, zap.Reflect(k, v)) + } + + m.logger.Debug("CompleteUpload.Request", fields...) + + u, err = m.next.CompleteUpload(ctx, upload) + + fields = []zapcore.Field{ + zap.Duration("time", time.Since(begin)), + } + + for k, v := range map[string]interface{}{ + "u": u, + "err": err} { + if k == "err" { + err, _ := v.(error) + fields = append(fields, zap.Error(err)) + continue + } + fields = append(fields, zap.Reflect(k, v)) + } + + m.logger.Debug("CompleteUpload.Response", fields...) + + return u, err +} + +func (m *loggingMiddleware) DeleteFile(ctx context.Context, file *files.File) (err error) { + begin := time.Now() + var fields []zapcore.Field + for k, v := range map[string]interface{}{ + "ctx": ctx, + "file": file} { + if k == "ctx" { + fields = append(fields, zap.String("principal", fmt.Sprint(auth.GetPrincipal(ctx)))) + continue + } + fields = append(fields, zap.Reflect(k, v)) + } + + m.logger.Debug("DeleteFile.Request", fields...) + + err = m.next.DeleteFile(ctx, file) + + fields = []zapcore.Field{ + zap.Duration("time", time.Since(begin)), + } + + for k, v := range map[string]interface{}{ + "err": err} { + if k == "err" { + err, _ := v.(error) + fields = append(fields, zap.Error(err)) + continue + } + fields = append(fields, zap.Reflect(k, v)) + } + + m.logger.Debug("DeleteFile.Response", fields...) + + return err +} + +func (m *loggingMiddleware) GetFile(ctx context.Context, file *files.File) (f *files.File, err error) { + begin := time.Now() + var fields []zapcore.Field + for k, v := range map[string]interface{}{ + "ctx": ctx, + "file": file} { + if k == "ctx" { + fields = append(fields, zap.String("principal", fmt.Sprint(auth.GetPrincipal(ctx)))) + continue + } + fields = append(fields, zap.Reflect(k, v)) + } + + m.logger.Debug("GetFile.Request", fields...) + + f, err = m.next.GetFile(ctx, file) + + fields = []zapcore.Field{ + zap.Duration("time", time.Since(begin)), + } + + for k, v := range map[string]interface{}{ + "f": f, + "err": err} { + if k == "err" { + err, _ := v.(error) + fields = append(fields, zap.Error(err)) + continue + } + fields = append(fields, zap.Reflect(k, v)) + } + + m.logger.Debug("GetFile.Response", fields...) + + return f, err +} + +func (m *loggingMiddleware) MoveUpload(ctx context.Context, upload *files.MultipartUpload) (file *files.File, err error) { + begin := time.Now() + var fields []zapcore.Field + for k, v := range map[string]interface{}{ + "ctx": ctx, + "upload": upload} { + if k == "ctx" { + fields = append(fields, zap.String("principal", fmt.Sprint(auth.GetPrincipal(ctx)))) + continue + } + fields = append(fields, zap.Reflect(k, v)) + } + + m.logger.Debug("MoveUpload.Request", fields...) + + file, err = m.next.MoveUpload(ctx, upload) + + fields = []zapcore.Field{ + zap.Duration("time", time.Since(begin)), + } + + for k, v := range map[string]interface{}{ + "file": file, + "err": err} { + if k == "err" { + err, _ := v.(error) + fields = append(fields, zap.Error(err)) + continue + } + fields = append(fields, zap.Reflect(k, v)) + } + + m.logger.Debug("MoveUpload.Response", fields...) + + return file, err +} + +func (m *loggingMiddleware) StartUpload(ctx context.Context, upload *files.MultipartUpload) (u *files.MultipartUpload, err error) { + begin := time.Now() + var fields []zapcore.Field + for k, v := range map[string]interface{}{ + "ctx": ctx, + "upload": upload} { + if k == "ctx" { + fields = append(fields, zap.String("principal", fmt.Sprint(auth.GetPrincipal(ctx)))) + continue + } + fields = append(fields, zap.Reflect(k, v)) + } + + m.logger.Debug("StartUpload.Request", fields...) + + u, err = m.next.StartUpload(ctx, upload) + + fields = []zapcore.Field{ + zap.Duration("time", time.Since(begin)), + } + + for k, v := range map[string]interface{}{ + "u": u, + "err": err} { + if k == "err" { + err, _ := v.(error) + fields = append(fields, zap.Error(err)) + continue + } + fields = append(fields, zap.Reflect(k, v)) + } + + m.logger.Debug("StartUpload.Response", fields...) + + return u, err +} + +func (m *loggingMiddleware) Upload(ctx context.Context, file *files.File) (u *files.Upload, err error) { + begin := time.Now() + var fields []zapcore.Field + for k, v := range map[string]interface{}{ + "ctx": ctx, + "file": file} { + if k == "ctx" { + fields = append(fields, zap.String("principal", fmt.Sprint(auth.GetPrincipal(ctx)))) + continue + } + fields = append(fields, zap.Reflect(k, v)) + } + + m.logger.Debug("Upload.Request", fields...) + + u, err = m.next.Upload(ctx, file) + + fields = []zapcore.Field{ + zap.Duration("time", time.Since(begin)), + } + + for k, v := range map[string]interface{}{ + "u": u, + "err": err} { + if k == "err" { + err, _ := v.(error) + fields = append(fields, zap.Error(err)) + continue + } + fields = append(fields, zap.Reflect(k, v)) + } + + m.logger.Debug("Upload.Response", fields...) + + return u, err +} diff --git a/pkg/files/middleware/middleware.go b/pkg/files/middleware/middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..39c64f8764e904b53fcce18bf8b990424ad03149 --- /dev/null +++ b/pkg/files/middleware/middleware.go @@ -0,0 +1,28 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/middleware +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/files -i Files -t ../../../assets/templates/middleware/middleware -o middleware.go -l "" + +import ( + "git.perx.ru/perxis/perxis-go/pkg/files" + "go.uber.org/zap" +) + +type Middleware func(files.Files) files.Files + +func WithLog(s files.Files, logger *zap.Logger, log_access bool) files.Files { + if logger == nil { + logger = zap.NewNop() + } + + logger = logger.Named("Files") + s = ErrorLoggingMiddleware(logger)(s) + if log_access { + s = LoggingMiddleware(logger)(s) + } + s = RecoveringMiddleware(logger)(s) + return s +} diff --git a/pkg/files/middleware/recovering_middleware.go b/pkg/files/middleware/recovering_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..3143498e490013dd747185a339c4111df107dd90 --- /dev/null +++ b/pkg/files/middleware/recovering_middleware.go @@ -0,0 +1,115 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/recovery +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/files -i Files -t ../../../assets/templates/middleware/recovery -o recovering_middleware.go -l "" + +import ( + "context" + "fmt" + + "git.perx.ru/perxis/perxis-go/pkg/files" + "go.uber.org/zap" +) + +// recoveringMiddleware implements files.Files that is instrumented with logging +type recoveringMiddleware struct { + logger *zap.Logger + next files.Files +} + +// RecoveringMiddleware instruments an implementation of the files.Files with simple logging +func RecoveringMiddleware(logger *zap.Logger) Middleware { + return func(next files.Files) files.Files { + return &recoveringMiddleware{ + next: next, + logger: logger, + } + } +} + +func (m *recoveringMiddleware) AbortUpload(ctx context.Context, upload *files.MultipartUpload) (err error) { + logger := m.logger + defer func() { + if r := recover(); r != nil { + logger.Error("panic", zap.Error(fmt.Errorf("%v", r))) + err = fmt.Errorf("%v", r) + } + }() + + return m.next.AbortUpload(ctx, upload) +} + +func (m *recoveringMiddleware) CompleteUpload(ctx context.Context, upload *files.MultipartUpload) (u *files.MultipartUpload, err error) { + logger := m.logger + defer func() { + if r := recover(); r != nil { + logger.Error("panic", zap.Error(fmt.Errorf("%v", r))) + err = fmt.Errorf("%v", r) + } + }() + + return m.next.CompleteUpload(ctx, upload) +} + +func (m *recoveringMiddleware) DeleteFile(ctx context.Context, file *files.File) (err error) { + logger := m.logger + defer func() { + if r := recover(); r != nil { + logger.Error("panic", zap.Error(fmt.Errorf("%v", r))) + err = fmt.Errorf("%v", r) + } + }() + + return m.next.DeleteFile(ctx, file) +} + +func (m *recoveringMiddleware) GetFile(ctx context.Context, file *files.File) (f *files.File, err error) { + logger := m.logger + defer func() { + if r := recover(); r != nil { + logger.Error("panic", zap.Error(fmt.Errorf("%v", r))) + err = fmt.Errorf("%v", r) + } + }() + + return m.next.GetFile(ctx, file) +} + +func (m *recoveringMiddleware) MoveUpload(ctx context.Context, upload *files.MultipartUpload) (file *files.File, err error) { + logger := m.logger + defer func() { + if r := recover(); r != nil { + logger.Error("panic", zap.Error(fmt.Errorf("%v", r))) + err = fmt.Errorf("%v", r) + } + }() + + return m.next.MoveUpload(ctx, upload) +} + +func (m *recoveringMiddleware) StartUpload(ctx context.Context, upload *files.MultipartUpload) (u *files.MultipartUpload, err error) { + logger := m.logger + defer func() { + if r := recover(); r != nil { + logger.Error("panic", zap.Error(fmt.Errorf("%v", r))) + err = fmt.Errorf("%v", r) + } + }() + + return m.next.StartUpload(ctx, upload) +} + +func (m *recoveringMiddleware) Upload(ctx context.Context, file *files.File) (u *files.Upload, err error) { + logger := m.logger + defer func() { + if r := recover(); r != nil { + logger.Error("panic", zap.Error(fmt.Errorf("%v", r))) + err = fmt.Errorf("%v", r) + } + }() + + return m.next.Upload(ctx, file) +} diff --git a/pkg/files/middleware/telemetry_middleware.go b/pkg/files/middleware/telemetry_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..21e10e8df709561cc9234df1a2621754c29ebe49 --- /dev/null +++ b/pkg/files/middleware/telemetry_middleware.go @@ -0,0 +1,182 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/telemetry +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/files -i Files -t ../../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l "" + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/files" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +// telemetryMiddleware implements files.Files interface instrumented with opentracing spans +type telemetryMiddleware struct { + files.Files + _instance string + _spanDecorator func(span trace.Span, params, results map[string]interface{}) +} + +// TelemetryMiddleware returns telemetryMiddleware +func TelemetryMiddleware(base files.Files, instance string, spanDecorator ...func(span trace.Span, params, results map[string]interface{})) telemetryMiddleware { + d := telemetryMiddleware{ + Files: base, + _instance: instance, + } + + if len(spanDecorator) > 0 && spanDecorator[0] != nil { + d._spanDecorator = spanDecorator[0] + } + + return d +} + +// AbortUpload implements files.Files +func (_d telemetryMiddleware) AbortUpload(ctx context.Context, upload *files.MultipartUpload) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Files.AbortUpload") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "upload": upload}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Files.AbortUpload(ctx, upload) +} + +// CompleteUpload implements files.Files +func (_d telemetryMiddleware) CompleteUpload(ctx context.Context, upload *files.MultipartUpload) (u *files.MultipartUpload, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Files.CompleteUpload") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "upload": upload}, map[string]interface{}{ + "u": u, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Files.CompleteUpload(ctx, upload) +} + +// DeleteFile implements files.Files +func (_d telemetryMiddleware) DeleteFile(ctx context.Context, file *files.File) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Files.DeleteFile") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "file": file}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Files.DeleteFile(ctx, file) +} + +// GetFile implements files.Files +func (_d telemetryMiddleware) GetFile(ctx context.Context, file *files.File) (f *files.File, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Files.GetFile") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "file": file}, map[string]interface{}{ + "f": f, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Files.GetFile(ctx, file) +} + +// MoveUpload implements files.Files +func (_d telemetryMiddleware) MoveUpload(ctx context.Context, upload *files.MultipartUpload) (file *files.File, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Files.MoveUpload") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "upload": upload}, map[string]interface{}{ + "file": file, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Files.MoveUpload(ctx, upload) +} + +// StartUpload implements files.Files +func (_d telemetryMiddleware) StartUpload(ctx context.Context, upload *files.MultipartUpload) (u *files.MultipartUpload, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Files.StartUpload") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "upload": upload}, map[string]interface{}{ + "u": u, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Files.StartUpload(ctx, upload) +} + +// Upload implements files.Files +func (_d telemetryMiddleware) Upload(ctx context.Context, file *files.File) (u *files.Upload, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Files.Upload") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "file": file}, map[string]interface{}{ + "u": u, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Files.Upload(ctx, file) +} diff --git a/pkg/files/mocks/Middleware.go b/pkg/files/mocks/Middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..4a47061df1e1fe7b868cba7da09a5615cf313985 --- /dev/null +++ b/pkg/files/mocks/Middleware.go @@ -0,0 +1,45 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + files "git.perx.ru/perxis/perxis-go/pkg/files" + + mock "github.com/stretchr/testify/mock" +) + +// Middleware is an autogenerated mock type for the Middleware type +type Middleware struct { + mock.Mock +} + +// Execute provides a mock function with given fields: _a0 +func (_m *Middleware) Execute(_a0 files.Files) files.Files { + ret := _m.Called(_a0) + + var r0 files.Files + if rf, ok := ret.Get(0).(func(files.Files) files.Files); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(files.Files) + } + } + + return r0 +} + +type mockConstructorTestingTNewMiddleware interface { + mock.TestingT + Cleanup(func()) +} + +// NewMiddleware creates a new instance of Middleware. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMiddleware(t mockConstructorTestingTNewMiddleware) *Middleware { + mock := &Middleware{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/files/mocks/Storage.go b/pkg/files/mocks/Storage.go new file mode 100644 index 0000000000000000000000000000000000000000..7d4a411253dc517fb1a034f79035cf85756daccd --- /dev/null +++ b/pkg/files/mocks/Storage.go @@ -0,0 +1,173 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + files "git.perx.ru/perxis/perxis-go/pkg/files" + mock "github.com/stretchr/testify/mock" +) + +// Storage is an autogenerated mock type for the Storage type +type Storage struct { + mock.Mock +} + +// AbortUpload provides a mock function with given fields: ctx, upload +func (_m *Storage) AbortUpload(ctx context.Context, upload *files.MultipartUpload) error { + ret := _m.Called(ctx, upload) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *files.MultipartUpload) error); ok { + r0 = rf(ctx, upload) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// CompleteUpload provides a mock function with given fields: ctx, upload +func (_m *Storage) CompleteUpload(ctx context.Context, upload *files.MultipartUpload) (*files.MultipartUpload, error) { + ret := _m.Called(ctx, upload) + + var r0 *files.MultipartUpload + if rf, ok := ret.Get(0).(func(context.Context, *files.MultipartUpload) *files.MultipartUpload); ok { + r0 = rf(ctx, upload) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*files.MultipartUpload) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *files.MultipartUpload) error); ok { + r1 = rf(ctx, upload) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// DeleteFile provides a mock function with given fields: ctx, file +func (_m *Storage) DeleteFile(ctx context.Context, file *files.File) error { + ret := _m.Called(ctx, file) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *files.File) error); ok { + r0 = rf(ctx, file) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// GetFile provides a mock function with given fields: ctx, file +func (_m *Storage) GetFile(ctx context.Context, file *files.File) (*files.File, error) { + ret := _m.Called(ctx, file) + + var r0 *files.File + if rf, ok := ret.Get(0).(func(context.Context, *files.File) *files.File); ok { + r0 = rf(ctx, file) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*files.File) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *files.File) error); ok { + r1 = rf(ctx, file) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Move provides a mock function with given fields: ctx, src, dst +func (_m *Storage) Move(ctx context.Context, src *files.File, dst *files.File) (*files.File, error) { + ret := _m.Called(ctx, src, dst) + + var r0 *files.File + if rf, ok := ret.Get(0).(func(context.Context, *files.File, *files.File) *files.File); ok { + r0 = rf(ctx, src, dst) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*files.File) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *files.File, *files.File) error); ok { + r1 = rf(ctx, src, dst) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StartUpload provides a mock function with given fields: ctx, upload +func (_m *Storage) StartUpload(ctx context.Context, upload *files.MultipartUpload) (*files.MultipartUpload, error) { + ret := _m.Called(ctx, upload) + + var r0 *files.MultipartUpload + if rf, ok := ret.Get(0).(func(context.Context, *files.MultipartUpload) *files.MultipartUpload); ok { + r0 = rf(ctx, upload) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*files.MultipartUpload) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *files.MultipartUpload) error); ok { + r1 = rf(ctx, upload) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Upload provides a mock function with given fields: ctx, file +func (_m *Storage) Upload(ctx context.Context, file *files.File) (*files.Upload, error) { + ret := _m.Called(ctx, file) + + var r0 *files.Upload + if rf, ok := ret.Get(0).(func(context.Context, *files.File) *files.Upload); ok { + r0 = rf(ctx, file) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*files.Upload) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *files.File) error); ok { + r1 = rf(ctx, file) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type mockConstructorTestingTNewStorage interface { + mock.TestingT + Cleanup(func()) +} + +// NewStorage creates a new instance of Storage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewStorage(t mockConstructorTestingTNewStorage) *Storage { + mock := &Storage{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/files/storage.go b/pkg/files/storage.go new file mode 100644 index 0000000000000000000000000000000000000000..085d01f8a21ca3bd922f31b85b137d99209815a6 --- /dev/null +++ b/pkg/files/storage.go @@ -0,0 +1,29 @@ +package files + +import "context" + +type Storage interface { + // StartUpload - инициирует процедуру загрузки файла РІ файловое хранилище. + // Рспользуется клиентским приложением для начала загрузки файла + StartUpload(ctx context.Context, upload *MultipartUpload) (*MultipartUpload, error) + + // CompleteUpload - завершает процедуру загрузки файла + CompleteUpload(ctx context.Context, upload *MultipartUpload) (*MultipartUpload, error) + + // AbortUpload - прерывает процедуру загрузки файла, РІСЃРµ загруженные части файла удаляются РёР· хранилища + AbortUpload(ctx context.Context, upload *MultipartUpload) error + + // Move - перемещает файл СЃ ключом src.Key РїРѕ РЅРѕРІРѕРјСѓ пути dst.Key + Move(ctx context.Context, src, dst *File) (*File, error) + + // Upload - одиночная загрузка файла РІ хранилище + // Максимальный размер загружаемого файла - 5ГБ + Upload(ctx context.Context, file *File) (*Upload, error) + + // GetFile - проверяет, существует ли файл РІ хранилище Рё + // возвращает объект 'File' СЃ заполненным URL + GetFile(ctx context.Context, file *File) (f *File, err error) + + // DeleteFile - удаляет файл РїРѕ ключу + DeleteFile(ctx context.Context, file *File) error +} diff --git a/pkg/images/middleware/error_logging_middleware.go b/pkg/images/middleware/error_logging_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..749db73b2ed5682c9725c920ae4b850eff5e67e1 --- /dev/null +++ b/pkg/images/middleware/error_logging_middleware.go @@ -0,0 +1,41 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/error_log +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/images -i Images -t ../../../assets/templates/middleware/error_log -o error_logging_middleware.go -l "" + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/files" + "git.perx.ru/perxis/perxis-go/pkg/images" + "go.uber.org/zap" +) + +// errorLoggingMiddleware implements images.Images that is instrumented with logging +type errorLoggingMiddleware struct { + logger *zap.Logger + next images.Images +} + +// ErrorLoggingMiddleware instruments an implementation of the images.Images with simple logging +func ErrorLoggingMiddleware(logger *zap.Logger) Middleware { + return func(next images.Images) images.Images { + return &errorLoggingMiddleware{ + next: next, + logger: logger, + } + } +} + +func (m *errorLoggingMiddleware) Get(ctx context.Context, source *files.File, opts *images.GetOptions) (result *files.File, err error) { + logger := m.logger + defer func() { + if err != nil { + logger.Warn("response error", zap.Error(err)) + } + }() + return m.next.Get(ctx, source, opts) +} diff --git a/pkg/images/middleware/logging_middleware.go b/pkg/images/middleware/logging_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..fb7d0af4faecfde621e295b0da8e6f2e098e56a1 --- /dev/null +++ b/pkg/images/middleware/logging_middleware.go @@ -0,0 +1,73 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/access_log +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/images -i Images -t ../../../assets/templates/middleware/access_log -o logging_middleware.go -l "" + +import ( + "context" + "fmt" + "time" + + "git.perx.ru/perxis/perxis-go/pkg/auth" + "git.perx.ru/perxis/perxis-go/pkg/files" + "git.perx.ru/perxis/perxis-go/pkg/images" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +// loggingMiddleware implements images.Images that is instrumented with logging +type loggingMiddleware struct { + logger *zap.Logger + next images.Images +} + +// LoggingMiddleware instruments an implementation of the images.Images with simple logging +func LoggingMiddleware(logger *zap.Logger) Middleware { + return func(next images.Images) images.Images { + return &loggingMiddleware{ + next: next, + logger: logger, + } + } +} + +func (m *loggingMiddleware) Get(ctx context.Context, source *files.File, opts *images.GetOptions) (result *files.File, err error) { + begin := time.Now() + var fields []zapcore.Field + for k, v := range map[string]interface{}{ + "ctx": ctx, + "source": source, + "opts": opts} { + if k == "ctx" { + fields = append(fields, zap.String("principal", fmt.Sprint(auth.GetPrincipal(ctx)))) + continue + } + fields = append(fields, zap.Reflect(k, v)) + } + + m.logger.Debug("Get.Request", fields...) + + result, err = m.next.Get(ctx, source, opts) + + fields = []zapcore.Field{ + zap.Duration("time", time.Since(begin)), + } + + for k, v := range map[string]interface{}{ + "result": result, + "err": err} { + if k == "err" { + err, _ := v.(error) + fields = append(fields, zap.Error(err)) + continue + } + fields = append(fields, zap.Reflect(k, v)) + } + + m.logger.Debug("Get.Response", fields...) + + return result, err +} diff --git a/pkg/images/middleware/middleware.go b/pkg/images/middleware/middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..d4717a0db627b3f11abfc569cd1c79e30300b93f --- /dev/null +++ b/pkg/images/middleware/middleware.go @@ -0,0 +1,28 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/middleware +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/images -i Images -t ../../../assets/templates/middleware/middleware -o middleware.go -l "" + +import ( + "git.perx.ru/perxis/perxis-go/pkg/images" + "go.uber.org/zap" +) + +type Middleware func(images.Images) images.Images + +func WithLog(s images.Images, logger *zap.Logger, log_access bool) images.Images { + if logger == nil { + logger = zap.NewNop() + } + + logger = logger.Named("Images") + s = ErrorLoggingMiddleware(logger)(s) + if log_access { + s = LoggingMiddleware(logger)(s) + } + s = RecoveringMiddleware(logger)(s) + return s +} diff --git a/pkg/images/middleware/recovering_middleware.go b/pkg/images/middleware/recovering_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..4fe31525e0b587e94a6cb8259ae551b38fd4f450 --- /dev/null +++ b/pkg/images/middleware/recovering_middleware.go @@ -0,0 +1,44 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/recovery +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/images -i Images -t ../../../assets/templates/middleware/recovery -o recovering_middleware.go -l "" + +import ( + "context" + "fmt" + + "git.perx.ru/perxis/perxis-go/pkg/files" + "git.perx.ru/perxis/perxis-go/pkg/images" + "go.uber.org/zap" +) + +// recoveringMiddleware implements images.Images that is instrumented with logging +type recoveringMiddleware struct { + logger *zap.Logger + next images.Images +} + +// RecoveringMiddleware instruments an implementation of the images.Images with simple logging +func RecoveringMiddleware(logger *zap.Logger) Middleware { + return func(next images.Images) images.Images { + return &recoveringMiddleware{ + next: next, + logger: logger, + } + } +} + +func (m *recoveringMiddleware) Get(ctx context.Context, source *files.File, opts *images.GetOptions) (result *files.File, err error) { + logger := m.logger + defer func() { + if r := recover(); r != nil { + logger.Error("panic", zap.Error(fmt.Errorf("%v", r))) + err = fmt.Errorf("%v", r) + } + }() + + return m.next.Get(ctx, source, opts) +} diff --git a/pkg/images/middleware/telemetry_middleware.go b/pkg/images/middleware/telemetry_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..b3cb8bef156613220dac2d1ad01a56bc4bba3723 --- /dev/null +++ b/pkg/images/middleware/telemetry_middleware.go @@ -0,0 +1,60 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/telemetry +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/images -i Images -t ../../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l "" + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/files" + "git.perx.ru/perxis/perxis-go/pkg/images" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +// telemetryMiddleware implements images.Images interface instrumented with opentracing spans +type telemetryMiddleware struct { + images.Images + _instance string + _spanDecorator func(span trace.Span, params, results map[string]interface{}) +} + +// TelemetryMiddleware returns telemetryMiddleware +func TelemetryMiddleware(base images.Images, instance string, spanDecorator ...func(span trace.Span, params, results map[string]interface{})) telemetryMiddleware { + d := telemetryMiddleware{ + Images: base, + _instance: instance, + } + + if len(spanDecorator) > 0 && spanDecorator[0] != nil { + d._spanDecorator = spanDecorator[0] + } + + return d +} + +// Get implements images.Images +func (_d telemetryMiddleware) Get(ctx context.Context, source *files.File, opts *images.GetOptions) (result *files.File, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Images.Get") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "source": source, + "opts": opts}, map[string]interface{}{ + "result": result, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Images.Get(ctx, source, opts) +} diff --git a/pkg/images/mocks/Middleware.go b/pkg/images/mocks/Middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..43ba1dd2b86fd43237c6e83c24a13928a8f8c2d3 --- /dev/null +++ b/pkg/images/mocks/Middleware.go @@ -0,0 +1,45 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + images "git.perx.ru/perxis/perxis-go/pkg/images" + + mock "github.com/stretchr/testify/mock" +) + +// Middleware is an autogenerated mock type for the Middleware type +type Middleware struct { + mock.Mock +} + +// Execute provides a mock function with given fields: _a0 +func (_m *Middleware) Execute(_a0 images.Images) images.Images { + ret := _m.Called(_a0) + + var r0 images.Images + if rf, ok := ret.Get(0).(func(images.Images) images.Images); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(images.Images) + } + } + + return r0 +} + +type mockConstructorTestingTNewMiddleware interface { + mock.TestingT + Cleanup(func()) +} + +// NewMiddleware creates a new instance of Middleware. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMiddleware(t mockConstructorTestingTNewMiddleware) *Middleware { + mock := &Middleware{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/invitations/middleware/telemetry_middleware.go b/pkg/invitations/middleware/telemetry_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..cf79342a3ee7ef978c18b1d785ec40e4d47523bc --- /dev/null +++ b/pkg/invitations/middleware/telemetry_middleware.go @@ -0,0 +1,144 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/telemetry +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/invitations -i Invitations -t ../../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l "" + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/invitations" + "git.perx.ru/perxis/perxis-go/pkg/options" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +// telemetryMiddleware implements invitations.Invitations interface instrumented with opentracing spans +type telemetryMiddleware struct { + invitations.Invitations + _instance string + _spanDecorator func(span trace.Span, params, results map[string]interface{}) +} + +// TelemetryMiddleware returns telemetryMiddleware +func TelemetryMiddleware(base invitations.Invitations, instance string, spanDecorator ...func(span trace.Span, params, results map[string]interface{})) telemetryMiddleware { + d := telemetryMiddleware{ + Invitations: base, + _instance: instance, + } + + if len(spanDecorator) > 0 && spanDecorator[0] != nil { + d._spanDecorator = spanDecorator[0] + } + + return d +} + +// Accept implements invitations.Invitations +func (_d telemetryMiddleware) Accept(ctx context.Context, invitationId string, userId string) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Invitations.Accept") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "invitationId": invitationId, + "userId": userId}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Invitations.Accept(ctx, invitationId, userId) +} + +// Create implements invitations.Invitations +func (_d telemetryMiddleware) Create(ctx context.Context, invitation *invitations.Invitation) (created *invitations.Invitation, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Invitations.Create") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "invitation": invitation}, map[string]interface{}{ + "created": created, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Invitations.Create(ctx, invitation) +} + +// Delete implements invitations.Invitations +func (_d telemetryMiddleware) Delete(ctx context.Context, invitationId string) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Invitations.Delete") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "invitationId": invitationId}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Invitations.Delete(ctx, invitationId) +} + +// Find implements invitations.Invitations +func (_d telemetryMiddleware) Find(ctx context.Context, filter *invitations.Filter, opts *options.FindOptions) (invitations []*invitations.Invitation, total int, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Invitations.Find") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "filter": filter, + "opts": opts}, map[string]interface{}{ + "invitations": invitations, + "total": total, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Invitations.Find(ctx, filter, opts) +} + +// Get implements invitations.Invitations +func (_d telemetryMiddleware) Get(ctx context.Context, invitationId string) (invitation *invitations.Invitation, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Invitations.Get") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "invitationId": invitationId}, map[string]interface{}{ + "invitation": invitation, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Invitations.Get(ctx, invitationId) +} diff --git a/pkg/invitations/mocks/Storage.go b/pkg/invitations/mocks/Storage.go new file mode 100644 index 0000000000000000000000000000000000000000..8739d1e1195931da4dfc05f2e62ad58ca7988365 --- /dev/null +++ b/pkg/invitations/mocks/Storage.go @@ -0,0 +1,162 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + invitations "git.perx.ru/perxis/perxis-go/pkg/invitations" + mock "github.com/stretchr/testify/mock" + + options "git.perx.ru/perxis/perxis-go/pkg/options" +) + +// Storage is an autogenerated mock type for the Storage type +type Storage struct { + mock.Mock +} + +// Create provides a mock function with given fields: ctx, create +func (_m *Storage) Create(ctx context.Context, create *invitations.Invitation) (*invitations.Invitation, error) { + ret := _m.Called(ctx, create) + + var r0 *invitations.Invitation + if rf, ok := ret.Get(0).(func(context.Context, *invitations.Invitation) *invitations.Invitation); ok { + r0 = rf(ctx, create) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*invitations.Invitation) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *invitations.Invitation) error); ok { + r1 = rf(ctx, create) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Delete provides a mock function with given fields: ctx, filter +func (_m *Storage) Delete(ctx context.Context, filter *invitations.Filter) (int, error) { + ret := _m.Called(ctx, filter) + + var r0 int + if rf, ok := ret.Get(0).(func(context.Context, *invitations.Filter) int); ok { + r0 = rf(ctx, filter) + } else { + r0 = ret.Get(0).(int) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *invitations.Filter) error); ok { + r1 = rf(ctx, filter) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Find provides a mock function with given fields: ctx, filter, opts +func (_m *Storage) Find(ctx context.Context, filter *invitations.Filter, opts *options.FindOptions) ([]*invitations.Invitation, int, error) { + ret := _m.Called(ctx, filter, opts) + + var r0 []*invitations.Invitation + if rf, ok := ret.Get(0).(func(context.Context, *invitations.Filter, *options.FindOptions) []*invitations.Invitation); ok { + r0 = rf(ctx, filter, opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*invitations.Invitation) + } + } + + var r1 int + if rf, ok := ret.Get(1).(func(context.Context, *invitations.Filter, *options.FindOptions) int); ok { + r1 = rf(ctx, filter, opts) + } else { + r1 = ret.Get(1).(int) + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, *invitations.Filter, *options.FindOptions) error); ok { + r2 = rf(ctx, filter, opts) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// Init provides a mock function with given fields: ctx +func (_m *Storage) Init(ctx context.Context) error { + ret := _m.Called(ctx) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Reset provides a mock function with given fields: ctx +func (_m *Storage) Reset(ctx context.Context) error { + ret := _m.Called(ctx) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Update provides a mock function with given fields: ctx, update, filter +func (_m *Storage) Update(ctx context.Context, update *invitations.Invitation, filter *invitations.Filter) (int, int, error) { + ret := _m.Called(ctx, update, filter) + + var r0 int + if rf, ok := ret.Get(0).(func(context.Context, *invitations.Invitation, *invitations.Filter) int); ok { + r0 = rf(ctx, update, filter) + } else { + r0 = ret.Get(0).(int) + } + + var r1 int + if rf, ok := ret.Get(1).(func(context.Context, *invitations.Invitation, *invitations.Filter) int); ok { + r1 = rf(ctx, update, filter) + } else { + r1 = ret.Get(1).(int) + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, *invitations.Invitation, *invitations.Filter) error); ok { + r2 = rf(ctx, update, filter) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +type mockConstructorTestingTNewStorage interface { + mock.TestingT + Cleanup(func()) +} + +// NewStorage creates a new instance of Storage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewStorage(t mockConstructorTestingTNewStorage) *Storage { + mock := &Storage{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/invitations/storage.go b/pkg/invitations/storage.go new file mode 100644 index 0000000000000000000000000000000000000000..047a33ea5ed0e84e064418f8774a8b852495efe9 --- /dev/null +++ b/pkg/invitations/storage.go @@ -0,0 +1,17 @@ +package invitations + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/options" +) + +type Storage interface { + Init(ctx context.Context) error + Reset(ctx context.Context) error + + Create(ctx context.Context, create *Invitation) (invitation *Invitation, err error) + Find(ctx context.Context, filter *Filter, opts *options.FindOptions) (invitations []*Invitation, total int, err error) + Delete(ctx context.Context, filter *Filter) (total int, err error) + Update(ctx context.Context, update *Invitation, filter *Filter) (updated, total int, err error) +} diff --git a/pkg/items/middleware/telemetry_middleware.go b/pkg/items/middleware/telemetry_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..1e07b57ac5e0320c0962acd9d96b514901d88ea5 --- /dev/null +++ b/pkg/items/middleware/telemetry_middleware.go @@ -0,0 +1,465 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/telemetry +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/items -i Items -t ../../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l "" + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/items" + "git.perx.ru/perxis/perxis-go/pkg/schema" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +// telemetryMiddleware implements items.Items interface instrumented with opentracing spans +type telemetryMiddleware struct { + items.Items + _instance string + _spanDecorator func(span trace.Span, params, results map[string]interface{}) +} + +// TelemetryMiddleware returns telemetryMiddleware +func TelemetryMiddleware(base items.Items, instance string, spanDecorator ...func(span trace.Span, params, results map[string]interface{})) telemetryMiddleware { + d := telemetryMiddleware{ + Items: base, + _instance: instance, + } + + if len(spanDecorator) > 0 && spanDecorator[0] != nil { + d._spanDecorator = spanDecorator[0] + } + + return d +} + +// Aggregate implements items.Items +func (_d telemetryMiddleware) Aggregate(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.AggregateOptions) (result map[string]interface{}, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Aggregate") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "collectionId": collectionId, + "filter": filter, + "options": options}, map[string]interface{}{ + "result": result, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Items.Aggregate(ctx, spaceId, envId, collectionId, filter, options...) +} + +// AggregatePublished implements items.Items +func (_d telemetryMiddleware) AggregatePublished(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.AggregatePublishedOptions) (result map[string]interface{}, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.AggregatePublished") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "collectionId": collectionId, + "filter": filter, + "options": options}, map[string]interface{}{ + "result": result, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Items.AggregatePublished(ctx, spaceId, envId, collectionId, filter, options...) +} + +// Archive implements items.Items +func (_d telemetryMiddleware) Archive(ctx context.Context, item *items.Item, options ...*items.ArchiveOptions) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Archive") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "item": item, + "options": options}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Items.Archive(ctx, item, options...) +} + +// Create implements items.Items +func (_d telemetryMiddleware) Create(ctx context.Context, item *items.Item, opts ...*items.CreateOptions) (created *items.Item, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Create") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "item": item, + "opts": opts}, map[string]interface{}{ + "created": created, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Items.Create(ctx, item, opts...) +} + +// Delete implements items.Items +func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, options ...*items.DeleteOptions) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Delete") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "collectionId": collectionId, + "itemId": itemId, + "options": options}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Items.Delete(ctx, spaceId, envId, collectionId, itemId, options...) +} + +// Find implements items.Items +func (_d telemetryMiddleware) Find(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.FindOptions) (items []*items.Item, total int, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Find") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "collectionId": collectionId, + "filter": filter, + "options": options}, map[string]interface{}{ + "items": items, + "total": total, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Items.Find(ctx, spaceId, envId, collectionId, filter, options...) +} + +// FindArchived implements items.Items +func (_d telemetryMiddleware) FindArchived(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.FindArchivedOptions) (items []*items.Item, total int, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.FindArchived") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "collectionId": collectionId, + "filter": filter, + "options": options}, map[string]interface{}{ + "items": items, + "total": total, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Items.FindArchived(ctx, spaceId, envId, collectionId, filter, options...) +} + +// FindPublished implements items.Items +func (_d telemetryMiddleware) FindPublished(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.FindPublishedOptions) (items []*items.Item, total int, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.FindPublished") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "collectionId": collectionId, + "filter": filter, + "options": options}, map[string]interface{}{ + "items": items, + "total": total, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Items.FindPublished(ctx, spaceId, envId, collectionId, filter, options...) +} + +// Get implements items.Items +func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, options ...*items.GetOptions) (item *items.Item, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Get") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "collectionId": collectionId, + "itemId": itemId, + "options": options}, map[string]interface{}{ + "item": item, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Items.Get(ctx, spaceId, envId, collectionId, itemId, options...) +} + +// GetPublished implements items.Items +func (_d telemetryMiddleware) GetPublished(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, options ...*items.GetPublishedOptions) (item *items.Item, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.GetPublished") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "collectionId": collectionId, + "itemId": itemId, + "options": options}, map[string]interface{}{ + "item": item, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Items.GetPublished(ctx, spaceId, envId, collectionId, itemId, options...) +} + +// GetRevision implements items.Items +func (_d telemetryMiddleware) GetRevision(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, revisionId string, options ...*items.GetRevisionOptions) (item *items.Item, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.GetRevision") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "collectionId": collectionId, + "itemId": itemId, + "revisionId": revisionId, + "options": options}, map[string]interface{}{ + "item": item, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Items.GetRevision(ctx, spaceId, envId, collectionId, itemId, revisionId, options...) +} + +// Introspect implements items.Items +func (_d telemetryMiddleware) Introspect(ctx context.Context, item *items.Item, opts ...*items.IntrospectOptions) (itm *items.Item, sch *schema.Schema, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Introspect") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "item": item, + "opts": opts}, map[string]interface{}{ + "itm": itm, + "sch": sch, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Items.Introspect(ctx, item, opts...) +} + +// ListRevisions implements items.Items +func (_d telemetryMiddleware) ListRevisions(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, options ...*items.ListRevisionsOptions) (items []*items.Item, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.ListRevisions") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "collectionId": collectionId, + "itemId": itemId, + "options": options}, map[string]interface{}{ + "items": items, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Items.ListRevisions(ctx, spaceId, envId, collectionId, itemId, options...) +} + +// Publish implements items.Items +func (_d telemetryMiddleware) Publish(ctx context.Context, item *items.Item, options ...*items.PublishOptions) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Publish") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "item": item, + "options": options}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Items.Publish(ctx, item, options...) +} + +// Unarchive implements items.Items +func (_d telemetryMiddleware) Unarchive(ctx context.Context, item *items.Item, options ...*items.UnarchiveOptions) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Unarchive") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "item": item, + "options": options}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Items.Unarchive(ctx, item, options...) +} + +// Undelete implements items.Items +func (_d telemetryMiddleware) Undelete(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, options ...*items.UndeleteOptions) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Undelete") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "envId": envId, + "collectionId": collectionId, + "itemId": itemId, + "options": options}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Items.Undelete(ctx, spaceId, envId, collectionId, itemId, options...) +} + +// Unpublish implements items.Items +func (_d telemetryMiddleware) Unpublish(ctx context.Context, item *items.Item, options ...*items.UnpublishOptions) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Unpublish") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "item": item, + "options": options}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Items.Unpublish(ctx, item, options...) +} + +// Update implements items.Items +func (_d telemetryMiddleware) Update(ctx context.Context, item *items.Item, options ...*items.UpdateOptions) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Update") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "item": item, + "options": options}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Items.Update(ctx, item, options...) +} diff --git a/pkg/items/mocks/ItemObserver.go b/pkg/items/mocks/ItemObserver.go new file mode 100644 index 0000000000000000000000000000000000000000..a72fb9b529eaf84c5da4c52fc2a62846f15cfb76 --- /dev/null +++ b/pkg/items/mocks/ItemObserver.go @@ -0,0 +1,25 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// ItemObserver is an autogenerated mock type for the ItemObserver type +type ItemObserver struct { + mock.Mock +} + +type mockConstructorTestingTNewItemObserver interface { + mock.TestingT + Cleanup(func()) +} + +// NewItemObserver creates a new instance of ItemObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewItemObserver(t mockConstructorTestingTNewItemObserver) *ItemObserver { + mock := &ItemObserver{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/items/mocks/ItemReadObserver.go b/pkg/items/mocks/ItemReadObserver.go new file mode 100644 index 0000000000000000000000000000000000000000..b14c8aafee42dabc44999993c56144763e4bd96d --- /dev/null +++ b/pkg/items/mocks/ItemReadObserver.go @@ -0,0 +1,111 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + items "git.perx.ru/perxis/perxis-go/pkg/items" + mock "github.com/stretchr/testify/mock" +) + +// ItemReadObserver is an autogenerated mock type for the ItemReadObserver type +type ItemReadObserver struct { + mock.Mock +} + +// OnPostFind provides a mock function with given fields: ctx, _a1, total +func (_m *ItemReadObserver) OnPostFind(ctx context.Context, _a1 []*items.Item, total int) ([]*items.Item, int, error) { + ret := _m.Called(ctx, _a1, total) + + var r0 []*items.Item + if rf, ok := ret.Get(0).(func(context.Context, []*items.Item, int) []*items.Item); ok { + r0 = rf(ctx, _a1, total) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*items.Item) + } + } + + var r1 int + if rf, ok := ret.Get(1).(func(context.Context, []*items.Item, int) int); ok { + r1 = rf(ctx, _a1, total) + } else { + r1 = ret.Get(1).(int) + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, []*items.Item, int) error); ok { + r2 = rf(ctx, _a1, total) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// OnPostGet provides a mock function with given fields: ctx, item +func (_m *ItemReadObserver) OnPostGet(ctx context.Context, item *items.Item) (*items.Item, error) { + ret := _m.Called(ctx, item) + + var r0 *items.Item + if rf, ok := ret.Get(0).(func(context.Context, *items.Item) *items.Item); ok { + r0 = rf(ctx, item) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*items.Item) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *items.Item) error); ok { + r1 = rf(ctx, item) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// OnPreFind provides a mock function with given fields: ctx, spaceId, envId, collectionId, filter, options +func (_m *ItemReadObserver) OnPreFind(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options *items.FindOptions) error { + ret := _m.Called(ctx, spaceId, envId, collectionId, filter, options) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, *items.Filter, *items.FindOptions) error); ok { + r0 = rf(ctx, spaceId, envId, collectionId, filter, options) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// OnPreGet provides a mock function with given fields: ctx, spaceId, envId, collectionId, itemId +func (_m *ItemReadObserver) OnPreGet(ctx context.Context, spaceId string, envId string, collectionId string, itemId string) error { + ret := _m.Called(ctx, spaceId, envId, collectionId, itemId) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) error); ok { + r0 = rf(ctx, spaceId, envId, collectionId, itemId) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +type mockConstructorTestingTNewItemReadObserver interface { + mock.TestingT + Cleanup(func()) +} + +// NewItemReadObserver creates a new instance of ItemReadObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewItemReadObserver(t mockConstructorTestingTNewItemReadObserver) *ItemReadObserver { + mock := &ItemReadObserver{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/items/mocks/Storage.go b/pkg/items/mocks/Storage.go new file mode 100644 index 0000000000000000000000000000000000000000..9c502969ad292d0f99ad247394001ca0e8e29011 --- /dev/null +++ b/pkg/items/mocks/Storage.go @@ -0,0 +1,581 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + collections "git.perx.ru/perxis/perxis-go/pkg/collections" + + items "git.perx.ru/perxis/perxis-go/pkg/items" + + mock "github.com/stretchr/testify/mock" +) + +// Storage is an autogenerated mock type for the Storage type +type Storage struct { + mock.Mock +} + +// Aggregate provides a mock function with given fields: ctx, coll, filter, options +func (_m *Storage) Aggregate(ctx context.Context, coll *collections.Collection, filter *items.Filter, options ...*items.AggregateOptions) (map[string]interface{}, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, coll, filter) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 map[string]interface{} + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Filter, ...*items.AggregateOptions) map[string]interface{}); ok { + r0 = rf(ctx, coll, filter, options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[string]interface{}) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *collections.Collection, *items.Filter, ...*items.AggregateOptions) error); ok { + r1 = rf(ctx, coll, filter, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AggregatePublished provides a mock function with given fields: ctx, coll, filter, options +func (_m *Storage) AggregatePublished(ctx context.Context, coll *collections.Collection, filter *items.Filter, options ...*items.AggregatePublishedOptions) (map[string]interface{}, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, coll, filter) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 map[string]interface{} + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Filter, ...*items.AggregatePublishedOptions) map[string]interface{}); ok { + r0 = rf(ctx, coll, filter, options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[string]interface{}) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *collections.Collection, *items.Filter, ...*items.AggregatePublishedOptions) error); ok { + r1 = rf(ctx, coll, filter, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Archive provides a mock function with given fields: ctx, archived, options +func (_m *Storage) Archive(ctx context.Context, archived *items.Item, options ...*items.ArchiveOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, archived) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *items.Item, ...*items.ArchiveOptions) error); ok { + r0 = rf(ctx, archived, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// ChangeRevisionsItemID provides a mock function with given fields: ctx, spaceId, envId, collectionId, itemId, newItemId +func (_m *Storage) ChangeRevisionsItemID(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, newItemId string) error { + ret := _m.Called(ctx, spaceId, envId, collectionId, itemId, newItemId) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, string) error); ok { + r0 = rf(ctx, spaceId, envId, collectionId, itemId, newItemId) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Copy provides a mock function with given fields: ctx, src, dst, itemSets +func (_m *Storage) Copy(ctx context.Context, src *collections.Collection, dst *collections.Collection, itemSets ...string) error { + _va := make([]interface{}, len(itemSets)) + for _i := range itemSets { + _va[_i] = itemSets[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, src, dst) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *collections.Collection, ...string) error); ok { + r0 = rf(ctx, src, dst, itemSets...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Create provides a mock function with given fields: ctx, coll, item, options +func (_m *Storage) Create(ctx context.Context, coll *collections.Collection, item *items.Item, options ...*items.CreateOptions) (*items.Item, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, coll, item) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *items.Item + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Item, ...*items.CreateOptions) *items.Item); ok { + r0 = rf(ctx, coll, item, options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*items.Item) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *collections.Collection, *items.Item, ...*items.CreateOptions) error); ok { + r1 = rf(ctx, coll, item, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CreateRevision provides a mock function with given fields: ctx, spaceId, envId, collectionId, itemId +func (_m *Storage) CreateRevision(ctx context.Context, spaceId string, envId string, collectionId string, itemId string) error { + ret := _m.Called(ctx, spaceId, envId, collectionId, itemId) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) error); ok { + r0 = rf(ctx, spaceId, envId, collectionId, itemId) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Find provides a mock function with given fields: ctx, coll, filter, opts +func (_m *Storage) Find(ctx context.Context, coll *collections.Collection, filter *items.Filter, opts ...*items.FindOptions) ([]*items.Item, int, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, coll, filter) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 []*items.Item + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Filter, ...*items.FindOptions) []*items.Item); ok { + r0 = rf(ctx, coll, filter, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*items.Item) + } + } + + var r1 int + if rf, ok := ret.Get(1).(func(context.Context, *collections.Collection, *items.Filter, ...*items.FindOptions) int); ok { + r1 = rf(ctx, coll, filter, opts...) + } else { + r1 = ret.Get(1).(int) + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, *collections.Collection, *items.Filter, ...*items.FindOptions) error); ok { + r2 = rf(ctx, coll, filter, opts...) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// FindArchived provides a mock function with given fields: ctx, coll, filter, opts +func (_m *Storage) FindArchived(ctx context.Context, coll *collections.Collection, filter *items.Filter, opts ...*items.FindArchivedOptions) ([]*items.Item, int, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, coll, filter) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 []*items.Item + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Filter, ...*items.FindArchivedOptions) []*items.Item); ok { + r0 = rf(ctx, coll, filter, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*items.Item) + } + } + + var r1 int + if rf, ok := ret.Get(1).(func(context.Context, *collections.Collection, *items.Filter, ...*items.FindArchivedOptions) int); ok { + r1 = rf(ctx, coll, filter, opts...) + } else { + r1 = ret.Get(1).(int) + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, *collections.Collection, *items.Filter, ...*items.FindArchivedOptions) error); ok { + r2 = rf(ctx, coll, filter, opts...) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// FindPublished provides a mock function with given fields: ctx, coll, filter, opts +func (_m *Storage) FindPublished(ctx context.Context, coll *collections.Collection, filter *items.Filter, opts ...*items.FindPublishedOptions) ([]*items.Item, int, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, coll, filter) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 []*items.Item + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Filter, ...*items.FindPublishedOptions) []*items.Item); ok { + r0 = rf(ctx, coll, filter, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*items.Item) + } + } + + var r1 int + if rf, ok := ret.Get(1).(func(context.Context, *collections.Collection, *items.Filter, ...*items.FindPublishedOptions) int); ok { + r1 = rf(ctx, coll, filter, opts...) + } else { + r1 = ret.Get(1).(int) + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, *collections.Collection, *items.Filter, ...*items.FindPublishedOptions) error); ok { + r2 = rf(ctx, coll, filter, opts...) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// GetRevision provides a mock function with given fields: ctx, coll, itemId, revisionId, options +func (_m *Storage) GetRevision(ctx context.Context, coll *collections.Collection, itemId string, revisionId string, options ...*items.GetRevisionOptions) (*items.Item, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, coll, itemId, revisionId) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *items.Item + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, string, string, ...*items.GetRevisionOptions) *items.Item); ok { + r0 = rf(ctx, coll, itemId, revisionId, options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*items.Item) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *collections.Collection, string, string, ...*items.GetRevisionOptions) error); ok { + r1 = rf(ctx, coll, itemId, revisionId, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Init provides a mock function with given fields: ctx, collection +func (_m *Storage) Init(ctx context.Context, collection *collections.Collection) error { + ret := _m.Called(ctx, collection) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection) error); ok { + r0 = rf(ctx, collection) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// ListRevisions provides a mock function with given fields: ctx, coll, itemId, options +func (_m *Storage) ListRevisions(ctx context.Context, coll *collections.Collection, itemId string, options ...*items.ListRevisionsOptions) ([]*items.Item, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, coll, itemId) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 []*items.Item + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, string, ...*items.ListRevisionsOptions) []*items.Item); ok { + r0 = rf(ctx, coll, itemId, options...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*items.Item) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *collections.Collection, string, ...*items.ListRevisionsOptions) error); ok { + r1 = rf(ctx, coll, itemId, options...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Publish provides a mock function with given fields: ctx, published, options +func (_m *Storage) Publish(ctx context.Context, published *items.Item, options ...*items.PublishOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, published) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *items.Item, ...*items.PublishOptions) error); ok { + r0 = rf(ctx, published, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// RemoveArchived provides a mock function with given fields: ctx, spaceId, envId, collectionId, itemId, options +func (_m *Storage) RemoveArchived(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, options ...*items.DeleteOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, spaceId, envId, collectionId, itemId) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, ...*items.DeleteOptions) error); ok { + r0 = rf(ctx, spaceId, envId, collectionId, itemId, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// RemoveItems provides a mock function with given fields: ctx, spaceId, envId, collectionId, itemId, options +func (_m *Storage) RemoveItems(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, options ...*items.DeleteOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, spaceId, envId, collectionId, itemId) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, ...*items.DeleteOptions) error); ok { + r0 = rf(ctx, spaceId, envId, collectionId, itemId, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// RemovePublished provides a mock function with given fields: ctx, spaceId, envId, collectionId, itemId, options +func (_m *Storage) RemovePublished(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, options ...*items.DeleteOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, spaceId, envId, collectionId, itemId) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, ...*items.DeleteOptions) error); ok { + r0 = rf(ctx, spaceId, envId, collectionId, itemId, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// RemoveRevision provides a mock function with given fields: ctx, spaceId, envId, collectionId, revision, options +func (_m *Storage) RemoveRevision(ctx context.Context, spaceId string, envId string, collectionId string, revision string, options ...*items.DeleteOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, spaceId, envId, collectionId, revision) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, ...*items.DeleteOptions) error); ok { + r0 = rf(ctx, spaceId, envId, collectionId, revision, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// RemoveRevisions provides a mock function with given fields: ctx, spaceId, envId, collectionId, itemId, options +func (_m *Storage) RemoveRevisions(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, options ...*items.DeleteOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, spaceId, envId, collectionId, itemId) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, ...*items.DeleteOptions) error); ok { + r0 = rf(ctx, spaceId, envId, collectionId, itemId, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Reset provides a mock function with given fields: ctx, spaceId, envId, collectionId +func (_m *Storage) Reset(ctx context.Context, spaceId string, envId string, collectionId string) error { + ret := _m.Called(ctx, spaceId, envId, collectionId) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) error); ok { + r0 = rf(ctx, spaceId, envId, collectionId) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Unarchive provides a mock function with given fields: ctx, unarchived, options +func (_m *Storage) Unarchive(ctx context.Context, unarchived *items.Item, options ...*items.UnarchiveOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, unarchived) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *items.Item, ...*items.UnarchiveOptions) error); ok { + r0 = rf(ctx, unarchived, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Unpublish provides a mock function with given fields: ctx, unpublished, options +func (_m *Storage) Unpublish(ctx context.Context, unpublished *items.Item, options ...*items.UnpublishOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, unpublished) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *items.Item, ...*items.UnpublishOptions) error); ok { + r0 = rf(ctx, unpublished, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Update provides a mock function with given fields: ctx, coll, item, options +func (_m *Storage) Update(ctx context.Context, coll *collections.Collection, item *items.Item, options ...*items.UpdateOptions) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, coll, item) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Item, ...*items.UpdateOptions) error); ok { + r0 = rf(ctx, coll, item, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +type mockConstructorTestingTNewStorage interface { + mock.TestingT + Cleanup(func()) +} + +// NewStorage creates a new instance of Storage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewStorage(t mockConstructorTestingTNewStorage) *Storage { + mock := &Storage{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/items/observer.go b/pkg/items/observer.go new file mode 100644 index 0000000000000000000000000000000000000000..6eb7194df4dbecd7f4b9e4aa4a86452785b5d801 --- /dev/null +++ b/pkg/items/observer.go @@ -0,0 +1,14 @@ +package items + +import ( + "context" +) + +type ItemObserver interface{} + +type ItemReadObserver interface { + OnPreGet(ctx context.Context, spaceId, envId, collectionId, itemId string) error + OnPostGet(ctx context.Context, item *Item) (*Item, error) + OnPreFind(ctx context.Context, spaceId, envId, collectionId string, filter *Filter, options *FindOptions) error + OnPostFind(ctx context.Context, items []*Item, total int) ([]*Item, int, error) +} diff --git a/pkg/items/storage.go b/pkg/items/storage.go new file mode 100644 index 0000000000000000000000000000000000000000..64548a009369fad6e74530e2ae5f52dd013e7997 --- /dev/null +++ b/pkg/items/storage.go @@ -0,0 +1,92 @@ +package items + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/collections" +) + +type Storage interface { + // Items + // --------------------------------------------------------------------------------------------- + // Р’СЃРµ пользовательские коллекции Perxis хранятся вместе Рё данные РјРѕРіСѓС‚ быть выбраны одновременно + // РёР· разных коллекций. + // + // Для работы СЃ Items используются 3 коллекции MongoDB между которыми записи переносятся РІ зависимости + // РѕС‚ РёС… статуса. + // - 'items' - рабочие записи СЃ которыми работает API управления контентом. Р’ коллекции находятся + // только текущие ревизии записи + // - 'revisions' - РІСЃРµ ревизии записи Р·Р° исключением текущей. Ревизии записей переносятся РІ данную + // коллекцию РїСЂРё создании РЅРѕРІРѕР№ ревизии записи. РџРѕРёСЃРє данных РїРѕ коллекции РЅРµ производится + // - 'published' - опубликованные записи, РІ данную коллекцию копируются записи РёР· `items` РїСЂРё + // публикации. Р’ коллекции находится только РѕРґРЅР° опубликованная ревизия. Коллекция обеспечивает + // быстрый РїРѕРёСЃРє, поэтому для данных строятся Spare-индексы СЃ использованием Схем + // - 'archived' - архивные записи, РІ данную коллекцию записи переносятся РїСЂРё архивировании РёР· `items`. + // РљРѕРїРёРё записей РёР· `published` РїСЂРё этом удаляются. + // --------------------------------------------------------------------------------------------- + + // Create - создать РЅРѕРІСѓСЋ запись + Create(ctx context.Context, coll *collections.Collection, item *Item, options ...*CreateOptions) (*Item, error) + + // CreateRevision - перенести ревизию РІ коллекцию Revisions + CreateRevision(ctx context.Context, spaceId, envId, collectionId, itemId string) error + + // Update - Обновление текущей ревизии или создание РЅРѕРІРѕР№, если РІ опциях передан флаг `ReplacePublishedRevision` + Update(ctx context.Context, coll *collections.Collection, item *Item, options ...*UpdateOptions) error + + // Find - РїРѕРёСЃРє записей РїРѕ рабочим записям, коллекция 'items' + Find(ctx context.Context, coll *collections.Collection, filter *Filter, opts ...*FindOptions) ([]*Item, int, error) + + // GetRevision - РїРѕРёСЃРє РѕРґРЅРѕР№ ревизии РѕРґРЅРѕР№ записи + GetRevision(ctx context.Context, coll *collections.Collection, itemId, revisionId string, options ...*GetRevisionOptions) (*Item, error) + + // ListRevisions - РїРѕРёСЃРє всех ревизий РѕРґРЅРѕР№ записи + ListRevisions(ctx context.Context, coll *collections.Collection, itemId string, options ...*ListRevisionsOptions) ([]*Item, error) + + // ChangeRevisionsItemID - заменить ID элемента Сѓ его ревизий + ChangeRevisionsItemID(ctx context.Context, spaceId, envId, collectionId, itemId, newItemId string) error + + // Publish - опубликовать запись + Publish(ctx context.Context, published *Item, options ...*PublishOptions) error + + // Unpublish - отменить публикацию записи + Unpublish(ctx context.Context, unpublished *Item, options ...*UnpublishOptions) error + + // FindPublished - РїРѕРёСЃРє РїРѕ опубликованным записям, коллекция 'items_published' + FindPublished(ctx context.Context, coll *collections.Collection, filter *Filter, opts ...*FindPublishedOptions) ([]*Item, int, error) + + // Archive - архивация записи + Archive(ctx context.Context, archived *Item, options ...*ArchiveOptions) error + + // Unarchive - разархивация записи + Unarchive(ctx context.Context, unarchived *Item, options ...*UnarchiveOptions) error + + // FindArchived - РїРѕРёСЃРє РїРѕ архивированным записям, коллекция 'items_archived' + FindArchived(ctx context.Context, coll *collections.Collection, filter *Filter, opts ...*FindArchivedOptions) ([]*Item, int, error) + + // RemoveItems - удаление записи РёР· коллекций Items + RemoveItems(ctx context.Context, spaceId, envId, collectionId, itemId string, options ...*DeleteOptions) error + + // RemovePublished - удаление записи РёР· коллекций Published + RemovePublished(ctx context.Context, spaceId, envId, collectionId, itemId string, options ...*DeleteOptions) error + + // RemoveRevisions - удаление записи РёР· всех ревизий элемента + RemoveRevisions(ctx context.Context, spaceId, envId, collectionId, itemId string, options ...*DeleteOptions) error + + // RemoveRevision - удаление конкретной ревизии РёР· Revisions + RemoveRevision(ctx context.Context, spaceId, envId, collectionId, revision string, options ...*DeleteOptions) error + + // RemoveArchived - удаление записи РёР· архива + RemoveArchived(ctx context.Context, spaceId, envId, collectionId, itemId string, options ...*DeleteOptions) error + + // Copy - копирование записей + Copy(ctx context.Context, src, dst *collections.Collection, itemSets ...string) error + + Reset(ctx context.Context, spaceId, envId, collectionId string) error + Init(ctx context.Context, collection *collections.Collection) error + + // Aggregate выполняет агрегацию данных + Aggregate(ctx context.Context, coll *collections.Collection, filter *Filter, options ...*AggregateOptions) (result map[string]interface{}, err error) + // AggregatePublished выполняет агрегацию опубликованных данных + AggregatePublished(ctx context.Context, coll *collections.Collection, filter *Filter, options ...*AggregatePublishedOptions) (result map[string]interface{}, err error) +} diff --git a/pkg/locales/middleware/telemetry_middleware.go b/pkg/locales/middleware/telemetry_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..3e335e19574e238a02a69dc19f373c62e7fc65a2 --- /dev/null +++ b/pkg/locales/middleware/telemetry_middleware.go @@ -0,0 +1,100 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/telemetry +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/locales -i Locales -t ../../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l "" + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/locales" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +// telemetryMiddleware implements locales.Locales interface instrumented with opentracing spans +type telemetryMiddleware struct { + locales.Locales + _instance string + _spanDecorator func(span trace.Span, params, results map[string]interface{}) +} + +// TelemetryMiddleware returns telemetryMiddleware +func TelemetryMiddleware(base locales.Locales, instance string, spanDecorator ...func(span trace.Span, params, results map[string]interface{})) telemetryMiddleware { + d := telemetryMiddleware{ + Locales: base, + _instance: instance, + } + + if len(spanDecorator) > 0 && spanDecorator[0] != nil { + d._spanDecorator = spanDecorator[0] + } + + return d +} + +// Create implements locales.Locales +func (_d telemetryMiddleware) Create(ctx context.Context, locale *locales.Locale) (created *locales.Locale, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Locales.Create") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "locale": locale}, map[string]interface{}{ + "created": created, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Locales.Create(ctx, locale) +} + +// Delete implements locales.Locales +func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string, localeId string) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Locales.Delete") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "localeId": localeId}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Locales.Delete(ctx, spaceId, localeId) +} + +// List implements locales.Locales +func (_d telemetryMiddleware) List(ctx context.Context, spaceId string) (locales []*locales.Locale, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Locales.List") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId}, map[string]interface{}{ + "locales": locales, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Locales.List(ctx, spaceId) +} diff --git a/pkg/locales/mocks/Storage.go b/pkg/locales/mocks/Storage.go new file mode 100644 index 0000000000000000000000000000000000000000..d37bd81cf7011e2498768c76102bb71a689eaf84 --- /dev/null +++ b/pkg/locales/mocks/Storage.go @@ -0,0 +1,120 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + locales "git.perx.ru/perxis/perxis-go/pkg/locales" + mock "github.com/stretchr/testify/mock" + + options "git.perx.ru/perxis/perxis-go/pkg/options" +) + +// Storage is an autogenerated mock type for the Storage type +type Storage struct { + mock.Mock +} + +// Create provides a mock function with given fields: ctx, locale +func (_m *Storage) Create(ctx context.Context, locale *locales.Locale) (*locales.Locale, error) { + ret := _m.Called(ctx, locale) + + var r0 *locales.Locale + if rf, ok := ret.Get(0).(func(context.Context, *locales.Locale) *locales.Locale); ok { + r0 = rf(ctx, locale) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*locales.Locale) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *locales.Locale) error); ok { + r1 = rf(ctx, locale) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Delete provides a mock function with given fields: ctx, spaceID, filter +func (_m *Storage) Delete(ctx context.Context, spaceID string, filter *locales.Filter) (int, error) { + ret := _m.Called(ctx, spaceID, filter) + + var r0 int + if rf, ok := ret.Get(0).(func(context.Context, string, *locales.Filter) int); ok { + r0 = rf(ctx, spaceID, filter) + } else { + r0 = ret.Get(0).(int) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string, *locales.Filter) error); ok { + r1 = rf(ctx, spaceID, filter) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Find provides a mock function with given fields: ctx, spaceID, filter, opts +func (_m *Storage) Find(ctx context.Context, spaceID string, filter *locales.Filter, opts *options.FindOptions) ([]*locales.Locale, int, error) { + ret := _m.Called(ctx, spaceID, filter, opts) + + var r0 []*locales.Locale + if rf, ok := ret.Get(0).(func(context.Context, string, *locales.Filter, *options.FindOptions) []*locales.Locale); ok { + r0 = rf(ctx, spaceID, filter, opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*locales.Locale) + } + } + + var r1 int + if rf, ok := ret.Get(1).(func(context.Context, string, *locales.Filter, *options.FindOptions) int); ok { + r1 = rf(ctx, spaceID, filter, opts) + } else { + r1 = ret.Get(1).(int) + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, string, *locales.Filter, *options.FindOptions) error); ok { + r2 = rf(ctx, spaceID, filter, opts) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// Reset provides a mock function with given fields: ctx, spaceID +func (_m *Storage) Reset(ctx context.Context, spaceID string) error { + ret := _m.Called(ctx, spaceID) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { + r0 = rf(ctx, spaceID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +type mockConstructorTestingTNewStorage interface { + mock.TestingT + Cleanup(func()) +} + +// NewStorage creates a new instance of Storage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewStorage(t mockConstructorTestingTNewStorage) *Storage { + mock := &Storage{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/locales/storage.go b/pkg/locales/storage.go new file mode 100644 index 0000000000000000000000000000000000000000..c345706c5925119cf3eb84a07f91e57ff764f46f --- /dev/null +++ b/pkg/locales/storage.go @@ -0,0 +1,20 @@ +package locales + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/options" +) + +type Storage interface { + Reset(ctx context.Context, spaceID string) error + + Create(ctx context.Context, locale *Locale) (created *Locale, err error) + Find(ctx context.Context, spaceID string, filter *Filter, opts *options.FindOptions) (locales []*Locale, total int, err error) + Delete(ctx context.Context, spaceID string, filter *Filter) (total int, err error) +} + +type Filter struct { + ID []string + Name []string +} diff --git a/pkg/members/middleware/telemetry_middleware.go b/pkg/members/middleware/telemetry_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..4d13a5d794a57fd9c470bae42bbfed4fe81743cc --- /dev/null +++ b/pkg/members/middleware/telemetry_middleware.go @@ -0,0 +1,164 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/telemetry +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/members -i Members -t ../../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l "" + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/members" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +// telemetryMiddleware implements members.Members interface instrumented with opentracing spans +type telemetryMiddleware struct { + members.Members + _instance string + _spanDecorator func(span trace.Span, params, results map[string]interface{}) +} + +// TelemetryMiddleware returns telemetryMiddleware +func TelemetryMiddleware(base members.Members, instance string, spanDecorator ...func(span trace.Span, params, results map[string]interface{})) telemetryMiddleware { + d := telemetryMiddleware{ + Members: base, + _instance: instance, + } + + if len(spanDecorator) > 0 && spanDecorator[0] != nil { + d._spanDecorator = spanDecorator[0] + } + + return d +} + +// Get implements members.Members +func (_d telemetryMiddleware) Get(ctx context.Context, orgId string, userId string) (role members.Role, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Members.Get") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "orgId": orgId, + "userId": userId}, map[string]interface{}{ + "role": role, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Members.Get(ctx, orgId, userId) +} + +// ListMembers implements members.Members +func (_d telemetryMiddleware) ListMembers(ctx context.Context, orgId string) (members []*members.Member, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Members.ListMembers") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "orgId": orgId}, map[string]interface{}{ + "members": members, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Members.ListMembers(ctx, orgId) +} + +// ListOrganizations implements members.Members +func (_d telemetryMiddleware) ListOrganizations(ctx context.Context, userId string) (organizations []*members.Member, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Members.ListOrganizations") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "userId": userId}, map[string]interface{}{ + "organizations": organizations, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Members.ListOrganizations(ctx, userId) +} + +// Remove implements members.Members +func (_d telemetryMiddleware) Remove(ctx context.Context, orgId string, userId string) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Members.Remove") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "orgId": orgId, + "userId": userId}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Members.Remove(ctx, orgId, userId) +} + +// RemoveAll implements members.Members +func (_d telemetryMiddleware) RemoveAll(ctx context.Context, orgId string) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Members.RemoveAll") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "orgId": orgId}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Members.RemoveAll(ctx, orgId) +} + +// Set implements members.Members +func (_d telemetryMiddleware) Set(ctx context.Context, orgId string, userId string, role members.Role) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Members.Set") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "orgId": orgId, + "userId": userId, + "role": role}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Members.Set(ctx, orgId, userId, role) +} diff --git a/pkg/members/mocks/Middleware.go b/pkg/members/mocks/Middleware.go index 22b7a5dd3f3a42862b9899e6554b049c4595835c..b953cf79d8239ef8da125e809bd29e1cf0a649f0 100644 --- a/pkg/members/mocks/Middleware.go +++ b/pkg/members/mocks/Middleware.go @@ -3,8 +3,7 @@ package mocks import ( - members "git.perx.ru/perxis/perxis-go/pkg/members" - + observer "git.perx.ru/perxis/perxis-go/pkg/members/observer" mock "github.com/stretchr/testify/mock" ) @@ -14,15 +13,15 @@ type Middleware struct { } // Execute provides a mock function with given fields: _a0 -func (_m *Middleware) Execute(_a0 members.Members) members.Members { +func (_m *Middleware) Execute(_a0 observer.Observer) observer.Observer { ret := _m.Called(_a0) - var r0 members.Members - if rf, ok := ret.Get(0).(func(members.Members) members.Members); ok { + var r0 observer.Observer + if rf, ok := ret.Get(0).(func(observer.Observer) observer.Observer); ok { r0 = rf(_a0) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(members.Members) + r0 = ret.Get(0).(observer.Observer) } } diff --git a/pkg/members/mocks/Storage.go b/pkg/members/mocks/Storage.go new file mode 100644 index 0000000000000000000000000000000000000000..1527b6e09fce71d7b35d84d04613d2dcbfa96249 --- /dev/null +++ b/pkg/members/mocks/Storage.go @@ -0,0 +1,118 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + members "git.perx.ru/perxis/perxis-go/pkg/members" + mock "github.com/stretchr/testify/mock" + + options "git.perx.ru/perxis/perxis-go/pkg/options" +) + +// Storage is an autogenerated mock type for the Storage type +type Storage struct { + mock.Mock +} + +// Find provides a mock function with given fields: ctx, filter, opts +func (_m *Storage) Find(ctx context.Context, filter *members.Filter, opts *options.FindOptions) ([]*members.Member, error) { + ret := _m.Called(ctx, filter, opts) + + var r0 []*members.Member + if rf, ok := ret.Get(0).(func(context.Context, *members.Filter, *options.FindOptions) []*members.Member); ok { + r0 = rf(ctx, filter, opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*members.Member) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *members.Filter, *options.FindOptions) error); ok { + r1 = rf(ctx, filter, opts) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Init provides a mock function with given fields: ctx +func (_m *Storage) Init(ctx context.Context) error { + ret := _m.Called(ctx) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Remove provides a mock function with given fields: ctx, filter +func (_m *Storage) Remove(ctx context.Context, filter *members.Filter) (int, error) { + ret := _m.Called(ctx, filter) + + var r0 int + if rf, ok := ret.Get(0).(func(context.Context, *members.Filter) int); ok { + r0 = rf(ctx, filter) + } else { + r0 = ret.Get(0).(int) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *members.Filter) error); ok { + r1 = rf(ctx, filter) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Reset provides a mock function with given fields: ctx +func (_m *Storage) Reset(ctx context.Context) error { + ret := _m.Called(ctx) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Set provides a mock function with given fields: ctx, orgID, userID, role +func (_m *Storage) Set(ctx context.Context, orgID string, userID string, role members.Role) error { + ret := _m.Called(ctx, orgID, userID, role) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, members.Role) error); ok { + r0 = rf(ctx, orgID, userID, role) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +type mockConstructorTestingTNewStorage interface { + mock.TestingT + Cleanup(func()) +} + +// NewStorage creates a new instance of Storage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewStorage(t mockConstructorTestingTNewStorage) *Storage { + mock := &Storage{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/members/storage.go b/pkg/members/storage.go new file mode 100644 index 0000000000000000000000000000000000000000..ec6daea171e0a69521770ed362a883a5aa6166f5 --- /dev/null +++ b/pkg/members/storage.go @@ -0,0 +1,22 @@ +package members + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/options" +) + +type Storage interface { + Reset(ctx context.Context) error + Init(ctx context.Context) error + + Set(ctx context.Context, orgID, userID string, role Role) (err error) + Remove(ctx context.Context, filter *Filter) (total int, err error) + Find(ctx context.Context, filter *Filter, opts *options.FindOptions) (memberships []*Member, err error) +} + +type Filter struct { + OrgID string + UserID string + Role Role +} diff --git a/pkg/organizations/middleware/telemetry_middleware.go b/pkg/organizations/middleware/telemetry_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..6589ed10ba1ee502c6620f8cbef20ed6da22bb29 --- /dev/null +++ b/pkg/organizations/middleware/telemetry_middleware.go @@ -0,0 +1,143 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/telemetry +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/organizations -i Organizations -t ../../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l "" + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/options" + "git.perx.ru/perxis/perxis-go/pkg/organizations" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +// telemetryMiddleware implements organizations.Organizations interface instrumented with opentracing spans +type telemetryMiddleware struct { + organizations.Organizations + _instance string + _spanDecorator func(span trace.Span, params, results map[string]interface{}) +} + +// TelemetryMiddleware returns telemetryMiddleware +func TelemetryMiddleware(base organizations.Organizations, instance string, spanDecorator ...func(span trace.Span, params, results map[string]interface{})) telemetryMiddleware { + d := telemetryMiddleware{ + Organizations: base, + _instance: instance, + } + + if len(spanDecorator) > 0 && spanDecorator[0] != nil { + d._spanDecorator = spanDecorator[0] + } + + return d +} + +// Create implements organizations.Organizations +func (_d telemetryMiddleware) Create(ctx context.Context, org *organizations.Organization) (created *organizations.Organization, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Organizations.Create") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "org": org}, map[string]interface{}{ + "created": created, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Organizations.Create(ctx, org) +} + +// Delete implements organizations.Organizations +func (_d telemetryMiddleware) Delete(ctx context.Context, orgId string) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Organizations.Delete") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "orgId": orgId}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Organizations.Delete(ctx, orgId) +} + +// Find implements organizations.Organizations +func (_d telemetryMiddleware) Find(ctx context.Context, filter *organizations.Filter, opts *options.FindOptions) (orgs []*organizations.Organization, total int, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Organizations.Find") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "filter": filter, + "opts": opts}, map[string]interface{}{ + "orgs": orgs, + "total": total, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Organizations.Find(ctx, filter, opts) +} + +// Get implements organizations.Organizations +func (_d telemetryMiddleware) Get(ctx context.Context, orgId string) (org *organizations.Organization, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Organizations.Get") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "orgId": orgId}, map[string]interface{}{ + "org": org, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Organizations.Get(ctx, orgId) +} + +// Update implements organizations.Organizations +func (_d telemetryMiddleware) Update(ctx context.Context, org *organizations.Organization) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Organizations.Update") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "org": org}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Organizations.Update(ctx, org) +} diff --git a/pkg/organizations/mocks/Storage.go b/pkg/organizations/mocks/Storage.go new file mode 100644 index 0000000000000000000000000000000000000000..6b2b7176ff452b0e5935b352ccc3ee112182eb0b --- /dev/null +++ b/pkg/organizations/mocks/Storage.go @@ -0,0 +1,162 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + options "git.perx.ru/perxis/perxis-go/pkg/options" + mock "github.com/stretchr/testify/mock" + + organizations "git.perx.ru/perxis/perxis-go/pkg/organizations" +) + +// Storage is an autogenerated mock type for the Storage type +type Storage struct { + mock.Mock +} + +// Create provides a mock function with given fields: ctx, org +func (_m *Storage) Create(ctx context.Context, org *organizations.Organization) (*organizations.Organization, error) { + ret := _m.Called(ctx, org) + + var r0 *organizations.Organization + if rf, ok := ret.Get(0).(func(context.Context, *organizations.Organization) *organizations.Organization); ok { + r0 = rf(ctx, org) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*organizations.Organization) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *organizations.Organization) error); ok { + r1 = rf(ctx, org) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Delete provides a mock function with given fields: ctx, filter +func (_m *Storage) Delete(ctx context.Context, filter *organizations.Filter) (int, error) { + ret := _m.Called(ctx, filter) + + var r0 int + if rf, ok := ret.Get(0).(func(context.Context, *organizations.Filter) int); ok { + r0 = rf(ctx, filter) + } else { + r0 = ret.Get(0).(int) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *organizations.Filter) error); ok { + r1 = rf(ctx, filter) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Find provides a mock function with given fields: ctx, filter, opts +func (_m *Storage) Find(ctx context.Context, filter *organizations.Filter, opts *options.FindOptions) ([]*organizations.Organization, int, error) { + ret := _m.Called(ctx, filter, opts) + + var r0 []*organizations.Organization + if rf, ok := ret.Get(0).(func(context.Context, *organizations.Filter, *options.FindOptions) []*organizations.Organization); ok { + r0 = rf(ctx, filter, opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*organizations.Organization) + } + } + + var r1 int + if rf, ok := ret.Get(1).(func(context.Context, *organizations.Filter, *options.FindOptions) int); ok { + r1 = rf(ctx, filter, opts) + } else { + r1 = ret.Get(1).(int) + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, *organizations.Filter, *options.FindOptions) error); ok { + r2 = rf(ctx, filter, opts) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// Init provides a mock function with given fields: ctx +func (_m *Storage) Init(ctx context.Context) error { + ret := _m.Called(ctx) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Reset provides a mock function with given fields: ctx +func (_m *Storage) Reset(ctx context.Context) error { + ret := _m.Called(ctx) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Update provides a mock function with given fields: ctx, update, filter +func (_m *Storage) Update(ctx context.Context, update *organizations.Organization, filter *organizations.Filter) (int, int, error) { + ret := _m.Called(ctx, update, filter) + + var r0 int + if rf, ok := ret.Get(0).(func(context.Context, *organizations.Organization, *organizations.Filter) int); ok { + r0 = rf(ctx, update, filter) + } else { + r0 = ret.Get(0).(int) + } + + var r1 int + if rf, ok := ret.Get(1).(func(context.Context, *organizations.Organization, *organizations.Filter) int); ok { + r1 = rf(ctx, update, filter) + } else { + r1 = ret.Get(1).(int) + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, *organizations.Organization, *organizations.Filter) error); ok { + r2 = rf(ctx, update, filter) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +type mockConstructorTestingTNewStorage interface { + mock.TestingT + Cleanup(func()) +} + +// NewStorage creates a new instance of Storage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewStorage(t mockConstructorTestingTNewStorage) *Storage { + mock := &Storage{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/organizations/storage.go b/pkg/organizations/storage.go new file mode 100644 index 0000000000000000000000000000000000000000..1e628303e3d36c8717b3f2214578a569cb2efc07 --- /dev/null +++ b/pkg/organizations/storage.go @@ -0,0 +1,17 @@ +package organizations + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/options" +) + +type Storage interface { + Create(ctx context.Context, org *Organization) (created *Organization, err error) + Find(ctx context.Context, filter *Filter, opts *options.FindOptions) (orgs []*Organization, total int, err error) + Delete(ctx context.Context, filter *Filter) (total int, err error) + Update(ctx context.Context, update *Organization, filter *Filter) (updated, total int, err error) + + Reset(ctx context.Context) error + Init(ctx context.Context) error +} diff --git a/pkg/roles/middleware/telemetry_middleware.go b/pkg/roles/middleware/telemetry_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..fe487489348a421c611c16b24c8fe689908dcaa8 --- /dev/null +++ b/pkg/roles/middleware/telemetry_middleware.go @@ -0,0 +1,142 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/telemetry +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/roles -i Roles -t ../../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l "" + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/roles" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +// telemetryMiddleware implements roles.Roles interface instrumented with opentracing spans +type telemetryMiddleware struct { + roles.Roles + _instance string + _spanDecorator func(span trace.Span, params, results map[string]interface{}) +} + +// TelemetryMiddleware returns telemetryMiddleware +func TelemetryMiddleware(base roles.Roles, instance string, spanDecorator ...func(span trace.Span, params, results map[string]interface{})) telemetryMiddleware { + d := telemetryMiddleware{ + Roles: base, + _instance: instance, + } + + if len(spanDecorator) > 0 && spanDecorator[0] != nil { + d._spanDecorator = spanDecorator[0] + } + + return d +} + +// Create implements roles.Roles +func (_d telemetryMiddleware) Create(ctx context.Context, role *roles.Role) (created *roles.Role, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Roles.Create") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "role": role}, map[string]interface{}{ + "created": created, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Roles.Create(ctx, role) +} + +// Delete implements roles.Roles +func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string, roleId string) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Roles.Delete") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "roleId": roleId}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Roles.Delete(ctx, spaceId, roleId) +} + +// Get implements roles.Roles +func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, roleId string) (role *roles.Role, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Roles.Get") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "roleId": roleId}, map[string]interface{}{ + "role": role, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Roles.Get(ctx, spaceId, roleId) +} + +// List implements roles.Roles +func (_d telemetryMiddleware) List(ctx context.Context, spaceId string) (roles []*roles.Role, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Roles.List") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId}, map[string]interface{}{ + "roles": roles, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Roles.List(ctx, spaceId) +} + +// Update implements roles.Roles +func (_d telemetryMiddleware) Update(ctx context.Context, role *roles.Role) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Roles.Update") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "role": role}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Roles.Update(ctx, role) +} diff --git a/pkg/roles/mocks/Storage.go b/pkg/roles/mocks/Storage.go new file mode 100644 index 0000000000000000000000000000000000000000..d2d525a19e2c10096a0a1222122e302ad5ea0ce7 --- /dev/null +++ b/pkg/roles/mocks/Storage.go @@ -0,0 +1,141 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + options "git.perx.ru/perxis/perxis-go/pkg/options" + mock "github.com/stretchr/testify/mock" + + roles "git.perx.ru/perxis/perxis-go/pkg/roles" +) + +// Storage is an autogenerated mock type for the Storage type +type Storage struct { + mock.Mock +} + +// Create provides a mock function with given fields: ctx, role +func (_m *Storage) Create(ctx context.Context, role *roles.Role) (*roles.Role, error) { + ret := _m.Called(ctx, role) + + var r0 *roles.Role + if rf, ok := ret.Get(0).(func(context.Context, *roles.Role) *roles.Role); ok { + r0 = rf(ctx, role) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*roles.Role) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *roles.Role) error); ok { + r1 = rf(ctx, role) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Delete provides a mock function with given fields: ctx, spaceID, roleID +func (_m *Storage) Delete(ctx context.Context, spaceID string, roleID string) error { + ret := _m.Called(ctx, spaceID, roleID) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { + r0 = rf(ctx, spaceID, roleID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Find provides a mock function with given fields: ctx, spaceID, f, opts +func (_m *Storage) Find(ctx context.Context, spaceID string, f *roles.Filter, opts *options.FindOptions) ([]*roles.Role, int, error) { + ret := _m.Called(ctx, spaceID, f, opts) + + var r0 []*roles.Role + if rf, ok := ret.Get(0).(func(context.Context, string, *roles.Filter, *options.FindOptions) []*roles.Role); ok { + r0 = rf(ctx, spaceID, f, opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*roles.Role) + } + } + + var r1 int + if rf, ok := ret.Get(1).(func(context.Context, string, *roles.Filter, *options.FindOptions) int); ok { + r1 = rf(ctx, spaceID, f, opts) + } else { + r1 = ret.Get(1).(int) + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, string, *roles.Filter, *options.FindOptions) error); ok { + r2 = rf(ctx, spaceID, f, opts) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// Reset provides a mock function with given fields: ctx, spaceID +func (_m *Storage) Reset(ctx context.Context, spaceID string) error { + ret := _m.Called(ctx, spaceID) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { + r0 = rf(ctx, spaceID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Update provides a mock function with given fields: ctx, role +func (_m *Storage) Update(ctx context.Context, role *roles.Role) (int, int, error) { + ret := _m.Called(ctx, role) + + var r0 int + if rf, ok := ret.Get(0).(func(context.Context, *roles.Role) int); ok { + r0 = rf(ctx, role) + } else { + r0 = ret.Get(0).(int) + } + + var r1 int + if rf, ok := ret.Get(1).(func(context.Context, *roles.Role) int); ok { + r1 = rf(ctx, role) + } else { + r1 = ret.Get(1).(int) + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, *roles.Role) error); ok { + r2 = rf(ctx, role) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +type mockConstructorTestingTNewStorage interface { + mock.TestingT + Cleanup(func()) +} + +// NewStorage creates a new instance of Storage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewStorage(t mockConstructorTestingTNewStorage) *Storage { + mock := &Storage{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/roles/storage.go b/pkg/roles/storage.go new file mode 100644 index 0000000000000000000000000000000000000000..91b76a5e03c6f292cf7d368d19603ac1c1c36595 --- /dev/null +++ b/pkg/roles/storage.go @@ -0,0 +1,21 @@ +package roles + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/options" +) + +type Storage interface { + Create(ctx context.Context, role *Role) (created *Role, err error) + Find(ctx context.Context, spaceID string, f *Filter, opts *options.FindOptions) ([]*Role, int, error) + Update(ctx context.Context, role *Role) (updated, total int, err error) + Delete(ctx context.Context, spaceID, roleID string) (err error) + + Reset(ctx context.Context, spaceID string) error +} + +type Filter struct { + ID string + Name string +} diff --git a/pkg/spaces/middleware/telemetry_middleware.go b/pkg/spaces/middleware/telemetry_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..2ef9f21e58095bdbfbfdc1216f6bdd565c7089e8 --- /dev/null +++ b/pkg/spaces/middleware/telemetry_middleware.go @@ -0,0 +1,161 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/telemetry +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/spaces -i Spaces -t ../../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l "" + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/spaces" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +// telemetryMiddleware implements spaces.Spaces interface instrumented with opentracing spans +type telemetryMiddleware struct { + spaces.Spaces + _instance string + _spanDecorator func(span trace.Span, params, results map[string]interface{}) +} + +// TelemetryMiddleware returns telemetryMiddleware +func TelemetryMiddleware(base spaces.Spaces, instance string, spanDecorator ...func(span trace.Span, params, results map[string]interface{})) telemetryMiddleware { + d := telemetryMiddleware{ + Spaces: base, + _instance: instance, + } + + if len(spanDecorator) > 0 && spanDecorator[0] != nil { + d._spanDecorator = spanDecorator[0] + } + + return d +} + +// Create implements spaces.Spaces +func (_d telemetryMiddleware) Create(ctx context.Context, space *spaces.Space) (created *spaces.Space, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Spaces.Create") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "space": space}, map[string]interface{}{ + "created": created, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Spaces.Create(ctx, space) +} + +// Delete implements spaces.Spaces +func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Spaces.Delete") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Spaces.Delete(ctx, spaceId) +} + +// Get implements spaces.Spaces +func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string) (space *spaces.Space, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Spaces.Get") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId}, map[string]interface{}{ + "space": space, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Spaces.Get(ctx, spaceId) +} + +// List implements spaces.Spaces +func (_d telemetryMiddleware) List(ctx context.Context, orgId string) (spaces []*spaces.Space, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Spaces.List") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "orgId": orgId}, map[string]interface{}{ + "spaces": spaces, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Spaces.List(ctx, orgId) +} + +// Update implements spaces.Spaces +func (_d telemetryMiddleware) Update(ctx context.Context, space *spaces.Space) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Spaces.Update") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "space": space}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Spaces.Update(ctx, space) +} + +// UpdateConfig implements spaces.Spaces +func (_d telemetryMiddleware) UpdateConfig(ctx context.Context, spaceId string, config *spaces.Config) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Spaces.UpdateConfig") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceId": spaceId, + "config": config}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Spaces.UpdateConfig(ctx, spaceId, config) +} diff --git a/pkg/spaces/mocks/SpaceCreatedObserver.go b/pkg/spaces/mocks/SpaceCreatedObserver.go new file mode 100644 index 0000000000000000000000000000000000000000..a85eced793564cc3fc27304881486329041c3d75 --- /dev/null +++ b/pkg/spaces/mocks/SpaceCreatedObserver.go @@ -0,0 +1,44 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + spaces "git.perx.ru/perxis/perxis-go/pkg/spaces" + mock "github.com/stretchr/testify/mock" +) + +// SpaceCreatedObserver is an autogenerated mock type for the SpaceCreatedObserver type +type SpaceCreatedObserver struct { + mock.Mock +} + +// OnSpaceCreated provides a mock function with given fields: ctx, space +func (_m *SpaceCreatedObserver) OnSpaceCreated(ctx context.Context, space *spaces.Space) error { + ret := _m.Called(ctx, space) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *spaces.Space) error); ok { + r0 = rf(ctx, space) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +type mockConstructorTestingTNewSpaceCreatedObserver interface { + mock.TestingT + Cleanup(func()) +} + +// NewSpaceCreatedObserver creates a new instance of SpaceCreatedObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewSpaceCreatedObserver(t mockConstructorTestingTNewSpaceCreatedObserver) *SpaceCreatedObserver { + mock := &SpaceCreatedObserver{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/spaces/mocks/SpaceDeletedObserver.go b/pkg/spaces/mocks/SpaceDeletedObserver.go new file mode 100644 index 0000000000000000000000000000000000000000..450173b03b0007c86b4dffee69a0c36522f9ce28 --- /dev/null +++ b/pkg/spaces/mocks/SpaceDeletedObserver.go @@ -0,0 +1,44 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + spaces "git.perx.ru/perxis/perxis-go/pkg/spaces" + mock "github.com/stretchr/testify/mock" +) + +// SpaceDeletedObserver is an autogenerated mock type for the SpaceDeletedObserver type +type SpaceDeletedObserver struct { + mock.Mock +} + +// OnSpaceDeleted provides a mock function with given fields: ctx, space +func (_m *SpaceDeletedObserver) OnSpaceDeleted(ctx context.Context, space *spaces.Space) error { + ret := _m.Called(ctx, space) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *spaces.Space) error); ok { + r0 = rf(ctx, space) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +type mockConstructorTestingTNewSpaceDeletedObserver interface { + mock.TestingT + Cleanup(func()) +} + +// NewSpaceDeletedObserver creates a new instance of SpaceDeletedObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewSpaceDeletedObserver(t mockConstructorTestingTNewSpaceDeletedObserver) *SpaceDeletedObserver { + mock := &SpaceDeletedObserver{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/spaces/mocks/SpaceObserver.go b/pkg/spaces/mocks/SpaceObserver.go new file mode 100644 index 0000000000000000000000000000000000000000..9c5006bf80047884f45637207d3ea6fdf0b702aa --- /dev/null +++ b/pkg/spaces/mocks/SpaceObserver.go @@ -0,0 +1,25 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// SpaceObserver is an autogenerated mock type for the SpaceObserver type +type SpaceObserver struct { + mock.Mock +} + +type mockConstructorTestingTNewSpaceObserver interface { + mock.TestingT + Cleanup(func()) +} + +// NewSpaceObserver creates a new instance of SpaceObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewSpaceObserver(t mockConstructorTestingTNewSpaceObserver) *SpaceObserver { + mock := &SpaceObserver{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/spaces/mocks/SpaceUpdatedObserver.go b/pkg/spaces/mocks/SpaceUpdatedObserver.go new file mode 100644 index 0000000000000000000000000000000000000000..a7ced9b2d7bab0618013b5f73cef304c40cecb57 --- /dev/null +++ b/pkg/spaces/mocks/SpaceUpdatedObserver.go @@ -0,0 +1,44 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + spaces "git.perx.ru/perxis/perxis-go/pkg/spaces" + mock "github.com/stretchr/testify/mock" +) + +// SpaceUpdatedObserver is an autogenerated mock type for the SpaceUpdatedObserver type +type SpaceUpdatedObserver struct { + mock.Mock +} + +// OnSpaceUpdated provides a mock function with given fields: ctx, before, space +func (_m *SpaceUpdatedObserver) OnSpaceUpdated(ctx context.Context, before *spaces.Space, space *spaces.Space) error { + ret := _m.Called(ctx, before, space) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *spaces.Space, *spaces.Space) error); ok { + r0 = rf(ctx, before, space) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +type mockConstructorTestingTNewSpaceUpdatedObserver interface { + mock.TestingT + Cleanup(func()) +} + +// NewSpaceUpdatedObserver creates a new instance of SpaceUpdatedObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewSpaceUpdatedObserver(t mockConstructorTestingTNewSpaceUpdatedObserver) *SpaceUpdatedObserver { + mock := &SpaceUpdatedObserver{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/spaces/mocks/Storage.go b/pkg/spaces/mocks/Storage.go new file mode 100644 index 0000000000000000000000000000000000000000..5223c772079c3719e1421dafe786498b17e0121c --- /dev/null +++ b/pkg/spaces/mocks/Storage.go @@ -0,0 +1,153 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + options "git.perx.ru/perxis/perxis-go/pkg/options" + mock "github.com/stretchr/testify/mock" + + spaces "git.perx.ru/perxis/perxis-go/pkg/spaces" +) + +// Storage is an autogenerated mock type for the Storage type +type Storage struct { + mock.Mock +} + +// Create provides a mock function with given fields: ctx, space +func (_m *Storage) Create(ctx context.Context, space *spaces.Space) error { + ret := _m.Called(ctx, space) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *spaces.Space) error); ok { + r0 = rf(ctx, space) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Delete provides a mock function with given fields: ctx, filter +func (_m *Storage) Delete(ctx context.Context, filter *spaces.Filter) (int, error) { + ret := _m.Called(ctx, filter) + + var r0 int + if rf, ok := ret.Get(0).(func(context.Context, *spaces.Filter) int); ok { + r0 = rf(ctx, filter) + } else { + r0 = ret.Get(0).(int) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *spaces.Filter) error); ok { + r1 = rf(ctx, filter) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Find provides a mock function with given fields: ctx, filter, opts +func (_m *Storage) Find(ctx context.Context, filter *spaces.Filter, opts *options.FindOptions) ([]*spaces.Space, int, error) { + ret := _m.Called(ctx, filter, opts) + + var r0 []*spaces.Space + if rf, ok := ret.Get(0).(func(context.Context, *spaces.Filter, *options.FindOptions) []*spaces.Space); ok { + r0 = rf(ctx, filter, opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*spaces.Space) + } + } + + var r1 int + if rf, ok := ret.Get(1).(func(context.Context, *spaces.Filter, *options.FindOptions) int); ok { + r1 = rf(ctx, filter, opts) + } else { + r1 = ret.Get(1).(int) + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, *spaces.Filter, *options.FindOptions) error); ok { + r2 = rf(ctx, filter, opts) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// Init provides a mock function with given fields: ctx +func (_m *Storage) Init(ctx context.Context) error { + ret := _m.Called(ctx) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Reset provides a mock function with given fields: ctx +func (_m *Storage) Reset(ctx context.Context) error { + ret := _m.Called(ctx) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Update provides a mock function with given fields: ctx, update, filter +func (_m *Storage) Update(ctx context.Context, update *spaces.Space, filter *spaces.Filter) (int, int, error) { + ret := _m.Called(ctx, update, filter) + + var r0 int + if rf, ok := ret.Get(0).(func(context.Context, *spaces.Space, *spaces.Filter) int); ok { + r0 = rf(ctx, update, filter) + } else { + r0 = ret.Get(0).(int) + } + + var r1 int + if rf, ok := ret.Get(1).(func(context.Context, *spaces.Space, *spaces.Filter) int); ok { + r1 = rf(ctx, update, filter) + } else { + r1 = ret.Get(1).(int) + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, *spaces.Space, *spaces.Filter) error); ok { + r2 = rf(ctx, update, filter) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +type mockConstructorTestingTNewStorage interface { + mock.TestingT + Cleanup(func()) +} + +// NewStorage creates a new instance of Storage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewStorage(t mockConstructorTestingTNewStorage) *Storage { + mock := &Storage{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/spaces/observer.go b/pkg/spaces/observer.go new file mode 100644 index 0000000000000000000000000000000000000000..b3d3e60b1746fcccfef3cc21439c74d605096e64 --- /dev/null +++ b/pkg/spaces/observer.go @@ -0,0 +1,17 @@ +package spaces + +import "context" + +type SpaceObserver interface{} + +type SpaceCreatedObserver interface { + OnSpaceCreated(ctx context.Context, space *Space) error +} + +type SpaceUpdatedObserver interface { + OnSpaceUpdated(ctx context.Context, before, space *Space) error +} + +type SpaceDeletedObserver interface { + OnSpaceDeleted(ctx context.Context, space *Space) error +} diff --git a/pkg/spaces/storage.go b/pkg/spaces/storage.go new file mode 100644 index 0000000000000000000000000000000000000000..52baf9da5cfaebf0cfb331698c7284d1eba809a2 --- /dev/null +++ b/pkg/spaces/storage.go @@ -0,0 +1,23 @@ +package spaces + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/options" +) + +type Storage interface { + Create(ctx context.Context, space *Space) error + Find(ctx context.Context, filter *Filter, opts *options.FindOptions) (spaces []*Space, total int, err error) + Delete(ctx context.Context, filter *Filter) (total int, err error) + Update(ctx context.Context, update *Space, filter *Filter) (updated, total int, err error) + Reset(ctx context.Context) error + Init(ctx context.Context) error +} + +type Filter struct { + ID []string `json:"id,omitempty" bson:"_id"` + OrgID []string `json:"org_id,omitempty" bson:"orgId"` + Name []string `json:"name,omitempty" bson:"name"` + State []State `json:"state,omitempty" bson:"state"` +} diff --git a/pkg/users/middleware/telemetry_middleware.go b/pkg/users/middleware/telemetry_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..a68b365d63d4c7668daf80035ca0f82d3d4bd598 --- /dev/null +++ b/pkg/users/middleware/telemetry_middleware.go @@ -0,0 +1,164 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: ../../../assets/templates/middleware/telemetry +// gowrap: http://github.com/hexdigest/gowrap + +package middleware + +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/users -i Users -t ../../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l "" + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/options" + "git.perx.ru/perxis/perxis-go/pkg/users" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +// telemetryMiddleware implements users.Users interface instrumented with opentracing spans +type telemetryMiddleware struct { + users.Users + _instance string + _spanDecorator func(span trace.Span, params, results map[string]interface{}) +} + +// TelemetryMiddleware returns telemetryMiddleware +func TelemetryMiddleware(base users.Users, instance string, spanDecorator ...func(span trace.Span, params, results map[string]interface{})) telemetryMiddleware { + d := telemetryMiddleware{ + Users: base, + _instance: instance, + } + + if len(spanDecorator) > 0 && spanDecorator[0] != nil { + d._spanDecorator = spanDecorator[0] + } + + return d +} + +// Create implements users.Users +func (_d telemetryMiddleware) Create(ctx context.Context, create *users.User) (user *users.User, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Users.Create") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "create": create}, map[string]interface{}{ + "user": user, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Users.Create(ctx, create) +} + +// Delete implements users.Users +func (_d telemetryMiddleware) Delete(ctx context.Context, userId string) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Users.Delete") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "userId": userId}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Users.Delete(ctx, userId) +} + +// Find implements users.Users +func (_d telemetryMiddleware) Find(ctx context.Context, filter *users.Filter, options *options.FindOptions) (users []*users.User, total int, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Users.Find") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "filter": filter, + "options": options}, map[string]interface{}{ + "users": users, + "total": total, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Users.Find(ctx, filter, options) +} + +// Get implements users.Users +func (_d telemetryMiddleware) Get(ctx context.Context, userId string) (user *users.User, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Users.Get") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "userId": userId}, map[string]interface{}{ + "user": user, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Users.Get(ctx, userId) +} + +// GetByIdentity implements users.Users +func (_d telemetryMiddleware) GetByIdentity(ctx context.Context, identity string) (user *users.User, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Users.GetByIdentity") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "identity": identity}, map[string]interface{}{ + "user": user, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Users.GetByIdentity(ctx, identity) +} + +// Update implements users.Users +func (_d telemetryMiddleware) Update(ctx context.Context, update *users.User) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Users.Update") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "update": update}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Users.Update(ctx, update) +} diff --git a/pkg/users/mocks/Storage.go b/pkg/users/mocks/Storage.go new file mode 100644 index 0000000000000000000000000000000000000000..e918d42414221cc2b6f29abe27116777714df08a --- /dev/null +++ b/pkg/users/mocks/Storage.go @@ -0,0 +1,162 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + options "git.perx.ru/perxis/perxis-go/pkg/options" + mock "github.com/stretchr/testify/mock" + + users "git.perx.ru/perxis/perxis-go/pkg/users" +) + +// Storage is an autogenerated mock type for the Storage type +type Storage struct { + mock.Mock +} + +// Create provides a mock function with given fields: ctx, create +func (_m *Storage) Create(ctx context.Context, create *users.User) (*users.User, error) { + ret := _m.Called(ctx, create) + + var r0 *users.User + if rf, ok := ret.Get(0).(func(context.Context, *users.User) *users.User); ok { + r0 = rf(ctx, create) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*users.User) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *users.User) error); ok { + r1 = rf(ctx, create) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Delete provides a mock function with given fields: ctx, filter +func (_m *Storage) Delete(ctx context.Context, filter *users.Filter) (int, error) { + ret := _m.Called(ctx, filter) + + var r0 int + if rf, ok := ret.Get(0).(func(context.Context, *users.Filter) int); ok { + r0 = rf(ctx, filter) + } else { + r0 = ret.Get(0).(int) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *users.Filter) error); ok { + r1 = rf(ctx, filter) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Find provides a mock function with given fields: ctx, filter, opts +func (_m *Storage) Find(ctx context.Context, filter *users.Filter, opts *options.FindOptions) ([]*users.User, int, error) { + ret := _m.Called(ctx, filter, opts) + + var r0 []*users.User + if rf, ok := ret.Get(0).(func(context.Context, *users.Filter, *options.FindOptions) []*users.User); ok { + r0 = rf(ctx, filter, opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*users.User) + } + } + + var r1 int + if rf, ok := ret.Get(1).(func(context.Context, *users.Filter, *options.FindOptions) int); ok { + r1 = rf(ctx, filter, opts) + } else { + r1 = ret.Get(1).(int) + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, *users.Filter, *options.FindOptions) error); ok { + r2 = rf(ctx, filter, opts) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// Init provides a mock function with given fields: ctx +func (_m *Storage) Init(ctx context.Context) error { + ret := _m.Called(ctx) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Reset provides a mock function with given fields: ctx +func (_m *Storage) Reset(ctx context.Context) error { + ret := _m.Called(ctx) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Update provides a mock function with given fields: ctx, update, filter +func (_m *Storage) Update(ctx context.Context, update *users.User, filter *users.Filter) (int, int, error) { + ret := _m.Called(ctx, update, filter) + + var r0 int + if rf, ok := ret.Get(0).(func(context.Context, *users.User, *users.Filter) int); ok { + r0 = rf(ctx, update, filter) + } else { + r0 = ret.Get(0).(int) + } + + var r1 int + if rf, ok := ret.Get(1).(func(context.Context, *users.User, *users.Filter) int); ok { + r1 = rf(ctx, update, filter) + } else { + r1 = ret.Get(1).(int) + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, *users.User, *users.Filter) error); ok { + r2 = rf(ctx, update, filter) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +type mockConstructorTestingTNewStorage interface { + mock.TestingT + Cleanup(func()) +} + +// NewStorage creates a new instance of Storage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewStorage(t mockConstructorTestingTNewStorage) *Storage { + mock := &Storage{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/users/storage.go b/pkg/users/storage.go new file mode 100644 index 0000000000000000000000000000000000000000..7600525f6cfdb0fb896fa3f477ed6cc493e26eff --- /dev/null +++ b/pkg/users/storage.go @@ -0,0 +1,17 @@ +package users + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/options" +) + +type Storage interface { + Create(ctx context.Context, create *User) (user *User, err error) + Find(ctx context.Context, filter *Filter, opts *options.FindOptions) (users []*User, total int, err error) + Update(ctx context.Context, update *User, filter *Filter) (updated, total int, err error) + Delete(ctx context.Context, filter *Filter) (total int, err error) + + Reset(ctx context.Context) error + Init(ctx context.Context) error +}