From b139196b2d205d068909f4e736248de9c8d5224f Mon Sep 17 00:00:00 2001 From: Brandon Forster Date: Mon, 10 Feb 2020 14:59:48 -0600 Subject: [PATCH] #204: Added structure so that a RegistryClient can use different algorithms for retrieving a URL. (#211) #206: Refactor usage of Context to make idiomatic. #209: Remove Endpointer structure. Signed-off-by: Brandon Forster --- README.md | 34 +- clients/command/client.go | 40 +- clients/command/client_test.go | 80 +--- clients/context.go | 2 +- clients/coredata/event.go | 103 +++-- clients/coredata/event_test.go | 78 +--- clients/coredata/reading.go | 103 ++--- clients/coredata/reading_test.go | 24 +- clients/coredata/value_descriptor.go | 98 ++-- clients/coredata/value_descriptor_test.go | 65 +-- clients/general/client.go | 12 +- clients/general/client_test.go | 40 +- clients/interfaces/endpointer.go | 27 -- .../urlstream.go} | 26 +- clients/logger/logger.go | 2 +- clients/metadata/addressable.go | 42 +- clients/metadata/addressable_test.go | 81 +--- clients/metadata/command.go | 54 +-- clients/metadata/command_test.go | 13 +- clients/metadata/device.go | 148 +++--- clients/metadata/device_profile.go | 70 +-- clients/metadata/device_profile_test.go | 25 +- clients/metadata/device_service.go | 34 +- clients/metadata/device_service_test.go | 11 +- clients/metadata/device_test.go | 36 +- clients/metadata/mocks/DeviceClient.go | 435 ------------------ clients/metadata/provision_watcher.go | 76 +-- clients/metadata/provision_watcher_test.go | 27 +- clients/notifications/client.go | 14 +- clients/notifications/client_test.go | 29 +- clients/request.go | 60 +-- clients/scheduler/interval.go | 54 +-- clients/scheduler/interval_action.go | 64 +-- clients/scheduler/interval_action_test.go | 146 ++---- clients/scheduler/interval_test.go | 141 ++---- clients/types/endpoint_params.go | 28 -- .../{factory.go => errors/errors.go} | 22 +- clients/urlclient/interfaces/retry.go | 32 ++ clients/urlclient/local.go | 10 +- clients/urlclient/local_test.go | 9 +- clients/urlclient/registry.go | 51 +- clients/urlclient/registry_test.go | 125 +++-- clients/urlclient/retry/once/strategy.go | 48 ++ clients/urlclient/retry/periodic/strategy.go | 77 ++++ models/interval.go | 8 +- models/resourceoperation_test.go | 16 +- 46 files changed, 955 insertions(+), 1765 deletions(-) delete mode 100644 clients/interfaces/endpointer.go rename clients/{urlclient/factory_test.go => interfaces/urlstream.go} (52%) delete mode 100644 clients/metadata/mocks/DeviceClient.go delete mode 100644 clients/types/endpoint_params.go rename clients/urlclient/{factory.go => errors/errors.go} (53%) create mode 100644 clients/urlclient/interfaces/retry.go create mode 100644 clients/urlclient/retry/once/strategy.go create mode 100644 clients/urlclient/retry/periodic/strategy.go diff --git a/README.md b/README.md index 76f8063f..fc7ca5d3 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,15 @@ # go-mod-core-contracts -This module contains the contract models used to describe data as it is passed via Request/Response between various EdgeX Foundry services. It also contains service clients for each service within the [edgex-go](https://github.com/edgexfoundry/edgex-go) repository. The definition of the various models and clients can be found in their respective top-level directories. +This module contains the contract models used to describe data as it is passed via Request/Response between various +EdgeX Foundry services. It also contains service clients for each service within the +[edgex-go](https://github.com/edgexfoundry/edgex-go) repository. The definition of the various models and clients can +be found in their respective top-level directories. -The default encoding for the models is JSON, although in at least one case -- [DeviceProfile](https://github.com/edgexfoundry/go-mod-core-contracts/blob/master/models/deviceprofile.go) -- YAML encoding is also supported since a device profile is defined as a YAML document. +The default encoding for the models is JSON, although in at least one case -- +[DeviceProfile](https://github.com/edgexfoundry/go-mod-core-contracts/blob/master/models/deviceprofile.go) -- +YAML encoding is also supported since a device profile is defined as a YAML document. ### Installation ### * Make sure you're using at least Go 1.11.1 and have modules enabled, i.e. have an initialized go.mod file * If your code is in your GOPATH then make sure ```GO111MODULE=on``` is set * Run ```go get github.com/edgexfoundry/go-mod-core-contracts``` * This will add the go-mod-core-contracts to the go.mod file and download it into the module cache - -### How to Use ### -In order to instantiate a service client, you would do the following: - -Let's say you want to utilize a client for the core-metadata service, the first thing you want to do is initialize an instance of [types.EndpointParams](https://github.com/edgexfoundry/go-mod-core-contracts/blob/master/clients/types/endpoint_params.go). This simple struct provides all the properties you need to address a given service endpoint. Population of the relevant properties might look like this: - -``` -params := types.EndpointParams{ - ServiceKey: internal.CoreMetaDataServiceKey, - Path: clients.ApiDeviceRoute, - UseRegistry: useRegistry, - Url: Configuration.Clients["Metadata"].Url() + clients.ApiDeviceRoute, - Interval: Configuration.Service.ClientMonitor, -} -``` -From there you simply pass the EndpointParams into the initialization function for the client you wish to use. In the above case, we're trying to initialize a client for the Device endpoint of the core-metadata service. -``` -mdc := metadata.NewDeviceClient(params, startup.Endpoint{RegistryClient: ®istryClient}) -``` -_More information on the `RegistryClient` can be found [here](https://github.com/edgexfoundry/go-mod-registry). The `RegistryClient` is only used if the `useRegistry` flag provided to the `EndpointParams` is true._ - -Once you have a reference to the client, you simply need to call its methods like so: -`_, err := mdc.CheckForDevice(device, ctx)` - -Each client has a `Monitor` goroutine in it. If the registry is being used, the Monitor's job is to refresh the protocol, host and port of your service client at some configured interval. The default interval is 15 seconds. diff --git a/clients/command/client.go b/clients/command/client.go index 18847f35..5c748b18 100644 --- a/clients/command/client.go +++ b/clients/command/client.go @@ -22,20 +22,18 @@ import ( "github.com/edgexfoundry/go-mod-core-contracts/clients" "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" - "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" ) // CommandClient interface defines interactions with the EdgeX Core Command microservice. type CommandClient interface { // Get issues a GET command targeting the specified device, using the specified command id - Get(deviceId string, commandId string, ctx context.Context) (string, error) + Get(ctx context.Context, deviceId string, commandId string) (string, error) // Put issues a PUT command targeting the specified device, using the specified command id - Put(deviceId string, commandId string, body string, ctx context.Context) (string, error) + Put(ctx context.Context, deviceId string, commandId string, body string) (string, error) // GetDeviceCommandByNames issues a GET command targeting the specified device, using the specified device and command name - GetDeviceCommandByNames(deviceName string, commandName string, ctx context.Context) (string, error) + GetDeviceCommandByNames(ctx context.Context, deviceName string, commandName string) (string, error) // PutDeviceCommandByNames issues a PUT command targeting the specified device, using the specified device and command names - PutDeviceCommandByNames(deviceName string, commandName string, body string, ctx context.Context) (string, error) + PutDeviceCommandByNames(ctx context.Context, deviceName string, commandName string, body string) (string, error) } type commandRestClient struct { @@ -43,37 +41,39 @@ type commandRestClient struct { } // NewCommandClient creates an instance of CommandClient -func NewCommandClient(params types.EndpointParams, m interfaces.Endpointer) CommandClient { - return &commandRestClient{urlClient: urlclient.New(params, m)} +func NewCommandClient(urlClient interfaces.URLClient) CommandClient { + return &commandRestClient{ + urlClient: urlClient, + } } -func (cc *commandRestClient) Get(deviceId string, commandId string, ctx context.Context) (string, error) { - return cc.getRequestJSONBody("/"+deviceId+"/command/"+commandId, ctx) +func (cc *commandRestClient) Get(ctx context.Context, deviceId string, commandId string) (string, error) { + return cc.getRequestJSONBody(ctx, "/"+deviceId+"/command/"+commandId) } -func (cc *commandRestClient) Put(deviceId string, commandId string, body string, ctx context.Context) (string, error) { - return clients.PutRequest("/"+deviceId+"/command/"+commandId, []byte(body), ctx, cc.urlClient) +func (cc *commandRestClient) Put(ctx context.Context, deviceId string, commandId string, body string) (string, error) { + return clients.PutRequest(ctx, "/"+deviceId+"/command/"+commandId, []byte(body), cc.urlClient) } func (cc *commandRestClient) GetDeviceCommandByNames( + ctx context.Context, deviceName string, - commandName string, - ctx context.Context) (string, error) { + commandName string) (string, error) { - return cc.getRequestJSONBody("/name/"+deviceName+"/command/"+commandName, ctx) + return cc.getRequestJSONBody(ctx, "/name/"+deviceName+"/command/"+commandName) } func (cc *commandRestClient) PutDeviceCommandByNames( + ctx context.Context, deviceName string, commandName string, - body string, - ctx context.Context) (string, error) { + body string) (string, error) { - return clients.PutRequest("/name/"+deviceName+"/command/"+commandName, []byte(body), ctx, cc.urlClient) + return clients.PutRequest(ctx, "/name/"+deviceName+"/command/"+commandName, []byte(body), cc.urlClient) } -func (cc *commandRestClient) getRequestJSONBody(urlSuffix string, ctx context.Context) (string, error) { - body, err := clients.GetRequest(urlSuffix, ctx, cc.urlClient) +func (cc *commandRestClient) getRequestJSONBody(ctx context.Context, urlSuffix string) (string, error) { + body, err := clients.GetRequest(ctx, urlSuffix, cc.urlClient) return string(body), err } diff --git a/clients/command/client_test.go b/clients/command/client_test.go index da592af9..2e81d6fb 100644 --- a/clients/command/client_test.go +++ b/clients/command/client_test.go @@ -21,27 +21,18 @@ import ( "testing" "github.com/edgexfoundry/go-mod-core-contracts/clients" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" + "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" + "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" ) func TestGetDeviceCommandById(t *testing.T) { - ts := testHttpServer(t, http.MethodGet, clients.ApiDeviceRoute+"/device1/command/command1") + ts := testHTTPServer(t, http.MethodGet, clients.ApiDeviceRoute+"/device1/command/command1") defer ts.Close() - url := ts.URL + clients.ApiDeviceRoute + cc := NewCommandClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiDeviceRoute))) - params := types.EndpointParams{ - ServiceKey: clients.CoreCommandServiceKey, - Path: clients.ApiDeviceRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault, - } - - cc := NewCommandClient(params, MockEndpoint{}) - - res, _ := cc.Get("device1", "command1", context.Background()) + res, _ := cc.Get(context.Background(), "device1", "command1") if res != "Ok" { t.Errorf("expected response body \"Ok\", but received %s", res) @@ -49,23 +40,13 @@ func TestGetDeviceCommandById(t *testing.T) { } func TestPutDeviceCommandById(t *testing.T) { - ts := testHttpServer(t, http.MethodPut, clients.ApiDeviceRoute+"/device1/command/command1") + ts := testHTTPServer(t, http.MethodPut, clients.ApiDeviceRoute+"/device1/command/command1") defer ts.Close() - url := ts.URL + clients.ApiDeviceRoute - - params := types.EndpointParams{ - ServiceKey: clients.CoreCommandServiceKey, - Path: clients.ApiDeviceRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault, - } - - cc := NewCommandClient(params, MockEndpoint{}) + cc := NewCommandClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiDeviceRoute))) - res, _ := cc.Put("device1", "command1", "body", context.Background()) + res, _ := cc.Put(context.Background(), "device1", "command1", "body") if res != "Ok" { t.Errorf("expected response body \"Ok\", but received %s", res) @@ -73,23 +54,13 @@ func TestPutDeviceCommandById(t *testing.T) { } func TestGetDeviceByName(t *testing.T) { - ts := testHttpServer(t, http.MethodGet, clients.ApiDeviceRoute+"/name/device1/command/command1") + ts := testHTTPServer(t, http.MethodGet, clients.ApiDeviceRoute+"/name/device1/command/command1") defer ts.Close() - url := ts.URL + clients.ApiDeviceRoute - - params := types.EndpointParams{ - ServiceKey: clients.CoreCommandServiceKey, - Path: clients.ApiDeviceRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault, - } - - cc := NewCommandClient(params, MockEndpoint{}) + cc := NewCommandClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiDeviceRoute))) - res, _ := cc.GetDeviceCommandByNames("device1", "command1", context.Background()) + res, _ := cc.GetDeviceCommandByNames(context.Background(), "device1", "command1") if res != "Ok" { t.Errorf("expected response body \"Ok\", but received %s", res) @@ -97,43 +68,26 @@ func TestGetDeviceByName(t *testing.T) { } func TestPutDeviceCommandByNames(t *testing.T) { - ts := testHttpServer(t, http.MethodPut, clients.ApiDeviceRoute+"/name/device1/command/command1") + ts := testHTTPServer(t, http.MethodPut, clients.ApiDeviceRoute+"/name/device1/command/command1") defer ts.Close() - url := ts.URL + clients.ApiDeviceRoute - - params := types.EndpointParams{ - ServiceKey: clients.CoreCommandServiceKey, - Path: clients.ApiDeviceRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault, - } - - cc := NewCommandClient(params, MockEndpoint{}) + cc := NewCommandClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiDeviceRoute))) - res, _ := cc.PutDeviceCommandByNames("device1", "command1", "body", context.Background()) + res, _ := cc.PutDeviceCommandByNames(context.Background(), "device1", "command1", "body") if res != "Ok" { t.Errorf("expected response body \"Ok\", but received %s", res) } } -type MockEndpoint struct { -} - -func (e MockEndpoint) Monitor(params types.EndpointParams) chan string { - return make(chan string, 1) -} - -// testHttpServer instantiates a test HTTP Server to be used for conveniently verifying a client's invocation -func testHttpServer(t *testing.T, matchingRequestMethod string, matchingRequestUri string) *httptest.Server { +// testHTTPServer instantiates a test HTTP Server to be used for conveniently verifying a client's invocation +func testHTTPServer(t *testing.T, matchingRequestMethod string, matchingRequestUri string) *httptest.Server { return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) if r.Method == matchingRequestMethod && r.RequestURI == matchingRequestUri { - w.Write([]byte("Ok")) + _, _ = w.Write([]byte("Ok")) } else { t.Errorf("expected endpoint %s to be invoked by client, %s invoked", matchingRequestUri, r.RequestURI) } diff --git a/clients/context.go b/clients/context.go index cbcbcafb..6f14a2f1 100644 --- a/clients/context.go +++ b/clients/context.go @@ -20,7 +20,7 @@ import ( // FromContext allows for the retrieval of the specified key's value from the supplied Context. // If the value is not found, an empty string is returned. -func FromContext(key string, ctx context.Context) string { +func FromContext(ctx context.Context, key string) string { hdr, ok := ctx.Value(key).(string) if !ok { hdr = "" diff --git a/clients/coredata/event.go b/clients/coredata/event.go index ee939d37..ad287ff7 100644 --- a/clients/coredata/event.go +++ b/clients/coredata/event.go @@ -26,8 +26,6 @@ import ( "github.com/edgexfoundry/go-mod-core-contracts/clients" "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" - "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" "github.com/edgexfoundry/go-mod-core-contracts/models" ) @@ -36,31 +34,31 @@ type EventClient interface { // Events gets a list of all events Events(ctx context.Context) ([]models.Event, error) // Event gets an event by its id - Event(id string, ctx context.Context) (models.Event, error) + Event(ctx context.Context, id string) (models.Event, error) // EventCount returns the total count of events EventCount(ctx context.Context) (int, error) // EventCountForDevice returns the total event count for the specified device - EventCountForDevice(deviceId string, ctx context.Context) (int, error) + EventCountForDevice(ctx context.Context, deviceId string) (int, error) // EventsForDevice returns events up to a specified number that were generated by a given device - EventsForDevice(id string, limit int, ctx context.Context) ([]models.Event, error) + EventsForDevice(ctx context.Context, deviceID string, limit int) ([]models.Event, error) // EventsForInterval returns events generated within a specific time period - EventsForInterval(start int, end int, limit int, ctx context.Context) ([]models.Event, error) + EventsForInterval(ctx context.Context, start int, end int, limit int) ([]models.Event, error) // EventsForDeviceAndValueDescriptor returns events for the specified device and value descriptor - EventsForDeviceAndValueDescriptor(deviceId string, vd string, limit int, ctx context.Context) ([]models.Event, error) + EventsForDeviceAndValueDescriptor(ctx context.Context, deviceId string, vd string, limit int) ([]models.Event, error) // Add will post a new event - Add(event *models.Event, ctx context.Context) (string, error) + Add(ctx context.Context, event *models.Event) (string, error) // AddBytes posts a new event using an array of bytes, supporting encoding of the event by the caller. - AddBytes(event []byte, ctx context.Context) (string, error) + AddBytes(ctx context.Context, event []byte) (string, error) // DeleteForDevice will delete events by the specified device name - DeleteForDevice(id string, ctx context.Context) error + DeleteForDevice(ctx context.Context, deviceID string) error // DeleteOld deletes events according to their age - DeleteOld(age int, ctx context.Context) error + DeleteOld(ctx context.Context, age int) error // Delete will delete an event by its id - Delete(id string, ctx context.Context) error + Delete(ctx context.Context, id string) error // MarkPushed designates an event as having been successfully exported - MarkPushed(id string, ctx context.Context) error + MarkPushed(ctx context.Context, id string) error // MarkPushedByChecksum designates an event as having been successfully exported using a checksum for the respective event. - MarkPushedByChecksum(checksum string, ctx context.Context) error + MarkPushedByChecksum(ctx context.Context, checksum string) error // MarshalEvent will perform JSON or CBOR encoding of the supplied Event. If one or more Readings on the Event // has a populated BinaryValue, the marshaling will be CBOR. Default is JSON. MarshalEvent(e models.Event) ([]byte, error) @@ -71,13 +69,15 @@ type eventRestClient struct { } // NewEventClient creates an instance of EventClient -func NewEventClient(params types.EndpointParams, m interfaces.Endpointer) EventClient { - return &eventRestClient{urlClient: urlclient.New(params, m)} +func NewEventClient(urlClient interfaces.URLClient) EventClient { + return &eventRestClient{ + urlClient: urlClient, + } } // Helper method to request and decode an event slice -func (e *eventRestClient) requestEventSlice(urlSuffix string, ctx context.Context) ([]models.Event, error) { - data, err := clients.GetRequest(urlSuffix, ctx, e.urlClient) +func (e *eventRestClient) requestEventSlice(ctx context.Context, urlSuffix string) ([]models.Event, error) { + data, err := clients.GetRequest(ctx, urlSuffix, e.urlClient) if err != nil { return []models.Event{}, err } @@ -92,8 +92,8 @@ func (e *eventRestClient) requestEventSlice(urlSuffix string, ctx context.Contex } // Helper method to request and decode an event -func (e *eventRestClient) requestEvent(urlSuffix string, ctx context.Context) (models.Event, error) { - data, err := clients.GetRequest(urlSuffix, ctx, e.urlClient) +func (e *eventRestClient) requestEvent(ctx context.Context, urlSuffix string) (models.Event, error) { + data, err := clients.GetRequest(ctx, urlSuffix, e.urlClient) if err != nil { return models.Event{}, err } @@ -104,78 +104,83 @@ func (e *eventRestClient) requestEvent(urlSuffix string, ctx context.Context) (m } func (e *eventRestClient) Events(ctx context.Context) ([]models.Event, error) { - return e.requestEventSlice("", ctx) + return e.requestEventSlice(ctx, "") } -func (e *eventRestClient) Event(id string, ctx context.Context) (models.Event, error) { - return e.requestEvent("/"+id, ctx) +func (e *eventRestClient) Event(ctx context.Context, id string) (models.Event, error) { + return e.requestEvent(ctx, "/"+id) } func (e *eventRestClient) EventCount(ctx context.Context) (int, error) { - return clients.CountRequest("/count", ctx, e.urlClient) + return clients.CountRequest(ctx, "/count", e.urlClient) } -func (e *eventRestClient) EventCountForDevice(deviceId string, ctx context.Context) (int, error) { - return clients.CountRequest("/count/"+url.QueryEscape(deviceId), ctx, e.urlClient) +func (e *eventRestClient) EventCountForDevice(ctx context.Context, deviceId string) (int, error) { + return clients.CountRequest(ctx, "/count/"+url.QueryEscape(deviceId), e.urlClient) } -func (e *eventRestClient) EventsForDevice(deviceId string, limit int, ctx context.Context) ([]models.Event, error) { - return e.requestEventSlice("/device/"+url.QueryEscape(deviceId)+"/"+strconv.Itoa(limit), ctx) +func (e *eventRestClient) EventsForDevice(ctx context.Context, deviceID string, limit int) ([]models.Event, error) { + return e.requestEventSlice(ctx, "/device/"+url.QueryEscape(deviceID)+"/"+strconv.Itoa(limit)) } -func (e *eventRestClient) EventsForInterval(start int, end int, limit int, ctx context.Context) ([]models.Event, error) { - return e.requestEventSlice("/"+strconv.Itoa(start)+"/"+strconv.Itoa(end)+"/"+strconv.Itoa(limit), ctx) +func (e *eventRestClient) EventsForInterval( + ctx context.Context, + start int, + end int, + limit int) ([]models.Event, error) { + + return e.requestEventSlice(ctx, "/"+strconv.Itoa(start)+"/"+strconv.Itoa(end)+"/"+strconv.Itoa(limit)) } func (e *eventRestClient) EventsForDeviceAndValueDescriptor( + ctx context.Context, deviceId string, vd string, - limit int, - ctx context.Context) ([]models.Event, error) { + limit int) ([]models.Event, error) { return e.requestEventSlice( + ctx, "/device/"+ url.QueryEscape(deviceId)+ "/valuedescriptor/"+ url.QueryEscape(vd)+ "/"+strconv.Itoa(limit), - ctx, ) } -func (e *eventRestClient) Add(event *models.Event, ctx context.Context) (string, error) { - content := clients.FromContext(clients.ContentType, ctx) +func (e *eventRestClient) Add(ctx context.Context, event *models.Event) (string, error) { + content := clients.FromContext(ctx, clients.ContentType) if content == clients.ContentTypeCBOR { - return clients.PostRequest("", event.CBOR(), ctx, e.urlClient) + return clients.PostRequest(ctx, "", event.CBOR(), e.urlClient) } else { - return clients.PostJsonRequest("", event, ctx, e.urlClient) + return clients.PostJSONRequest(ctx, "", event, e.urlClient) } } -func (e *eventRestClient) AddBytes(event []byte, ctx context.Context) (string, error) { - return clients.PostRequest("", event, ctx, e.urlClient) +func (e *eventRestClient) AddBytes(ctx context.Context, event []byte) (string, error) { + return clients.PostRequest(ctx, "", event, e.urlClient) } -func (e *eventRestClient) Delete(id string, ctx context.Context) error { - return clients.DeleteRequest("/id/"+id, ctx, e.urlClient) +func (e *eventRestClient) Delete(ctx context.Context, id string) error { + return clients.DeleteRequest(ctx, "/id/"+id, e.urlClient) } -func (e *eventRestClient) DeleteForDevice(deviceId string, ctx context.Context) error { - return clients.DeleteRequest("/device/"+url.QueryEscape(deviceId), ctx, e.urlClient) +func (e *eventRestClient) DeleteForDevice(ctx context.Context, deviceID string) error { + return clients.DeleteRequest(ctx, "/device/"+url.QueryEscape(deviceID), e.urlClient) } -func (e *eventRestClient) DeleteOld(age int, ctx context.Context) error { - return clients.DeleteRequest("/removeold/age/"+strconv.Itoa(age), ctx, e.urlClient) +func (e *eventRestClient) DeleteOld(ctx context.Context, age int) error { + return clients.DeleteRequest(ctx, "/removeold/age/"+strconv.Itoa(age), e.urlClient) } -func (e *eventRestClient) MarkPushed(id string, ctx context.Context) error { - _, err := clients.PutRequest("/id/"+id, nil, ctx, e.urlClient) +func (e *eventRestClient) MarkPushed(ctx context.Context, id string) error { + _, err := clients.PutRequest(ctx, "/id/"+id, nil, e.urlClient) return err } -func (e *eventRestClient) MarkPushedByChecksum(checksum string, ctx context.Context) error { - _, err := clients.PutRequest("/checksum/"+checksum, nil, ctx, e.urlClient) +func (e *eventRestClient) MarkPushedByChecksum(ctx context.Context, checksum string) error { + _, err := clients.PutRequest(ctx, "/checksum/"+checksum, nil, e.urlClient) return err } diff --git a/clients/coredata/event_test.go b/clients/coredata/event_test.go index ca83e6ae..0b583541 100644 --- a/clients/coredata/event_test.go +++ b/clients/coredata/event_test.go @@ -19,13 +19,13 @@ package coredata import ( "context" "encoding/json" - "fmt" "net/http" "net/http/httptest" "testing" "github.com/edgexfoundry/go-mod-core-contracts/clients" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" + "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" + "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" "github.com/edgexfoundry/go-mod-core-contracts/models" "github.com/ugorji/go/codec" @@ -57,18 +57,9 @@ func TestMarkPushed(t *testing.T) { defer ts.Close() - url := ts.URL + clients.ApiEventRoute + ec := NewEventClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiEventRoute))) - params := types.EndpointParams{ - ServiceKey: clients.CoreDataServiceKey, - Path: clients.ApiEventRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault} - - ec := NewEventClient(params, mockCoreDataEndpoint{}) - - err := ec.MarkPushed(TestId, context.Background()) + err := ec.MarkPushed(context.Background(), TestId) if err != nil { t.FailNow() @@ -92,18 +83,9 @@ func TestMarkPushedByChecksum(t *testing.T) { defer ts.Close() - url := ts.URL + clients.ApiEventRoute - - params := types.EndpointParams{ - ServiceKey: clients.CoreDataServiceKey, - Path: clients.ApiEventRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault} + ec := NewEventClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiEventRoute))) - ec := NewEventClient(params, mockCoreDataEndpoint{}) - - err := ec.MarkPushedByChecksum(TestChecksum, context.Background()) + err := ec.MarkPushedByChecksum(context.Background(), TestChecksum) if err != nil { t.FailNow() @@ -122,7 +104,7 @@ func TestGetEvents(t *testing.T) { t.Errorf("expected uri path is %s, actual uri path is %s", clients.ApiEventRoute, r.URL.EscapedPath()) } - w.Write([]byte("[" + + _, _ = w.Write([]byte("[" + "{" + "\"Device\" : \"" + TestEventDevice1 + "\"" + "}," + @@ -135,16 +117,7 @@ func TestGetEvents(t *testing.T) { defer ts.Close() - url := ts.URL + clients.ApiEventRoute - - params := types.EndpointParams{ - ServiceKey: clients.CoreDataServiceKey, - Path: clients.ApiEventRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault} - - ec := NewEventClient(params, mockCoreDataEndpoint{}) + ec := NewEventClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiEventRoute))) eArr, err := ec.Events(context.Background()) if err != nil { @@ -166,31 +139,6 @@ func TestGetEvents(t *testing.T) { } } -func TestNewEventClientWithConsul(t *testing.T) { - deviceUrl := "http://localhost:48080" + clients.ApiEventRoute - params := types.EndpointParams{ - ServiceKey: clients.CoreDataServiceKey, - Path: clients.ApiEventRoute, - UseRegistry: true, - Url: deviceUrl, - Interval: clients.ClientMonitorDefault} - - ec := NewEventClient(params, mockCoreDataEndpoint{}) - - r, ok := ec.(*eventRestClient) - if !ok { - t.Error("ec is not of expected type") - } - - url, err := r.urlClient.Prefix() - - if err != nil { - t.Error("url was not initialized") - } else if url != deviceUrl { - t.Errorf("unexpected url value %s", url) - } -} - func TestMarshalEvent(t *testing.T) { var eventResult models.Event binaryEvent := testEvent @@ -199,7 +147,7 @@ func TestMarshalEvent(t *testing.T) { regularEvent := testEvent regularEvent.Readings = append(regularEvent.Readings, testReading) - client := NewEventClient(types.EndpointParams{Url: "test"}, mockCoreDataEndpoint{}) + client := NewEventClient(urlclient.NewLocalClient("test")) tests := []struct { name string @@ -236,11 +184,3 @@ func TestMarshalEvent(t *testing.T) { }) } } - -type mockCoreDataEndpoint struct{} - -func (e mockCoreDataEndpoint) Monitor(params types.EndpointParams) chan string { - ch := make(chan string, 1) - ch <- fmt.Sprintf("http://%s:%v%s", "localhost", 48080, params.Path) - return ch -} diff --git a/clients/coredata/reading.go b/clients/coredata/reading.go index c96512f6..9313092a 100644 --- a/clients/coredata/reading.go +++ b/clients/coredata/reading.go @@ -25,8 +25,6 @@ import ( "github.com/edgexfoundry/go-mod-core-contracts/clients" "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" - "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" "github.com/edgexfoundry/go-mod-core-contracts/models" ) @@ -37,25 +35,25 @@ type ReadingClient interface { // ReadingCount returns a count of the total readings ReadingCount(ctx context.Context) (int, error) // Reading returns a reading by its id - Reading(id string, ctx context.Context) (models.Reading, error) + Reading(ctx context.Context, id string) (models.Reading, error) // ReadingsForDevice returns readings up to a specified limit for a given device - ReadingsForDevice(deviceId string, limit int, ctx context.Context) ([]models.Reading, error) + ReadingsForDevice(ctx context.Context, deviceId string, limit int) ([]models.Reading, error) // ReadingsForNameAndDevice returns readings up to a specified limit for a given device and value descriptor name - ReadingsForNameAndDevice(name string, deviceId string, limit int, ctx context.Context) ([]models.Reading, error) + ReadingsForNameAndDevice(ctx context.Context, name string, deviceId string, limit int) ([]models.Reading, error) // ReadingsForName returns readings up to a specified limit for a given value descriptor name - ReadingsForName(name string, limit int, ctx context.Context) ([]models.Reading, error) + ReadingsForName(ctx context.Context, name string, limit int) ([]models.Reading, error) // ReadingsForUOMLabel returns readings up to a specified limit for a given UOM label - ReadingsForUOMLabel(uomLabel string, limit int, ctx context.Context) ([]models.Reading, error) + ReadingsForUOMLabel(ctx context.Context, uomLabel string, limit int) ([]models.Reading, error) // ReadingsForLabel returns readings up to a specified limit for a given label - ReadingsForLabel(label string, limit int, ctx context.Context) ([]models.Reading, error) + ReadingsForLabel(ctx context.Context, label string, limit int) ([]models.Reading, error) // ReadingsForType returns readings up to a specified limit of a given type - ReadingsForType(readingType string, limit int, ctx context.Context) ([]models.Reading, error) + ReadingsForType(ctx context.Context, readingType string, limit int) ([]models.Reading, error) // ReadingsForInterval returns readings up to a specified limit generated within a specific time period - ReadingsForInterval(start int, end int, limit int, ctx context.Context) ([]models.Reading, error) + ReadingsForInterval(ctx context.Context, start int, end int, limit int) ([]models.Reading, error) // Add a new reading - Add(readiing *models.Reading, ctx context.Context) (string, error) + Add(ctx context.Context, reading *models.Reading) (string, error) // Delete eliminates a reading by its id - Delete(id string, ctx context.Context) error + Delete(ctx context.Context, id string) error } type readingRestClient struct { @@ -63,13 +61,15 @@ type readingRestClient struct { } // NewReadingClient creates an instance of a ReadingClient -func NewReadingClient(params types.EndpointParams, m interfaces.Endpointer) ReadingClient { - return &readingRestClient{urlClient: urlclient.New(params, m)} +func NewReadingClient(urlClient interfaces.URLClient) ReadingClient { + return &readingRestClient{ + urlClient: urlClient, + } } // Helper method to request and decode a reading slice -func (r *readingRestClient) requestReadingSlice(urlSuffix string, ctx context.Context) ([]models.Reading, error) { - data, err := clients.GetRequest(urlSuffix, ctx, r.urlClient) +func (r *readingRestClient) requestReadingSlice(ctx context.Context, urlSuffix string) ([]models.Reading, error) { + data, err := clients.GetRequest(ctx, urlSuffix, r.urlClient) if err != nil { return []models.Reading{}, err } @@ -80,8 +80,8 @@ func (r *readingRestClient) requestReadingSlice(urlSuffix string, ctx context.Co } // Helper method to request and decode a reading -func (r *readingRestClient) requestReading(urlSuffix string, ctx context.Context) (models.Reading, error) { - data, err := clients.GetRequest(urlSuffix, ctx, r.urlClient) +func (r *readingRestClient) requestReading(ctx context.Context, urlSuffix string) (models.Reading, error) { + data, err := clients.GetRequest(ctx, urlSuffix, r.urlClient) if err != nil { return models.Reading{}, err } @@ -92,78 +92,71 @@ func (r *readingRestClient) requestReading(urlSuffix string, ctx context.Context } func (r *readingRestClient) Readings(ctx context.Context) ([]models.Reading, error) { - return r.requestReadingSlice("", ctx) + return r.requestReadingSlice(ctx, "") } -func (r *readingRestClient) Reading(id string, ctx context.Context) (models.Reading, error) { - return r.requestReading("/"+id, ctx) +func (r *readingRestClient) Reading(ctx context.Context, id string) (models.Reading, error) { + return r.requestReading(ctx, "/"+id) } func (r *readingRestClient) ReadingCount(ctx context.Context) (int, error) { - return clients.CountRequest("/count", ctx, r.urlClient) + return clients.CountRequest(ctx, "/count", r.urlClient) } func (r *readingRestClient) ReadingsForDevice( + ctx context.Context, deviceId string, - limit int, - ctx context.Context) ([]models.Reading, error) { + limit int) ([]models.Reading, error) { - return r.requestReadingSlice("/device/"+url.QueryEscape(deviceId)+"/"+strconv.Itoa(limit), ctx) + return r.requestReadingSlice(ctx, "/device/"+url.QueryEscape(deviceId)+"/"+strconv.Itoa(limit)) } func (r *readingRestClient) ReadingsForNameAndDevice( + ctx context.Context, name string, deviceId string, - limit int, - ctx context.Context) ([]models.Reading, error) { + limit int) ([]models.Reading, error) { - return r.requestReadingSlice( - "/name/"+ - url.QueryEscape(name)+ - "/device/"+ - url.QueryEscape(deviceId)+ - "/"+strconv.Itoa(limit), - ctx, - ) + return r.requestReadingSlice(ctx, "/name/"+ + url.QueryEscape(name)+ + "/device/"+ + url.QueryEscape(deviceId)+ + "/"+strconv.Itoa(limit)) } -func (r *readingRestClient) ReadingsForName(name string, limit int, ctx context.Context) ([]models.Reading, error) { - return r.requestReadingSlice("/name/"+url.QueryEscape(name)+"/"+strconv.Itoa(limit), ctx) +func (r *readingRestClient) ReadingsForName(ctx context.Context, name string, limit int) ([]models.Reading, error) { + return r.requestReadingSlice(ctx, "/name/"+url.QueryEscape(name)+"/"+strconv.Itoa(limit)) } func (r *readingRestClient) ReadingsForUOMLabel( + ctx context.Context, uomLabel string, - limit int, - ctx context.Context) ([]models.Reading, error) { + limit int) ([]models.Reading, error) { - return r.requestReadingSlice("/uomlabel/"+url.QueryEscape(uomLabel)+"/"+strconv.Itoa(limit), ctx) + return r.requestReadingSlice(ctx, "/uomlabel/"+url.QueryEscape(uomLabel)+"/"+strconv.Itoa(limit)) } -func (r *readingRestClient) ReadingsForLabel(label string, limit int, ctx context.Context) ([]models.Reading, error) { - return r.requestReadingSlice("/label/"+url.QueryEscape(label)+"/"+strconv.Itoa(limit), ctx) +func (r *readingRestClient) ReadingsForLabel(ctx context.Context, label string, limit int) ([]models.Reading, error) { + return r.requestReadingSlice(ctx, "/label/"+url.QueryEscape(label)+"/"+strconv.Itoa(limit)) } func (r *readingRestClient) ReadingsForType( + ctx context.Context, readingType string, - limit int, - ctx context.Context) ([]models.Reading, error) { + limit int) ([]models.Reading, error) { - return r.requestReadingSlice("/type/"+url.QueryEscape(readingType)+"/"+strconv.Itoa(limit), ctx) + return r.requestReadingSlice(ctx, "/type/"+url.QueryEscape(readingType)+"/"+strconv.Itoa(limit)) } -func (r *readingRestClient) ReadingsForInterval( - start int, - end int, - limit int, - ctx context.Context) ([]models.Reading, error) { +func (r *readingRestClient) ReadingsForInterval(ctx context.Context, start int, end int, limit int) ([]models.Reading, error) { - return r.requestReadingSlice("/"+strconv.Itoa(start)+"/"+strconv.Itoa(end)+"/"+strconv.Itoa(limit), ctx) + return r.requestReadingSlice(ctx, "/"+strconv.Itoa(start)+"/"+strconv.Itoa(end)+"/"+strconv.Itoa(limit)) } -func (r *readingRestClient) Add(reading *models.Reading, ctx context.Context) (string, error) { - return clients.PostJsonRequest("", reading, ctx, r.urlClient) +func (r *readingRestClient) Add(ctx context.Context, reading *models.Reading) (string, error) { + return clients.PostJSONRequest(ctx, "", reading, r.urlClient) } -func (r *readingRestClient) Delete(id string, ctx context.Context) error { - return clients.DeleteRequest("/id/"+id, ctx, r.urlClient) +func (r *readingRestClient) Delete(ctx context.Context, id string) error { + return clients.DeleteRequest(ctx, "/id/"+id, r.urlClient) } diff --git a/clients/coredata/reading_test.go b/clients/coredata/reading_test.go index 6fe73b58..d8982df7 100644 --- a/clients/coredata/reading_test.go +++ b/clients/coredata/reading_test.go @@ -24,7 +24,8 @@ import ( "testing" "github.com/edgexfoundry/go-mod-core-contracts/clients" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" + "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" + "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" "github.com/edgexfoundry/go-mod-core-contracts/models" ) @@ -67,16 +68,7 @@ func TestGetReadings(t *testing.T) { defer ts.Close() - url := ts.URL + clients.ApiReadingRoute - - params := types.EndpointParams{ - ServiceKey: clients.CoreDataServiceKey, - Path: clients.ApiReadingRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault} - - rc := NewReadingClient(params, mockCoreDataEndpoint{}) + rc := NewReadingClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiReadingRoute))) rArr, err := rc.Readings(context.Background()) if err != nil { @@ -101,14 +93,8 @@ func TestGetReadings(t *testing.T) { func TestNewReadingClientWithConsul(t *testing.T) { deviceUrl := "http://localhost:48080" + clients.ApiReadingRoute - params := types.EndpointParams{ - ServiceKey: clients.CoreDataServiceKey, - Path: clients.ApiReadingRoute, - UseRegistry: true, - Url: deviceUrl, - Interval: clients.ClientMonitorDefault} - - rc := NewReadingClient(params, mockCoreDataEndpoint{}) + + rc := NewReadingClient(urlclient.NewLocalClient(interfaces.URLStream(deviceUrl))) r, ok := rc.(*readingRestClient) if !ok { diff --git a/clients/coredata/value_descriptor.go b/clients/coredata/value_descriptor.go index 64af6fbd..6509537a 100644 --- a/clients/coredata/value_descriptor.go +++ b/clients/coredata/value_descriptor.go @@ -22,8 +22,6 @@ import ( "github.com/edgexfoundry/go-mod-core-contracts/clients" "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" - "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" "github.com/edgexfoundry/go-mod-core-contracts/models" ) @@ -32,44 +30,46 @@ type ValueDescriptorClient interface { // ValueDescriptors returns a list of all value descriptors ValueDescriptors(ctx context.Context) ([]models.ValueDescriptor, error) // ValueDescriptor returns the value descriptor for the specified id - ValueDescriptor(id string, ctx context.Context) (models.ValueDescriptor, error) + ValueDescriptor(ctx context.Context, id string) (models.ValueDescriptor, error) // ValueDescriptorForName returns the value descriptor for the specified name - ValueDescriptorForName(name string, ctx context.Context) (models.ValueDescriptor, error) + ValueDescriptorForName(ctx context.Context, name string) (models.ValueDescriptor, error) // ValueDescriptorsByLabel returns the value descriptors for the specified label - ValueDescriptorsByLabel(label string, ctx context.Context) ([]models.ValueDescriptor, error) + ValueDescriptorsByLabel(ctx context.Context, label string) ([]models.ValueDescriptor, error) // ValueDescriptorsForDevice returns the value descriptors associated with readings from the specified device (by id) - ValueDescriptorsForDevice(deviceId string, ctx context.Context) ([]models.ValueDescriptor, error) + ValueDescriptorsForDevice(ctx context.Context, deviceId string) ([]models.ValueDescriptor, error) // ValueDescriptorsForDeviceByName returns the value descriptors associated with readings from the specified device (by name) - ValueDescriptorsForDeviceByName(deviceName string, ctx context.Context) ([]models.ValueDescriptor, error) + ValueDescriptorsForDeviceByName(ctx context.Context, deviceName string) ([]models.ValueDescriptor, error) // ValueDescriptorsByUomLabel returns the value descriptors for the specified uomLabel - ValueDescriptorsByUomLabel(uomLabel string, ctx context.Context) ([]models.ValueDescriptor, error) + ValueDescriptorsByUomLabel(ctx context.Context, uomLabel string) ([]models.ValueDescriptor, error) // ValueDescriptorsUsage return a map describing which ValueDescriptors are currently in use. The key is the // ValueDescriptor name and the value is a bool specifying if the ValueDescriptor is in use. - ValueDescriptorsUsage(names []string, ctx context.Context) (map[string]bool, error) + ValueDescriptorsUsage(ctx context.Context, names []string) (map[string]bool, error) // Adds the specified value descriptor - Add(vdr *models.ValueDescriptor, ctx context.Context) (string, error) + Add(ctx context.Context, vdr *models.ValueDescriptor) (string, error) // Updates the specified value descriptor - Update(vdr *models.ValueDescriptor, ctx context.Context) error + Update(ctx context.Context, vdr *models.ValueDescriptor) error // Delete eliminates a value descriptor (specified by id) - Delete(id string, ctx context.Context) error + Delete(ctx context.Context, id string) error // Delete eliminates a value descriptor (specified by name) - DeleteByName(name string, ctx context.Context) error + DeleteByName(ctx context.Context, name string) error } type valueDescriptorRestClient struct { urlClient interfaces.URLClient } -func NewValueDescriptorClient(params types.EndpointParams, m interfaces.Endpointer) ValueDescriptorClient { - return &valueDescriptorRestClient{urlClient: urlclient.New(params, m)} +func NewValueDescriptorClient(urlClient interfaces.URLClient) ValueDescriptorClient { + return &valueDescriptorRestClient{ + urlClient: urlClient, + } } // Helper method to request and decode a valuedescriptor slice func (v *valueDescriptorRestClient) requestValueDescriptorSlice( - urlSuffix string, - ctx context.Context) ([]models.ValueDescriptor, error) { + ctx context.Context, + urlSuffix string) ([]models.ValueDescriptor, error) { - data, err := clients.GetRequest(urlSuffix, ctx, v.urlClient) + data, err := clients.GetRequest(ctx, urlSuffix, v.urlClient) if err != nil { return []models.ValueDescriptor{}, err } @@ -81,10 +81,10 @@ func (v *valueDescriptorRestClient) requestValueDescriptorSlice( // Helper method to request and decode a device func (v *valueDescriptorRestClient) requestValueDescriptor( - urlSuffix string, - ctx context.Context) (models.ValueDescriptor, error) { + ctx context.Context, + urlSuffix string) (models.ValueDescriptor, error) { - data, err := clients.GetRequest(urlSuffix, ctx, v.urlClient) + data, err := clients.GetRequest(ctx, urlSuffix, v.urlClient) if err != nil { return models.ValueDescriptor{}, err } @@ -95,49 +95,39 @@ func (v *valueDescriptorRestClient) requestValueDescriptor( } func (v *valueDescriptorRestClient) ValueDescriptors(ctx context.Context) ([]models.ValueDescriptor, error) { - return v.requestValueDescriptorSlice("", ctx) + return v.requestValueDescriptorSlice(ctx, "") } -func (v *valueDescriptorRestClient) ValueDescriptor(id string, ctx context.Context) (models.ValueDescriptor, error) { - return v.requestValueDescriptor("/"+id, ctx) +func (v *valueDescriptorRestClient) ValueDescriptor(ctx context.Context, id string) (models.ValueDescriptor, error) { + return v.requestValueDescriptor(ctx, "/"+id) } -func (v *valueDescriptorRestClient) ValueDescriptorForName( - name string, - ctx context.Context) (models.ValueDescriptor, error) { +func (v *valueDescriptorRestClient) ValueDescriptorForName(ctx context.Context, name string) (models.ValueDescriptor, error) { - return v.requestValueDescriptor("/name/"+url.QueryEscape(name), ctx) + return v.requestValueDescriptor(ctx, "/name/"+url.QueryEscape(name)) } -func (v *valueDescriptorRestClient) ValueDescriptorsByLabel( - label string, - ctx context.Context) ([]models.ValueDescriptor, error) { +func (v *valueDescriptorRestClient) ValueDescriptorsByLabel(ctx context.Context, label string) ([]models.ValueDescriptor, error) { - return v.requestValueDescriptorSlice("/label/"+url.QueryEscape(label), ctx) + return v.requestValueDescriptorSlice(ctx, "/label/"+url.QueryEscape(label)) } -func (v *valueDescriptorRestClient) ValueDescriptorsForDevice( - deviceId string, - ctx context.Context) ([]models.ValueDescriptor, error) { +func (v *valueDescriptorRestClient) ValueDescriptorsForDevice(ctx context.Context, deviceId string) ([]models.ValueDescriptor, error) { - return v.requestValueDescriptorSlice("/deviceid/"+deviceId, ctx) + return v.requestValueDescriptorSlice(ctx, "/deviceid/"+deviceId) } -func (v *valueDescriptorRestClient) ValueDescriptorsForDeviceByName( - deviceName string, - ctx context.Context) ([]models.ValueDescriptor, error) { +func (v *valueDescriptorRestClient) ValueDescriptorsForDeviceByName(ctx context.Context, deviceName string) ([]models.ValueDescriptor, error) { - return v.requestValueDescriptorSlice("/devicename/"+deviceName, ctx) + return v.requestValueDescriptorSlice(ctx, "/devicename/"+deviceName) } -func (v *valueDescriptorRestClient) ValueDescriptorsByUomLabel( - uomLabel string, - ctx context.Context) ([]models.ValueDescriptor, error) { +func (v *valueDescriptorRestClient) ValueDescriptorsByUomLabel(ctx context.Context, uomLabel string) ([]models.ValueDescriptor, error) { - return v.requestValueDescriptorSlice("/uomlabel/"+uomLabel, ctx) + return v.requestValueDescriptorSlice(ctx, "/uomlabel/"+uomLabel) } -func (v *valueDescriptorRestClient) ValueDescriptorsUsage(names []string, ctx context.Context) (map[string]bool, error) { +func (v *valueDescriptorRestClient) ValueDescriptorsUsage(ctx context.Context, names []string) (map[string]bool, error) { urlPrefix, err := v.urlClient.Prefix() if err != nil { return nil, err @@ -152,7 +142,7 @@ func (v *valueDescriptorRestClient) ValueDescriptorsUsage(names []string, ctx co q.Add("names", strings.Join(names, ",")) u.RawQuery = q.Encode() - data, err := clients.GetRequestWithURL(u.String(), ctx) + data, err := clients.GetRequestWithURL(ctx, u.String()) if err != nil { return nil, err } @@ -165,20 +155,20 @@ func (v *valueDescriptorRestClient) ValueDescriptorsUsage(names []string, ctx co return usage, err } -func (v *valueDescriptorRestClient) Add(vdr *models.ValueDescriptor, ctx context.Context) (string, error) { - return clients.PostJsonRequest("", vdr, ctx, v.urlClient) +func (v *valueDescriptorRestClient) Add(ctx context.Context, vdr *models.ValueDescriptor) (string, error) { + return clients.PostJSONRequest(ctx, "", vdr, v.urlClient) } -func (v *valueDescriptorRestClient) Update(vdr *models.ValueDescriptor, ctx context.Context) error { - return clients.UpdateRequest("", vdr, ctx, v.urlClient) +func (v *valueDescriptorRestClient) Update(ctx context.Context, vdr *models.ValueDescriptor) error { + return clients.UpdateRequest(ctx, "", vdr, v.urlClient) } -func (v *valueDescriptorRestClient) Delete(id string, ctx context.Context) error { - return clients.DeleteRequest("/id/"+id, ctx, v.urlClient) +func (v *valueDescriptorRestClient) Delete(ctx context.Context, id string) error { + return clients.DeleteRequest(ctx, "/id/"+id, v.urlClient) } -func (v *valueDescriptorRestClient) DeleteByName(name string, ctx context.Context) error { - return clients.DeleteRequest("/name/"+name, ctx, v.urlClient) +func (v *valueDescriptorRestClient) DeleteByName(ctx context.Context, name string) error { + return clients.DeleteRequest(ctx, "/name/"+name, v.urlClient) } // flattenValueDescriptorUsage puts all key and values into one map. diff --git a/clients/coredata/value_descriptor_test.go b/clients/coredata/value_descriptor_test.go index 2152baeb..a7ad941d 100644 --- a/clients/coredata/value_descriptor_test.go +++ b/clients/coredata/value_descriptor_test.go @@ -23,7 +23,8 @@ import ( "testing" "github.com/edgexfoundry/go-mod-core-contracts/clients" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" + "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" + "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" "github.com/edgexfoundry/go-mod-core-contracts/models" ) @@ -65,22 +66,13 @@ func TestGetvaluedescriptors(t *testing.T) { if err != nil { t.Errorf("marshaling error: %s", err.Error()) } - w.Write(data) + _, _ = w.Write(data) })) defer ts.Close() - url := ts.URL + clients.ApiValueDescriptorRoute - - params := types.EndpointParams{ - ServiceKey: clients.CoreDataServiceKey, - Path: clients.ApiValueDescriptorRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault} - - vdc := NewValueDescriptorClient(params, mockCoreDataEndpoint{}) + vdc := NewValueDescriptorClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiValueDescriptorRoute))) vdArr, err := vdc.ValueDescriptors(context.Background()) if err != nil { @@ -119,22 +111,13 @@ func TestValueDescriptorUsage(t *testing.T) { if err != nil { t.Errorf("marshaling error: %s", err.Error()) } - w.Write(data) + _, _ = w.Write(data) })) defer ts.Close() - url := ts.URL + clients.ApiValueDescriptorRoute - - params := types.EndpointParams{ - ServiceKey: clients.CoreDataServiceKey, - Path: clients.ApiValueDescriptorRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault} - - vdc := NewValueDescriptorClient(params, mockCoreDataEndpoint{}) - usage, err := vdc.ValueDescriptorsUsage([]string{testValueDesciptorDescription1, testValueDesciptorDescription2}, context.Background()) + vdc := NewValueDescriptorClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiValueDescriptorRoute))) + usage, err := vdc.ValueDescriptorsUsage(context.Background(), []string{testValueDesciptorDescription1, testValueDesciptorDescription2}) if err != nil { t.Errorf(err.Error()) t.FailNow() @@ -151,17 +134,8 @@ func TestValueDescriptorUsageSerializationError(t *testing.T) { })) defer ts.Close() - url := ts.URL + clients.ApiValueDescriptorRoute - - params := types.EndpointParams{ - ServiceKey: clients.CoreDataServiceKey, - Path: clients.ApiValueDescriptorRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault} - - vdc := NewValueDescriptorClient(params, mockCoreDataEndpoint{}) - _, err := vdc.ValueDescriptorsUsage([]string{testValueDesciptorDescription1, testValueDesciptorDescription2}, context.Background()) + vdc := NewValueDescriptorClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiValueDescriptorRoute))) + _, err := vdc.ValueDescriptorsUsage(context.Background(), []string{testValueDesciptorDescription1, testValueDesciptorDescription2}) if err == nil { t.Error("Expected an error") return @@ -169,15 +143,8 @@ func TestValueDescriptorUsageSerializationError(t *testing.T) { } func TestValueDescriptorUsageGetRequestError(t *testing.T) { - params := types.EndpointParams{ - ServiceKey: clients.CoreDataServiceKey, - Path: clients.ApiValueDescriptorRoute, - UseRegistry: false, - Url: "!@#", - Interval: clients.ClientMonitorDefault} - - vdc := NewValueDescriptorClient(params, mockCoreDataEndpoint{}) - _, err := vdc.ValueDescriptorsUsage([]string{testValueDesciptorDescription1, testValueDesciptorDescription2}, context.Background()) + vdc := NewValueDescriptorClient(urlclient.NewLocalClient("!%&")) + _, err := vdc.ValueDescriptorsUsage(context.Background(), []string{testValueDesciptorDescription1, testValueDesciptorDescription2}) if err == nil { t.Error("Expected an error") return @@ -186,14 +153,8 @@ func TestValueDescriptorUsageGetRequestError(t *testing.T) { func TestNewValueDescriptorClientWithConsul(t *testing.T) { deviceUrl := "http://localhost:48080" + clients.ApiValueDescriptorRoute - params := types.EndpointParams{ - ServiceKey: clients.CoreDataServiceKey, - Path: clients.ApiValueDescriptorRoute, - UseRegistry: true, - Url: deviceUrl, - Interval: clients.ClientMonitorDefault} - - vdc := NewValueDescriptorClient(params, mockCoreDataEndpoint{}) + + vdc := NewValueDescriptorClient(urlclient.NewLocalClient(interfaces.URLStream(deviceUrl))) r, ok := vdc.(*valueDescriptorRestClient) if !ok { diff --git a/clients/general/client.go b/clients/general/client.go index c9a5712e..751a8744 100644 --- a/clients/general/client.go +++ b/clients/general/client.go @@ -21,8 +21,6 @@ import ( "github.com/edgexfoundry/go-mod-core-contracts/clients" "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" - "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" ) type GeneralClient interface { @@ -37,12 +35,14 @@ type generalRestClient struct { } // NewGeneralClient creates an instance of GeneralClient -func NewGeneralClient(params types.EndpointParams, m interfaces.Endpointer) GeneralClient { - return &generalRestClient{urlClient: urlclient.New(params, m)} +func NewGeneralClient(urlClient interfaces.URLClient) GeneralClient { + return &generalRestClient{ + urlClient: urlClient, + } } func (gc *generalRestClient) FetchConfiguration(ctx context.Context) (string, error) { - body, err := clients.GetRequest(clients.ApiConfigRoute, ctx, gc.urlClient) + body, err := clients.GetRequest(ctx, clients.ApiConfigRoute, gc.urlClient) if err != nil { return "", err } @@ -51,7 +51,7 @@ func (gc *generalRestClient) FetchConfiguration(ctx context.Context) (string, er } func (gc *generalRestClient) FetchMetrics(ctx context.Context) (string, error) { - body, err := clients.GetRequest(clients.ApiMetricsRoute, ctx, gc.urlClient) + body, err := clients.GetRequest(ctx, clients.ApiMetricsRoute, gc.urlClient) if err != nil { return "", err } diff --git a/clients/general/client_test.go b/clients/general/client_test.go index 50b5903c..cf678a59 100644 --- a/clients/general/client_test.go +++ b/clients/general/client_test.go @@ -22,25 +22,18 @@ import ( "testing" "github.com/edgexfoundry/go-mod-core-contracts/clients" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" + "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" + "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" ) const ( TestUnexpectedMsgFormatStr = "unexpected result, active: '%s' but expected: '%s'" ) -type mockGeneralEndpoint struct { -} - -func (e mockGeneralEndpoint) Monitor(params types.EndpointParams) chan string { - return make(chan string, 1) -} - func TestGetConfig(t *testing.T) { - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) - w.Write([]byte("{ 'status' : 'OK' }")) + _, _ = w.Write([]byte("{ 'status' : 'OK' }")) if r.Method != http.MethodGet { t.Errorf(TestUnexpectedMsgFormatStr, r.Method, http.MethodGet) } @@ -51,17 +44,7 @@ func TestGetConfig(t *testing.T) { defer ts.Close() - url := ts.URL - - params := types.EndpointParams{ - ServiceKey: clients.SystemManagementAgentServiceKey, - Path: "/", - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault, - } - - mc := NewGeneralClient(params, mockGeneralEndpoint{}) + mc := NewGeneralClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL))) responseJSON, err := mc.FetchConfiguration(context.Background()) if err != nil { @@ -70,10 +53,9 @@ func TestGetConfig(t *testing.T) { } func TestGetMetrics(t *testing.T) { - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) - w.Write([]byte("{ 'status' : 'OK' }")) + _, _ = w.Write([]byte("{ 'status' : 'OK' }")) if r.Method != http.MethodGet { t.Errorf(TestUnexpectedMsgFormatStr, r.Method, http.MethodGet) } @@ -84,17 +66,7 @@ func TestGetMetrics(t *testing.T) { defer ts.Close() - url := ts.URL - - params := types.EndpointParams{ - ServiceKey: clients.SystemManagementAgentServiceKey, - Path: "/", - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault, - } - - mc := NewGeneralClient(params, mockGeneralEndpoint{}) + mc := NewGeneralClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL))) responseJSON, err := mc.FetchMetrics(context.Background()) if err != nil { diff --git a/clients/interfaces/endpointer.go b/clients/interfaces/endpointer.go deleted file mode 100644 index ed6c11fa..00000000 --- a/clients/interfaces/endpointer.go +++ /dev/null @@ -1,27 +0,0 @@ -/******************************************************************************* - * Copyright 2019 Dell Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - *******************************************************************************/ - -package interfaces - -import "github.com/edgexfoundry/go-mod-core-contracts/clients/types" - -// Endpointer is the interface for types that need to implement or simulate integration -// with a service discovery provider. -type Endpointer interface { - // Monitor is responsible for looking up information about the service endpoint corresponding - // to the params.ServiceKey property. The name "Monitor" implies that this lookup will be done - // at a regular interval. Information about the service from the discovery provider should be - // used to construct a URLClient which will then be pushed to the returned channel. - Monitor(params types.EndpointParams) chan string -} diff --git a/clients/urlclient/factory_test.go b/clients/interfaces/urlstream.go similarity index 52% rename from clients/urlclient/factory_test.go rename to clients/interfaces/urlstream.go index 50af25d3..f3718d32 100644 --- a/clients/urlclient/factory_test.go +++ b/clients/interfaces/urlstream.go @@ -12,28 +12,6 @@ * the License. *******************************************************************************/ -package urlclient +package interfaces -import ( - "testing" - - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" -) - -func TestClientFactoryLocal(t *testing.T) { - actualClient := New(types.EndpointParams{UseRegistry: false}, mockEndpoint{}) - _, isLocalClient := actualClient.(*localClient) - - if !isLocalClient { - t.Fatalf("expected type %T, found %T", localClient{}, actualClient) - } -} - -func TestClientFactoryRegistry(t *testing.T) { - actualClient := New(types.EndpointParams{UseRegistry: true}, mockEndpoint{}) - _, isRegistryClient := actualClient.(*registryClient) - - if !isRegistryClient { - t.Fatalf("expected type %T, found %T", registryClient{}, actualClient) - } -} +type URLStream string diff --git a/clients/logger/logger.go b/clients/logger/logger.go index 152dbc3a..5bb9a434 100644 --- a/clients/logger/logger.go +++ b/clients/logger/logger.go @@ -251,7 +251,7 @@ func (lc edgeXLogger) buildLogEntry(logLevel string, msg string, args ...interfa // Send the log as an http request func (lc edgeXLogger) sendLog(logEntry models.LogEntry) { go func() { - _, err := clients.PostJsonRequestWithURL(lc.logTarget, logEntry, context.Background()) + _, err := clients.PostJSONRequestWithURL(context.Background(), lc.logTarget, logEntry) if err != nil { fmt.Println(err.Error()) } diff --git a/clients/metadata/addressable.go b/clients/metadata/addressable.go index 410fe482..387054c4 100644 --- a/clients/metadata/addressable.go +++ b/clients/metadata/addressable.go @@ -22,23 +22,21 @@ import ( "github.com/edgexfoundry/go-mod-core-contracts/clients" "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" - "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" "github.com/edgexfoundry/go-mod-core-contracts/models" ) // AddressableClient defines the interface for interactions with the Addressable endpoint on core-metadata. type AddressableClient interface { // Add creates a new Addressable and returns the ID of the new item if successful. - Add(addr *models.Addressable, ctx context.Context) (string, error) + Add(ctx context.Context, addr *models.Addressable) (string, error) // Addressable returns an Addressable for the specified ID - Addressable(id string, ctx context.Context) (models.Addressable, error) + Addressable(ctx context.Context, id string) (models.Addressable, error) // Addressable returns an Addressable for the specified name - AddressableForName(name string, ctx context.Context) (models.Addressable, error) + AddressableForName(ctx context.Context, name string) (models.Addressable, error) // Update will update the Addressable data - Update(addr models.Addressable, ctx context.Context) error + Update(ctx context.Context, addr models.Addressable) error // Delete will eliminate the Addressable for the specified ID - Delete(id string, ctx context.Context) error + Delete(ctx context.Context, id string) error } type addressableRestClient struct { @@ -46,13 +44,15 @@ type addressableRestClient struct { } // NewAddressableClient creates an instance of AddressableClient -func NewAddressableClient(params types.EndpointParams, m interfaces.Endpointer) AddressableClient { - return &addressableRestClient{urlClient: urlclient.New(params, m)} +func NewAddressableClient(urlClient interfaces.URLClient) AddressableClient { + return &addressableRestClient{ + urlClient: urlClient, + } } // Helper method to request and decode an addressable -func (a *addressableRestClient) requestAddressable(urlSuffix string, ctx context.Context) (models.Addressable, error) { - data, err := clients.GetRequest(urlSuffix, ctx, a.urlClient) +func (a *addressableRestClient) requestAddressable(ctx context.Context, urlSuffix string) (models.Addressable, error) { + data, err := clients.GetRequest(ctx, urlSuffix, a.urlClient) if err != nil { return models.Addressable{}, err } @@ -62,22 +62,22 @@ func (a *addressableRestClient) requestAddressable(urlSuffix string, ctx context return add, err } -func (a *addressableRestClient) Add(addr *models.Addressable, ctx context.Context) (string, error) { - return clients.PostJsonRequest("", addr, ctx, a.urlClient) +func (a *addressableRestClient) Add(ctx context.Context, addr *models.Addressable) (string, error) { + return clients.PostJSONRequest(ctx, "", addr, a.urlClient) } -func (a *addressableRestClient) Addressable(id string, ctx context.Context) (models.Addressable, error) { - return a.requestAddressable("/"+id, ctx) +func (a *addressableRestClient) Addressable(ctx context.Context, id string) (models.Addressable, error) { + return a.requestAddressable(ctx, "/"+id) } -func (a *addressableRestClient) AddressableForName(name string, ctx context.Context) (models.Addressable, error) { - return a.requestAddressable("/name/"+url.QueryEscape(name), ctx) +func (a *addressableRestClient) AddressableForName(ctx context.Context, name string) (models.Addressable, error) { + return a.requestAddressable(ctx, "/name/"+url.QueryEscape(name)) } -func (a *addressableRestClient) Update(addr models.Addressable, ctx context.Context) error { - return clients.UpdateRequest("", addr, ctx, a.urlClient) +func (a *addressableRestClient) Update(ctx context.Context, addr models.Addressable) error { + return clients.UpdateRequest(ctx, "", addr, a.urlClient) } -func (a *addressableRestClient) Delete(id string, ctx context.Context) error { - return clients.DeleteRequest("/id/"+id, ctx, a.urlClient) +func (a *addressableRestClient) Delete(ctx context.Context, id string) error { + return clients.DeleteRequest(ctx, "/id/"+id, a.urlClient) } diff --git a/clients/metadata/addressable_test.go b/clients/metadata/addressable_test.go index 4901d0ed..37aa5513 100644 --- a/clients/metadata/addressable_test.go +++ b/clients/metadata/addressable_test.go @@ -24,20 +24,15 @@ import ( "github.com/google/uuid" "github.com/edgexfoundry/go-mod-core-contracts/clients" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" + "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" + "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" "github.com/edgexfoundry/go-mod-core-contracts/models" ) func TestNewAddressableClientWithConsul(t *testing.T) { addressableURL := "http://localhost:48081" + clients.ApiAddressableRoute - params := types.EndpointParams{ - ServiceKey: clients.CoreMetaDataServiceKey, - Path: clients.ApiAddressableRoute, - UseRegistry: true, - Url: addressableURL, - Interval: clients.ClientMonitorDefault} - ac := NewAddressableClient(params, mockCoreMetaDataEndpoint{}) + ac := NewAddressableClient(urlclient.NewLocalClient(interfaces.URLStream(addressableURL))) r, ok := ac.(*addressableRestClient) if !ok { @@ -73,23 +68,15 @@ func TestAddAddressable(t *testing.T) { t.Errorf("expected uri path is %s, actual uri path is %s", clients.ApiAddressableRoute, r.URL.EscapedPath()) } - w.Write([]byte(addingAddressableID)) + _, _ = w.Write([]byte(addingAddressableID)) })) defer ts.Close() - url := ts.URL + clients.ApiAddressableRoute + ac := NewAddressableClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiAddressableRoute))) - params := types.EndpointParams{ - ServiceKey: clients.CoreMetaDataServiceKey, - Path: clients.ApiAddressableRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault} - ac := NewAddressableClient(params, mockCoreMetaDataEndpoint{}) - - receivedAddressableID, err := ac.Add(&addressable, context.Background()) + receivedAddressableID, err := ac.Add(context.Background(), &addressable) if err != nil { t.Error(err.Error()) } @@ -119,24 +106,16 @@ func TestGetAddressable(t *testing.T) { } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(addressable) + _ = json.NewEncoder(w).Encode(addressable) })) defer ts.Close() - url := ts.URL + clients.ApiAddressableRoute - - params := types.EndpointParams{ - ServiceKey: clients.CoreMetaDataServiceKey, - Path: clients.ApiAddressableRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault} - ac := NewAddressableClient(params, mockCoreMetaDataEndpoint{}) + ac := NewAddressableClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiAddressableRoute))) - receivedAddressable, err := ac.Addressable(addressable.Id, context.Background()) + receivedAddressable, err := ac.Addressable(context.Background(), addressable.Id) if err != nil { - t.Error(err.Error()) + t.Fatal(err.Error()) } if receivedAddressable.String() != addressable.String() { @@ -164,24 +143,16 @@ func TestGetAddressableForName(t *testing.T) { } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(addressable) + _ = json.NewEncoder(w).Encode(addressable) })) defer ts.Close() - url := ts.URL + clients.ApiAddressableRoute - - params := types.EndpointParams{ - ServiceKey: clients.CoreMetaDataServiceKey, - Path: clients.ApiAddressableRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault} - ac := NewAddressableClient(params, mockCoreMetaDataEndpoint{}) + ac := NewAddressableClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiAddressableRoute))) - receivedAddressable, err := ac.AddressableForName(addressable.Name, context.Background()) + receivedAddressable, err := ac.AddressableForName(context.Background(), addressable.Name) if err != nil { - t.Error(err.Error()) + t.Fatal(err.Error()) } if receivedAddressable.String() != addressable.String() { @@ -211,17 +182,9 @@ func TestUpdateAddressable(t *testing.T) { defer ts.Close() - url := ts.URL + clients.ApiAddressableRoute - - params := types.EndpointParams{ - ServiceKey: clients.CoreMetaDataServiceKey, - Path: clients.ApiAddressableRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault} - ac := NewAddressableClient(params, mockCoreMetaDataEndpoint{}) + ac := NewAddressableClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiAddressableRoute))) - err := ac.Update(addressable, context.Background()) + err := ac.Update(context.Background(), addressable) if err != nil { t.Error(err.Error()) } @@ -250,17 +213,9 @@ func TestDeleteAddressable(t *testing.T) { defer ts.Close() - url := ts.URL + clients.ApiAddressableRoute - - params := types.EndpointParams{ - ServiceKey: clients.CoreMetaDataServiceKey, - Path: clients.ApiAddressableRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault} - ac := NewAddressableClient(params, mockCoreMetaDataEndpoint{}) + ac := NewAddressableClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiAddressableRoute))) - err := ac.Delete(addressable.Id, context.Background()) + err := ac.Delete(context.Background(), addressable.Id) if err != nil { t.Error(err.Error()) } diff --git a/clients/metadata/command.go b/clients/metadata/command.go index 84ef64aa..2d569b19 100644 --- a/clients/metadata/command.go +++ b/clients/metadata/command.go @@ -20,27 +20,25 @@ import ( "github.com/edgexfoundry/go-mod-core-contracts/clients" "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" - "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" "github.com/edgexfoundry/go-mod-core-contracts/models" ) // CommandClient defines the interface for interactions with the Command endpoint on core-metadata. type CommandClient interface { // Add a new command - Add(com *models.Command, ctx context.Context) (string, error) + Add(ctx context.Context, com *models.Command) (string, error) // Command obtains the command for the specified ID - Command(id string, ctx context.Context) (models.Command, error) + Command(ctx context.Context, id string) (models.Command, error) // Commands lists all the commands Commands(ctx context.Context) ([]models.Command, error) // CommandsForName lists all the commands for the specified name - CommandsForName(name string, ctx context.Context) ([]models.Command, error) + CommandsForName(ctx context.Context, name string) ([]models.Command, error) // CommandsForDeviceId list all commands for device with specified ID - CommandsForDeviceId(id string, ctx context.Context) ([]models.Command, error) + CommandsForDeviceId(ctx context.Context, id string) ([]models.Command, error) // Delete a command for the specified ID - Delete(id string, ctx context.Context) error + Delete(ctx context.Context, id string) error // Update a command - Update(com models.Command, ctx context.Context) error + Update(ctx context.Context, com models.Command) error } type commandRestClient struct { @@ -48,13 +46,15 @@ type commandRestClient struct { } // NewCommandClient creates an instance of CommandClient -func NewCommandClient(params types.EndpointParams, m interfaces.Endpointer) CommandClient { - return &commandRestClient{urlClient: urlclient.New(params, m)} +func NewCommandClient(urlClient interfaces.URLClient) CommandClient { + return &commandRestClient{ + urlClient: urlClient, + } } // Helper method to request and decode a command -func (c *commandRestClient) requestCommand(urlSuffix string, ctx context.Context) (models.Command, error) { - data, err := clients.GetRequest(urlSuffix, ctx, c.urlClient) +func (c *commandRestClient) requestCommand(ctx context.Context, urlSuffix string) (models.Command, error) { + data, err := clients.GetRequest(ctx, urlSuffix, c.urlClient) if err != nil { return models.Command{}, err } @@ -65,8 +65,8 @@ func (c *commandRestClient) requestCommand(urlSuffix string, ctx context.Context } // Helper method to request and decode a command slice -func (c *commandRestClient) requestCommandSlice(urlSuffix string, ctx context.Context) ([]models.Command, error) { - data, err := clients.GetRequest(urlSuffix, ctx, c.urlClient) +func (c *commandRestClient) requestCommandSlice(ctx context.Context, urlSuffix string) ([]models.Command, error) { + data, err := clients.GetRequest(ctx, urlSuffix, c.urlClient) if err != nil { return []models.Command{}, err } @@ -76,30 +76,30 @@ func (c *commandRestClient) requestCommandSlice(urlSuffix string, ctx context.Co return comSlice, err } -func (c *commandRestClient) Command(id string, ctx context.Context) (models.Command, error) { - return c.requestCommand("/"+id, ctx) +func (c *commandRestClient) Command(ctx context.Context, id string) (models.Command, error) { + return c.requestCommand(ctx, "/"+id) } func (c *commandRestClient) Commands(ctx context.Context) ([]models.Command, error) { - return c.requestCommandSlice("", ctx) + return c.requestCommandSlice(ctx, "") } -func (c *commandRestClient) CommandsForName(name string, ctx context.Context) ([]models.Command, error) { - return c.requestCommandSlice("/name/"+name, ctx) +func (c *commandRestClient) CommandsForName(ctx context.Context, name string) ([]models.Command, error) { + return c.requestCommandSlice(ctx, "/name/"+name) } -func (c *commandRestClient) CommandsForDeviceId(id string, ctx context.Context) ([]models.Command, error) { - return c.requestCommandSlice("/device/"+id, ctx) +func (c *commandRestClient) CommandsForDeviceId(ctx context.Context, id string) ([]models.Command, error) { + return c.requestCommandSlice(ctx, "/device/"+id) } -func (c *commandRestClient) Add(com *models.Command, ctx context.Context) (string, error) { - return clients.PostJsonRequest("", com, ctx, c.urlClient) +func (c *commandRestClient) Add(ctx context.Context, com *models.Command) (string, error) { + return clients.PostJSONRequest(ctx, "", com, c.urlClient) } -func (c *commandRestClient) Update(com models.Command, ctx context.Context) error { - return clients.UpdateRequest("", com, ctx, c.urlClient) +func (c *commandRestClient) Update(ctx context.Context, com models.Command) error { + return clients.UpdateRequest(ctx, "", com, c.urlClient) } -func (c *commandRestClient) Delete(id string, ctx context.Context) error { - return clients.DeleteRequest("/id/"+id, ctx, c.urlClient) +func (c *commandRestClient) Delete(ctx context.Context, id string) error { + return clients.DeleteRequest(ctx, "/id/"+id, c.urlClient) } diff --git a/clients/metadata/command_test.go b/clients/metadata/command_test.go index c9ecb3ad..347c4f1c 100644 --- a/clients/metadata/command_test.go +++ b/clients/metadata/command_test.go @@ -18,19 +18,14 @@ import ( "testing" "github.com/edgexfoundry/go-mod-core-contracts/clients" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" + "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" + "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" ) func TestNewCommandClientWithConsul(t *testing.T) { deviceUrl := "http://localhost:48081" + clients.ApiCommandRoute - params := types.EndpointParams{ - ServiceKey: clients.CoreMetaDataServiceKey, - Path: clients.ApiCommandRoute, - UseRegistry: true, - Url: deviceUrl, - Interval: clients.ClientMonitorDefault} - - cc := NewCommandClient(params, mockCoreMetaDataEndpoint{}) + + cc := NewCommandClient(urlclient.NewLocalClient(interfaces.URLStream(deviceUrl))) r, ok := cc.(*commandRestClient) if !ok { diff --git a/clients/metadata/device.go b/clients/metadata/device.go index 729b41cd..9dd23a8f 100644 --- a/clients/metadata/device.go +++ b/clients/metadata/device.go @@ -22,55 +22,53 @@ import ( "github.com/edgexfoundry/go-mod-core-contracts/clients" "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" - "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" "github.com/edgexfoundry/go-mod-core-contracts/models" ) // DeviceClient defines the interface for interactions with the Device endpoint on core-metadata. type DeviceClient interface { // Add creates a new device - Add(dev *models.Device, ctx context.Context) (string, error) + Add(ctx context.Context, dev *models.Device) (string, error) // Delete eliminates a device for the specified ID - Delete(id string, ctx context.Context) error + Delete(ctx context.Context, id string) error // DeleteByName eliminates a device for the specified name - DeleteByName(name string, ctx context.Context) error + DeleteByName(ctx context.Context, name string) error // CheckForDevice will return a Device if one already exists for the specified device name - CheckForDevice(token string, ctx context.Context) (models.Device, error) + CheckForDevice(ctx context.Context, token string) (models.Device, error) // Device loads the device for the specified ID - Device(id string, ctx context.Context) (models.Device, error) + Device(ctx context.Context, id string) (models.Device, error) // DeviceForName loads the device for the specified name - DeviceForName(name string, ctx context.Context) (models.Device, error) + DeviceForName(ctx context.Context, name string) (models.Device, error) // Devices lists all devices Devices(ctx context.Context) ([]models.Device, error) // DevicesByLabel lists all devices for the specified label - DevicesByLabel(label string, ctx context.Context) ([]models.Device, error) + DevicesByLabel(ctx context.Context, label string) ([]models.Device, error) // DevicesForProfile lists all devices for the specified profile ID - DevicesForProfile(profileid string, ctx context.Context) ([]models.Device, error) + DevicesForProfile(ctx context.Context, profileid string) ([]models.Device, error) // DevicesForProfileByName lists all devices for the specified profile name - DevicesForProfileByName(profileName string, ctx context.Context) ([]models.Device, error) + DevicesForProfileByName(ctx context.Context, profileName string) ([]models.Device, error) // DevicesForService lists all devices for the specified device service ID - DevicesForService(serviceid string, ctx context.Context) ([]models.Device, error) + DevicesForService(ctx context.Context, serviceid string) ([]models.Device, error) // DevicesForServiceByName lists all devices for the specified device service name - DevicesForServiceByName(serviceName string, ctx context.Context) ([]models.Device, error) + DevicesForServiceByName(ctx context.Context, serviceName string) ([]models.Device, error) // Update the specified device - Update(dev models.Device, ctx context.Context) error + Update(ctx context.Context, dev models.Device) error // UpdateAdminState modifies a device's AdminState for the specified device ID - UpdateAdminState(id string, adminState string, ctx context.Context) error + UpdateAdminState(ctx context.Context, id string, adminState string) error // UpdateAdminStateByName modifies a device's AdminState according to the specified device name - UpdateAdminStateByName(name string, adminState string, ctx context.Context) error + UpdateAdminStateByName(ctx context.Context, name string, adminState string) error // UpdateLastConnected updates a device's last connected timestamp according to the specified device ID - UpdateLastConnected(id string, time int64, ctx context.Context) error + UpdateLastConnected(ctx context.Context, id string, time int64) error // UpdateLastConnectedByName updates a device's last connected timestamp according to the specified device name - UpdateLastConnectedByName(name string, time int64, ctx context.Context) error + UpdateLastConnectedByName(ctx context.Context, name string, time int64) error // UpdateLastReported updates a device's last reported timestamp according to the specified device ID - UpdateLastReported(id string, time int64, ctx context.Context) error + UpdateLastReported(ctx context.Context, id string, time int64) error // UpdateLastReportedByName updates a device's last reported timestamp according to the specified device name - UpdateLastReportedByName(name string, time int64, ctx context.Context) error + UpdateLastReportedByName(ctx context.Context, name string, time int64) error // UpdateOpState updates a device's last OperatingState according to the specified device ID - UpdateOpState(id string, opState string, ctx context.Context) error + UpdateOpState(ctx context.Context, id string, opState string) error // UpdateOpStateByName updates a device's last OperatingState according to the specified device name - UpdateOpStateByName(name string, opState string, ctx context.Context) error + UpdateOpStateByName(ctx context.Context, name string, opState string) error } type deviceRestClient struct { @@ -78,13 +76,15 @@ type deviceRestClient struct { } // NewDeviceClient creates an instance of DeviceClient -func NewDeviceClient(params types.EndpointParams, m interfaces.Endpointer) DeviceClient { - return &deviceRestClient{urlClient: urlclient.New(params, m)} +func NewDeviceClient(urlClient interfaces.URLClient) DeviceClient { + return &deviceRestClient{ + urlClient: urlClient, + } } // Helper method to request and decode a device -func (d *deviceRestClient) requestDevice(urlSuffix string, ctx context.Context) (models.Device, error) { - data, err := clients.GetRequest(urlSuffix, ctx, d.urlClient) +func (d *deviceRestClient) requestDevice(ctx context.Context, urlSuffix string) (models.Device, error) { + data, err := clients.GetRequest(ctx, urlSuffix, d.urlClient) if err != nil { return models.Device{}, err } @@ -95,8 +95,8 @@ func (d *deviceRestClient) requestDevice(urlSuffix string, ctx context.Context) } // Helper method to request and decode a device slice -func (d *deviceRestClient) requestDeviceSlice(urlSuffix string, ctx context.Context) ([]models.Device, error) { - data, err := clients.GetRequest(urlSuffix, ctx, d.urlClient) +func (d *deviceRestClient) requestDeviceSlice(ctx context.Context, urlSuffix string) ([]models.Device, error) { + data, err := clients.GetRequest(ctx, urlSuffix, d.urlClient) if err != nil { return []models.Device{}, err } @@ -106,104 +106,94 @@ func (d *deviceRestClient) requestDeviceSlice(urlSuffix string, ctx context.Cont return dSlice, err } -func (d *deviceRestClient) CheckForDevice(token string, ctx context.Context) (models.Device, error) { - return d.requestDevice("/check/"+token, ctx) +func (d *deviceRestClient) CheckForDevice(ctx context.Context, token string) (models.Device, error) { + return d.requestDevice(ctx, "/check/"+token) } -func (d *deviceRestClient) Device(id string, ctx context.Context) (models.Device, error) { - return d.requestDevice("/"+id, ctx) +func (d *deviceRestClient) Device(ctx context.Context, id string) (models.Device, error) { + return d.requestDevice(ctx, "/"+id) } func (d *deviceRestClient) Devices(ctx context.Context) ([]models.Device, error) { - return d.requestDeviceSlice("", ctx) + return d.requestDeviceSlice(ctx, "") } -func (d *deviceRestClient) DeviceForName(name string, ctx context.Context) (models.Device, error) { - return d.requestDevice("/name/"+url.QueryEscape(name), ctx) +func (d *deviceRestClient) DeviceForName(ctx context.Context, name string) (models.Device, error) { + return d.requestDevice(ctx, "/name/"+url.QueryEscape(name)) } -func (d *deviceRestClient) DevicesByLabel(label string, ctx context.Context) ([]models.Device, error) { - return d.requestDeviceSlice("/label/"+url.QueryEscape(label), ctx) +func (d *deviceRestClient) DevicesByLabel(ctx context.Context, label string) ([]models.Device, error) { + return d.requestDeviceSlice(ctx, "/label/"+url.QueryEscape(label)) } -func (d *deviceRestClient) DevicesForService(serviceId string, ctx context.Context) ([]models.Device, error) { - return d.requestDeviceSlice("/service/"+serviceId, ctx) +func (d *deviceRestClient) DevicesForService(ctx context.Context, serviceId string) ([]models.Device, error) { + return d.requestDeviceSlice(ctx, "/service/"+serviceId) } -func (d *deviceRestClient) DevicesForServiceByName(serviceName string, ctx context.Context) ([]models.Device, error) { - return d.requestDeviceSlice("/servicename/"+url.QueryEscape(serviceName), ctx) +func (d *deviceRestClient) DevicesForServiceByName(ctx context.Context, serviceName string) ([]models.Device, error) { + return d.requestDeviceSlice(ctx, "/servicename/"+url.QueryEscape(serviceName)) } -func (d *deviceRestClient) DevicesForProfile(profileId string, ctx context.Context) ([]models.Device, error) { - return d.requestDeviceSlice("/profile/"+profileId, ctx) +func (d *deviceRestClient) DevicesForProfile(ctx context.Context, profileId string) ([]models.Device, error) { + return d.requestDeviceSlice(ctx, "/profile/"+profileId) } -func (d *deviceRestClient) DevicesForProfileByName(profileName string, ctx context.Context) ([]models.Device, error) { - return d.requestDeviceSlice("/profilename/"+url.QueryEscape(profileName), ctx) +func (d *deviceRestClient) DevicesForProfileByName(ctx context.Context, profileName string) ([]models.Device, error) { + return d.requestDeviceSlice(ctx, "/profilename/"+url.QueryEscape(profileName)) } -func (d *deviceRestClient) Add(dev *models.Device, ctx context.Context) (string, error) { - return clients.PostJsonRequest("", dev, ctx, d.urlClient) +func (d *deviceRestClient) Add(ctx context.Context, dev *models.Device) (string, error) { + return clients.PostJSONRequest(ctx, "", dev, d.urlClient) } -func (d *deviceRestClient) Update(dev models.Device, ctx context.Context) error { - return clients.UpdateRequest("", dev, ctx, d.urlClient) +func (d *deviceRestClient) Update(ctx context.Context, dev models.Device) error { + return clients.UpdateRequest(ctx, "", dev, d.urlClient) } -func (d *deviceRestClient) UpdateLastConnected(id string, time int64, ctx context.Context) error { - _, err := clients.PutRequest("/"+id+"/lastconnected/"+strconv.FormatInt(time, 10), nil, ctx, d.urlClient) +func (d *deviceRestClient) UpdateLastConnected(ctx context.Context, id string, time int64) error { + _, err := clients.PutRequest(ctx, "/"+id+"/lastconnected/"+strconv.FormatInt(time, 10), nil, d.urlClient) return err } -func (d *deviceRestClient) UpdateLastConnectedByName(name string, time int64, ctx context.Context) error { - _, err := clients.PutRequest( - "/name/"+url.QueryEscape(name)+"/lastconnected/"+strconv.FormatInt(time, 10), - nil, - ctx, - d.urlClient, - ) +func (d *deviceRestClient) UpdateLastConnectedByName(ctx context.Context, name string, time int64) error { + _, err := clients.PutRequest(ctx, "/name/"+url.QueryEscape(name)+"/lastconnected/"+strconv.FormatInt(time, 10), nil, d.urlClient) return err } -func (d *deviceRestClient) UpdateLastReported(id string, time int64, ctx context.Context) error { - _, err := clients.PutRequest("/"+id+"/lastreported/"+strconv.FormatInt(time, 10), nil, ctx, d.urlClient) +func (d *deviceRestClient) UpdateLastReported(ctx context.Context, id string, time int64) error { + _, err := clients.PutRequest(ctx, "/"+id+"/lastreported/"+strconv.FormatInt(time, 10), nil, d.urlClient) return err } -func (d *deviceRestClient) UpdateLastReportedByName(name string, time int64, ctx context.Context) error { - _, err := clients.PutRequest( - "/name/"+url.QueryEscape(name)+"/lastreported/"+strconv.FormatInt(time, 10), - nil, - ctx, - d.urlClient, - ) +func (d *deviceRestClient) UpdateLastReportedByName(ctx context.Context, name string, time int64) error { + _, err := clients.PutRequest(ctx, "/name/"+url.QueryEscape(name)+"/lastreported/"+strconv.FormatInt(time, 10), nil, d.urlClient) return err } -func (d *deviceRestClient) UpdateOpState(id string, opState string, ctx context.Context) error { - _, err := clients.PutRequest("/"+id+"/opstate/"+opState, nil, ctx, d.urlClient) +func (d *deviceRestClient) UpdateOpState(ctx context.Context, id string, opState string) error { + _, err := clients.PutRequest(ctx, "/"+id+"/opstate/"+opState, nil, d.urlClient) return err } -func (d *deviceRestClient) UpdateOpStateByName(name string, opState string, ctx context.Context) error { - _, err := clients.PutRequest("/name/"+url.QueryEscape(name)+"/opstate/"+opState, nil, ctx, d.urlClient) +func (d *deviceRestClient) UpdateOpStateByName(ctx context.Context, name string, opState string) error { + _, err := clients.PutRequest(ctx, "/name/"+url.QueryEscape(name)+"/opstate/"+opState, nil, d.urlClient) return err } -func (d *deviceRestClient) UpdateAdminState(id string, adminState string, ctx context.Context) error { - _, err := clients.PutRequest("/"+id+"/adminstate/"+adminState, nil, ctx, d.urlClient) +func (d *deviceRestClient) UpdateAdminState(ctx context.Context, id string, adminState string) error { + _, err := clients.PutRequest(ctx, "/"+id+"/adminstate/"+adminState, nil, d.urlClient) return err } -func (d *deviceRestClient) UpdateAdminStateByName(name string, adminState string, ctx context.Context) error { - _, err := clients.PutRequest("/name/"+url.QueryEscape(name)+"/adminstate/"+adminState, nil, ctx, d.urlClient) +func (d *deviceRestClient) UpdateAdminStateByName(ctx context.Context, name string, adminState string) error { + _, err := clients.PutRequest(ctx, "/name/"+url.QueryEscape(name)+"/adminstate/"+adminState, nil, d.urlClient) return err } -func (d *deviceRestClient) Delete(id string, ctx context.Context) error { - return clients.DeleteRequest("/id/"+id, ctx, d.urlClient) +func (d *deviceRestClient) Delete(ctx context.Context, id string) error { + return clients.DeleteRequest(ctx, "/id/"+id, d.urlClient) } -func (d *deviceRestClient) DeleteByName(name string, ctx context.Context) error { - return clients.DeleteRequest("/name/"+url.QueryEscape(name), ctx, d.urlClient) +func (d *deviceRestClient) DeleteByName(ctx context.Context, name string) error { + return clients.DeleteRequest(ctx, "/name/"+url.QueryEscape(name), d.urlClient) } diff --git a/clients/metadata/device_profile.go b/clients/metadata/device_profile.go index d0f4a829..e797ec22 100644 --- a/clients/metadata/device_profile.go +++ b/clients/metadata/device_profile.go @@ -21,31 +21,29 @@ import ( "github.com/edgexfoundry/go-mod-core-contracts/clients" "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" - "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" "github.com/edgexfoundry/go-mod-core-contracts/models" ) // DeviceProfileClient defines the interface for interactions with the DeviceProfile endpoint on metadata. type DeviceProfileClient interface { // Add a new device profile - Add(dp *models.DeviceProfile, ctx context.Context) (string, error) + Add(ctx context.Context, dp *models.DeviceProfile) (string, error) // Delete eliminates a device profile for the specified ID - Delete(id string, ctx context.Context) error + Delete(ctx context.Context, id string) error // DeleteByName eliminates a device profile for the specified name - DeleteByName(name string, ctx context.Context) error + DeleteByName(ctx context.Context, name string) error // DeviceProfile loads the device profile for the specified ID - DeviceProfile(id string, ctx context.Context) (models.DeviceProfile, error) + DeviceProfile(ctx context.Context, id string) (models.DeviceProfile, error) // DeviceProfiles lists all device profiles DeviceProfiles(ctx context.Context) ([]models.DeviceProfile, error) // DeviceProfileForName loads the device profile for the specified name - DeviceProfileForName(name string, ctx context.Context) (models.DeviceProfile, error) + DeviceProfileForName(ctx context.Context, name string) (models.DeviceProfile, error) // Update a device profile - Update(dp models.DeviceProfile, ctx context.Context) error + Update(ctx context.Context, dp models.DeviceProfile) error // Upload a new device profile using raw YAML content - Upload(yamlString string, ctx context.Context) (string, error) + Upload(ctx context.Context, yamlString string) (string, error) // Upload a new device profile using a file in YAML format - UploadFile(yamlFilePath string, ctx context.Context) (string, error) + UploadFile(ctx context.Context, yamlFilePath string) (string, error) } type deviceProfileRestClient struct { @@ -53,16 +51,18 @@ type deviceProfileRestClient struct { } // Return an instance of DeviceProfileClient -func NewDeviceProfileClient(params types.EndpointParams, m interfaces.Endpointer) DeviceProfileClient { - return &deviceProfileRestClient{urlClient: urlclient.New(params, m)} +func NewDeviceProfileClient(urlClient interfaces.URLClient) DeviceProfileClient { + return &deviceProfileRestClient{ + urlClient: urlClient, + } } // Helper method to request and decode a device profile func (dpc *deviceProfileRestClient) requestDeviceProfile( - urlSuffix string, - ctx context.Context) (models.DeviceProfile, error) { + ctx context.Context, + urlSuffix string) (models.DeviceProfile, error) { - data, err := clients.GetRequest(urlSuffix, ctx, dpc.urlClient) + data, err := clients.GetRequest(ctx, urlSuffix, dpc.urlClient) if err != nil { return models.DeviceProfile{}, err } @@ -74,10 +74,10 @@ func (dpc *deviceProfileRestClient) requestDeviceProfile( // Helper method to request and decode a device profile slice func (dpc *deviceProfileRestClient) requestDeviceProfileSlice( - urlSuffix string, - ctx context.Context) ([]models.DeviceProfile, error) { + ctx context.Context, + urlSuffix string) ([]models.DeviceProfile, error) { - data, err := clients.GetRequest(urlSuffix, ctx, dpc.urlClient) + data, err := clients.GetRequest(ctx, urlSuffix, dpc.urlClient) if err != nil { return []models.DeviceProfile{}, err } @@ -87,40 +87,40 @@ func (dpc *deviceProfileRestClient) requestDeviceProfileSlice( return dpSlice, err } -func (dpc *deviceProfileRestClient) Add(dp *models.DeviceProfile, ctx context.Context) (string, error) { - return clients.PostJsonRequest("", dp, ctx, dpc.urlClient) +func (dpc *deviceProfileRestClient) Add(ctx context.Context, dp *models.DeviceProfile) (string, error) { + return clients.PostJSONRequest(ctx, "", dp, dpc.urlClient) } -func (dpc *deviceProfileRestClient) Delete(id string, ctx context.Context) error { - return clients.DeleteRequest("/id/"+id, ctx, dpc.urlClient) +func (dpc *deviceProfileRestClient) Delete(ctx context.Context, id string) error { + return clients.DeleteRequest(ctx, "/id/"+id, dpc.urlClient) } -func (dpc *deviceProfileRestClient) DeleteByName(name string, ctx context.Context) error { - return clients.DeleteRequest("/name/"+url.QueryEscape(name), ctx, dpc.urlClient) +func (dpc *deviceProfileRestClient) DeleteByName(ctx context.Context, name string) error { + return clients.DeleteRequest(ctx, "/name/"+url.QueryEscape(name), dpc.urlClient) } -func (dpc *deviceProfileRestClient) DeviceProfile(id string, ctx context.Context) (models.DeviceProfile, error) { - return dpc.requestDeviceProfile("/"+id, ctx) +func (dpc *deviceProfileRestClient) DeviceProfile(ctx context.Context, id string) (models.DeviceProfile, error) { + return dpc.requestDeviceProfile(ctx, "/"+id) } func (dpc *deviceProfileRestClient) DeviceProfiles(ctx context.Context) ([]models.DeviceProfile, error) { - return dpc.requestDeviceProfileSlice("", ctx) + return dpc.requestDeviceProfileSlice(ctx, "") } -func (dpc *deviceProfileRestClient) DeviceProfileForName(name string, ctx context.Context) (models.DeviceProfile, error) { - return dpc.requestDeviceProfile("/name/"+name, ctx) +func (dpc *deviceProfileRestClient) DeviceProfileForName(ctx context.Context, name string) (models.DeviceProfile, error) { + return dpc.requestDeviceProfile(ctx, "/name/"+name) } -func (dpc *deviceProfileRestClient) Update(dp models.DeviceProfile, ctx context.Context) error { - return clients.UpdateRequest("", dp, ctx, dpc.urlClient) +func (dpc *deviceProfileRestClient) Update(ctx context.Context, dp models.DeviceProfile) error { + return clients.UpdateRequest(ctx, "", dp, dpc.urlClient) } -func (dpc *deviceProfileRestClient) Upload(yamlString string, ctx context.Context) (string, error) { +func (dpc *deviceProfileRestClient) Upload(ctx context.Context, yamlString string) (string, error) { ctx = context.WithValue(ctx, clients.ContentType, clients.ContentTypeYAML) - return clients.PostRequest("/upload", []byte(yamlString), ctx, dpc.urlClient) + return clients.PostRequest(ctx, "/upload", []byte(yamlString), dpc.urlClient) } -func (dpc *deviceProfileRestClient) UploadFile(yamlFilePath string, ctx context.Context) (string, error) { - return clients.UploadFileRequest("/uploadfile", yamlFilePath, ctx, dpc.urlClient) +func (dpc *deviceProfileRestClient) UploadFile(ctx context.Context, yamlFilePath string) (string, error) { + return clients.UploadFileRequest(ctx, "/uploadfile", yamlFilePath, dpc.urlClient) } diff --git a/clients/metadata/device_profile_test.go b/clients/metadata/device_profile_test.go index 1d45fea4..794c6c64 100644 --- a/clients/metadata/device_profile_test.go +++ b/clients/metadata/device_profile_test.go @@ -21,20 +21,15 @@ import ( "testing" "github.com/edgexfoundry/go-mod-core-contracts/clients" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" + "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" + "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" "github.com/edgexfoundry/go-mod-core-contracts/models" ) func TestNewDeviceProfileClientWithConsul(t *testing.T) { deviceUrl := "http://localhost:48081" + clients.ApiCommandRoute - params := types.EndpointParams{ - ServiceKey: clients.CoreMetaDataServiceKey, - Path: clients.ApiCommandRoute, - UseRegistry: true, - Url: deviceUrl, - Interval: clients.ClientMonitorDefault} - dpc := NewDeviceProfileClient(params, mockCoreMetaDataEndpoint{}) + dpc := NewDeviceProfileClient(urlclient.NewLocalClient(interfaces.URLStream(deviceUrl))) r, ok := dpc.(*deviceProfileRestClient) if !ok { @@ -68,23 +63,15 @@ func TestUpdateDeviceProfile(t *testing.T) { t.Errorf("expected uri path is %s, actual uri path is %s", clients.ApiDeviceProfileRoute, r.URL.EscapedPath()) } - w.Write([]byte("true")) + _, _ = w.Write([]byte("true")) })) defer ts.Close() - url := ts.URL + clients.ApiDeviceProfileRoute + dpc := NewDeviceProfileClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiDeviceProfileRoute))) - params := types.EndpointParams{ - ServiceKey: clients.CoreMetaDataServiceKey, - Path: clients.ApiDeviceProfileRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault} - dpc := NewDeviceProfileClient(params, mockCoreMetaDataEndpoint{}) - - err := dpc.Update(p, context.Background()) + err := dpc.Update(context.Background(), p) if err != nil { t.Error(err.Error()) } diff --git a/clients/metadata/device_service.go b/clients/metadata/device_service.go index 7b50e721..f8b1c8c6 100644 --- a/clients/metadata/device_service.go +++ b/clients/metadata/device_service.go @@ -21,21 +21,19 @@ import ( "github.com/edgexfoundry/go-mod-core-contracts/clients" "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" - "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" "github.com/edgexfoundry/go-mod-core-contracts/models" ) // DeviceServiceClient defines the interface for interactions with the DeviceService endpoint on metadata. type DeviceServiceClient interface { // Add a new device service - Add(ds *models.DeviceService, ctx context.Context) (string, error) + Add(ctx context.Context, ds *models.DeviceService) (string, error) // DeviceServiceForName loads a device service for the specified name - DeviceServiceForName(name string, ctx context.Context) (models.DeviceService, error) + DeviceServiceForName(ctx context.Context, name string) (models.DeviceService, error) // UpdateLastConnected updates a device service's last connected timestamp for the specified service ID - UpdateLastConnected(id string, time int64, ctx context.Context) error + UpdateLastConnected(ctx context.Context, id string, time int64) error // UpdateLastReported updates a device service's last reported timestamp for the specified service ID - UpdateLastReported(id string, time int64, ctx context.Context) error + UpdateLastReported(ctx context.Context, id string, time int64) error } type deviceServiceRestClient struct { @@ -43,29 +41,29 @@ type deviceServiceRestClient struct { } // NewDeviceServiceClient creates an instance of DeviceServiceClient -func NewDeviceServiceClient(params types.EndpointParams, m interfaces.Endpointer) DeviceServiceClient { - return &deviceServiceRestClient{urlClient: urlclient.New(params, m)} +func NewDeviceServiceClient(urlClient interfaces.URLClient) DeviceServiceClient { + return &deviceServiceRestClient{ + urlClient: urlClient, + } } -func (dsc *deviceServiceRestClient) UpdateLastConnected(id string, time int64, ctx context.Context) error { - _, err := clients.PutRequest("/"+id+"/lastconnected/"+strconv.FormatInt(time, 10), nil, ctx, dsc.urlClient) +func (dsc *deviceServiceRestClient) UpdateLastConnected(ctx context.Context, id string, time int64) error { + _, err := clients.PutRequest(ctx, "/"+id+"/lastconnected/"+strconv.FormatInt(time, 10), nil, dsc.urlClient) return err } -func (dsc *deviceServiceRestClient) UpdateLastReported(id string, time int64, ctx context.Context) error { - _, err := clients.PutRequest("/"+id+"/lastreported/"+strconv.FormatInt(time, 10), nil, ctx, dsc.urlClient) +func (dsc *deviceServiceRestClient) UpdateLastReported(ctx context.Context, id string, time int64) error { + _, err := clients.PutRequest(ctx, "/"+id+"/lastreported/"+strconv.FormatInt(time, 10), nil, dsc.urlClient) return err } -func (dsc *deviceServiceRestClient) Add(ds *models.DeviceService, ctx context.Context) (string, error) { - return clients.PostJsonRequest("", ds, ctx, dsc.urlClient) +func (dsc *deviceServiceRestClient) Add(ctx context.Context, ds *models.DeviceService) (string, error) { + return clients.PostJSONRequest(ctx, "", ds, dsc.urlClient) } -func (dsc *deviceServiceRestClient) DeviceServiceForName( - name string, - ctx context.Context) (models.DeviceService, error) { +func (dsc *deviceServiceRestClient) DeviceServiceForName(ctx context.Context, name string) (models.DeviceService, error) { - data, err := clients.GetRequest("/name/"+name, ctx, dsc.urlClient) + data, err := clients.GetRequest(ctx, "/name/"+name, dsc.urlClient) if err != nil { return models.DeviceService{}, err } diff --git a/clients/metadata/device_service_test.go b/clients/metadata/device_service_test.go index ff44deef..c2856236 100644 --- a/clients/metadata/device_service_test.go +++ b/clients/metadata/device_service_test.go @@ -18,19 +18,14 @@ import ( "testing" "github.com/edgexfoundry/go-mod-core-contracts/clients" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" + "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" + "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" ) func TestNewDeviceServiceClientWithConsul(t *testing.T) { deviceServiceUrl := "http://localhost:48081" + clients.ApiDeviceServiceRoute - params := types.EndpointParams{ - ServiceKey: clients.CoreMetaDataServiceKey, - Path: clients.ApiDeviceServiceRoute, - UseRegistry: true, - Url: deviceServiceUrl, - Interval: clients.ClientMonitorDefault} - dsc := NewDeviceServiceClient(params, mockCoreMetaDataEndpoint{}) + dsc := NewDeviceServiceClient(urlclient.NewLocalClient(interfaces.URLStream(deviceServiceUrl))) r, ok := dsc.(*deviceServiceRestClient) if !ok { t.Error("dsc is not of expected type") diff --git a/clients/metadata/device_test.go b/clients/metadata/device_test.go index e6bcba00..8958ab0d 100644 --- a/clients/metadata/device_test.go +++ b/clients/metadata/device_test.go @@ -16,18 +16,16 @@ package metadata import ( "context" - "fmt" "net/http" "net/http/httptest" "testing" "github.com/edgexfoundry/go-mod-core-contracts/clients" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" + "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" + "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" "github.com/edgexfoundry/go-mod-core-contracts/models" ) -// Test adding a device using the device urlClient - // Test adding a device using the device urlClient func TestAddDevice(t *testing.T) { @@ -53,23 +51,15 @@ func TestAddDevice(t *testing.T) { t.Errorf("expected uri path is %s, actual uri path is %s", clients.ApiDeviceRoute, r.URL.EscapedPath()) } - w.Write([]byte(addingDeviceId)) + _, _ = w.Write([]byte(addingDeviceId)) })) defer ts.Close() - url := ts.URL + clients.ApiDeviceRoute - - params := types.EndpointParams{ - ServiceKey: clients.CoreMetaDataServiceKey, - Path: clients.ApiDeviceRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault} - dc := NewDeviceClient(params, mockCoreMetaDataEndpoint{}) + dc := NewDeviceClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiDeviceRoute))) - receivedDeviceId, err := dc.Add(&d, context.Background()) + receivedDeviceId, err := dc.Add(context.Background(), &d) if err != nil { t.Error(err.Error()) } @@ -81,14 +71,8 @@ func TestAddDevice(t *testing.T) { func TestNewDeviceClientWithConsul(t *testing.T) { deviceUrl := "http://localhost:48081" + clients.ApiDeviceRoute - params := types.EndpointParams{ - ServiceKey: clients.CoreMetaDataServiceKey, - Path: clients.ApiDeviceRoute, - UseRegistry: true, - Url: deviceUrl, - Interval: clients.ClientMonitorDefault} - dc := NewDeviceClient(params, mockCoreMetaDataEndpoint{}) + dc := NewDeviceClient(urlclient.NewLocalClient(interfaces.URLStream(deviceUrl))) r, ok := dc.(*deviceRestClient) if !ok { @@ -103,11 +87,3 @@ func TestNewDeviceClientWithConsul(t *testing.T) { t.Errorf("unexpected url value %s", url) } } - -type mockCoreMetaDataEndpoint struct{} - -func (e mockCoreMetaDataEndpoint) Monitor(params types.EndpointParams) chan string { - ch := make(chan string, 1) - ch <- fmt.Sprintf("http://%s:%v%s", "localhost", 48081, params.Path) - return ch -} diff --git a/clients/metadata/mocks/DeviceClient.go b/clients/metadata/mocks/DeviceClient.go deleted file mode 100644 index 478e09f3..00000000 --- a/clients/metadata/mocks/DeviceClient.go +++ /dev/null @@ -1,435 +0,0 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. - -package mocks - -import context "context" - -import mock "github.com/stretchr/testify/mock" -import models "github.com/edgexfoundry/go-mod-core-contracts/models" - -// DeviceClient is an autogenerated mock type for the DeviceClient type -type DeviceClient struct { - mock.Mock -} - -// Add provides a mock function with given fields: dev, ctx -func (_m *DeviceClient) Add(dev *models.Device, ctx context.Context) (string, error) { - ret := _m.Called(dev, ctx) - - var r0 string - if rf, ok := ret.Get(0).(func(*models.Device, context.Context) string); ok { - r0 = rf(dev, ctx) - } else { - r0 = ret.Get(0).(string) - } - - var r1 error - if rf, ok := ret.Get(1).(func(*models.Device, context.Context) error); ok { - r1 = rf(dev, ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// CheckForDevice provides a mock function with given fields: token, ctx -func (_m *DeviceClient) CheckForDevice(token string, ctx context.Context) (models.Device, error) { - ret := _m.Called(token, ctx) - - var r0 models.Device - if rf, ok := ret.Get(0).(func(string, context.Context) models.Device); ok { - r0 = rf(token, ctx) - } else { - r0 = ret.Get(0).(models.Device) - } - - var r1 error - if rf, ok := ret.Get(1).(func(string, context.Context) error); ok { - r1 = rf(token, ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Delete provides a mock function with given fields: id, ctx -func (_m *DeviceClient) Delete(id string, ctx context.Context) error { - ret := _m.Called(id, ctx) - - var r0 error - if rf, ok := ret.Get(0).(func(string, context.Context) error); ok { - r0 = rf(id, ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// DeleteByName provides a mock function with given fields: name, ctx -func (_m *DeviceClient) DeleteByName(name string, ctx context.Context) error { - ret := _m.Called(name, ctx) - - var r0 error - if rf, ok := ret.Get(0).(func(string, context.Context) error); ok { - r0 = rf(name, ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Device provides a mock function with given fields: id, ctx -func (_m *DeviceClient) Device(id string, ctx context.Context) (models.Device, error) { - ret := _m.Called(id, ctx) - - var r0 models.Device - if rf, ok := ret.Get(0).(func(string, context.Context) models.Device); ok { - r0 = rf(id, ctx) - } else { - r0 = ret.Get(0).(models.Device) - } - - var r1 error - if rf, ok := ret.Get(1).(func(string, context.Context) error); ok { - r1 = rf(id, ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DeviceForName provides a mock function with given fields: name, ctx -func (_m *DeviceClient) DeviceForName(name string, ctx context.Context) (models.Device, error) { - ret := _m.Called(name, ctx) - - var r0 models.Device - if rf, ok := ret.Get(0).(func(string, context.Context) models.Device); ok { - r0 = rf(name, ctx) - } else { - r0 = ret.Get(0).(models.Device) - } - - var r1 error - if rf, ok := ret.Get(1).(func(string, context.Context) error); ok { - r1 = rf(name, ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Devices provides a mock function with given fields: ctx -func (_m *DeviceClient) Devices(ctx context.Context) ([]models.Device, error) { - ret := _m.Called(ctx) - - var r0 []models.Device - if rf, ok := ret.Get(0).(func(context.Context) []models.Device); ok { - r0 = rf(ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]models.Device) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DevicesByLabel provides a mock function with given fields: label, ctx -func (_m *DeviceClient) DevicesByLabel(label string, ctx context.Context) ([]models.Device, error) { - ret := _m.Called(label, ctx) - - var r0 []models.Device - if rf, ok := ret.Get(0).(func(string, context.Context) []models.Device); ok { - r0 = rf(label, ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]models.Device) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(string, context.Context) error); ok { - r1 = rf(label, ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DevicesForAddressable provides a mock function with given fields: addressableid, ctx -func (_m *DeviceClient) DevicesForAddressable(addressableid string, ctx context.Context) ([]models.Device, error) { - ret := _m.Called(addressableid, ctx) - - var r0 []models.Device - if rf, ok := ret.Get(0).(func(string, context.Context) []models.Device); ok { - r0 = rf(addressableid, ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]models.Device) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(string, context.Context) error); ok { - r1 = rf(addressableid, ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DevicesForAddressableByName provides a mock function with given fields: addressableName, ctx -func (_m *DeviceClient) DevicesForAddressableByName(addressableName string, ctx context.Context) ([]models.Device, error) { - ret := _m.Called(addressableName, ctx) - - var r0 []models.Device - if rf, ok := ret.Get(0).(func(string, context.Context) []models.Device); ok { - r0 = rf(addressableName, ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]models.Device) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(string, context.Context) error); ok { - r1 = rf(addressableName, ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DevicesForProfile provides a mock function with given fields: profileid, ctx -func (_m *DeviceClient) DevicesForProfile(profileid string, ctx context.Context) ([]models.Device, error) { - ret := _m.Called(profileid, ctx) - - var r0 []models.Device - if rf, ok := ret.Get(0).(func(string, context.Context) []models.Device); ok { - r0 = rf(profileid, ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]models.Device) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(string, context.Context) error); ok { - r1 = rf(profileid, ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DevicesForProfileByName provides a mock function with given fields: profileName, ctx -func (_m *DeviceClient) DevicesForProfileByName(profileName string, ctx context.Context) ([]models.Device, error) { - ret := _m.Called(profileName, ctx) - - var r0 []models.Device - if rf, ok := ret.Get(0).(func(string, context.Context) []models.Device); ok { - r0 = rf(profileName, ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]models.Device) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(string, context.Context) error); ok { - r1 = rf(profileName, ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DevicesForService provides a mock function with given fields: serviceid, ctx -func (_m *DeviceClient) DevicesForService(serviceid string, ctx context.Context) ([]models.Device, error) { - ret := _m.Called(serviceid, ctx) - - var r0 []models.Device - if rf, ok := ret.Get(0).(func(string, context.Context) []models.Device); ok { - r0 = rf(serviceid, ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]models.Device) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(string, context.Context) error); ok { - r1 = rf(serviceid, ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DevicesForServiceByName provides a mock function with given fields: serviceName, ctx -func (_m *DeviceClient) DevicesForServiceByName(serviceName string, ctx context.Context) ([]models.Device, error) { - ret := _m.Called(serviceName, ctx) - - var r0 []models.Device - if rf, ok := ret.Get(0).(func(string, context.Context) []models.Device); ok { - r0 = rf(serviceName, ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]models.Device) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(string, context.Context) error); ok { - r1 = rf(serviceName, ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Update provides a mock function with given fields: dev, ctx -func (_m *DeviceClient) Update(dev models.Device, ctx context.Context) error { - ret := _m.Called(dev, ctx) - - var r0 error - if rf, ok := ret.Get(0).(func(models.Device, context.Context) error); ok { - r0 = rf(dev, ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// UpdateAdminState provides a mock function with given fields: id, adminState, ctx -func (_m *DeviceClient) UpdateAdminState(id string, adminState string, ctx context.Context) error { - ret := _m.Called(id, adminState, ctx) - - var r0 error - if rf, ok := ret.Get(0).(func(string, string, context.Context) error); ok { - r0 = rf(id, adminState, ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// UpdateAdminStateByName provides a mock function with given fields: name, adminState, ctx -func (_m *DeviceClient) UpdateAdminStateByName(name string, adminState string, ctx context.Context) error { - ret := _m.Called(name, adminState, ctx) - - var r0 error - if rf, ok := ret.Get(0).(func(string, string, context.Context) error); ok { - r0 = rf(name, adminState, ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// UpdateLastConnected provides a mock function with given fields: id, time, ctx -func (_m *DeviceClient) UpdateLastConnected(id string, time int64, ctx context.Context) error { - ret := _m.Called(id, time, ctx) - - var r0 error - if rf, ok := ret.Get(0).(func(string, int64, context.Context) error); ok { - r0 = rf(id, time, ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// UpdateLastConnectedByName provides a mock function with given fields: name, time, ctx -func (_m *DeviceClient) UpdateLastConnectedByName(name string, time int64, ctx context.Context) error { - ret := _m.Called(name, time, ctx) - - var r0 error - if rf, ok := ret.Get(0).(func(string, int64, context.Context) error); ok { - r0 = rf(name, time, ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// UpdateLastReported provides a mock function with given fields: id, time, ctx -func (_m *DeviceClient) UpdateLastReported(id string, time int64, ctx context.Context) error { - ret := _m.Called(id, time, ctx) - - var r0 error - if rf, ok := ret.Get(0).(func(string, int64, context.Context) error); ok { - r0 = rf(id, time, ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// UpdateLastReportedByName provides a mock function with given fields: name, time, ctx -func (_m *DeviceClient) UpdateLastReportedByName(name string, time int64, ctx context.Context) error { - ret := _m.Called(name, time, ctx) - - var r0 error - if rf, ok := ret.Get(0).(func(string, int64, context.Context) error); ok { - r0 = rf(name, time, ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// UpdateOpState provides a mock function with given fields: id, opState, ctx -func (_m *DeviceClient) UpdateOpState(id string, opState string, ctx context.Context) error { - ret := _m.Called(id, opState, ctx) - - var r0 error - if rf, ok := ret.Get(0).(func(string, string, context.Context) error); ok { - r0 = rf(id, opState, ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// UpdateOpStateByName provides a mock function with given fields: name, opState, ctx -func (_m *DeviceClient) UpdateOpStateByName(name string, opState string, ctx context.Context) error { - ret := _m.Called(name, opState, ctx) - - var r0 error - if rf, ok := ret.Get(0).(func(string, string, context.Context) error); ok { - r0 = rf(name, opState, ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} diff --git a/clients/metadata/provision_watcher.go b/clients/metadata/provision_watcher.go index 5954716d..dc9c7ffd 100644 --- a/clients/metadata/provision_watcher.go +++ b/clients/metadata/provision_watcher.go @@ -21,33 +21,31 @@ import ( "github.com/edgexfoundry/go-mod-core-contracts/clients" "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" - "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" "github.com/edgexfoundry/go-mod-core-contracts/models" ) // ProvisionWatcherClient defines the interface for interactions with the ProvisionWatcher endpoint on metadata. type ProvisionWatcherClient interface { // Add a new provision watcher - Add(dev *models.ProvisionWatcher, ctx context.Context) (string, error) + Add(ctx context.Context, dev *models.ProvisionWatcher) (string, error) // Delete a provision watcher for the specified ID - Delete(id string, ctx context.Context) error + Delete(ctx context.Context, id string) error // ProvisionWatcher loads an instance of a provision watcher for the specified ID - ProvisionWatcher(id string, ctx context.Context) (models.ProvisionWatcher, error) + ProvisionWatcher(ctx context.Context, id string) (models.ProvisionWatcher, error) // ProvisionWatcherForName loads an instance of a provision watcher for the specified name - ProvisionWatcherForName(name string, ctx context.Context) (models.ProvisionWatcher, error) + ProvisionWatcherForName(ctx context.Context, name string) (models.ProvisionWatcher, error) // ProvisionWatchers lists all provision watchers. ProvisionWatchers(ctx context.Context) ([]models.ProvisionWatcher, error) // ProvisionWatchersForService lists all provision watchers associated with the specified device service id - ProvisionWatchersForService(serviceId string, ctx context.Context) ([]models.ProvisionWatcher, error) + ProvisionWatchersForService(ctx context.Context, serviceId string) ([]models.ProvisionWatcher, error) // ProvisionWatchersForServiceByName lists all provision watchers associated with the specified device service name - ProvisionWatchersForServiceByName(serviceName string, ctx context.Context) ([]models.ProvisionWatcher, error) + ProvisionWatchersForServiceByName(ctx context.Context, serviceName string) ([]models.ProvisionWatcher, error) // ProvisionWatchersForProfile lists all provision watchers associated with the specified device profile ID - ProvisionWatchersForProfile(profileid string, ctx context.Context) ([]models.ProvisionWatcher, error) + ProvisionWatchersForProfile(ctx context.Context, profileID string) ([]models.ProvisionWatcher, error) // ProvisionWatchersForProfileByName lists all provision watchers associated with the specified device profile name - ProvisionWatchersForProfileByName(profileName string, ctx context.Context) ([]models.ProvisionWatcher, error) + ProvisionWatchersForProfileByName(ctx context.Context, profileName string) ([]models.ProvisionWatcher, error) // Update the provision watcher - Update(dev models.ProvisionWatcher, ctx context.Context) error + Update(ctx context.Context, dev models.ProvisionWatcher) error } type provisionWatcherRestClient struct { @@ -55,16 +53,18 @@ type provisionWatcherRestClient struct { } // NewProvisionWatcherClient creates an instance of ProvisionWatcherClient -func NewProvisionWatcherClient(params types.EndpointParams, m interfaces.Endpointer) ProvisionWatcherClient { - return &provisionWatcherRestClient{urlClient: urlclient.New(params, m)} +func NewProvisionWatcherClient(urlClient interfaces.URLClient) ProvisionWatcherClient { + return &provisionWatcherRestClient{ + urlClient: urlClient, + } } // Helper method to request and decode a provision watcher func (pwc *provisionWatcherRestClient) requestProvisionWatcher( - urlSuffix string, - ctx context.Context) (models.ProvisionWatcher, error) { + ctx context.Context, + urlSuffix string) (models.ProvisionWatcher, error) { - data, err := clients.GetRequest(urlSuffix, ctx, pwc.urlClient) + data, err := clients.GetRequest(ctx, urlSuffix, pwc.urlClient) if err != nil { return models.ProvisionWatcher{}, err } @@ -76,10 +76,10 @@ func (pwc *provisionWatcherRestClient) requestProvisionWatcher( // Helper method to request and decode a provision watcher slice func (pwc *provisionWatcherRestClient) requestProvisionWatcherSlice( - urlSuffix string, - ctx context.Context) ([]models.ProvisionWatcher, error) { + ctx context.Context, + urlSuffix string) ([]models.ProvisionWatcher, error) { - data, err := clients.GetRequest(urlSuffix, ctx, pwc.urlClient) + data, err := clients.GetRequest(ctx, urlSuffix, pwc.urlClient) if err != nil { return []models.ProvisionWatcher{}, err } @@ -89,42 +89,42 @@ func (pwc *provisionWatcherRestClient) requestProvisionWatcherSlice( return pwSlice, err } -func (pwc *provisionWatcherRestClient) ProvisionWatcher(id string, ctx context.Context) (models.ProvisionWatcher, error) { - return pwc.requestProvisionWatcher("/"+id, ctx) +func (pwc *provisionWatcherRestClient) ProvisionWatcher(ctx context.Context, id string) (models.ProvisionWatcher, error) { + return pwc.requestProvisionWatcher(ctx, "/"+id) } func (pwc *provisionWatcherRestClient) ProvisionWatchers(ctx context.Context) ([]models.ProvisionWatcher, error) { - return pwc.requestProvisionWatcherSlice("", ctx) + return pwc.requestProvisionWatcherSlice(ctx, "") } -func (pwc *provisionWatcherRestClient) ProvisionWatcherForName(name string, ctx context.Context) (models.ProvisionWatcher, error) { - return pwc.requestProvisionWatcher("/name/"+url.QueryEscape(name), ctx) +func (pwc *provisionWatcherRestClient) ProvisionWatcherForName(ctx context.Context, name string) (models.ProvisionWatcher, error) { + return pwc.requestProvisionWatcher(ctx, "/name/"+url.QueryEscape(name)) } -func (pwc *provisionWatcherRestClient) ProvisionWatchersForService(serviceId string, ctx context.Context) ([]models.ProvisionWatcher, error) { - return pwc.requestProvisionWatcherSlice("/service/"+serviceId, ctx) +func (pwc *provisionWatcherRestClient) ProvisionWatchersForService(ctx context.Context, serviceId string) ([]models.ProvisionWatcher, error) { + return pwc.requestProvisionWatcherSlice(ctx, "/service/"+serviceId) } -func (pwc *provisionWatcherRestClient) ProvisionWatchersForServiceByName(serviceName string, ctx context.Context) ([]models.ProvisionWatcher, error) { - return pwc.requestProvisionWatcherSlice("/servicename/"+url.QueryEscape(serviceName), ctx) +func (pwc *provisionWatcherRestClient) ProvisionWatchersForServiceByName(ctx context.Context, serviceName string) ([]models.ProvisionWatcher, error) { + return pwc.requestProvisionWatcherSlice(ctx, "/servicename/"+url.QueryEscape(serviceName)) } -func (pwc *provisionWatcherRestClient) ProvisionWatchersForProfile(profileId string, ctx context.Context) ([]models.ProvisionWatcher, error) { - return pwc.requestProvisionWatcherSlice("/profile/"+profileId, ctx) +func (pwc *provisionWatcherRestClient) ProvisionWatchersForProfile(ctx context.Context, profileID string) ([]models.ProvisionWatcher, error) { + return pwc.requestProvisionWatcherSlice(ctx, "/profile/"+profileID) } -func (pwc *provisionWatcherRestClient) ProvisionWatchersForProfileByName(profileName string, ctx context.Context) ([]models.ProvisionWatcher, error) { - return pwc.requestProvisionWatcherSlice("/profilename/"+url.QueryEscape(profileName), ctx) +func (pwc *provisionWatcherRestClient) ProvisionWatchersForProfileByName(ctx context.Context, profileName string) ([]models.ProvisionWatcher, error) { + return pwc.requestProvisionWatcherSlice(ctx, "/profilename/"+url.QueryEscape(profileName)) } -func (pwc *provisionWatcherRestClient) Add(dev *models.ProvisionWatcher, ctx context.Context) (string, error) { - return clients.PostJsonRequest("", dev, ctx, pwc.urlClient) +func (pwc *provisionWatcherRestClient) Add(ctx context.Context, dev *models.ProvisionWatcher) (string, error) { + return clients.PostJSONRequest(ctx, "", dev, pwc.urlClient) } -func (pwc *provisionWatcherRestClient) Update(dev models.ProvisionWatcher, ctx context.Context) error { - return clients.UpdateRequest("", dev, ctx, pwc.urlClient) +func (pwc *provisionWatcherRestClient) Update(ctx context.Context, dev models.ProvisionWatcher) error { + return clients.UpdateRequest(ctx, "", dev, pwc.urlClient) } -func (pwc *provisionWatcherRestClient) Delete(id string, ctx context.Context) error { - return clients.DeleteRequest("/id/"+id, ctx, pwc.urlClient) +func (pwc *provisionWatcherRestClient) Delete(ctx context.Context, id string) error { + return clients.DeleteRequest(ctx, "/id/"+id, pwc.urlClient) } diff --git a/clients/metadata/provision_watcher_test.go b/clients/metadata/provision_watcher_test.go index abef0bdf..d96afd15 100644 --- a/clients/metadata/provision_watcher_test.go +++ b/clients/metadata/provision_watcher_test.go @@ -22,7 +22,8 @@ import ( "testing" "github.com/edgexfoundry/go-mod-core-contracts/clients" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" + "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" + "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" "github.com/edgexfoundry/go-mod-core-contracts/models" ) @@ -49,23 +50,15 @@ func TestAddProvisionWatcher(t *testing.T) { t.Errorf("expected uri path is %s, actual uri path is %s", clients.ApiProvisionWatcherRoute, r.URL.EscapedPath()) } - w.Write([]byte(addingProvisionWatcherID)) + _, _ = w.Write([]byte(addingProvisionWatcherID)) })) defer ts.Close() - url := ts.URL + clients.ApiProvisionWatcherRoute + sc := NewProvisionWatcherClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiProvisionWatcherRoute))) - params := types.EndpointParams{ - ServiceKey: clients.CoreMetaDataServiceKey, - Path: clients.ApiProvisionWatcherRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault} - sc := NewProvisionWatcherClient(params, mockCoreMetaDataEndpoint{}) - - receivedProvisionWatcherID, err := sc.Add(&se, context.Background()) + receivedProvisionWatcherID, err := sc.Add(context.Background(), &se) if err != nil { t.Error(err.Error()) } @@ -77,14 +70,8 @@ func TestAddProvisionWatcher(t *testing.T) { func TestNewProvisionWatcherClientWithConsul(t *testing.T) { provisionWatcherURL := "http://localhost:48081" + clients.ApiProvisionWatcherRoute - params := types.EndpointParams{ - ServiceKey: clients.CoreMetaDataServiceKey, - Path: clients.ApiProvisionWatcherRoute, - UseRegistry: true, - Url: provisionWatcherURL, - Interval: clients.ClientMonitorDefault} - - sc := NewProvisionWatcherClient(params, mockCoreMetaDataEndpoint{}) + + sc := NewProvisionWatcherClient(urlclient.NewLocalClient(interfaces.URLStream(provisionWatcherURL))) r, ok := sc.(*provisionWatcherRestClient) if !ok { diff --git a/clients/notifications/client.go b/clients/notifications/client.go index cce7a63b..2f3e2175 100644 --- a/clients/notifications/client.go +++ b/clients/notifications/client.go @@ -20,8 +20,6 @@ import ( "github.com/edgexfoundry/go-mod-core-contracts/clients" "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" - "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" ) type CategoryEnum string @@ -50,7 +48,7 @@ const ( // NotificationsClient defines the interface for interactions with the EdgeX Foundry support-notifications service. type NotificationsClient interface { // SendNotification sends a notification. - SendNotification(n Notification, ctx context.Context) error + SendNotification(ctx context.Context, n Notification) error } // Type struct for REST-specific implementation of the NotificationsClient interface @@ -74,11 +72,13 @@ type Notification struct { } // NewNotificationsClient creates an instance of NotificationsClient -func NewNotificationsClient(params types.EndpointParams, m interfaces.Endpointer) NotificationsClient { - return ¬ificationsRestClient{urlClient: urlclient.New(params, m)} +func NewNotificationsClient(urlClient interfaces.URLClient) NotificationsClient { + return ¬ificationsRestClient{ + urlClient: urlClient, + } } -func (nc *notificationsRestClient) SendNotification(n Notification, ctx context.Context) error { - _, err := clients.PostJsonRequest("", n, ctx, nc.urlClient) +func (nc *notificationsRestClient) SendNotification(ctx context.Context, n Notification) error { + _, err := clients.PostJSONRequest(ctx, "", n, nc.urlClient) return err } diff --git a/clients/notifications/client_test.go b/clients/notifications/client_test.go index 0438fb49..ee4ec244 100644 --- a/clients/notifications/client_test.go +++ b/clients/notifications/client_test.go @@ -15,7 +15,8 @@ import ( "testing" "github.com/edgexfoundry/go-mod-core-contracts/clients" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" + "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" + "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" ) // Test common const @@ -39,7 +40,7 @@ const ( func TestReceiveNotification(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) - w.Write([]byte("{ 'status' : 'OK' }")) + _, _ = w.Write([]byte("{ 'status' : 'OK' }")) if r.Method != http.MethodPost { t.Errorf(TestUnexpectedMsgFormatStr, r.Method, http.MethodPost) } @@ -48,10 +49,10 @@ func TestReceiveNotification(t *testing.T) { } result, _ := ioutil.ReadAll(r.Body) - r.Body.Close() + _ = r.Body.Close() var receivedNotification Notification - json.Unmarshal([]byte(result), &receivedNotification) + _ = json.Unmarshal([]byte(result), &receivedNotification) if receivedNotification.Sender != TestNotificationSender { t.Errorf(TestUnexpectedMsgFormatStr, receivedNotification.Sender, TestNotificationSender) @@ -93,17 +94,7 @@ func TestReceiveNotification(t *testing.T) { defer ts.Close() - url := ts.URL + clients.ApiNotificationRoute - - params := types.EndpointParams{ - ServiceKey: clients.CoreMetaDataServiceKey, - Path: clients.ApiNotificationRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault, - } - - nc := NewNotificationsClient(params, mockNotificationEndpoint{}) + nc := NewNotificationsClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiNotificationRoute))) notification := Notification{ Sender: TestNotificationSender, @@ -115,11 +106,5 @@ func TestReceiveNotification(t *testing.T) { Labels: []string{TestNotificationLabel1, TestNotificationLabel2}, } - nc.SendNotification(notification, context.Background()) -} - -type mockNotificationEndpoint struct{} - -func (e mockNotificationEndpoint) Monitor(params types.EndpointParams) chan string { - return make(chan string, 1) + _ = nc.SendNotification(context.Background(), notification) } diff --git a/clients/request.go b/clients/request.go index 87755146..6db931d9 100644 --- a/clients/request.go +++ b/clients/request.go @@ -47,24 +47,24 @@ func makeRequest(req *http.Request) (*http.Response, error) { // GetRequest will make a GET request to the specified URL with the root URL retrieved by the URLClient prepended. // It returns the body as a byte array if successful and an error otherwise. -func GetRequest(urlSuffix string, ctx context.Context, urlClient interfaces.URLClient) ([]byte, error) { +func GetRequest(ctx context.Context, urlSuffix string, urlClient interfaces.URLClient) ([]byte, error) { urlPrefix, err := urlClient.Prefix() if err != nil { return nil, err } - return GetRequestWithURL(urlPrefix+urlSuffix, ctx) + return GetRequestWithURL(ctx, urlPrefix+urlSuffix) } // GetRequestWithURL will make a GET request to the specified URL. // It returns the body as a byte array if successful and an error otherwise. -func GetRequestWithURL(url string, ctx context.Context) ([]byte, error) { +func GetRequestWithURL(ctx context.Context, url string) ([]byte, error) { req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { return nil, err } - c := NewCorrelatedRequest(req, ctx) + c := NewCorrelatedRequest(ctx, req) resp, err := makeRequest(c.Request) if err != nil { return nil, err @@ -87,9 +87,9 @@ func GetRequestWithURL(url string, ctx context.Context) ([]byte, error) { } // Helper method to make the count request -func CountRequest(urlSuffix string, ctx context.Context, urlClient interfaces.URLClient) (int, error) { +func CountRequest(ctx context.Context, urlSuffix string, urlClient interfaces.URLClient) (int, error) { // do not get URLPrefix here since GetRequest does it - data, err := GetRequest(urlSuffix, ctx, urlClient) + data, err := GetRequest(ctx, urlSuffix, urlClient) if err != nil { return 0, err } @@ -102,10 +102,10 @@ func CountRequest(urlSuffix string, ctx context.Context, urlClient interfaces.UR } // Helper method to make the post JSON request and return the body -func PostJsonRequest( +func PostJSONRequest( + ctx context.Context, urlSuffix string, data interface{}, - ctx context.Context, urlClient interfaces.URLClient) (string, error) { jsonStr, err := json.Marshal(data) @@ -116,13 +116,13 @@ func PostJsonRequest( ctx = context.WithValue(ctx, ContentType, ContentTypeJSON) // do not get URLPrefix here since PostRequest does it - return PostRequest(urlSuffix, jsonStr, ctx, urlClient) + return PostRequest(ctx, urlSuffix, jsonStr, urlClient) } -// PostJsonRequestWithURL will make a POST request to the specified URL with the object passed in +// PostJSONRequestWithURL will make a POST request to the specified URL with the object passed in // marshaled into a JSON formatted byte array. // It returns the body on success and an error otherwise. -func PostJsonRequestWithURL(url string, data interface{}, ctx context.Context) (string, error) { +func PostJSONRequestWithURL(ctx context.Context, url string, data interface{}) (string, error) { jsonStr, err := json.Marshal(data) if err != nil { return "", err @@ -130,23 +130,23 @@ func PostJsonRequestWithURL(url string, data interface{}, ctx context.Context) ( ctx = context.WithValue(ctx, ContentType, ContentTypeJSON) - return PostRequestWithURL(url, jsonStr, ctx) + return PostRequestWithURL(ctx, url, jsonStr) } // Helper method to make the post request and return the body -func PostRequest(urlSuffix string, data []byte, ctx context.Context, urlClient interfaces.URLClient) (string, error) { +func PostRequest(ctx context.Context, urlSuffix string, data []byte, urlClient interfaces.URLClient) (string, error) { urlPrefix, err := urlClient.Prefix() if err != nil { return "", err } - return PostRequestWithURL(urlPrefix+urlSuffix, data, ctx) + return PostRequestWithURL(ctx, urlPrefix+urlSuffix, data) } // PostRequestWithURL will make a POST request to the specified URL. // It returns the body as a byte array if successful and an error otherwise. -func PostRequestWithURL(url string, data []byte, ctx context.Context) (string, error) { - content := FromContext(ContentType, ctx) +func PostRequestWithURL(ctx context.Context, url string, data []byte) (string, error) { + content := FromContext(ctx, ContentType) if content == "" { content = ContentTypeJSON } @@ -157,7 +157,7 @@ func PostRequestWithURL(url string, data []byte, ctx context.Context) (string, e } req.Header.Set(ContentType, content) - c := NewCorrelatedRequest(req, ctx) + c := NewCorrelatedRequest(ctx, req) resp, err := makeRequest(c.Request) if err != nil { return "", err @@ -182,9 +182,10 @@ func PostRequestWithURL(url string, data []byte, ctx context.Context) (string, e // Helper method to make a post request in order to upload a file and return the request body func UploadFileRequest( + ctx context.Context, urlSuffix string, filePath string, - ctx context.Context, urlClient interfaces.URLClient) (string, error) { + urlClient interfaces.URLClient) (string, error) { fileContents, err := ioutil.ReadFile(filePath) if err != nil { @@ -215,7 +216,7 @@ func UploadFileRequest( } req.Header.Add(ContentType, writer.FormDataContentType()) - c := NewCorrelatedRequest(req, ctx) + c := NewCorrelatedRequest(ctx, req) resp, err := makeRequest(c.Request) if err != nil { return "", err @@ -239,19 +240,19 @@ func UploadFileRequest( } // Helper method to make the update request -func UpdateRequest(urlSuffix string, data interface{}, ctx context.Context, urlClient interfaces.URLClient) error { +func UpdateRequest(ctx context.Context, urlSuffix string, data interface{}, urlClient interfaces.URLClient) error { jsonStr, err := json.Marshal(data) if err != nil { return err } // do not get URLPrefix here since PutRequest does it - _, err = PutRequest(urlSuffix, jsonStr, ctx, urlClient) + _, err = PutRequest(ctx, urlSuffix, jsonStr, urlClient) return err } // Helper method to make the put request -func PutRequest(urlSuffix string, body []byte, ctx context.Context, urlClient interfaces.URLClient) (string, error) { +func PutRequest(ctx context.Context, urlSuffix string, body []byte, urlClient interfaces.URLClient) (string, error) { var err error var req *http.Request @@ -261,8 +262,11 @@ func PutRequest(urlSuffix string, body []byte, ctx context.Context, urlClient in } if body != nil { req, err = http.NewRequest(http.MethodPut, urlPrefix+urlSuffix, bytes.NewReader(body)) + if err != nil { + return "", err + } - content := FromContext(ContentType, ctx) + content := FromContext(ctx, ContentType) if content == "" { content = ContentTypeJSON } @@ -274,7 +278,7 @@ func PutRequest(urlSuffix string, body []byte, ctx context.Context, urlClient in return "", err } - c := NewCorrelatedRequest(req, ctx) + c := NewCorrelatedRequest(ctx, req) resp, err := makeRequest(c.Request) if err != nil { return "", err @@ -298,7 +302,7 @@ func PutRequest(urlSuffix string, body []byte, ctx context.Context, urlClient in } // Helper method to make the delete request -func DeleteRequest(urlSuffix string, ctx context.Context, urlClient interfaces.URLClient) error { +func DeleteRequest(ctx context.Context, urlSuffix string, urlClient interfaces.URLClient) error { urlPrefix, err := urlClient.Prefix() if err != nil { return err @@ -309,7 +313,7 @@ func DeleteRequest(urlSuffix string, ctx context.Context, urlClient interfaces.U return err } - c := NewCorrelatedRequest(req, ctx) + c := NewCorrelatedRequest(ctx, req) resp, err := makeRequest(c.Request) if err != nil { return err @@ -338,9 +342,9 @@ type CorrelatedRequest struct { // NewCorrelatedRequest will add the Correlation ID header to the supplied request. If no Correlation ID header is // present in the supplied context, one will be created along with a value. -func NewCorrelatedRequest(req *http.Request, ctx context.Context) CorrelatedRequest { +func NewCorrelatedRequest(ctx context.Context, req *http.Request) CorrelatedRequest { c := CorrelatedRequest{Request: req} - correlation := FromContext(CorrelationHeader, ctx) + correlation := FromContext(ctx, CorrelationHeader) if len(correlation) == 0 { correlation = uuid.New().String() } diff --git a/clients/scheduler/interval.go b/clients/scheduler/interval.go index 3ec2d9f4..126b1bb9 100644 --- a/clients/scheduler/interval.go +++ b/clients/scheduler/interval.go @@ -22,27 +22,25 @@ import ( "github.com/edgexfoundry/go-mod-core-contracts/clients" "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" - "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" "github.com/edgexfoundry/go-mod-core-contracts/models" ) // IntervalClient defines the interface for interactions with the Interval endpoint on support-scheduler. type IntervalClient interface { // Add a new scheduling interval - Add(dev *models.Interval, ctx context.Context) (string, error) + Add(ctx context.Context, interval *models.Interval) (string, error) // Delete eliminates a scheduling interval for the specified ID - Delete(id string, ctx context.Context) error + Delete(ctx context.Context, id string) error // Delete eliminates a scheduling interval for the specified name - DeleteByName(name string, ctx context.Context) error + DeleteByName(ctx context.Context, name string) error // Interval loads the scheduling interval for the specified ID - Interval(id string, ctx context.Context) (models.Interval, error) + Interval(ctx context.Context, id string) (models.Interval, error) // IntervalForName loads the scheduling interval for the specified name - IntervalForName(name string, ctx context.Context) (models.Interval, error) + IntervalForName(ctx context.Context, name string) (models.Interval, error) // Intervals lists all scheduling intervals Intervals(ctx context.Context) ([]models.Interval, error) // Update a scheduling interval - Update(interval models.Interval, ctx context.Context) error + Update(ctx context.Context, interval models.Interval) error } type intervalRestClient struct { @@ -50,41 +48,43 @@ type intervalRestClient struct { } // NewIntervalClient creates an instance of IntervalClient -func NewIntervalClient(params types.EndpointParams, m interfaces.Endpointer) IntervalClient { - return &intervalRestClient{urlClient: urlclient.New(params, m)} +func NewIntervalClient(urlClient interfaces.URLClient) IntervalClient { + return &intervalRestClient{ + urlClient: urlClient, + } } -func (ic *intervalRestClient) Add(interval *models.Interval, ctx context.Context) (string, error) { - return clients.PostJsonRequest("", interval, ctx, ic.urlClient) +func (ic *intervalRestClient) Add(ctx context.Context, interval *models.Interval) (string, error) { + return clients.PostJSONRequest(ctx, "", interval, ic.urlClient) } -func (ic *intervalRestClient) Delete(id string, ctx context.Context) error { - return clients.DeleteRequest("/id/"+id, ctx, ic.urlClient) +func (ic *intervalRestClient) Delete(ctx context.Context, id string) error { + return clients.DeleteRequest(ctx, "/id/"+id, ic.urlClient) } -func (ic *intervalRestClient) DeleteByName(name string, ctx context.Context) error { - return clients.DeleteRequest("/name/"+url.QueryEscape(name), ctx, ic.urlClient) +func (ic *intervalRestClient) DeleteByName(ctx context.Context, name string) error { + return clients.DeleteRequest(ctx, "/name/"+url.QueryEscape(name), ic.urlClient) } -func (ic *intervalRestClient) Interval(id string, ctx context.Context) (models.Interval, error) { - return ic.requestInterval("/"+id, ctx) +func (ic *intervalRestClient) Interval(ctx context.Context, id string) (models.Interval, error) { + return ic.requestInterval(ctx, "/"+id) } -func (ic *intervalRestClient) IntervalForName(name string, ctx context.Context) (models.Interval, error) { - return ic.requestInterval("/name/"+url.QueryEscape(name), ctx) +func (ic *intervalRestClient) IntervalForName(ctx context.Context, name string) (models.Interval, error) { + return ic.requestInterval(ctx, "/name/"+url.QueryEscape(name)) } func (ic *intervalRestClient) Intervals(ctx context.Context) ([]models.Interval, error) { - return ic.requestIntervalSlice("", ctx) + return ic.requestIntervalSlice(ctx, "") } -func (ic *intervalRestClient) Update(interval models.Interval, ctx context.Context) error { - return clients.UpdateRequest("", interval, ctx, ic.urlClient) +func (ic *intervalRestClient) Update(ctx context.Context, interval models.Interval) error { + return clients.UpdateRequest(ctx, "", interval, ic.urlClient) } // helper request and decode an interval -func (ic *intervalRestClient) requestInterval(urlSuffix string, ctx context.Context) (models.Interval, error) { - data, err := clients.GetRequest(urlSuffix, ctx, ic.urlClient) +func (ic *intervalRestClient) requestInterval(ctx context.Context, urlSuffix string) (models.Interval, error) { + data, err := clients.GetRequest(ctx, urlSuffix, ic.urlClient) if err != nil { return models.Interval{}, err } @@ -99,8 +99,8 @@ func (ic *intervalRestClient) requestInterval(urlSuffix string, ctx context.Cont } // helper returns a slice of intervals -func (ic *intervalRestClient) requestIntervalSlice(urlSuffix string, ctx context.Context) ([]models.Interval, error) { - data, err := clients.GetRequest(urlSuffix, ctx, ic.urlClient) +func (ic *intervalRestClient) requestIntervalSlice(ctx context.Context, urlSuffix string) ([]models.Interval, error) { + data, err := clients.GetRequest(ctx, urlSuffix, ic.urlClient) if err != nil { return []models.Interval{}, err } diff --git a/clients/scheduler/interval_action.go b/clients/scheduler/interval_action.go index b920fe42..3becafab 100644 --- a/clients/scheduler/interval_action.go +++ b/clients/scheduler/interval_action.go @@ -21,29 +21,27 @@ import ( "github.com/edgexfoundry/go-mod-core-contracts/clients" "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" - "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" "github.com/edgexfoundry/go-mod-core-contracts/models" ) // IntervalActionClient defines the interface for interactions with the IntervalAction endpoint on support-scheduler. type IntervalActionClient interface { // Add a new schedule interval action - Add(dev *models.IntervalAction, ctx context.Context) (string, error) + Add(ctx context.Context, ia *models.IntervalAction) (string, error) // Delete a schedule interval action for the specified ID - Delete(id string, ctx context.Context) error + Delete(ctx context.Context, id string) error // Delete a schedule interval action for the specified name - DeleteByName(name string, ctx context.Context) error + DeleteByName(ctx context.Context, name string) error // IntervalAction loads a schedule interval action for the specified ID - IntervalAction(id string, ctx context.Context) (models.IntervalAction, error) + IntervalAction(ctx context.Context, id string) (models.IntervalAction, error) // IntervalActionForName loads a schedule interval action for the specified name - IntervalActionForName(name string, ctx context.Context) (models.IntervalAction, error) + IntervalActionForName(ctx context.Context, name string) (models.IntervalAction, error) // IntervalActions lists all schedule interval actions IntervalActions(ctx context.Context) ([]models.IntervalAction, error) // IntervalActionsForTargetByName lists all schedule interval actions that target a particular service - IntervalActionsForTargetByName(name string, ctx context.Context) ([]models.IntervalAction, error) + IntervalActionsForTargetByName(ctx context.Context, name string) ([]models.IntervalAction, error) // Update a schedule interval action - Update(dev models.IntervalAction, ctx context.Context) error + Update(ctx context.Context, ia models.IntervalAction) error } type intervalActionRestClient struct { @@ -51,16 +49,18 @@ type intervalActionRestClient struct { } // NewIntervalActionClient creates an instance of IntervalActionClient -func NewIntervalActionClient(params types.EndpointParams, m interfaces.Endpointer) IntervalActionClient { - return &intervalActionRestClient{urlClient: urlclient.New(params, m)} +func NewIntervalActionClient(urlClient interfaces.URLClient) IntervalActionClient { + return &intervalActionRestClient{ + urlClient: urlClient, + } } // Helper method to request and decode an interval action func (iac *intervalActionRestClient) requestIntervalAction( - urlSuffix string, - ctx context.Context) (models.IntervalAction, error) { + ctx context.Context, + urlSuffix string) (models.IntervalAction, error) { - data, err := clients.GetRequest(urlSuffix, ctx, iac.urlClient) + data, err := clients.GetRequest(ctx, urlSuffix, iac.urlClient) if err != nil { return models.IntervalAction{}, err } @@ -76,10 +76,10 @@ func (iac *intervalActionRestClient) requestIntervalAction( // Helper method to request and decode an interval action slice func (iac *intervalActionRestClient) requestIntervalActionSlice( - urlSuffix string, - ctx context.Context) ([]models.IntervalAction, error) { + ctx context.Context, + urlSuffix string) ([]models.IntervalAction, error) { - data, err := clients.GetRequest(urlSuffix, ctx, iac.urlClient) + data, err := clients.GetRequest(ctx, urlSuffix, iac.urlClient) if err != nil { return []models.IntervalAction{}, err } @@ -93,34 +93,34 @@ func (iac *intervalActionRestClient) requestIntervalActionSlice( return iaSlice, nil } -func (iac *intervalActionRestClient) Add(ia *models.IntervalAction, ctx context.Context) (string, error) { - return clients.PostJsonRequest("", ia, ctx, iac.urlClient) +func (iac *intervalActionRestClient) Add(ctx context.Context, ia *models.IntervalAction) (string, error) { + return clients.PostJSONRequest(ctx, "", ia, iac.urlClient) } -func (iac *intervalActionRestClient) Delete(id string, ctx context.Context) error { - return clients.DeleteRequest("/id/"+id, ctx, iac.urlClient) +func (iac *intervalActionRestClient) Delete(ctx context.Context, id string) error { + return clients.DeleteRequest(ctx, "/id/"+id, iac.urlClient) } -func (iac *intervalActionRestClient) DeleteByName(name string, ctx context.Context) error { - return clients.DeleteRequest("/name/"+url.QueryEscape(name), ctx, iac.urlClient) +func (iac *intervalActionRestClient) DeleteByName(ctx context.Context, name string) error { + return clients.DeleteRequest(ctx, "/name/"+url.QueryEscape(name), iac.urlClient) } -func (iac *intervalActionRestClient) IntervalAction(id string, ctx context.Context) (models.IntervalAction, error) { - return iac.requestIntervalAction("/"+id, ctx) +func (iac *intervalActionRestClient) IntervalAction(ctx context.Context, id string) (models.IntervalAction, error) { + return iac.requestIntervalAction(ctx, "/"+id) } -func (iac *intervalActionRestClient) IntervalActionForName(name string, ctx context.Context) (models.IntervalAction, error) { - return iac.requestIntervalAction("/name/"+url.QueryEscape(name), ctx) +func (iac *intervalActionRestClient) IntervalActionForName(ctx context.Context, name string) (models.IntervalAction, error) { + return iac.requestIntervalAction(ctx, "/name/"+url.QueryEscape(name)) } func (iac *intervalActionRestClient) IntervalActions(ctx context.Context) ([]models.IntervalAction, error) { - return iac.requestIntervalActionSlice("", ctx) + return iac.requestIntervalActionSlice(ctx, "") } -func (iac *intervalActionRestClient) IntervalActionsForTargetByName(name string, ctx context.Context) ([]models.IntervalAction, error) { - return iac.requestIntervalActionSlice("/target/"+url.QueryEscape(name), ctx) +func (iac *intervalActionRestClient) IntervalActionsForTargetByName(ctx context.Context, name string) ([]models.IntervalAction, error) { + return iac.requestIntervalActionSlice(ctx, "/target/"+url.QueryEscape(name)) } -func (iac *intervalActionRestClient) Update(ia models.IntervalAction, ctx context.Context) error { - return clients.UpdateRequest("", ia, ctx, iac.urlClient) +func (iac *intervalActionRestClient) Update(ctx context.Context, ia models.IntervalAction) error { + return clients.UpdateRequest(ctx, "", ia, iac.urlClient) } diff --git a/clients/scheduler/interval_action_test.go b/clients/scheduler/interval_action_test.go index 626d3b6f..699e1d3f 100644 --- a/clients/scheduler/interval_action_test.go +++ b/clients/scheduler/interval_action_test.go @@ -23,7 +23,9 @@ import ( "testing" "github.com/edgexfoundry/go-mod-core-contracts/clients" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" + "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" + "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" + "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient/retry/periodic" "github.com/edgexfoundry/go-mod-core-contracts/models" ) @@ -68,23 +70,13 @@ var testIntervalAction2 = models.IntervalAction{ } func TestIntervalActionRestClient_Add(t *testing.T) { - ts := testHttpServer(t, http.MethodPost, clients.ApiIntervalActionRoute) + ts := testHTTPServer(t, http.MethodPost, clients.ApiIntervalActionRoute) defer ts.Close() - url := ts.URL + clients.ApiIntervalActionRoute + iac := NewIntervalActionClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiIntervalActionRoute))) - params := types.EndpointParams{ - ServiceKey: clients.SupportSchedulerServiceKey, - Path: clients.ApiIntervalActionRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault, - } - - iac := NewIntervalActionClient(params, MockEndpoint{}) - - res, err := iac.Add(&testIntervalAction1, context.Background()) + res, err := iac.Add(context.Background(), &testIntervalAction1) if res == "" { t.Fatal("unexpected empty string response") @@ -96,23 +88,13 @@ func TestIntervalActionRestClient_Add(t *testing.T) { } func TestIntervalActionRestClient_Delete(t *testing.T) { - ts := testHttpServer(t, http.MethodDelete, clients.ApiIntervalActionRoute) + ts := testHTTPServer(t, http.MethodDelete, clients.ApiIntervalActionRoute) defer ts.Close() - url := ts.URL + clients.ApiIntervalActionRoute - - params := types.EndpointParams{ - ServiceKey: clients.SupportSchedulerServiceKey, - Path: clients.ApiIntervalActionRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault, - } + ic := NewIntervalActionClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiIntervalActionRoute))) - ic := NewIntervalActionClient(params, MockEndpoint{}) - - err := ic.Delete(testID1, context.Background()) + err := ic.Delete(context.Background(), testID1) if err != nil { t.Fatalf("unexpected error %s", err.Error()) @@ -120,23 +102,13 @@ func TestIntervalActionRestClient_Delete(t *testing.T) { } func TestIntervalActionRestClient_DeleteByName(t *testing.T) { - ts := testHttpServer(t, http.MethodDelete, clients.ApiIntervalActionRoute) + ts := testHTTPServer(t, http.MethodDelete, clients.ApiIntervalActionRoute) defer ts.Close() - url := ts.URL + clients.ApiIntervalActionRoute - - params := types.EndpointParams{ - ServiceKey: clients.SupportSchedulerServiceKey, - Path: clients.ApiIntervalActionRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault, - } - - ic := NewIntervalActionClient(params, MockEndpoint{}) + ic := NewIntervalActionClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiIntervalActionRoute))) - err := ic.DeleteByName(testIntervalAction1.Name, context.Background()) + err := ic.DeleteByName(context.Background(), testIntervalAction1.Name) if err != nil { t.Fatalf("unexpected error %s", err.Error()) @@ -189,36 +161,29 @@ func TestIntervalActionRestClient_IntervalAction(t *testing.T) { }{ {"happy path", testIntervalAction1.ID, - NewIntervalActionClient(types.EndpointParams{ - ServiceKey: clients.SupportSchedulerServiceKey, - Path: clients.ApiIntervalActionRoute, - UseRegistry: false, - Url: ts.URL + clients.ApiIntervalActionRoute, - Interval: clients.ClientMonitorDefault, - }, MockEndpoint{}), + NewIntervalActionClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiIntervalActionRoute))), false, }, { - "nil client", + "client error", testIntervalAction1.ID, - NewIntervalActionClient(types.EndpointParams{}, nil), + NewIntervalActionClient( + urlclient.NewRegistryClient(make(chan interfaces.URLStream), + periodic.New(1, 0)), + ), true, }, {"bad JSON marshal", testIntervalAction1.ID, - NewIntervalActionClient(types.EndpointParams{ - ServiceKey: clients.SupportSchedulerServiceKey, - Path: clients.ApiIntervalActionRoute, - UseRegistry: false, - Url: badJSONServer.URL + clients.ApiIntervalActionRoute, - Interval: clients.ClientMonitorDefault, - }, MockEndpoint{}), + NewIntervalActionClient(urlclient.NewLocalClient(interfaces.URLStream( + badJSONServer.URL + clients.ApiIntervalActionRoute, + ))), true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - res, err := tt.ic.IntervalAction(tt.IntervalActionID, context.Background()) + res, err := tt.ic.IntervalAction(context.Background(), tt.IntervalActionID) emptyIntervalAction := models.IntervalAction{} @@ -259,19 +224,9 @@ func TestIntervalActionRestClient_IntervalActionForName(t *testing.T) { defer ts.Close() - url := ts.URL + clients.ApiIntervalActionRoute + ic := NewIntervalActionClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiIntervalActionRoute))) - params := types.EndpointParams{ - ServiceKey: clients.SupportSchedulerServiceKey, - Path: clients.ApiIntervalActionRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault, - } - - ic := NewIntervalActionClient(params, MockEndpoint{}) - - _, err := ic.IntervalActionForName(testIntervalAction1.Name, context.Background()) + _, err := ic.IntervalActionForName(context.Background(), testIntervalAction1.Name) if err != nil { t.Fatalf("unexpected error %s", err.Error()) @@ -324,28 +279,19 @@ func TestIntervalActionRestClient_IntervalActions(t *testing.T) { expectedError bool }{ {"happy path", - NewIntervalActionClient(types.EndpointParams{ - ServiceKey: clients.SupportSchedulerServiceKey, - Path: clients.ApiIntervalActionRoute, - UseRegistry: false, - Url: ts.URL + clients.ApiIntervalActionRoute, - Interval: clients.ClientMonitorDefault, - }, MockEndpoint{}), + NewIntervalActionClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiIntervalActionRoute))), false, }, { - "nil client", - NewIntervalActionClient(types.EndpointParams{}, nil), + "client error", + NewIntervalActionClient(urlclient.NewRegistryClient(make(chan interfaces.URLStream), + periodic.New(1, 0)), + ), true, }, {"bad JSON marshal", - NewIntervalActionClient(types.EndpointParams{ - ServiceKey: clients.SupportSchedulerServiceKey, - Path: clients.ApiIntervalActionRoute, - UseRegistry: false, - Url: badJSONServer.URL + clients.ApiIntervalActionRoute, - Interval: clients.ClientMonitorDefault, - }, MockEndpoint{}), + NewIntervalActionClient(urlclient.NewLocalClient( + interfaces.URLStream(badJSONServer.URL + clients.ApiIntervalActionRoute))), true, }, } @@ -394,19 +340,9 @@ func TestIntervalActionRestClient_IntervalActionsForTargetByName(t *testing.T) { defer ts.Close() - url := ts.URL + clients.ApiIntervalActionRoute - - params := types.EndpointParams{ - ServiceKey: clients.SupportSchedulerServiceKey, - Path: clients.ApiIntervalActionRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault, - } + ic := NewIntervalActionClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiIntervalActionRoute))) - ic := NewIntervalActionClient(params, MockEndpoint{}) - - _, err := ic.IntervalActionsForTargetByName(testIntervalAction1.Target, context.Background()) + _, err := ic.IntervalActionsForTargetByName(context.Background(), testIntervalAction1.Target) if err != nil { t.Fatalf("unexpected error %s", err.Error()) @@ -414,23 +350,13 @@ func TestIntervalActionRestClient_IntervalActionsForTargetByName(t *testing.T) { } func TestIntervalActionRestClient_Update(t *testing.T) { - ts := testHttpServer(t, http.MethodPut, clients.ApiIntervalActionRoute) + ts := testHTTPServer(t, http.MethodPut, clients.ApiIntervalActionRoute) defer ts.Close() - url := ts.URL + clients.ApiIntervalActionRoute - - params := types.EndpointParams{ - ServiceKey: clients.SupportSchedulerServiceKey, - Path: clients.ApiIntervalActionRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault, - } - - ic := NewIntervalActionClient(params, MockEndpoint{}) + ic := NewIntervalActionClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiIntervalActionRoute))) - err := ic.Update(testIntervalAction1, context.Background()) + err := ic.Update(context.Background(), testIntervalAction1) if err != nil { t.Fatalf("unexpected error %s", err.Error()) diff --git a/clients/scheduler/interval_test.go b/clients/scheduler/interval_test.go index 4fa20682..6f45cd6a 100644 --- a/clients/scheduler/interval_test.go +++ b/clients/scheduler/interval_test.go @@ -23,7 +23,9 @@ import ( "testing" "github.com/edgexfoundry/go-mod-core-contracts/clients" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" + "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" + "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient" + "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient/retry/periodic" "github.com/edgexfoundry/go-mod-core-contracts/models" ) @@ -61,7 +63,7 @@ var testInterval2 = models.Interval{ } func TestIntervalRestClient_Add(t *testing.T) { - ts := testHttpServer(t, http.MethodPost, clients.ApiIntervalRoute) + ts := testHTTPServer(t, http.MethodPost, clients.ApiIntervalRoute) defer ts.Close() @@ -73,25 +75,21 @@ func TestIntervalRestClient_Add(t *testing.T) { }{ {"happy path", testInterval1, - NewIntervalClient(types.EndpointParams{ - ServiceKey: clients.SupportSchedulerServiceKey, - Path: clients.ApiIntervalRoute, - UseRegistry: false, - Url: ts.URL + clients.ApiIntervalRoute, - Interval: clients.ClientMonitorDefault, - }, MockEndpoint{}), + NewIntervalClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiIntervalRoute))), false, }, { - "nil client", + "client error", testInterval1, - NewIntervalClient(types.EndpointParams{}, nil), + NewIntervalClient(urlclient.NewRegistryClient(make(chan interfaces.URLStream), + periodic.New(1, 0)), + ), true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - res, err := tt.ic.Add(&tt.interval, context.Background()) + res, err := tt.ic.Add(context.Background(), &tt.interval) if !tt.expectedError && res == "" { t.Error("unexpected empty string response") @@ -109,23 +107,13 @@ func TestIntervalRestClient_Add(t *testing.T) { } func TestIntervalRestClient_Delete(t *testing.T) { - ts := testHttpServer(t, http.MethodDelete, clients.ApiIntervalRoute) + ts := testHTTPServer(t, http.MethodDelete, clients.ApiIntervalRoute) defer ts.Close() - url := ts.URL + clients.ApiIntervalRoute + ic := NewIntervalClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiIntervalRoute))) - params := types.EndpointParams{ - ServiceKey: clients.SupportSchedulerServiceKey, - Path: clients.ApiIntervalRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault, - } - - ic := NewIntervalClient(params, MockEndpoint{}) - - err := ic.Delete(testID1, context.Background()) + err := ic.Delete(context.Background(), testID1) if err != nil { t.Fatalf("unexpected error %s", err.Error()) @@ -133,23 +121,13 @@ func TestIntervalRestClient_Delete(t *testing.T) { } func TestIntervalRestClient_DeleteByName(t *testing.T) { - ts := testHttpServer(t, http.MethodDelete, clients.ApiIntervalRoute) + ts := testHTTPServer(t, http.MethodDelete, clients.ApiIntervalRoute) defer ts.Close() - url := ts.URL + clients.ApiIntervalRoute - - params := types.EndpointParams{ - ServiceKey: clients.SupportSchedulerServiceKey, - Path: clients.ApiIntervalRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault, - } - - ic := NewIntervalClient(params, MockEndpoint{}) + ic := NewIntervalClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiIntervalRoute))) - err := ic.DeleteByName(testInterval1.Name, context.Background()) + err := ic.DeleteByName(context.Background(), testInterval1.Name) if err != nil { t.Fatalf("unexpected error %s", err.Error()) @@ -202,36 +180,26 @@ func TestIntervalRestClient_Interval(t *testing.T) { }{ {"happy path", testInterval1.ID, - NewIntervalClient(types.EndpointParams{ - ServiceKey: clients.SupportSchedulerServiceKey, - Path: clients.ApiIntervalRoute, - UseRegistry: false, - Url: ts.URL + clients.ApiIntervalRoute, - Interval: clients.ClientMonitorDefault, - }, MockEndpoint{}), + NewIntervalClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiIntervalRoute))), false, }, { - "nil client", + "client error", testInterval1.ID, - NewIntervalClient(types.EndpointParams{}, nil), + NewIntervalClient(urlclient.NewRegistryClient(make(chan interfaces.URLStream), + periodic.New(1, 0)), + ), true, }, {"bad JSON marshal", testInterval1.ID, - NewIntervalClient(types.EndpointParams{ - ServiceKey: clients.SupportSchedulerServiceKey, - Path: clients.ApiIntervalRoute, - UseRegistry: false, - Url: badJSONServer.URL + clients.ApiIntervalRoute, - Interval: clients.ClientMonitorDefault, - }, MockEndpoint{}), + NewIntervalClient(urlclient.NewLocalClient(interfaces.URLStream(badJSONServer.URL + clients.ApiIntervalRoute))), true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - res, err := tt.ic.Interval(tt.intervalID, context.Background()) + res, err := tt.ic.Interval(context.Background(), tt.intervalID) emptyInterval := models.Interval{} @@ -272,19 +240,9 @@ func TestIntervalRestClient_IntervalForName(t *testing.T) { defer ts.Close() - url := ts.URL + clients.ApiIntervalRoute - - params := types.EndpointParams{ - ServiceKey: clients.SupportSchedulerServiceKey, - Path: clients.ApiIntervalRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault, - } - - ic := NewIntervalClient(params, MockEndpoint{}) + ic := NewIntervalClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiIntervalRoute))) - _, err := ic.IntervalForName(testInterval1.Name, context.Background()) + _, err := ic.IntervalForName(context.Background(), testInterval1.Name) if err != nil { t.Fatalf("unexpected error %s", err.Error()) @@ -337,28 +295,18 @@ func TestIntervalRestClient_Intervals(t *testing.T) { expectedError bool }{ {"happy path", - NewIntervalClient(types.EndpointParams{ - ServiceKey: clients.SupportSchedulerServiceKey, - Path: clients.ApiIntervalRoute, - UseRegistry: false, - Url: ts.URL + clients.ApiIntervalRoute, - Interval: clients.ClientMonitorDefault, - }, MockEndpoint{}), + NewIntervalClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiIntervalRoute))), false, }, { - "nil client", - NewIntervalClient(types.EndpointParams{}, nil), + "client error", + NewIntervalClient(urlclient.NewRegistryClient(make(chan interfaces.URLStream), + periodic.New(1, 0)), + ), true, }, {"bad JSON marshal", - NewIntervalClient(types.EndpointParams{ - ServiceKey: clients.SupportSchedulerServiceKey, - Path: clients.ApiIntervalRoute, - UseRegistry: false, - Url: badJSONServer.URL + clients.ApiIntervalRoute, - Interval: clients.ClientMonitorDefault, - }, MockEndpoint{}), + NewIntervalClient(urlclient.NewLocalClient(interfaces.URLStream(badJSONServer.URL + clients.ApiIntervalRoute))), true, }, } @@ -384,38 +332,21 @@ func TestIntervalRestClient_Intervals(t *testing.T) { } func TestIntervalRestClient_Update(t *testing.T) { - ts := testHttpServer(t, http.MethodPut, clients.ApiIntervalRoute) + ts := testHTTPServer(t, http.MethodPut, clients.ApiIntervalRoute) defer ts.Close() - url := ts.URL + clients.ApiIntervalRoute - - params := types.EndpointParams{ - ServiceKey: clients.SupportSchedulerServiceKey, - Path: clients.ApiIntervalRoute, - UseRegistry: false, - Url: url, - Interval: clients.ClientMonitorDefault, - } - - ic := NewIntervalClient(params, MockEndpoint{}) + ic := NewIntervalClient(urlclient.NewLocalClient(interfaces.URLStream(ts.URL + clients.ApiIntervalRoute))) - err := ic.Update(testInterval1, context.Background()) + err := ic.Update(context.Background(), testInterval1) if err != nil { t.Fatalf("unexpected error %s", err.Error()) } } -type MockEndpoint struct { -} - -func (e MockEndpoint) Monitor(_ types.EndpointParams) chan string { - return make(chan string, 1) -} - -// testHttpServer instantiates a test HTTP Server to be used for conveniently verifying a client's invocation -func testHttpServer(t *testing.T, matchingRequestMethod string, matchingRequestUri string) *httptest.Server { +// testHTTPServer instantiates a test HTTP Server to be used for conveniently verifying a client's invocation +func testHTTPServer(t *testing.T, matchingRequestMethod string, matchingRequestUri string) *httptest.Server { return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) diff --git a/clients/types/endpoint_params.go b/clients/types/endpoint_params.go deleted file mode 100644 index e748164e..00000000 --- a/clients/types/endpoint_params.go +++ /dev/null @@ -1,28 +0,0 @@ -/******************************************************************************* - * Copyright 2019 Dell Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - *******************************************************************************/ - -/* - Package types provides supporting types that facilitate the various service client implementations. -*/ -package types - -// EndpointParams is a type that allows for the passing of common parameters to service clients -// for initialization. -type EndpointParams struct { - ServiceKey string // The key of the service as found in the service registry (e.g. Consul) - Path string // The path to the service's endpoint following port number in the URL - UseRegistry bool // An indication of whether or not endpoint information should be obtained from a service registry provider. - Url string // If a service registry is not being used, then provide the full URL endpoint - Interval int // The interval in milliseconds governing how often the client polls to keep the endpoint current -} diff --git a/clients/urlclient/factory.go b/clients/urlclient/errors/errors.go similarity index 53% rename from clients/urlclient/factory.go rename to clients/urlclient/errors/errors.go index 65fbe84c..572e0172 100644 --- a/clients/urlclient/factory.go +++ b/clients/urlclient/errors/errors.go @@ -12,19 +12,15 @@ * the License. *******************************************************************************/ -// urlclient provides concrete implementation types that implement the URLClient interface. -// These types should all, in some way or another, provide some mechanism to fill in service data at runtime. -package urlclient +// errors defines a set of errors that urlclient will use. +package errors -import ( - "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" -) +type timeoutError struct{} -// New provides the correct concrete implementation of the URLClient given the params provided. -func New(params types.EndpointParams, m interfaces.Endpointer) interfaces.URLClient { - if params.UseRegistry { - return newRegistryClient(params, m, 10) - } - return newLocalClient(params) +func NewTimeoutError() timeoutError { + return timeoutError{} +} + +func (timeoutError) Error() string { + return "unable to initialize client" } diff --git a/clients/urlclient/interfaces/retry.go b/clients/urlclient/interfaces/retry.go new file mode 100644 index 00000000..29a0a9f6 --- /dev/null +++ b/clients/urlclient/interfaces/retry.go @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright 2020 Dell Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + *******************************************************************************/ + +// interfaces defines contracts specific to the urlclient package +package interfaces + +// RetryStrategy defines some way to verify that a RegistryClient has received data. +// It accomplishes this by monitoring the values pointed to in its parameters, +// which communicate the state of the RegistryClient. +// When the values pointed to by the parameters are in the desired state, +// the URL that should be passed back to the RegistryClient should be returned by the RetryStrategy. +type RetryStrategy interface { + // Retry defines the actual behavior of the RegistryClient and how it processes the URL. + Retry(url *string) (string, error) + + // IsInitialized communicates whether the value of the URL is currently being updated or not. + IsInitialized() bool + + // SetInitialization updates the value of the lock. + SetInitialization(value bool) +} diff --git a/clients/urlclient/local.go b/clients/urlclient/local.go index 7e8a0160..c3f0698b 100644 --- a/clients/urlclient/local.go +++ b/clients/urlclient/local.go @@ -14,19 +14,17 @@ package urlclient -import ( - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" -) +import "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" // localClient defines a ClientURL implementation that returns the struct field for the URL. type localClient struct { url string } -// newLocalClient returns a pointer to a localClient. -func newLocalClient(params types.EndpointParams) *localClient { +// NewLocalClient returns a pointer to a localClient. +func NewLocalClient(urlStreamResult interfaces.URLStream) *localClient { return &localClient{ - url: params.Url, + url: string(urlStreamResult), } } diff --git a/clients/urlclient/local_test.go b/clients/urlclient/local_test.go index 90b0079d..2acc6028 100644 --- a/clients/urlclient/local_test.go +++ b/clients/urlclient/local_test.go @@ -17,20 +17,19 @@ package urlclient import ( "testing" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" + "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" ) func TestNewLocalClient(t *testing.T) { - actualClient := newLocalClient(types.EndpointParams{UseRegistry: false}) + actualClient := NewLocalClient(interfaces.URLStream(expectedURL)) if actualClient == nil { - t.Fatal("nil returned from newLocalClient") + t.Fatal("nil returned from NewLocalClient") } } func TestLocalClient_URLPrefix(t *testing.T) { - expectedURL := "http://domain.com" - urlClient := newLocalClient(types.EndpointParams{Url: expectedURL}) + urlClient := NewLocalClient(interfaces.URLStream(expectedURL)) actualURL, err := urlClient.Prefix() diff --git a/clients/urlclient/registry.go b/clients/urlclient/registry.go index 82411b77..9e4c9182 100644 --- a/clients/urlclient/registry.go +++ b/clients/urlclient/registry.go @@ -15,62 +15,41 @@ package urlclient import ( - "errors" - "time" - "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" + urlClientInterfaces "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient/interfaces" ) // registryClient defines a URLClient implementation that checks for an update from an asynchronously run // EndpointMonitor that will emit a correct URL from the remote registry. type registryClient struct { - url string - timeout int - initialized bool + url string + strategy urlClientInterfaces.RetryStrategy } -var TimeoutError = errors.New("unable to initialize client") - -// newRegistryClient returns a pointer to a registryClient. +// NewRegistryClient returns a pointer to a registryClient. // A pointer is used so that when using configuration from a registry, the Prefix can be updated asynchronously. -func newRegistryClient(params types.EndpointParams, m interfaces.Endpointer, timeout int) *registryClient { - e := registryClient{ - timeout: timeout, - initialized: false, +func NewRegistryClient( + urlStream chan interfaces.URLStream, + strategy urlClientInterfaces.RetryStrategy) *registryClient { + c := registryClient{ + strategy: strategy, } - go func(ch chan string) { + go func(ch chan interfaces.URLStream) { for { select { case url := <-ch: - e.url = url - e.initialized = true + c.url = string(url) + strategy.SetInitialization(false) } } - }(m.Monitor(params)) + }(urlStream) - return &e + return &c } // Prefix waits for URLClient to be updated for timeout seconds. If a value is loaded in that time, it returns it. // Otherwise, it returns an error. func (c *registryClient) Prefix() (string, error) { - if c.initialized { - return c.url, nil - } - - timer := time.After(time.Duration(c.timeout) * time.Second) - ticker := time.Tick(500 * time.Millisecond) - for { - select { - case <-timer: - return "", TimeoutError - case <-ticker: - if c.initialized && len(c.url) != 0 { - return c.url, nil - } - // do not handle uninitialized case here, we need to keep trying - } - } + return c.strategy.Retry(&c.url) } diff --git a/clients/urlclient/registry_test.go b/clients/urlclient/registry_test.go index 074ef174..82e323a5 100644 --- a/clients/urlclient/registry_test.go +++ b/clients/urlclient/registry_test.go @@ -15,30 +15,46 @@ package urlclient import ( - "fmt" "testing" + "time" - "github.com/edgexfoundry/go-mod-core-contracts/clients/types" + interfaces2 "github.com/edgexfoundry/go-mod-core-contracts/clients/interfaces" + "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient/errors" + "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient/interfaces" + "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient/retry/once" + "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient/retry/periodic" ) +var timeoutError = errors.NewTimeoutError() +var expectedURL = "http://domain.com" + func TestNewRegistryClient(t *testing.T) { - actualClient := newRegistryClient(types.EndpointParams{UseRegistry: true}, mockEndpoint{}, 100) + actualClient := NewRegistryClient( + makeTestStream(), + periodic.New(500, 10), + ) if actualClient == nil { - t.Fatal("nil returned from newRegistryClient") + t.Fatal("nil returned from NewRegistryClient") } } -func TestRegistryClient_URLPrefix(t *testing.T) { - expectedURL := "http://domain.com" - testEndpoint := mockEndpoint{ch: make(chan string, 1)} - urlClient := newRegistryClient(types.EndpointParams{}, testEndpoint, 100) - testEndpoint.SendToChannel() +func TestRegistryClient_Prefix_Periodic(t *testing.T) { + strategy := periodic.New(500, 10) + testStream := makeTestStream() + + urlClient := NewRegistryClient( + testStream, + strategy, + ) + testStream <- interfaces2.URLStream(expectedURL) + + // don't sleep, we need to actuate the retry code actualURL, err := urlClient.Prefix() if err != nil { - t.Fatalf("unexpected error %s", err.Error()) + t.Fatalf("unexpected error: %s", err.Error()) } if actualURL != expectedURL { @@ -46,23 +62,65 @@ func TestRegistryClient_URLPrefix(t *testing.T) { } } -func TestRegistryClient_URLPrefixInitialized(t *testing.T) { - expectedURL := "http://domain.com" - testEndpoint := mockEndpoint{ch: make(chan string, 1)} - urlClient := newRegistryClient(types.EndpointParams{}, testEndpoint, 100) - testEndpoint.SendToChannel() +func TestRegistryClient_Prefix_Periodic_Initialized(t *testing.T) { + // use impossible timing to ensure that if hit, the retry logic will error out + strategy := periodic.New(1, 0) + testStream := makeTestStream() + + urlClient := NewRegistryClient( + testStream, + strategy, + ) + + testStream <- interfaces2.URLStream(expectedURL) + + // sleep so that the retry code doesn't run and we only execute the shortcut + sleep(t, strategy) - // set up prerequisite condition, call Prefix once to set initialized to true actualURL, err := urlClient.Prefix() + if err != nil { - t.Fatalf("unexpected error in precondition %s", err.Error()) + t.Fatalf("unexpected error: %s", err.Error()) + } + + if actualURL != expectedURL { + t.Fatalf("expected URL %s, found URL %s", expectedURL, actualURL) + } +} + +func TestRegistryClient_Prefix_Periodic_TimedOut(t *testing.T) { + urlClient := NewRegistryClient( + makeTestStream(), + periodic.New(1, 0), + ) + + actualURL, err := urlClient.Prefix() + + if err == nil || actualURL != "" { + t.Fatal("expected error") + } + + if err != timeoutError { + t.Fatalf("expected error %s, found error %s", timeoutError.Error(), err.Error()) } +} + +func TestRegistryClient_Prefix_Once(t *testing.T) { + strategy := once.New() + testStream := makeTestStream() - // call Prefix again without sending another message on the channel - actualURL, err = urlClient.Prefix() + urlClient := NewRegistryClient( + testStream, + strategy, + ) + testStream <- interfaces2.URLStream(expectedURL) + + sleep(t, strategy) + + actualURL, err := urlClient.Prefix() if err != nil { - t.Fatalf("unexpected error %s", err.Error()) + t.Fatalf("unexpected error: %s", err.Error()) } if actualURL != expectedURL { @@ -70,8 +128,11 @@ func TestRegistryClient_URLPrefixInitialized(t *testing.T) { } } -func TestRegistryClient_URLPrefix_TimedOut(t *testing.T) { - urlClient := newRegistryClient(types.EndpointParams{}, mockEndpoint{}, 1) +func TestRegistryClient_Prefix_Once_NotAvailable(t *testing.T) { + urlClient := NewRegistryClient( + makeTestStream(), + once.New(), + ) actualURL, err := urlClient.Prefix() @@ -79,19 +140,21 @@ func TestRegistryClient_URLPrefix_TimedOut(t *testing.T) { t.Fatal("expected error") } - if err != TimeoutError { - t.Fatalf("expected error %s, found error %s", TimeoutError.Error(), err.Error()) + if err != timeoutError { + t.Fatalf("expected error %s, found error %s", timeoutError.Error(), err.Error()) } } -type mockEndpoint struct { - ch chan string -} +func sleep(t *testing.T, strategy interfaces.RetryStrategy) { + for i := 1; strategy.IsInitialized(); i++ { + if i == 5 { + t.Fatal("waited too long for strategy to unlock") + } -func (e mockEndpoint) Monitor(_ types.EndpointParams) chan string { - return e.ch + time.Sleep(time.Second) + } } -func (e mockEndpoint) SendToChannel() { - e.ch <- fmt.Sprint("http://domain.com") +func makeTestStream() chan interfaces2.URLStream { + return make(chan interfaces2.URLStream) } diff --git a/clients/urlclient/retry/once/strategy.go b/clients/urlclient/retry/once/strategy.go new file mode 100644 index 00000000..5a9c4831 --- /dev/null +++ b/clients/urlclient/retry/once/strategy.go @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright 2020 Dell Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + *******************************************************************************/ + +// once is designed to poll for the data one time. If successful, it returns the data, otherwise it returns an error. +package once + +import ( + "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient/errors" +) + +// strategy is designed to poll for the data one time. If successful, it returns the data, otherwise it returns an error. +type strategy struct { + isInitialized bool +} + +func New() *strategy { + return &strategy{true} +} + +// Retry is designed to poll for the data one time. If successful, it returns the data, otherwise it returns an error. +func (o *strategy) Retry(url *string) (string, error) { + if !o.isInitialized { + return *url, nil + } + + return "", errors.NewTimeoutError() +} + +// IsInitialized communicates whether the value of the URL is currently being updated or not. +func (o *strategy) IsInitialized() bool { + return o.isInitialized +} + +// SetInitialization updates the value of the lock. +func (o *strategy) SetInitialization(value bool) { + o.isInitialized = value +} diff --git a/clients/urlclient/retry/periodic/strategy.go b/clients/urlclient/retry/periodic/strategy.go new file mode 100644 index 00000000..6d9500b0 --- /dev/null +++ b/clients/urlclient/retry/periodic/strategy.go @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright 2020 Dell Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + *******************************************************************************/ + +// periodic is designed to poll for the data on a regular frequency until the timeout happens. +package periodic + +import ( + "time" + + "github.com/edgexfoundry/go-mod-core-contracts/clients/urlclient/errors" +) + +// strategy is designed to poll for the data on a regular frequency until the timeout happens. +// tickTime defines the interval in milliseconds for how often the URL should be queried. +// timeout defines the interval in seconds for how long the algorithm should query before giving up. +type strategy struct { + tickTime time.Duration + timeout time.Duration + isInitialized bool +} + +// New provides an implementation of Retry that is designed to +// poll for the data on a regular frequency until the timeout happens. +// tickTime defines the interval in milliseconds for how often the URL should be queried. +// timeout defines the interval in seconds for how long the algorithm should query before giving up. +func New(interval, timeout int) *strategy { + return &strategy{ + tickTime: time.Duration(interval), + timeout: time.Duration(timeout), + isInitialized: true, + } +} + +// Retry is designed to poll for the data on a regular frequency until the timeout happens. +func (p *strategy) Retry(url *string) (string, error) { + if !p.isInitialized { + return *url, nil + } + + p.SetInitialization(true) + defer p.SetInitialization(false) + + timer := time.After(p.timeout * time.Second) + ticker := time.Tick(p.tickTime * time.Millisecond) + for { + select { + case <-timer: + return "", errors.NewTimeoutError() + case <-ticker: + if !p.isInitialized && len(*url) != 0 { + return *url, nil + } + // do not handle uninitialized case here, we need to keep trying + } + } +} + +// IsInitialized communicates whether the value of the URL is currently being updated or not. +func (p *strategy) IsInitialized() bool { + return p.isInitialized +} + +// SetInitialization updates the value of the guard variable. +func (p *strategy) SetInitialization(value bool) { + p.isInitialized = value +} diff --git a/models/interval.go b/models/interval.go index 0265619f..a966b86e 100644 --- a/models/interval.go +++ b/models/interval.go @@ -32,8 +32,8 @@ type Interval struct { Timestamps Timestamps ID string `json:"id,omitempty"` Name string `json:"name,omitempty"` // non-database identifier for a shcedule (*must be quitue) - Start string `json:"start,omitempty"` // Start time i ISO 8601 format YYYYMMDD'T'HHmmss @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyymmdd'T'HHmmss") - End string `json:"end,omitempty"` // Start time i ISO 8601 format YYYYMMDD'T'HHmmss @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyymmdd'T'HHmmss") + Start string `json:"start,omitempty"` // Start time i ISO 8601 format YYYYMMDD'T'HHmmss + End string `json:"end,omitempty"` // Start time i ISO 8601 format YYYYMMDD'T'HHmmss Frequency string `json:"frequency,omitempty"` // how frequently should the event occur according ISO 8601 Cron string `json:"cron,omitempty"` // cron styled regular expression indicating how often the action under interval should occur. Use either runOnce, frequency or cron and not all. RunOnce bool `json:"runOnce,omitempty"` // boolean indicating that this interval runs one time - at the time indicated by the start @@ -46,8 +46,8 @@ func (i Interval) MarshalJSON() ([]byte, error) { Timestamps *Timestamps `json:",omitempty"` ID string `json:"id,omitempty"` Name string `json:"name,omitempty"` // non-database identifier for a schedule (*must be quitue) - Start string `json:"start,omitempty"` // Start time i ISO 8601 format YYYYMMDD'T'HHmmss @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyymmdd'T'HHmmss") - End string `json:"end,omitempty"` // Start time i ISO 8601 format YYYYMMDD'T'HHmmss @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyymmdd'T'HHmmss") + Start string `json:"start,omitempty"` // Start time i ISO 8601 format YYYYMMDD'T'HHmmss + End string `json:"end,omitempty"` // Start time i ISO 8601 format YYYYMMDD'T'HHmmss Frequency string `json:"frequency,omitempty"` // how frequently should the event occur Cron string `json:"cron,omitempty"` // cron styled regular expression indicating how often the action under schedule should occur. Use either runOnce, frequency or cron and not all. RunOnce bool `json:"runOnce,omitempty"` // boolean indicating that this interval runs one time - at the time indicated by the start diff --git a/models/resourceoperation_test.go b/models/resourceoperation_test.go index c4e31319..1ebc2984 100644 --- a/models/resourceoperation_test.go +++ b/models/resourceoperation_test.go @@ -106,7 +106,7 @@ func TestResourceOperation_FieldsAutoPopulation_MarshalJSON(t *testing.T) { oldResourceOperation := ResourceOperation{Object: TestRODeviceResource, Resource: TestDeviceCommand} newResourceOperation := ResourceOperation{DeviceResource: TestRODeviceResource, DeviceCommand: TestDeviceCommand} oldNewResourceOperation := ResourceOperation{Object: "XX", DeviceResource: TestRODeviceResource, Resource: "XX", DeviceCommand: TestDeviceCommand} - expectedJsonString := "{\"object\":\"" + TestRODeviceResource + "\"" + + expectedJSONString := "{\"object\":\"" + TestRODeviceResource + "\"" + ",\"deviceResource\":\"" + TestRODeviceResource + "\"" + ",\"resource\":\"" + TestDeviceCommand + "\"" + ",\"deviceCommand\":\"" + TestDeviceCommand + "\"}" @@ -124,7 +124,7 @@ func TestResourceOperation_FieldsAutoPopulation_MarshalJSON(t *testing.T) { if err != nil { t.Errorf("ResourceOperation.MarshalJSON() error = %v", err) } - if string(jsonBytes) != expectedJsonString { + if string(jsonBytes) != expectedJSONString { t.Errorf("Fields auto population is unexpected: %s, ", string(jsonBytes)) } }) @@ -132,11 +132,11 @@ func TestResourceOperation_FieldsAutoPopulation_MarshalJSON(t *testing.T) { } func TestResourceOperation_FieldsAutoPopulation_UnmarshalJSON(t *testing.T) { - oldJson := "{\"object\":\"" + TestRODeviceResource + "\"" + + oldJSON := "{\"object\":\"" + TestRODeviceResource + "\"" + ",\"resource\":\"" + TestDeviceCommand + "\"}" - newJson := "{\"deviceResource\":\"" + TestRODeviceResource + "\"" + + newJSON := "{\"deviceResource\":\"" + TestRODeviceResource + "\"" + ",\"deviceCommand\":\"" + TestDeviceCommand + "\"}" - oldNewJson := "{\"object\":\"XX\"" + + oldNewJSON := "{\"object\":\"XX\"" + ",\"deviceResource\":\"" + TestRODeviceResource + "\"" + ",\"resource\":\"XX\"" + ",\"deviceCommand\":\"" + TestDeviceCommand + "\"}" @@ -144,9 +144,9 @@ func TestResourceOperation_FieldsAutoPopulation_UnmarshalJSON(t *testing.T) { name string json string }{ - {"old fields only", oldJson}, - {"new fields only", newJson}, - {"new fields and old fields are different", oldNewJson}, + {"old fields only", oldJSON}, + {"new fields only", newJSON}, + {"new fields and old fields are different", oldNewJSON}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {