From 56454cffbe8d97561d6306726dc868ddcb0c9abe Mon Sep 17 00:00:00 2001 From: akeemphilbert Date: Sat, 30 Mar 2024 19:48:52 -0400 Subject: [PATCH] feature: #279 Stored setting up Default write controller * Added interface for event store * Setup GORM based event store * Changed the resourced repository to have the event dispatcher injected (instead of making it implement the event dispatcher) --- v2/rest/api.go | 2 +- v2/rest/controllers.go | 8 +- v2/rest/controllers_test.go | 64 +++ v2/rest/event.go | 104 ++--- v2/rest/event_test.go | 124 ++++++ v2/rest/fixtures/blog.yaml | 1 + v2/rest/gorm.go | 118 ++++++ v2/rest/interfaces.go | 8 +- v2/rest/repository.go | 90 +--- v2/rest/repository_test.go | 157 ++----- v2/rest/resource.go | 17 +- v2/rest/resource_test.go | 40 +- v2/rest/rest_mocks_test.go | 825 ++++++++++++++++++++++++++++++++++++ 13 files changed, 1231 insertions(+), 327 deletions(-) create mode 100644 v2/rest/controllers_test.go create mode 100644 v2/rest/event_test.go diff --git a/v2/rest/api.go b/v2/rest/api.go index 661e7169..ce0dc157 100644 --- a/v2/rest/api.go +++ b/v2/rest/api.go @@ -32,7 +32,7 @@ var API = fx.Module("rest", NewGORM, NewGORMResourceRepository, NewCommandDispatcher, - NewEventDispatcher, + NewGORMEventStore, ), fx.Invoke(RouteInitializer, registerHooks), ) diff --git a/v2/rest/controllers.go b/v2/rest/controllers.go index 5df85a78..9e31da5b 100644 --- a/v2/rest/controllers.go +++ b/v2/rest/controllers.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/getkin/kin-openapi/openapi3" "github.com/labstack/echo/v4" + "io" "net/http" "strconv" ) @@ -64,9 +65,12 @@ func DefaultWriteController(logger Log, commandDispatcher CommandDispatcher, res } var resource *BasicResource - if err := ctxt.Bind(&resource); err != nil { - return NewControllerError("unexpected resource", err, http.StatusBadRequest) + body, err := io.ReadAll(ctxt.Request().Body) + if err != nil { + ctxt.Logger().Debugf("unexpected error reading request body: %s", err) + return NewControllerError("unexpected error reading request body", err, http.StatusBadRequest) } + resource, err = new(BasicResource).FromSchema(api, body) //not sure this is correct payload, err := json.Marshal(&ResourceCreateParams{ Resource: resource, diff --git a/v2/rest/controllers_test.go b/v2/rest/controllers_test.go new file mode 100644 index 00000000..24a73cec --- /dev/null +++ b/v2/rest/controllers_test.go @@ -0,0 +1,64 @@ +package rest_test + +import ( + "github.com/getkin/kin-openapi/openapi3" + "github.com/labstack/echo/v4" + "github.com/wepala/weos/v2/rest" + "golang.org/x/net/context" + "net/http" + "net/http/httptest" + "strings" + "testing" +) + +func TestDefaultWriteController(t *testing.T) { + schema, err := openapi3.NewLoader().LoadFromFile("fixtures/blog.yaml") + if err != nil { + t.Fatalf("error encountered loading schema '%s'", err) + } + logger := &LogMock{ + DebugfFunc: func(format string, args ...interface{}) { + + }, + DebugFunc: func(args ...interface{}) { + + }, + ErrorfFunc: func(format string, args ...interface{}) { + + }, + ErrorFunc: func(args ...interface{}) { + + }, + } + t.Run("create a simple resource", func(t *testing.T) { + repository := &RepositoryMock{ + PersistFunc: func(ctxt context.Context, logger rest.Log, resources []rest.Resource) []error { + return nil + }, + } + commandDispatcher := &CommandDispatcherMock{ + DispatchFunc: func(ctx context.Context, command *rest.Command, repository rest.Repository, logger rest.Log) (interface{}, error) { + return nil, nil + }, + } + controller := rest.DefaultWriteController(logger, commandDispatcher, repository, schema, nil, nil) + e := echo.New() + e.POST("/*", controller) + resp := httptest.NewRecorder() + req := httptest.NewRequest(echo.POST, "/blogs/test", strings.NewReader(`{ + "@id": "/blogs/test", + "@type": "http://schema.org/Blog", + "title":"test" +}`)) + req.Header.Set(echo.HeaderContentType, "application/ld+json") + e.ServeHTTP(resp, req) + if resp.Code != http.StatusCreated { + t.Errorf("expected status code %d, got %d", http.StatusCreated, resp.Code) + } + + if len(commandDispatcher.DispatchCalls()) != 1 { + t.Errorf("expected dispatch to be called once, got %d", len(commandDispatcher.DispatchCalls())) + } + + }) +} diff --git a/v2/rest/event.go b/v2/rest/event.go index 81b86ff8..ac112e3a 100644 --- a/v2/rest/event.go +++ b/v2/rest/event.go @@ -2,82 +2,8 @@ package rest import ( "encoding/json" - "go.uber.org/fx" - "golang.org/x/net/context" - "sync" ) -type EventDispatcherParams struct { - fx.In - EventConfigs []EventHandlerConfig `group:"eventHandlers"` -} - -type EventDispatcherResult struct { - fx.Out - Dispatcher EventDispatcher -} - -func NewEventDispatcher(p EventDispatcherParams) EventDispatcherResult { - dispatcher := &DefaultEventDisptacher{ - handlers: make(map[string][]EventHandler), - } - for _, config := range p.EventConfigs { - dispatcher.AddSubscriber(config) - } - return EventDispatcherResult{} -} - -type EventHandlerConfig struct { - ResourceType string - Type string - Handler EventHandler -} - -type DefaultEventDisptacher struct { - handlers map[string][]EventHandler - handlerPanicked bool -} - -func (e *DefaultEventDisptacher) Dispatch(ctx context.Context, event Event) []error { - //mutex helps keep state between routines - var errors []error - var wg sync.WaitGroup - if handlers, ok := e.handlers[event.Type]; ok { - for i := 0; i < len(handlers); i++ { - //handler := handlers[i] - wg.Add(1) - go func() { - defer func() { - if r := recover(); r != nil { - e.handlerPanicked = true - } - wg.Done() - }() - - //err := handler(ctx, event) - //if err != nil { - // errors = append(errors, err) - //} - - }() - } - wg.Wait() - } - - return errors -} - -func (e *DefaultEventDisptacher) AddSubscriber(config EventHandlerConfig) { - if e.handlers == nil { - e.handlers = map[string][]EventHandler{} - } - e.handlers[config.Type] = append(e.handlers[config.Type], config.Handler) -} - -func (e *DefaultEventDisptacher) GetSubscribers() map[string][]EventHandler { - return e.handlers -} - type Event struct { ID string `json:"id"` Type string `json:"type"` @@ -97,3 +23,33 @@ type EventMeta struct { AccountID string `json:"accountId"` Created string `json:"created"` } + +func (e *Event) NewChange(event *Event) { + //TODO implement me + panic("implement me") +} + +func (e *Event) GetNewChanges() []Resource { + //TODO implement me + panic("implement me") +} + +func (e *Event) Persist() { + //TODO implement me + panic("implement me") +} + +func (e *Event) GetType() string { + //TODO implement me + panic("implement me") +} + +func (e *Event) GetSequenceNo() int { + //TODO implement me + panic("implement me") +} + +func (e *Event) GetID() string { + //TODO implement me + panic("implement me") +} diff --git a/v2/rest/event_test.go b/v2/rest/event_test.go new file mode 100644 index 00000000..2b318c58 --- /dev/null +++ b/v2/rest/event_test.go @@ -0,0 +1,124 @@ +package rest_test + +import ( + "github.com/wepala/weos/v2/rest" + "golang.org/x/net/context" + "testing" +) + +func TestDefaultEventDisptacher_AddSubscriber(t *testing.T) { + t.Run("add subscriber for event type only", func(t *testing.T) { + eventDispatcher := new(rest.GORMEventStore) + err := eventDispatcher.AddSubscriber(rest.EventHandlerConfig{ + Type: "create", + Handler: func(ctx context.Context, logger rest.Log, event rest.Event) error { + return nil + }, + }) + if err != nil { + t.Errorf("expected no error, got %s", err) + } + handlers := eventDispatcher.GetSubscribers("") + if len(handlers) != 1 { + t.Errorf("expected 1 handler, got %d", len(handlers)) + } + if handler, ok := handlers["create"]; !ok { + t.Errorf("expected handler for create event type") + } else { + if handler == nil { + t.Errorf("expected handler for create event type") + } + } + }) + t.Run("add subscriber for resource type and event", func(t *testing.T) { + eventDispatcher := new(rest.GORMEventStore) + err := eventDispatcher.AddSubscriber(rest.EventHandlerConfig{ + ResourceType: "Article", + Type: "create", + Handler: func(ctx context.Context, logger rest.Log, event rest.Event) error { + return nil + }, + }) + if err != nil { + t.Errorf("expected no error, got %s", err) + } + handlers := eventDispatcher.GetSubscribers("Article") + if len(handlers) != 1 { + t.Errorf("expected 1 handler, got %d", len(handlers)) + } + if handler, ok := handlers["create"]; !ok { + t.Errorf("expected handler for create event type") + } else { + if handler == nil { + t.Errorf("expected handler for create event type") + } + } + }) + t.Run("adding subscriber without handler should throw error", func(t *testing.T) { + eventDispatcher := new(rest.GORMEventStore) + err := eventDispatcher.AddSubscriber(rest.EventHandlerConfig{ + Type: "create", + }) + if err == nil { + t.Errorf("expected error, got nil") + } + }) +} + +func TestResourceRepository_Dispatch(t *testing.T) { + logger := &LogMock{ + DebugfFunc: func(format string, args ...interface{}) { + + }, + DebugFunc: func(args ...interface{}) { + + }, + ErrorfFunc: func(format string, args ...interface{}) { + + }, + ErrorFunc: func(args ...interface{}) { + + }, + } + t.Run("should trigger resource specific handler and generic event type handler", func(t *testing.T) { + createHandlerHit := false + articleCreateHandlerHit := false + eventDispatcher := new(rest.GORMEventStore) + err := eventDispatcher.AddSubscriber(rest.EventHandlerConfig{ + Type: "create", + Handler: func(ctx context.Context, logger rest.Log, event rest.Event) error { + createHandlerHit = true + return nil + }, + }) + if err != nil { + t.Errorf("expected no error, got %s", err) + } + err = eventDispatcher.AddSubscriber(rest.EventHandlerConfig{ + Type: "create", + ResourceType: "Article", + Handler: func(ctx context.Context, logger rest.Log, event rest.Event) error { + articleCreateHandlerHit = true + return nil + }, + }) + if err != nil { + t.Errorf("expected no error, got %s", err) + } + errors := eventDispatcher.Dispatch(context.Background(), rest.Event{ + Type: "create", + Meta: rest.EventMeta{ + ResourceType: "Article", + }, + }, logger) + if len(errors) != 0 { + t.Errorf("expected no errors, got %d", len(errors)) + } + if !createHandlerHit { + t.Errorf("expected create handler to be hit") + } + if !articleCreateHandlerHit { + t.Errorf("expected article create handler to be hit") + } + }) +} diff --git a/v2/rest/fixtures/blog.yaml b/v2/rest/fixtures/blog.yaml index 41bf9de7..34cd2609 100644 --- a/v2/rest/fixtures/blog.yaml +++ b/v2/rest/fixtures/blog.yaml @@ -875,3 +875,4 @@ paths: responses: 200: description: Delete author + diff --git a/v2/rest/gorm.go b/v2/rest/gorm.go index d730688c..ff668afd 100644 --- a/v2/rest/gorm.go +++ b/v2/rest/gorm.go @@ -17,6 +17,7 @@ import ( "os" "strconv" "strings" + "sync" "time" ) @@ -207,3 +208,120 @@ func (w GORMResourceRepository) Delete(ctxt context.Context, logger Log, resourc result := w.db.Delete(resource) return result.Error } + +type GORMEventStoreParams struct { + fx.In + GORMDB *gorm.DB + EventConfigs []EventHandlerConfig `group:"eventHandlers"` +} + +type GORMEventStoreResult struct { + fx.Out + Dispatcher EventDispatcher +} + +func NewGORMEventStore(p GORMEventStoreParams) GORMEventStoreResult { + dispatcher := &GORMEventStore{ + handlers: make(map[string]map[string][]EventHandler), + } + for _, config := range p.EventConfigs { + dispatcher.AddSubscriber(config) + } + return GORMEventStoreResult{} +} + +type EventHandlerConfig struct { + ResourceType string + Type string + Handler EventHandler +} + +type GORMEventStore struct { + handlers map[string]map[string][]EventHandler + handlerPanicked bool +} + +func (e *GORMEventStore) Dispatch(ctx context.Context, event Event, logger Log) []error { + //mutex helps keep state between routines + var errors []error + var wg sync.WaitGroup + if resourceTypeHandlers, ok := e.handlers[event.Meta.ResourceType]; ok { + + if handlers, ok := resourceTypeHandlers[event.Type]; ok { + //check to see if there were handlers registered for the event type that is not specific to a resource type + if event.Meta.ResourceType != "" { + if eventTypeHandlers, ok := e.handlers[""]; ok { + if ehandlers, ok := eventTypeHandlers[event.Type]; ok { + handlers = append(handlers, ehandlers...) + } + } + } + for i := 0; i < len(handlers); i++ { + handler := handlers[i] + wg.Add(1) + go func() { + defer func() { + if r := recover(); r != nil { + logger.Errorf("handler panicked %s", r) + } + wg.Done() + }() + + err := handler(ctx, logger, event) + if err != nil { + errors = append(errors, err) + } + + }() + } + wg.Wait() + } + + } + + return errors +} + +func (e *GORMEventStore) AddSubscriber(handler EventHandlerConfig) error { + if handler.Handler == nil { + return fmt.Errorf("event handler cannot be nil") + } + if e.handlers == nil { + e.handlers = make(map[string]map[string][]EventHandler) + } + if _, ok := e.handlers[handler.ResourceType]; !ok { + e.handlers[handler.ResourceType] = make(map[string][]EventHandler) + } + if _, ok := e.handlers[handler.ResourceType][handler.Type]; !ok { + e.handlers[handler.ResourceType][handler.Type] = make([]EventHandler, 0) + } + e.handlers[handler.ResourceType][handler.Type] = append(e.handlers[handler.ResourceType][handler.Type], handler.Handler) + return nil +} + +func (e *GORMEventStore) GetSubscribers(resourceType string) map[string][]EventHandler { + if handlers, ok := e.handlers[resourceType]; ok { + return handlers + } + return nil +} + +func (e *GORMEventStore) GetByURI(ctxt context.Context, logger Log, uri string) (Resource, error) { + //TODO implement me + panic("implement me") +} + +func (e *GORMEventStore) GetByKey(ctxt context.Context, identifiers map[string]interface{}) (Resource, error) { + //TODO implement me + panic("implement me") +} + +func (e *GORMEventStore) GetList(ctx context.Context, page int, limit int, query string, sortOptions map[string]string, filterOptions map[string]interface{}) ([]Resource, int64, error) { + //TODO implement me + panic("implement me") +} + +func (e *GORMEventStore) GetByProperties(ctxt context.Context, identifiers map[string]interface{}) ([]Entity, error) { + //TODO implement me + panic("implement me") +} diff --git a/v2/rest/interfaces.go b/v2/rest/interfaces.go index 5d86c78d..dfc2130f 100644 --- a/v2/rest/interfaces.go +++ b/v2/rest/interfaces.go @@ -1,4 +1,4 @@ -//go:generate moq -out rest_mocks_test.go -pkg rest_test . Log Repository Projection +//go:generate moq -out rest_mocks_test.go -pkg rest_test . Log Repository Projection CommandDispatcher EventDispatcher EventStore package rest import ( @@ -49,6 +49,12 @@ type EventDispatcher interface { Dispatch(ctx context.Context, event Event, logger Log) []error } +type EventStore interface { + Repository + EventDispatcher + Projection +} + type Projection interface { GetByURI(ctxt context.Context, logger Log, uri string) (Resource, error) // GetByKey returns a single content entity diff --git a/v2/rest/repository.go b/v2/rest/repository.go index 4e3aa097..44bcd66f 100644 --- a/v2/rest/repository.go +++ b/v2/rest/repository.go @@ -1,15 +1,14 @@ package rest import ( - "fmt" "go.uber.org/fx" "golang.org/x/net/context" - "sync" ) type ResourceRepositoryParams struct { fx.In - Handlers []EventHandlerConfig `group:"projections"` + EventStore EventStore + Handlers []EventHandlerConfig `group:"projections"` } type ResourceRepositoryResult struct { @@ -18,96 +17,29 @@ type ResourceRepositoryResult struct { } // NewResourceRepository creates a new resource repository and registers all the event handlers -func NewResourceRepository(p ResourceRepositoryParams) ResourceRepositoryResult { +func NewResourceRepository(p ResourceRepositoryParams) (ResourceRepositoryResult, error) { repo := ResourceRepository{ - handlers: make(map[string]map[string][]EventHandler), + eventStore: p.EventStore, } for _, handler := range p.Handlers { - repo.AddSubscriber(handler) + err := p.EventStore.AddSubscriber(handler) + if err != nil { + return ResourceRepositoryResult{}, err + } } return ResourceRepositoryResult{ Repository: repo, - } + }, nil } type ResourceRepository struct { - handlers map[string]map[string][]EventHandler -} - -func (r *ResourceRepository) AddSubscriber(handler EventHandlerConfig) error { - if handler.Handler == nil { - return fmt.Errorf("event handler cannot be nil") - } - if r.handlers == nil { - r.handlers = make(map[string]map[string][]EventHandler) - } - if _, ok := r.handlers[handler.ResourceType]; !ok { - r.handlers[handler.ResourceType] = make(map[string][]EventHandler) - } - if _, ok := r.handlers[handler.ResourceType][handler.Type]; !ok { - r.handlers[handler.ResourceType][handler.Type] = make([]EventHandler, 0) - } - r.handlers[handler.ResourceType][handler.Type] = append(r.handlers[handler.ResourceType][handler.Type], handler.Handler) - return nil -} - -// GetSubscribers returns all the event handlers for a specific resource type -func (r *ResourceRepository) GetSubscribers(resourceType string) map[string][]EventHandler { - if handlers, ok := r.handlers[resourceType]; ok { - return handlers - } - return nil -} - -// Dispatch executes all the event handlers for a specific event -func (r *ResourceRepository) Dispatch(ctx context.Context, event Event, logger Log) []error { - //mutex helps keep state between routines - var errors []error - var wg sync.WaitGroup - if resourceTypeHandlers, ok := r.handlers[event.Meta.ResourceType]; ok { - - if handlers, ok := resourceTypeHandlers[event.Type]; ok { - //check to see if there were handlers registered for the event type that is not specific to a resource type - if event.Meta.ResourceType != "" { - if eventTypeHandlers, ok := r.handlers[""]; ok { - if ehandlers, ok := eventTypeHandlers[event.Type]; ok { - handlers = append(handlers, ehandlers...) - } - } - } - for i := 0; i < len(handlers); i++ { - handler := handlers[i] - wg.Add(1) - go func() { - defer func() { - if r := recover(); r != nil { - logger.Errorf("handler panicked %s", r) - } - wg.Done() - }() - - err := handler(ctx, logger, event) - if err != nil { - errors = append(errors, err) - } - - }() - } - wg.Wait() - } - - } - - return errors + eventStore EventStore } func (r *ResourceRepository) Persist(ctxt context.Context, logger Log, resources []Resource) []error { var errs []error for _, resource := range resources { - for _, event := range resource.GetNewChanges() { - terrs := r.Dispatch(ctxt, *event, logger) - errs = append(errs, terrs...) - } + r.eventStore.Persist(ctxt, logger, resource.GetNewChanges()) } return errs } diff --git a/v2/rest/repository_test.go b/v2/rest/repository_test.go index 2493f3e7..d3c635ab 100644 --- a/v2/rest/repository_test.go +++ b/v2/rest/repository_test.go @@ -7,126 +7,8 @@ import ( "testing" ) -func TestResourceRepository_AddSubscriber(t *testing.T) { - t.Run("add subscriber for event type only", func(t *testing.T) { - resourceRepository := new(rest.ResourceRepository) - err := resourceRepository.AddSubscriber(rest.EventHandlerConfig{ - Type: "create", - Handler: func(ctx context.Context, logger rest.Log, event rest.Event) error { - return nil - }, - }) - if err != nil { - t.Errorf("expected no error, got %s", err) - } - handlers := resourceRepository.GetSubscribers("") - if len(handlers) != 1 { - t.Errorf("expected 1 handler, got %d", len(handlers)) - } - if handler, ok := handlers["create"]; !ok { - t.Errorf("expected handler for create event type") - } else { - if handler == nil { - t.Errorf("expected handler for create event type") - } - } - }) - t.Run("add subscriber for resource type and event", func(t *testing.T) { - resourceRepository := new(rest.ResourceRepository) - err := resourceRepository.AddSubscriber(rest.EventHandlerConfig{ - ResourceType: "Article", - Type: "create", - Handler: func(ctx context.Context, logger rest.Log, event rest.Event) error { - return nil - }, - }) - if err != nil { - t.Errorf("expected no error, got %s", err) - } - handlers := resourceRepository.GetSubscribers("Article") - if len(handlers) != 1 { - t.Errorf("expected 1 handler, got %d", len(handlers)) - } - if handler, ok := handlers["create"]; !ok { - t.Errorf("expected handler for create event type") - } else { - if handler == nil { - t.Errorf("expected handler for create event type") - } - } - }) - t.Run("adding subscriber without handler should throw error", func(t *testing.T) { - resourceRepository := new(rest.ResourceRepository) - err := resourceRepository.AddSubscriber(rest.EventHandlerConfig{ - Type: "create", - }) - if err == nil { - t.Errorf("expected error, got nil") - } - }) -} - -func TestResourceRepository_Dispatch(t *testing.T) { - logger := &LogMock{ - DebugfFunc: func(format string, args ...interface{}) { - - }, - DebugFunc: func(args ...interface{}) { - - }, - ErrorfFunc: func(format string, args ...interface{}) { - - }, - ErrorFunc: func(args ...interface{}) { - - }, - } - t.Run("should trigger resource specific handler and generic event type handler", func(t *testing.T) { - createHandlerHit := false - articleCreateHandlerHit := false - resourceRepository := new(rest.ResourceRepository) - err := resourceRepository.AddSubscriber(rest.EventHandlerConfig{ - Type: "create", - Handler: func(ctx context.Context, logger rest.Log, event rest.Event) error { - createHandlerHit = true - return nil - }, - }) - if err != nil { - t.Errorf("expected no error, got %s", err) - } - err = resourceRepository.AddSubscriber(rest.EventHandlerConfig{ - Type: "create", - ResourceType: "Article", - Handler: func(ctx context.Context, logger rest.Log, event rest.Event) error { - articleCreateHandlerHit = true - return nil - }, - }) - if err != nil { - t.Errorf("expected no error, got %s", err) - } - errors := resourceRepository.Dispatch(context.Background(), rest.Event{ - Type: "create", - Meta: rest.EventMeta{ - ResourceType: "Article", - }, - }, logger) - if len(errors) != 0 { - t.Errorf("expected no errors, got %d", len(errors)) - } - if !createHandlerHit { - t.Errorf("expected create handler to be hit") - } - if !articleCreateHandlerHit { - t.Errorf("expected article create handler to be hit") - } - }) -} - func TestResourceRepository_Persist(t *testing.T) { - var blogSchema *openapi3.SchemaRef - var ok bool + logger := &LogMock{ DebugfFunc: func(format string, args ...interface{}) { @@ -145,24 +27,39 @@ func TestResourceRepository_Persist(t *testing.T) { if err != nil { t.Fatalf("error encountered loading schema '%s'", err) } - if blogSchema, ok = schema.Components.Schemas["Blog"]; !ok { - t.Fatalf("expected schema to have Blog, got %v", schema.Components.Schemas) - - } t.Run("should trigger Blog create event", func(t *testing.T) { createBlogHandlerHit := false - resource, err := new(rest.BasicResource).FromSchema("", blogSchema.Value, []byte(`{"title": "test"}`)) + resource, err := new(rest.BasicResource).FromSchema(schema, []byte(`{ + "@id": "/blogs/test", + "@type": "http://schema.org/Blog", + "title": "test" +}`)) + if err != nil { + t.Fatalf("expected no error, got %s", err) + } - resourceRepository := new(rest.ResourceRepository) - err = resourceRepository.AddSubscriber(rest.EventHandlerConfig{ - Type: "create", - ResourceType: "http://schema.org/Blog", - Handler: func(ctx context.Context, logger rest.Log, event rest.Event) error { + eventDispatcher := &EventStoreMock{ + AddSubscriberFunc: func(config rest.EventHandlerConfig) error { + return nil + }, + DispatchFunc: func(ctx context.Context, event rest.Event, logger rest.Log) []error { + //TODO check that the event is the correct one createBlogHandlerHit = true return nil }, - }) + PersistFunc: func(ctxt context.Context, logger rest.Log, resources []rest.Resource) []error { + return nil + }, + } + params := rest.ResourceRepositoryParams{ + EventStore: eventDispatcher, + } + result, err := rest.NewResourceRepository(params) + if err != nil { + t.Fatalf("expected no error, got %s", err) + } + resourceRepository := result.Repository if err != nil { t.Fatalf("expected no error, got %s", err) } diff --git a/v2/rest/resource.go b/v2/rest/resource.go index 839847ec..a19d1774 100644 --- a/v2/rest/resource.go +++ b/v2/rest/resource.go @@ -2,6 +2,7 @@ package rest import ( "encoding/json" + "fmt" "github.com/getkin/kin-openapi/openapi3" "github.com/segmentio/ksuid" "time" @@ -9,7 +10,7 @@ import ( type EventSourced interface { NewChange(event *Event) - GetNewChanges() []*Event + GetNewChanges() []Resource Persist() } @@ -23,7 +24,7 @@ type Resource interface { type BasicResource struct { body map[string]interface{} Metadata ResourceMetadata - newEvents []*Event + newEvents []Resource } type ResourceMetadata struct { @@ -53,23 +54,19 @@ func (r *BasicResource) UnmarshalJSON(data []byte) error { } // FromSchema creates a new BasicResource from a schema and data -func (r *BasicResource) FromSchema(schemaName string, schema *openapi3.Schema, data []byte) (*BasicResource, error) { +func (r *BasicResource) FromSchema(schema *openapi3.T, data []byte) (*BasicResource, error) { err := r.UnmarshalJSON(data) //TODO use the schema to validate the data //TODO fill in any missing blanks if r.GetType() == "" { - if resourceType, ok := schema.Extensions["x-rdf-type"]; ok { - r.body["@type"] = resourceType - } else { - r.body["@type"] = schemaName - } + return nil, fmt.Errorf("missing type") } r.NewChange(NewResourceEvent("create", r, r.body)) return r, err } func (r *BasicResource) IsValid() bool { - //TODO implement me + //TODO this should use the matched schema from the OpenAPI spec to validate the resource panic("implement me") } @@ -108,7 +105,7 @@ func (r *BasicResource) NewChange(event *Event) { } // GetNewChanges returns the list of new events -func (r *BasicResource) GetNewChanges() []*Event { +func (r *BasicResource) GetNewChanges() []Resource { return r.newEvents } diff --git a/v2/rest/resource_test.go b/v2/rest/resource_test.go index 8d874c44..3422ba81 100644 --- a/v2/rest/resource_test.go +++ b/v2/rest/resource_test.go @@ -7,18 +7,12 @@ import ( ) func TestBasicResource_FromSchema(t *testing.T) { - var blogSchema *openapi3.SchemaRef - var ok bool schema, err := openapi3.NewLoader().LoadFromFile("fixtures/blog.yaml") if err != nil { t.Fatalf("error encountered loading schema '%s'", err) } - if blogSchema, ok = schema.Components.Schemas["Blog"]; !ok { - t.Fatalf("expected schema to have Blog, got %v", schema.Components.Schemas) - - } t.Run("create a simple resource", func(t *testing.T) { - resource, err := new(rest.BasicResource).FromSchema("", blogSchema.Value, []byte(`{ + resource, err := new(rest.BasicResource).FromSchema(schema, []byte(`{ "@id": "http://example.com/resource/1", "@type": "http://schema.org/Blog", "title": "test" @@ -34,7 +28,11 @@ func TestBasicResource_FromSchema(t *testing.T) { if len(events) != 1 { t.Fatalf("expected 1 event to be created, got %d", len(events)) } - event := events[0] + var event *rest.Event + var ok bool + if event, ok = events[0].(*rest.Event); !ok { + t.Fatalf("expected event to be of type Event") + } if event.Type != "create" { t.Errorf("expected event type to be create, got %s", event.Type) } @@ -45,31 +43,13 @@ func TestBasicResource_FromSchema(t *testing.T) { t.Errorf("expected event resource id to be http://example.com/resource/1, got %s", event.Meta.ResourceID) } }) - t.Run("resource type not specified should use the type in the schema", func(t *testing.T) { - resource, err := new(rest.BasicResource).FromSchema("", blogSchema.Value, []byte(`{ + t.Run("resource type not specified should return an error", func(t *testing.T) { + _, err := new(rest.BasicResource).FromSchema(schema, []byte(`{ "@id": "http://example.com/resource/1", "title": "test" }`)) - if err != nil { - t.Fatalf("expected no error, got %s", err) - } - if resource == nil { - t.Fatalf("expected resource to be created") - } - // check that the expected events were created - events := resource.GetNewChanges() - if len(events) != 1 { - t.Fatalf("expected 1 event to be created, got %d", len(events)) - } - event := events[0] - if event.Type != "create" { - t.Errorf("expected event type to be create, got %s", event.Type) - } - if event.Meta.ResourceType != "http://schema.org/Blog" { - t.Errorf("expected event resource type to be http://schema.org/Blog, got %s", event.Meta.ResourceType) - } - if event.Meta.ResourceID != "http://example.com/resource/1" { - t.Errorf("expected event resource id to be http://example.com/resource/1, got %s", event.Meta.ResourceID) + if err == nil { + t.Fatalf("expected error, got %s", err) } }) } diff --git a/v2/rest/rest_mocks_test.go b/v2/rest/rest_mocks_test.go index cdf2e353..4d306036 100644 --- a/v2/rest/rest_mocks_test.go +++ b/v2/rest/rest_mocks_test.go @@ -1074,3 +1074,828 @@ func (mock *ProjectionMock) GetListCalls() []struct { mock.lockGetList.RUnlock() return calls } + +// Ensure, that CommandDispatcherMock does implement rest.CommandDispatcher. +// If this is not the case, regenerate this file with moq. +var _ rest.CommandDispatcher = &CommandDispatcherMock{} + +// CommandDispatcherMock is a mock implementation of rest.CommandDispatcher. +// +// func TestSomethingThatUsesCommandDispatcher(t *testing.T) { +// +// // make and configure a mocked rest.CommandDispatcher +// mockedCommandDispatcher := &CommandDispatcherMock{ +// AddSubscriberFunc: func(command rest.CommandConfig) map[string][]rest.CommandHandler { +// panic("mock out the AddSubscriber method") +// }, +// DispatchFunc: func(ctx context.Context, command *rest.Command, repository rest.Repository, logger rest.Log) (interface{}, error) { +// panic("mock out the Dispatch method") +// }, +// GetSubscribersFunc: func() map[string][]rest.CommandHandler { +// panic("mock out the GetSubscribers method") +// }, +// } +// +// // use mockedCommandDispatcher in code that requires rest.CommandDispatcher +// // and then make assertions. +// +// } +type CommandDispatcherMock struct { + // AddSubscriberFunc mocks the AddSubscriber method. + AddSubscriberFunc func(command rest.CommandConfig) map[string][]rest.CommandHandler + + // DispatchFunc mocks the Dispatch method. + DispatchFunc func(ctx context.Context, command *rest.Command, repository rest.Repository, logger rest.Log) (interface{}, error) + + // GetSubscribersFunc mocks the GetSubscribers method. + GetSubscribersFunc func() map[string][]rest.CommandHandler + + // calls tracks calls to the methods. + calls struct { + // AddSubscriber holds details about calls to the AddSubscriber method. + AddSubscriber []struct { + // Command is the command argument value. + Command rest.CommandConfig + } + // Dispatch holds details about calls to the Dispatch method. + Dispatch []struct { + // Ctx is the ctx argument value. + Ctx context.Context + // Command is the command argument value. + Command *rest.Command + // Repository is the repository argument value. + Repository rest.Repository + // Logger is the logger argument value. + Logger rest.Log + } + // GetSubscribers holds details about calls to the GetSubscribers method. + GetSubscribers []struct { + } + } + lockAddSubscriber sync.RWMutex + lockDispatch sync.RWMutex + lockGetSubscribers sync.RWMutex +} + +// AddSubscriber calls AddSubscriberFunc. +func (mock *CommandDispatcherMock) AddSubscriber(command rest.CommandConfig) map[string][]rest.CommandHandler { + if mock.AddSubscriberFunc == nil { + panic("CommandDispatcherMock.AddSubscriberFunc: method is nil but CommandDispatcher.AddSubscriber was just called") + } + callInfo := struct { + Command rest.CommandConfig + }{ + Command: command, + } + mock.lockAddSubscriber.Lock() + mock.calls.AddSubscriber = append(mock.calls.AddSubscriber, callInfo) + mock.lockAddSubscriber.Unlock() + return mock.AddSubscriberFunc(command) +} + +// AddSubscriberCalls gets all the calls that were made to AddSubscriber. +// Check the length with: +// +// len(mockedCommandDispatcher.AddSubscriberCalls()) +func (mock *CommandDispatcherMock) AddSubscriberCalls() []struct { + Command rest.CommandConfig +} { + var calls []struct { + Command rest.CommandConfig + } + mock.lockAddSubscriber.RLock() + calls = mock.calls.AddSubscriber + mock.lockAddSubscriber.RUnlock() + return calls +} + +// Dispatch calls DispatchFunc. +func (mock *CommandDispatcherMock) Dispatch(ctx context.Context, command *rest.Command, repository rest.Repository, logger rest.Log) (interface{}, error) { + if mock.DispatchFunc == nil { + panic("CommandDispatcherMock.DispatchFunc: method is nil but CommandDispatcher.Dispatch was just called") + } + callInfo := struct { + Ctx context.Context + Command *rest.Command + Repository rest.Repository + Logger rest.Log + }{ + Ctx: ctx, + Command: command, + Repository: repository, + Logger: logger, + } + mock.lockDispatch.Lock() + mock.calls.Dispatch = append(mock.calls.Dispatch, callInfo) + mock.lockDispatch.Unlock() + return mock.DispatchFunc(ctx, command, repository, logger) +} + +// DispatchCalls gets all the calls that were made to Dispatch. +// Check the length with: +// +// len(mockedCommandDispatcher.DispatchCalls()) +func (mock *CommandDispatcherMock) DispatchCalls() []struct { + Ctx context.Context + Command *rest.Command + Repository rest.Repository + Logger rest.Log +} { + var calls []struct { + Ctx context.Context + Command *rest.Command + Repository rest.Repository + Logger rest.Log + } + mock.lockDispatch.RLock() + calls = mock.calls.Dispatch + mock.lockDispatch.RUnlock() + return calls +} + +// GetSubscribers calls GetSubscribersFunc. +func (mock *CommandDispatcherMock) GetSubscribers() map[string][]rest.CommandHandler { + if mock.GetSubscribersFunc == nil { + panic("CommandDispatcherMock.GetSubscribersFunc: method is nil but CommandDispatcher.GetSubscribers was just called") + } + callInfo := struct { + }{} + mock.lockGetSubscribers.Lock() + mock.calls.GetSubscribers = append(mock.calls.GetSubscribers, callInfo) + mock.lockGetSubscribers.Unlock() + return mock.GetSubscribersFunc() +} + +// GetSubscribersCalls gets all the calls that were made to GetSubscribers. +// Check the length with: +// +// len(mockedCommandDispatcher.GetSubscribersCalls()) +func (mock *CommandDispatcherMock) GetSubscribersCalls() []struct { +} { + var calls []struct { + } + mock.lockGetSubscribers.RLock() + calls = mock.calls.GetSubscribers + mock.lockGetSubscribers.RUnlock() + return calls +} + +// Ensure, that EventDispatcherMock does implement rest.EventDispatcher. +// If this is not the case, regenerate this file with moq. +var _ rest.EventDispatcher = &EventDispatcherMock{} + +// EventDispatcherMock is a mock implementation of rest.EventDispatcher. +// +// func TestSomethingThatUsesEventDispatcher(t *testing.T) { +// +// // make and configure a mocked rest.EventDispatcher +// mockedEventDispatcher := &EventDispatcherMock{ +// AddSubscriberFunc: func(handler rest.EventHandlerConfig) error { +// panic("mock out the AddSubscriber method") +// }, +// DispatchFunc: func(ctx context.Context, event rest.Event, logger rest.Log) []error { +// panic("mock out the Dispatch method") +// }, +// GetSubscribersFunc: func() []rest.EventHandler { +// panic("mock out the GetSubscribers method") +// }, +// } +// +// // use mockedEventDispatcher in code that requires rest.EventDispatcher +// // and then make assertions. +// +// } +type EventDispatcherMock struct { + // AddSubscriberFunc mocks the AddSubscriber method. + AddSubscriberFunc func(handler rest.EventHandlerConfig) error + + // DispatchFunc mocks the Dispatch method. + DispatchFunc func(ctx context.Context, event rest.Event, logger rest.Log) []error + + // GetSubscribersFunc mocks the GetSubscribers method. + GetSubscribersFunc func() []rest.EventHandler + + // calls tracks calls to the methods. + calls struct { + // AddSubscriber holds details about calls to the AddSubscriber method. + AddSubscriber []struct { + // Handler is the handler argument value. + Handler rest.EventHandlerConfig + } + // Dispatch holds details about calls to the Dispatch method. + Dispatch []struct { + // Ctx is the ctx argument value. + Ctx context.Context + // Event is the event argument value. + Event rest.Event + // Logger is the logger argument value. + Logger rest.Log + } + // GetSubscribers holds details about calls to the GetSubscribers method. + GetSubscribers []struct { + } + } + lockAddSubscriber sync.RWMutex + lockDispatch sync.RWMutex + lockGetSubscribers sync.RWMutex +} + +// AddSubscriber calls AddSubscriberFunc. +func (mock *EventDispatcherMock) AddSubscriber(handler rest.EventHandlerConfig) error { + if mock.AddSubscriberFunc == nil { + panic("EventDispatcherMock.AddSubscriberFunc: method is nil but EventDispatcher.AddSubscriber was just called") + } + callInfo := struct { + Handler rest.EventHandlerConfig + }{ + Handler: handler, + } + mock.lockAddSubscriber.Lock() + mock.calls.AddSubscriber = append(mock.calls.AddSubscriber, callInfo) + mock.lockAddSubscriber.Unlock() + return mock.AddSubscriberFunc(handler) +} + +// AddSubscriberCalls gets all the calls that were made to AddSubscriber. +// Check the length with: +// +// len(mockedEventDispatcher.AddSubscriberCalls()) +func (mock *EventDispatcherMock) AddSubscriberCalls() []struct { + Handler rest.EventHandlerConfig +} { + var calls []struct { + Handler rest.EventHandlerConfig + } + mock.lockAddSubscriber.RLock() + calls = mock.calls.AddSubscriber + mock.lockAddSubscriber.RUnlock() + return calls +} + +// Dispatch calls DispatchFunc. +func (mock *EventDispatcherMock) Dispatch(ctx context.Context, event rest.Event, logger rest.Log) []error { + if mock.DispatchFunc == nil { + panic("EventDispatcherMock.DispatchFunc: method is nil but EventDispatcher.Dispatch was just called") + } + callInfo := struct { + Ctx context.Context + Event rest.Event + Logger rest.Log + }{ + Ctx: ctx, + Event: event, + Logger: logger, + } + mock.lockDispatch.Lock() + mock.calls.Dispatch = append(mock.calls.Dispatch, callInfo) + mock.lockDispatch.Unlock() + return mock.DispatchFunc(ctx, event, logger) +} + +// DispatchCalls gets all the calls that were made to Dispatch. +// Check the length with: +// +// len(mockedEventDispatcher.DispatchCalls()) +func (mock *EventDispatcherMock) DispatchCalls() []struct { + Ctx context.Context + Event rest.Event + Logger rest.Log +} { + var calls []struct { + Ctx context.Context + Event rest.Event + Logger rest.Log + } + mock.lockDispatch.RLock() + calls = mock.calls.Dispatch + mock.lockDispatch.RUnlock() + return calls +} + +// GetSubscribers calls GetSubscribersFunc. +func (mock *EventDispatcherMock) GetSubscribers() []rest.EventHandler { + if mock.GetSubscribersFunc == nil { + panic("EventDispatcherMock.GetSubscribersFunc: method is nil but EventDispatcher.GetSubscribers was just called") + } + callInfo := struct { + }{} + mock.lockGetSubscribers.Lock() + mock.calls.GetSubscribers = append(mock.calls.GetSubscribers, callInfo) + mock.lockGetSubscribers.Unlock() + return mock.GetSubscribersFunc() +} + +// GetSubscribersCalls gets all the calls that were made to GetSubscribers. +// Check the length with: +// +// len(mockedEventDispatcher.GetSubscribersCalls()) +func (mock *EventDispatcherMock) GetSubscribersCalls() []struct { +} { + var calls []struct { + } + mock.lockGetSubscribers.RLock() + calls = mock.calls.GetSubscribers + mock.lockGetSubscribers.RUnlock() + return calls +} + +// Ensure, that EventStoreMock does implement rest.EventStore. +// If this is not the case, regenerate this file with moq. +var _ rest.EventStore = &EventStoreMock{} + +// EventStoreMock is a mock implementation of rest.EventStore. +// +// func TestSomethingThatUsesEventStore(t *testing.T) { +// +// // make and configure a mocked rest.EventStore +// mockedEventStore := &EventStoreMock{ +// AddSubscriberFunc: func(handler rest.EventHandlerConfig) error { +// panic("mock out the AddSubscriber method") +// }, +// DispatchFunc: func(ctx context.Context, event rest.Event, logger rest.Log) []error { +// panic("mock out the Dispatch method") +// }, +// GetByKeyFunc: func(ctxt context.Context, identifiers map[string]interface{}) (rest.Resource, error) { +// panic("mock out the GetByKey method") +// }, +// GetByPropertiesFunc: func(ctxt context.Context, identifiers map[string]interface{}) ([]rest.Entity, error) { +// panic("mock out the GetByProperties method") +// }, +// GetByURIFunc: func(ctxt context.Context, logger rest.Log, uri string) (rest.Resource, error) { +// panic("mock out the GetByURI method") +// }, +// GetListFunc: func(ctx context.Context, page int, limit int, query string, sortOptions map[string]string, filterOptions map[string]interface{}) ([]rest.Resource, int64, error) { +// panic("mock out the GetList method") +// }, +// GetSubscribersFunc: func() []rest.EventHandler { +// panic("mock out the GetSubscribers method") +// }, +// PersistFunc: func(ctxt context.Context, logger rest.Log, resources []rest.Resource) []error { +// panic("mock out the Persist method") +// }, +// RemoveFunc: func(ctxt context.Context, logger rest.Log, resources []rest.Resource) []error { +// panic("mock out the Remove method") +// }, +// } +// +// // use mockedEventStore in code that requires rest.EventStore +// // and then make assertions. +// +// } +type EventStoreMock struct { + // AddSubscriberFunc mocks the AddSubscriber method. + AddSubscriberFunc func(handler rest.EventHandlerConfig) error + + // DispatchFunc mocks the Dispatch method. + DispatchFunc func(ctx context.Context, event rest.Event, logger rest.Log) []error + + // GetByKeyFunc mocks the GetByKey method. + GetByKeyFunc func(ctxt context.Context, identifiers map[string]interface{}) (rest.Resource, error) + + // GetByPropertiesFunc mocks the GetByProperties method. + GetByPropertiesFunc func(ctxt context.Context, identifiers map[string]interface{}) ([]rest.Entity, error) + + // GetByURIFunc mocks the GetByURI method. + GetByURIFunc func(ctxt context.Context, logger rest.Log, uri string) (rest.Resource, error) + + // GetListFunc mocks the GetList method. + GetListFunc func(ctx context.Context, page int, limit int, query string, sortOptions map[string]string, filterOptions map[string]interface{}) ([]rest.Resource, int64, error) + + // GetSubscribersFunc mocks the GetSubscribers method. + GetSubscribersFunc func() []rest.EventHandler + + // PersistFunc mocks the Persist method. + PersistFunc func(ctxt context.Context, logger rest.Log, resources []rest.Resource) []error + + // RemoveFunc mocks the Remove method. + RemoveFunc func(ctxt context.Context, logger rest.Log, resources []rest.Resource) []error + + // calls tracks calls to the methods. + calls struct { + // AddSubscriber holds details about calls to the AddSubscriber method. + AddSubscriber []struct { + // Handler is the handler argument value. + Handler rest.EventHandlerConfig + } + // Dispatch holds details about calls to the Dispatch method. + Dispatch []struct { + // Ctx is the ctx argument value. + Ctx context.Context + // Event is the event argument value. + Event rest.Event + // Logger is the logger argument value. + Logger rest.Log + } + // GetByKey holds details about calls to the GetByKey method. + GetByKey []struct { + // Ctxt is the ctxt argument value. + Ctxt context.Context + // Identifiers is the identifiers argument value. + Identifiers map[string]interface{} + } + // GetByProperties holds details about calls to the GetByProperties method. + GetByProperties []struct { + // Ctxt is the ctxt argument value. + Ctxt context.Context + // Identifiers is the identifiers argument value. + Identifiers map[string]interface{} + } + // GetByURI holds details about calls to the GetByURI method. + GetByURI []struct { + // Ctxt is the ctxt argument value. + Ctxt context.Context + // Logger is the logger argument value. + Logger rest.Log + // URI is the uri argument value. + URI string + } + // GetList holds details about calls to the GetList method. + GetList []struct { + // Ctx is the ctx argument value. + Ctx context.Context + // Page is the page argument value. + Page int + // Limit is the limit argument value. + Limit int + // Query is the query argument value. + Query string + // SortOptions is the sortOptions argument value. + SortOptions map[string]string + // FilterOptions is the filterOptions argument value. + FilterOptions map[string]interface{} + } + // GetSubscribers holds details about calls to the GetSubscribers method. + GetSubscribers []struct { + } + // Persist holds details about calls to the Persist method. + Persist []struct { + // Ctxt is the ctxt argument value. + Ctxt context.Context + // Logger is the logger argument value. + Logger rest.Log + // Resources is the resources argument value. + Resources []rest.Resource + } + // Remove holds details about calls to the Remove method. + Remove []struct { + // Ctxt is the ctxt argument value. + Ctxt context.Context + // Logger is the logger argument value. + Logger rest.Log + // Resources is the resources argument value. + Resources []rest.Resource + } + } + lockAddSubscriber sync.RWMutex + lockDispatch sync.RWMutex + lockGetByKey sync.RWMutex + lockGetByProperties sync.RWMutex + lockGetByURI sync.RWMutex + lockGetList sync.RWMutex + lockGetSubscribers sync.RWMutex + lockPersist sync.RWMutex + lockRemove sync.RWMutex +} + +// AddSubscriber calls AddSubscriberFunc. +func (mock *EventStoreMock) AddSubscriber(handler rest.EventHandlerConfig) error { + if mock.AddSubscriberFunc == nil { + panic("EventStoreMock.AddSubscriberFunc: method is nil but EventStore.AddSubscriber was just called") + } + callInfo := struct { + Handler rest.EventHandlerConfig + }{ + Handler: handler, + } + mock.lockAddSubscriber.Lock() + mock.calls.AddSubscriber = append(mock.calls.AddSubscriber, callInfo) + mock.lockAddSubscriber.Unlock() + return mock.AddSubscriberFunc(handler) +} + +// AddSubscriberCalls gets all the calls that were made to AddSubscriber. +// Check the length with: +// +// len(mockedEventStore.AddSubscriberCalls()) +func (mock *EventStoreMock) AddSubscriberCalls() []struct { + Handler rest.EventHandlerConfig +} { + var calls []struct { + Handler rest.EventHandlerConfig + } + mock.lockAddSubscriber.RLock() + calls = mock.calls.AddSubscriber + mock.lockAddSubscriber.RUnlock() + return calls +} + +// Dispatch calls DispatchFunc. +func (mock *EventStoreMock) Dispatch(ctx context.Context, event rest.Event, logger rest.Log) []error { + if mock.DispatchFunc == nil { + panic("EventStoreMock.DispatchFunc: method is nil but EventStore.Dispatch was just called") + } + callInfo := struct { + Ctx context.Context + Event rest.Event + Logger rest.Log + }{ + Ctx: ctx, + Event: event, + Logger: logger, + } + mock.lockDispatch.Lock() + mock.calls.Dispatch = append(mock.calls.Dispatch, callInfo) + mock.lockDispatch.Unlock() + return mock.DispatchFunc(ctx, event, logger) +} + +// DispatchCalls gets all the calls that were made to Dispatch. +// Check the length with: +// +// len(mockedEventStore.DispatchCalls()) +func (mock *EventStoreMock) DispatchCalls() []struct { + Ctx context.Context + Event rest.Event + Logger rest.Log +} { + var calls []struct { + Ctx context.Context + Event rest.Event + Logger rest.Log + } + mock.lockDispatch.RLock() + calls = mock.calls.Dispatch + mock.lockDispatch.RUnlock() + return calls +} + +// GetByKey calls GetByKeyFunc. +func (mock *EventStoreMock) GetByKey(ctxt context.Context, identifiers map[string]interface{}) (rest.Resource, error) { + if mock.GetByKeyFunc == nil { + panic("EventStoreMock.GetByKeyFunc: method is nil but EventStore.GetByKey was just called") + } + callInfo := struct { + Ctxt context.Context + Identifiers map[string]interface{} + }{ + Ctxt: ctxt, + Identifiers: identifiers, + } + mock.lockGetByKey.Lock() + mock.calls.GetByKey = append(mock.calls.GetByKey, callInfo) + mock.lockGetByKey.Unlock() + return mock.GetByKeyFunc(ctxt, identifiers) +} + +// GetByKeyCalls gets all the calls that were made to GetByKey. +// Check the length with: +// +// len(mockedEventStore.GetByKeyCalls()) +func (mock *EventStoreMock) GetByKeyCalls() []struct { + Ctxt context.Context + Identifiers map[string]interface{} +} { + var calls []struct { + Ctxt context.Context + Identifiers map[string]interface{} + } + mock.lockGetByKey.RLock() + calls = mock.calls.GetByKey + mock.lockGetByKey.RUnlock() + return calls +} + +// GetByProperties calls GetByPropertiesFunc. +func (mock *EventStoreMock) GetByProperties(ctxt context.Context, identifiers map[string]interface{}) ([]rest.Entity, error) { + if mock.GetByPropertiesFunc == nil { + panic("EventStoreMock.GetByPropertiesFunc: method is nil but EventStore.GetByProperties was just called") + } + callInfo := struct { + Ctxt context.Context + Identifiers map[string]interface{} + }{ + Ctxt: ctxt, + Identifiers: identifiers, + } + mock.lockGetByProperties.Lock() + mock.calls.GetByProperties = append(mock.calls.GetByProperties, callInfo) + mock.lockGetByProperties.Unlock() + return mock.GetByPropertiesFunc(ctxt, identifiers) +} + +// GetByPropertiesCalls gets all the calls that were made to GetByProperties. +// Check the length with: +// +// len(mockedEventStore.GetByPropertiesCalls()) +func (mock *EventStoreMock) GetByPropertiesCalls() []struct { + Ctxt context.Context + Identifiers map[string]interface{} +} { + var calls []struct { + Ctxt context.Context + Identifiers map[string]interface{} + } + mock.lockGetByProperties.RLock() + calls = mock.calls.GetByProperties + mock.lockGetByProperties.RUnlock() + return calls +} + +// GetByURI calls GetByURIFunc. +func (mock *EventStoreMock) GetByURI(ctxt context.Context, logger rest.Log, uri string) (rest.Resource, error) { + if mock.GetByURIFunc == nil { + panic("EventStoreMock.GetByURIFunc: method is nil but EventStore.GetByURI was just called") + } + callInfo := struct { + Ctxt context.Context + Logger rest.Log + URI string + }{ + Ctxt: ctxt, + Logger: logger, + URI: uri, + } + mock.lockGetByURI.Lock() + mock.calls.GetByURI = append(mock.calls.GetByURI, callInfo) + mock.lockGetByURI.Unlock() + return mock.GetByURIFunc(ctxt, logger, uri) +} + +// GetByURICalls gets all the calls that were made to GetByURI. +// Check the length with: +// +// len(mockedEventStore.GetByURICalls()) +func (mock *EventStoreMock) GetByURICalls() []struct { + Ctxt context.Context + Logger rest.Log + URI string +} { + var calls []struct { + Ctxt context.Context + Logger rest.Log + URI string + } + mock.lockGetByURI.RLock() + calls = mock.calls.GetByURI + mock.lockGetByURI.RUnlock() + return calls +} + +// GetList calls GetListFunc. +func (mock *EventStoreMock) GetList(ctx context.Context, page int, limit int, query string, sortOptions map[string]string, filterOptions map[string]interface{}) ([]rest.Resource, int64, error) { + if mock.GetListFunc == nil { + panic("EventStoreMock.GetListFunc: method is nil but EventStore.GetList was just called") + } + callInfo := struct { + Ctx context.Context + Page int + Limit int + Query string + SortOptions map[string]string + FilterOptions map[string]interface{} + }{ + Ctx: ctx, + Page: page, + Limit: limit, + Query: query, + SortOptions: sortOptions, + FilterOptions: filterOptions, + } + mock.lockGetList.Lock() + mock.calls.GetList = append(mock.calls.GetList, callInfo) + mock.lockGetList.Unlock() + return mock.GetListFunc(ctx, page, limit, query, sortOptions, filterOptions) +} + +// GetListCalls gets all the calls that were made to GetList. +// Check the length with: +// +// len(mockedEventStore.GetListCalls()) +func (mock *EventStoreMock) GetListCalls() []struct { + Ctx context.Context + Page int + Limit int + Query string + SortOptions map[string]string + FilterOptions map[string]interface{} +} { + var calls []struct { + Ctx context.Context + Page int + Limit int + Query string + SortOptions map[string]string + FilterOptions map[string]interface{} + } + mock.lockGetList.RLock() + calls = mock.calls.GetList + mock.lockGetList.RUnlock() + return calls +} + +// GetSubscribers calls GetSubscribersFunc. +func (mock *EventStoreMock) GetSubscribers() []rest.EventHandler { + if mock.GetSubscribersFunc == nil { + panic("EventStoreMock.GetSubscribersFunc: method is nil but EventStore.GetSubscribers was just called") + } + callInfo := struct { + }{} + mock.lockGetSubscribers.Lock() + mock.calls.GetSubscribers = append(mock.calls.GetSubscribers, callInfo) + mock.lockGetSubscribers.Unlock() + return mock.GetSubscribersFunc() +} + +// GetSubscribersCalls gets all the calls that were made to GetSubscribers. +// Check the length with: +// +// len(mockedEventStore.GetSubscribersCalls()) +func (mock *EventStoreMock) GetSubscribersCalls() []struct { +} { + var calls []struct { + } + mock.lockGetSubscribers.RLock() + calls = mock.calls.GetSubscribers + mock.lockGetSubscribers.RUnlock() + return calls +} + +// Persist calls PersistFunc. +func (mock *EventStoreMock) Persist(ctxt context.Context, logger rest.Log, resources []rest.Resource) []error { + if mock.PersistFunc == nil { + panic("EventStoreMock.PersistFunc: method is nil but EventStore.Persist was just called") + } + callInfo := struct { + Ctxt context.Context + Logger rest.Log + Resources []rest.Resource + }{ + Ctxt: ctxt, + Logger: logger, + Resources: resources, + } + mock.lockPersist.Lock() + mock.calls.Persist = append(mock.calls.Persist, callInfo) + mock.lockPersist.Unlock() + return mock.PersistFunc(ctxt, logger, resources) +} + +// PersistCalls gets all the calls that were made to Persist. +// Check the length with: +// +// len(mockedEventStore.PersistCalls()) +func (mock *EventStoreMock) PersistCalls() []struct { + Ctxt context.Context + Logger rest.Log + Resources []rest.Resource +} { + var calls []struct { + Ctxt context.Context + Logger rest.Log + Resources []rest.Resource + } + mock.lockPersist.RLock() + calls = mock.calls.Persist + mock.lockPersist.RUnlock() + return calls +} + +// Remove calls RemoveFunc. +func (mock *EventStoreMock) Remove(ctxt context.Context, logger rest.Log, resources []rest.Resource) []error { + if mock.RemoveFunc == nil { + panic("EventStoreMock.RemoveFunc: method is nil but EventStore.Remove was just called") + } + callInfo := struct { + Ctxt context.Context + Logger rest.Log + Resources []rest.Resource + }{ + Ctxt: ctxt, + Logger: logger, + Resources: resources, + } + mock.lockRemove.Lock() + mock.calls.Remove = append(mock.calls.Remove, callInfo) + mock.lockRemove.Unlock() + return mock.RemoveFunc(ctxt, logger, resources) +} + +// RemoveCalls gets all the calls that were made to Remove. +// Check the length with: +// +// len(mockedEventStore.RemoveCalls()) +func (mock *EventStoreMock) RemoveCalls() []struct { + Ctxt context.Context + Logger rest.Log + Resources []rest.Resource +} { + var calls []struct { + Ctxt context.Context + Logger rest.Log + Resources []rest.Resource + } + mock.lockRemove.RLock() + calls = mock.calls.Remove + mock.lockRemove.RUnlock() + return calls +}