diff --git a/service/submitqueue/gateway/server/main.go b/service/submitqueue/gateway/server/main.go index 38f3f9be..7a46023c 100644 --- a/service/submitqueue/gateway/server/main.go +++ b/service/submitqueue/gateway/server/main.go @@ -52,12 +52,12 @@ import ( // GatewayServer wraps the controller and implements the gRPC service interface type GatewayServer struct { pb.UnimplementedSubmitQueueGatewayServer - pingController *controller.PingController - landController *controller.LandController - cancelController *controller.CancelController - requestSummaryController *controller.RequestSummaryController - listController *controller.ListController - requestHistoryController *controller.RequestHistoryController + pingController controller.PingController + landController controller.LandController + cancelController controller.CancelController + requestSummaryController controller.RequestSummaryController + listController controller.ListController + requestHistoryController controller.RequestHistoryController } // Ping delegates to the controller diff --git a/submitqueue/gateway/controller/cancel.go b/submitqueue/gateway/controller/cancel.go index 8a19848a..ead31cc3 100644 --- a/submitqueue/gateway/controller/cancel.go +++ b/submitqueue/gateway/controller/cancel.go @@ -35,7 +35,13 @@ import ( // and may still race a successful merge), publishes a CancelRequest to the cancel topic, // and returns a response. The orchestrator-side cancel controller performs the actual // state transitions and emits the terminal RequestStatusCancelled log entry. -type CancelController struct { +type CancelController interface { + Cancel(ctx context.Context, req entity.CancelRequest) error +} + +var _ CancelController = (*cancelController)(nil) + +type cancelController struct { logger *zap.SugaredLogger metricsScope tally.Scope requestSummaryStore storage.RequestSummaryStore @@ -46,8 +52,8 @@ type CancelController struct { // NewCancelController creates a new instance of the gateway cancel controller. // The controller writes a RequestStatusCancelling log entry through the shared materializer and // publishes cancel requests to the topic registered under topickey.TopicKeyCancel. -func NewCancelController(logger *zap.SugaredLogger, scope tally.Scope, store storage.Storage, registry consumer.TopicRegistry) *CancelController { - return &CancelController{ +func NewCancelController(logger *zap.SugaredLogger, scope tally.Scope, store storage.Storage, registry consumer.TopicRegistry) CancelController { + return &cancelController{ logger: logger, metricsScope: scope, requestSummaryStore: store.GetRequestSummaryStore(), @@ -64,7 +70,7 @@ func NewCancelController(logger *zap.SugaredLogger, scope tally.Scope, store sto // completion before the cancel propagates may still land. The RequestStatusCancelling // entry written here records the user's intent; the terminal outcome is reflected by a // later RequestStatusCancelled (orchestrator side) or RequestStatusLanded entry. -func (c *CancelController) Cancel(ctx context.Context, req entity.CancelRequest) (retErr error) { +func (c *cancelController) Cancel(ctx context.Context, req entity.CancelRequest) (retErr error) { const opName = "cancel" op := metrics.Begin(c.metricsScope, opName, metrics.StorageLatencyBuckets) @@ -113,7 +119,7 @@ func (c *CancelController) Cancel(ctx context.Context, req entity.CancelRequest) } // publishToQueue publishes a cancel request to the cancel queue for async processing. -func (c *CancelController) publishToQueue(ctx context.Context, cancelRequest entity.CancelRequest) error { +func (c *cancelController) publishToQueue(ctx context.Context, cancelRequest entity.CancelRequest) error { payload, err := cancelRequest.ToBytes() if err != nil { return fmt.Errorf("failed to serialize cancel request: %w", err) diff --git a/submitqueue/gateway/controller/land.go b/submitqueue/gateway/controller/land.go index 878427ca..114e1e3a 100644 --- a/submitqueue/gateway/controller/land.go +++ b/submitqueue/gateway/controller/land.go @@ -62,7 +62,13 @@ func IsUnrecognizedQueue(err error) bool { } // LandController handles land business logic for the gateway -type LandController struct { +type LandController interface { + Land(ctx context.Context, req entity.LandRequest) (entity.LandResult, error) +} + +var _ LandController = (*landController)(nil) + +type landController struct { logger *zap.SugaredLogger metricsScope tally.Scope counter counter.Counter @@ -75,8 +81,8 @@ type LandController struct { // NewLandController creates a new instance of the gateway land controller. // The controller publishes land requests to the topic registered under // topickey.TopicKeyStart in the registry. -func NewLandController(logger *zap.SugaredLogger, scope tally.Scope, counter counter.Counter, store storage.Storage, queueConfigs queueconfig.Store, registry consumer.TopicRegistry) *LandController { - return &LandController{ +func NewLandController(logger *zap.SugaredLogger, scope tally.Scope, counter counter.Counter, store storage.Storage, queueConfigs queueconfig.Store, registry consumer.TopicRegistry) LandController { + return &landController{ logger: logger, metricsScope: scope.SubScope("land_controller"), counter: counter, @@ -88,7 +94,7 @@ func NewLandController(logger *zap.SugaredLogger, scope tally.Scope, counter cou } // Land handles the land request and returns the ID assigned to the accepted request. -func (c *LandController) Land(ctx context.Context, req entity.LandRequest) (result entity.LandResult, retErr error) { +func (c *landController) Land(ctx context.Context, req entity.LandRequest) (result entity.LandResult, retErr error) { const opName = "land" op := metrics.Begin(c.metricsScope, opName, metrics.StorageLatencyBuckets) @@ -179,7 +185,7 @@ func (c *LandController) Land(ctx context.Context, req entity.LandRequest) (resu } // publishToQueue publishes a land request to the request queue for async processing. -func (c *LandController) publishToQueue(ctx context.Context, landRequest entity.LandRequest) error { +func (c *landController) publishToQueue(ctx context.Context, landRequest entity.LandRequest) error { // Serialize land request entity to JSON payload, err := landRequest.ToBytes() if err != nil { diff --git a/submitqueue/gateway/controller/list.go b/submitqueue/gateway/controller/list.go index ed2d9111..657a216e 100644 --- a/submitqueue/gateway/controller/list.go +++ b/submitqueue/gateway/controller/list.go @@ -45,7 +45,13 @@ type listPageToken struct { } // ListController handles bounded queue receipt-history queries. -type ListController struct { +type ListController interface { + List(ctx context.Context, req entity.ListRequest) (entity.ListResult, error) +} + +var _ ListController = (*listController)(nil) + +type listController struct { logger *zap.SugaredLogger metricsScope tally.Scope requestQueueSummaryStore storage.RequestQueueSummaryStore @@ -53,8 +59,8 @@ type ListController struct { } // NewListController creates a gateway list controller. -func NewListController(logger *zap.SugaredLogger, scope tally.Scope, requestQueueSummaryStore storage.RequestQueueSummaryStore, queueConfigs queueconfig.Store) *ListController { - return &ListController{ +func NewListController(logger *zap.SugaredLogger, scope tally.Scope, requestQueueSummaryStore storage.RequestQueueSummaryStore, queueConfigs queueconfig.Store) ListController { + return &listController{ logger: logger, metricsScope: scope.SubScope("list_controller"), requestQueueSummaryStore: requestQueueSummaryStore, @@ -63,7 +69,7 @@ func NewListController(logger *zap.SugaredLogger, scope tally.Scope, requestQueu } // List returns one page of requests received for a queue in the supplied half-open time range. -func (c *ListController) List(ctx context.Context, req entity.ListRequest) (result entity.ListResult, retErr error) { +func (c *listController) List(ctx context.Context, req entity.ListRequest) (result entity.ListResult, retErr error) { op := metrics.Begin(c.metricsScope, "list", metrics.StorageLatencyBuckets) defer func() { op.Complete(retErr) }() diff --git a/submitqueue/gateway/controller/list_test.go b/submitqueue/gateway/controller/list_test.go index 3ec52e52..2a9741b3 100644 --- a/submitqueue/gateway/controller/list_test.go +++ b/submitqueue/gateway/controller/list_test.go @@ -130,7 +130,7 @@ func TestList_Errors(t *testing.T) { } } -func newConfiguredListController(ctrl *gomock.Controller, store storage.RequestQueueSummaryStore) *ListController { +func newConfiguredListController(ctrl *gomock.Controller, store storage.RequestQueueSummaryStore) ListController { queueConfigs := qcmock.NewMockStore(ctrl) queueConfigs.EXPECT().Get(gomock.Any(), "q").Return(entity.QueueConfig{}, nil) return NewListController(zap.NewNop().Sugar(), tally.NoopScope, store, queueConfigs) diff --git a/submitqueue/gateway/controller/ping.go b/submitqueue/gateway/controller/ping.go index 47027248..777fb695 100644 --- a/submitqueue/gateway/controller/ping.go +++ b/submitqueue/gateway/controller/ping.go @@ -26,21 +26,27 @@ import ( ) // PingController handles ping business logic for the gateway -type PingController struct { +type PingController interface { + Ping(ctx context.Context, req *pb.PingRequest) (*pb.PingResponse, error) +} + +var _ PingController = (*pingController)(nil) + +type pingController struct { logger *zap.Logger metricsScope tally.Scope } // NewPingController creates a new instance of the gateway ping controller -func NewPingController(logger *zap.Logger, scope tally.Scope) *PingController { - return &PingController{ +func NewPingController(logger *zap.Logger, scope tally.Scope) PingController { + return &pingController{ logger: logger, metricsScope: scope, } } // Ping handles the ping request and returns a response -func (c *PingController) Ping(ctx context.Context, req *pb.PingRequest) (resp *pb.PingResponse, retErr error) { +func (c *pingController) Ping(ctx context.Context, req *pb.PingRequest) (resp *pb.PingResponse, retErr error) { const opName = "ping" op := metrics.Begin(c.metricsScope, opName, metrics.FastLatencyBuckets) diff --git a/submitqueue/gateway/controller/request_history.go b/submitqueue/gateway/controller/request_history.go index 58d0a6b1..1a7141ca 100644 --- a/submitqueue/gateway/controller/request_history.go +++ b/submitqueue/gateway/controller/request_history.go @@ -30,7 +30,14 @@ import ( ) // RequestHistoryController handles retained request-log history lookups. -type RequestHistoryController struct { +type RequestHistoryController interface { + GetRequestHistoryByID(ctx context.Context, req entity.GetRequestHistoryByIDRequest) ([]entity.RequestLog, error) + GetRequestHistoryByChangeURI(ctx context.Context, req entity.GetRequestHistoryByChangeURIRequest) ([]entity.RequestHistory, error) +} + +var _ RequestHistoryController = (*requestHistoryController)(nil) + +type requestHistoryController struct { logger *zap.SugaredLogger metricsScope tally.Scope requestLogStore storage.RequestLogStore @@ -38,8 +45,8 @@ type RequestHistoryController struct { } // NewRequestHistoryController creates a gateway request-history controller. -func NewRequestHistoryController(logger *zap.SugaredLogger, scope tally.Scope, requestLogStore storage.RequestLogStore, requestURIStore storage.RequestURIStore) *RequestHistoryController { - return &RequestHistoryController{ +func NewRequestHistoryController(logger *zap.SugaredLogger, scope tally.Scope, requestLogStore storage.RequestLogStore, requestURIStore storage.RequestURIStore) RequestHistoryController { + return &requestHistoryController{ logger: logger, metricsScope: scope.SubScope("request_history_controller"), requestLogStore: requestLogStore, @@ -48,7 +55,7 @@ func NewRequestHistoryController(logger *zap.SugaredLogger, scope tally.Scope, r } // GetRequestHistoryByID returns every retained request-log event for one sqid. -func (c *RequestHistoryController) GetRequestHistoryByID(ctx context.Context, req entity.GetRequestHistoryByIDRequest) (logs []entity.RequestLog, retErr error) { +func (c *requestHistoryController) GetRequestHistoryByID(ctx context.Context, req entity.GetRequestHistoryByIDRequest) (logs []entity.RequestLog, retErr error) { op := metrics.Begin(c.metricsScope, "get_by_id", metrics.StorageLatencyBuckets) defer func() { op.Complete(retErr) }() @@ -72,7 +79,7 @@ func (c *RequestHistoryController) GetRequestHistoryByID(ctx context.Context, re } // GetRequestHistoryByChangeURI returns retained histories for an exact pinned change URI. -func (c *RequestHistoryController) GetRequestHistoryByChangeURI(ctx context.Context, req entity.GetRequestHistoryByChangeURIRequest) (result []entity.RequestHistory, retErr error) { +func (c *requestHistoryController) GetRequestHistoryByChangeURI(ctx context.Context, req entity.GetRequestHistoryByChangeURIRequest) (result []entity.RequestHistory, retErr error) { op := metrics.Begin(c.metricsScope, "get_by_change_uri", metrics.StorageLatencyBuckets) defer func() { op.Complete(retErr) }() diff --git a/submitqueue/gateway/controller/request_history_test.go b/submitqueue/gateway/controller/request_history_test.go index 2fd814ae..0898aa82 100644 --- a/submitqueue/gateway/controller/request_history_test.go +++ b/submitqueue/gateway/controller/request_history_test.go @@ -85,7 +85,7 @@ func TestHistoryErrors(t *testing.T) { backendErr := fmt.Errorf("backend down") tests := []struct { name string - call func(*RequestHistoryController) error + call func(RequestHistoryController) error setup func(*storagemock.MockRequestLogStore, *storagemock.MockRequestURIStore) wantInvalid bool wantNotFound bool @@ -95,7 +95,7 @@ func TestHistoryErrors(t *testing.T) { }{ { name: "empty sqid", - call: func(c *RequestHistoryController) error { + call: func(c RequestHistoryController) error { _, err := c.GetRequestHistoryByID(context.Background(), entity.GetRequestHistoryByIDRequest{}) return err }, @@ -104,7 +104,7 @@ func TestHistoryErrors(t *testing.T) { }, { name: "empty change URI", - call: func(c *RequestHistoryController) error { + call: func(c RequestHistoryController) error { _, err := c.GetRequestHistoryByChangeURI(context.Background(), entity.GetRequestHistoryByChangeURIRequest{}) return err }, @@ -116,7 +116,7 @@ func TestHistoryErrors(t *testing.T) { setup: func(logStore *storagemock.MockRequestLogStore, _ *storagemock.MockRequestURIStore) { logStore.EXPECT().List(gomock.Any(), "missing/1").Return(nil, storage.ErrNotFound) }, - call: func(c *RequestHistoryController) error { + call: func(c RequestHistoryController) error { _, err := c.GetRequestHistoryByID(context.Background(), entity.GetRequestHistoryByIDRequest{ID: "missing/1"}) return err }, @@ -128,7 +128,7 @@ func TestHistoryErrors(t *testing.T) { setup: func(logStore *storagemock.MockRequestLogStore, _ *storagemock.MockRequestURIStore) { logStore.EXPECT().List(gomock.Any(), "queue/1").Return(nil, backendErr) }, - call: func(c *RequestHistoryController) error { + call: func(c RequestHistoryController) error { _, err := c.GetRequestHistoryByID(context.Background(), entity.GetRequestHistoryByIDRequest{ID: "queue/1"}) return err }, @@ -138,7 +138,7 @@ func TestHistoryErrors(t *testing.T) { setup: func(_ *storagemock.MockRequestLogStore, uriStore *storagemock.MockRequestURIStore) { uriStore.EXPECT().ListByURI(gomock.Any(), "uri", 101).Return(nil, nil) }, - call: func(c *RequestHistoryController) error { + call: func(c RequestHistoryController) error { _, err := c.GetRequestHistoryByChangeURI(context.Background(), entity.GetRequestHistoryByChangeURIRequest{ChangeURI: "uri"}) return err }, @@ -150,7 +150,7 @@ func TestHistoryErrors(t *testing.T) { setup: func(_ *storagemock.MockRequestLogStore, uriStore *storagemock.MockRequestURIStore) { uriStore.EXPECT().ListByURI(gomock.Any(), "uri", 101).Return(make([]entity.RequestURI, 101), nil) }, - call: func(c *RequestHistoryController) error { + call: func(c RequestHistoryController) error { _, err := c.GetRequestHistoryByChangeURI(context.Background(), entity.GetRequestHistoryByChangeURIRequest{ChangeURI: "uri"}) return err }, @@ -163,7 +163,7 @@ func TestHistoryErrors(t *testing.T) { uriStore.EXPECT().ListByURI(gomock.Any(), "uri", 101).Return([]entity.RequestURI{{RequestID: "queue/1"}}, nil) logStore.EXPECT().List(gomock.Any(), "queue/1").Return(nil, storage.ErrNotFound) }, - call: func(c *RequestHistoryController) error { + call: func(c RequestHistoryController) error { _, err := c.GetRequestHistoryByChangeURI(context.Background(), entity.GetRequestHistoryByChangeURIRequest{ChangeURI: "uri"}) return err }, @@ -176,7 +176,7 @@ func TestHistoryErrors(t *testing.T) { uriStore.EXPECT().ListByURI(gomock.Any(), "uri", 101).Return([]entity.RequestURI{{RequestID: "malformed"}}, nil) logStore.EXPECT().List(gomock.Any(), "malformed").Return([]entity.RequestLog{{RequestID: "malformed"}}, nil) }, - call: func(c *RequestHistoryController) error { + call: func(c RequestHistoryController) error { _, err := c.GetRequestHistoryByChangeURI(context.Background(), entity.GetRequestHistoryByChangeURIRequest{ChangeURI: "uri"}) return err }, diff --git a/submitqueue/gateway/controller/request_summary.go b/submitqueue/gateway/controller/request_summary.go index fc0929d3..8359a721 100644 --- a/submitqueue/gateway/controller/request_summary.go +++ b/submitqueue/gateway/controller/request_summary.go @@ -27,7 +27,14 @@ import ( ) // RequestSummaryController handles materialized request-summary lookups for the gateway. -type RequestSummaryController struct { +type RequestSummaryController interface { + GetRequestSummaryByID(ctx context.Context, req entity.GetRequestSummaryByIDRequest) (entity.RequestSummary, error) + GetRequestSummaryByChangeURI(ctx context.Context, req entity.GetRequestSummaryByChangeURIRequest) ([]entity.RequestSummary, error) +} + +var _ RequestSummaryController = (*requestSummaryController)(nil) + +type requestSummaryController struct { logger *zap.SugaredLogger metricsScope tally.Scope requestSummaryStore storage.RequestSummaryStore @@ -35,8 +42,8 @@ type RequestSummaryController struct { } // NewRequestSummaryController creates a gateway request-summary controller. -func NewRequestSummaryController(logger *zap.SugaredLogger, scope tally.Scope, requestSummaryStore storage.RequestSummaryStore, requestURIStore storage.RequestURIStore) *RequestSummaryController { - return &RequestSummaryController{ +func NewRequestSummaryController(logger *zap.SugaredLogger, scope tally.Scope, requestSummaryStore storage.RequestSummaryStore, requestURIStore storage.RequestURIStore) RequestSummaryController { + return &requestSummaryController{ logger: logger, metricsScope: scope.SubScope("request_summary_controller"), requestSummaryStore: requestSummaryStore, @@ -45,7 +52,7 @@ func NewRequestSummaryController(logger *zap.SugaredLogger, scope tally.Scope, r } // GetRequestSummaryByID returns the current materialized view of one request. -func (c *RequestSummaryController) GetRequestSummaryByID(ctx context.Context, req entity.GetRequestSummaryByIDRequest) (summary entity.RequestSummary, retErr error) { +func (c *requestSummaryController) GetRequestSummaryByID(ctx context.Context, req entity.GetRequestSummaryByIDRequest) (summary entity.RequestSummary, retErr error) { op := metrics.Begin(c.metricsScope, "get_by_id", metrics.StorageLatencyBuckets) defer func() { op.Complete(retErr) }() @@ -72,7 +79,7 @@ func (c *RequestSummaryController) GetRequestSummaryByID(ctx context.Context, re } // GetRequestSummaryByChangeURI returns current materialized views for an exact pinned change URI. -func (c *RequestSummaryController) GetRequestSummaryByChangeURI(ctx context.Context, req entity.GetRequestSummaryByChangeURIRequest) (summaries []entity.RequestSummary, retErr error) { +func (c *requestSummaryController) GetRequestSummaryByChangeURI(ctx context.Context, req entity.GetRequestSummaryByChangeURIRequest) (summaries []entity.RequestSummary, retErr error) { op := metrics.Begin(c.metricsScope, "get_by_change_uri", metrics.StorageLatencyBuckets) defer func() { op.Complete(retErr) }() diff --git a/submitqueue/gateway/controller/request_summary_test.go b/submitqueue/gateway/controller/request_summary_test.go index f54d78a8..04440f5e 100644 --- a/submitqueue/gateway/controller/request_summary_test.go +++ b/submitqueue/gateway/controller/request_summary_test.go @@ -80,7 +80,7 @@ func TestStatusErrors(t *testing.T) { backendErr := fmt.Errorf("backend down") tests := []struct { name string - call func(*RequestSummaryController) error + call func(RequestSummaryController) error setup func(*storagemock.MockRequestSummaryStore, *storagemock.MockRequestURIStore) wantInvalid bool wantNotFound bool @@ -90,7 +90,7 @@ func TestStatusErrors(t *testing.T) { }{ { name: "empty sqid", - call: func(c *RequestSummaryController) error { + call: func(c RequestSummaryController) error { _, err := c.GetRequestSummaryByID(context.Background(), entity.GetRequestSummaryByIDRequest{}) return err }, @@ -99,7 +99,7 @@ func TestStatusErrors(t *testing.T) { }, { name: "empty change URI", - call: func(c *RequestSummaryController) error { + call: func(c RequestSummaryController) error { _, err := c.GetRequestSummaryByChangeURI(context.Background(), entity.GetRequestSummaryByChangeURIRequest{}) return err }, @@ -111,7 +111,7 @@ func TestStatusErrors(t *testing.T) { setup: func(summaryStore *storagemock.MockRequestSummaryStore, _ *storagemock.MockRequestURIStore) { summaryStore.EXPECT().Get(gomock.Any(), "missing/1").Return(entity.RequestSummary{}, storage.ErrNotFound) }, - call: func(c *RequestSummaryController) error { + call: func(c RequestSummaryController) error { _, err := c.GetRequestSummaryByID(context.Background(), entity.GetRequestSummaryByIDRequest{ID: "missing/1"}) return err }, @@ -126,7 +126,7 @@ func TestStatusErrors(t *testing.T) { Status: entity.RequestStatusAccepting, }, nil) }, - call: func(c *RequestSummaryController) error { + call: func(c RequestSummaryController) error { _, err := c.GetRequestSummaryByID(context.Background(), entity.GetRequestSummaryByIDRequest{ID: "queue/1"}) return err }, @@ -138,7 +138,7 @@ func TestStatusErrors(t *testing.T) { setup: func(summaryStore *storagemock.MockRequestSummaryStore, _ *storagemock.MockRequestURIStore) { summaryStore.EXPECT().Get(gomock.Any(), "queue/1").Return(entity.RequestSummary{}, backendErr) }, - call: func(c *RequestSummaryController) error { + call: func(c RequestSummaryController) error { _, err := c.GetRequestSummaryByID(context.Background(), entity.GetRequestSummaryByIDRequest{ID: "queue/1"}) return err }, @@ -148,7 +148,7 @@ func TestStatusErrors(t *testing.T) { setup: func(_ *storagemock.MockRequestSummaryStore, uriStore *storagemock.MockRequestURIStore) { uriStore.EXPECT().ListByURI(gomock.Any(), "uri", 101).Return([]entity.RequestURI{}, nil) }, - call: func(c *RequestSummaryController) error { + call: func(c RequestSummaryController) error { _, err := c.GetRequestSummaryByChangeURI(context.Background(), entity.GetRequestSummaryByChangeURIRequest{ChangeURI: "uri"}) return err }, @@ -160,7 +160,7 @@ func TestStatusErrors(t *testing.T) { setup: func(_ *storagemock.MockRequestSummaryStore, uriStore *storagemock.MockRequestURIStore) { uriStore.EXPECT().ListByURI(gomock.Any(), "uri", 101).Return(make([]entity.RequestURI, 101), nil) }, - call: func(c *RequestSummaryController) error { + call: func(c RequestSummaryController) error { _, err := c.GetRequestSummaryByChangeURI(context.Background(), entity.GetRequestSummaryByChangeURIRequest{ChangeURI: "uri"}) return err }, @@ -173,7 +173,7 @@ func TestStatusErrors(t *testing.T) { uriStore.EXPECT().ListByURI(gomock.Any(), "uri", 101).Return([]entity.RequestURI{{RequestID: "missing/1"}}, nil) summaryStore.EXPECT().Get(gomock.Any(), "missing/1").Return(entity.RequestSummary{}, storage.ErrNotFound) }, - call: func(c *RequestSummaryController) error { + call: func(c RequestSummaryController) error { _, err := c.GetRequestSummaryByChangeURI(context.Background(), entity.GetRequestSummaryByChangeURIRequest{ChangeURI: "uri"}) return err },