diff --git a/app-service-template/go.mod b/app-service-template/go.mod index 14c805d18..f84bcc11c 100644 --- a/app-service-template/go.mod +++ b/app-service-template/go.mod @@ -6,7 +6,7 @@ go 1.15 require ( github.com/edgexfoundry/app-functions-sdk-go/v2 v2.0.0-dev.52 - github.com/edgexfoundry/go-mod-core-contracts/v2 v2.0.0-dev.91 + github.com/edgexfoundry/go-mod-core-contracts/v2 v2.0.0-dev.98 github.com/google/uuid v1.2.0 github.com/stretchr/testify v1.7.0 ) diff --git a/app-service-template/res/configuration.toml b/app-service-template/res/configuration.toml index ebcd09b43..cf146a480 100644 --- a/app-service-template/res/configuration.toml +++ b/app-service-template/res/configuration.toml @@ -76,6 +76,21 @@ TokenFile = '/tmp/edgex/secrets/new-app-service/secrets-token.json' Host = 'localhost' Port = 59880 + [Clients.core-metadata] + Protocol = 'http' + Host = 'localhost' + Port = 59881 + + [Clients.core-command] + Protocol = 'http' + Host = 'localhost' + Port = 59882 + + [Clients.support-notifications] + Protocol = 'http' + Host = 'localhost' + Port = 59860 + [Trigger] Type="edgex-messagebus" [Trigger.EdgexMessageBus] diff --git a/go.mod b/go.mod index 067dd4e56..bb027b6fd 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/diegoholiveira/jsonlogic v1.0.1-0.20200220175622-ab7989be08b9 github.com/eclipse/paho.mqtt.golang v1.3.4 github.com/edgexfoundry/go-mod-bootstrap/v2 v2.0.0-dev.61 - github.com/edgexfoundry/go-mod-core-contracts/v2 v2.0.0-dev.91 + github.com/edgexfoundry/go-mod-core-contracts/v2 v2.0.0-dev.98 github.com/edgexfoundry/go-mod-messaging/v2 v2.0.0-dev.13 github.com/edgexfoundry/go-mod-registry/v2 v2.0.0-dev.7 github.com/fxamacker/cbor/v2 v2.2.0 diff --git a/internal/app/configurable.go b/internal/app/configurable.go index 1b3a3d7c1..c1f6a5fec 100644 --- a/internal/app/configurable.go +++ b/internal/app/configurable.go @@ -24,6 +24,7 @@ import ( "github.com/edgexfoundry/app-functions-sdk-go/v2/pkg/interfaces" "github.com/edgexfoundry/app-functions-sdk-go/v2/pkg/transforms" "github.com/edgexfoundry/app-functions-sdk-go/v2/pkg/util" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2" "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/logger" ) @@ -49,8 +50,11 @@ const ( Retain = "retain" AutoReconnect = "autoreconnect" ConnectTimeout = "connecttimeout" + ProfileName = "profilename" DeviceName = "devicename" - ReadingName = "readingname" + ResourceName = "resourcename" + ValueType = "valuetype" + MediaType = "mediatype" Rule = "rule" BatchThreshold = "batchthreshold" TimeInterval = "timeinterval" @@ -189,22 +193,60 @@ func (app *Configurable) Transform(parameters map[string]string) interfaces.AppF // CoreServices then your deviceName and readingName must exist in the CoreMetadata and be properly registered in EdgeX. // This function is a configuration function and returns a function pointer. func (app *Configurable) PushToCore(parameters map[string]string) interfaces.AppFunction { + profileName, ok := parameters[ProfileName] + if !ok { + app.lc.Errorf("Could not find %s", ProfileName) + return nil + } deviceName, ok := parameters[DeviceName] if !ok { - app.lc.Error("Could not find " + DeviceName) + app.lc.Errorf("Could not find %s", DeviceName) + return nil + } + resourceName, ok := parameters[ResourceName] + if !ok { + app.lc.Errorf("Could not find %s", ResourceName) return nil } - readingName, ok := parameters[ReadingName] + valueType, ok := parameters[ValueType] if !ok { - app.lc.Error("Could not find " + ReadingName) + app.lc.Errorf("Could not find %s", ValueType) return nil } + + profileName = strings.TrimSpace(profileName) deviceName = strings.TrimSpace(deviceName) - readingName = strings.TrimSpace(readingName) - transform := transforms.CoreData{ - DeviceName: deviceName, - ReadingName: readingName, + resourceName = strings.TrimSpace(resourceName) + valueType = strings.TrimSpace(valueType) + + var transform *transforms.CoreData + + // Converts to upper case and validates it is a validates ValueType + valueType, err := v2.NormalizeValueType(valueType) + if err != nil { + app.lc.Error(err.Error()) + return nil } + + if valueType == v2.ValueTypeBinary { + mediaType, ok := parameters[MediaType] + if !ok { + app.lc.Error("Could not find " + MediaType) + return nil + } + + mediaType = strings.TrimSpace(mediaType) + + if len(mediaType) == 0 { + app.lc.Error("MediaType can not be empty when ValueType=Binary") + return nil + } + + transform = transforms.NewCoreDataBinaryReading(profileName, deviceName, resourceName, mediaType) + } else { + transform = transforms.NewCoreDataSimpleReading(profileName, deviceName, resourceName, valueType) + } + return transform.PushToCoreData } diff --git a/internal/app/configurable_test.go b/internal/app/configurable_test.go index 457ce1a4e..e26d447b1 100644 --- a/internal/app/configurable_test.go +++ b/internal/app/configurable_test.go @@ -414,3 +414,60 @@ func TestEncrypt(t *testing.T) { }) } } + +func TestConfigurable_PushToCore(t *testing.T) { + configurable := Configurable{lc: lc} + + profileName := "MyProfile" + deviceName := "MyDevice" + resourceName := "MyResource" + simpleValueType := "int64" + binaryValueType := "binary" + badValueType := "bogus" + mediaType := "application/mxl" + emptyMediaType := "" + + tests := []struct { + Name string + ProfileName *string + DeviceName *string + ResourceName *string + ValueType *string + MediaType *string + ExpectNil bool + }{ + {"Valid simple", &profileName, &deviceName, &resourceName, &simpleValueType, nil, false}, + {"Invalid simple - missing profile", nil, &deviceName, &resourceName, &simpleValueType, nil, true}, + {"Invalid simple - missing device", &profileName, nil, &resourceName, &simpleValueType, nil, true}, + {"Invalid simple - missing resource", &profileName, &deviceName, nil, &simpleValueType, nil, true}, + {"Invalid simple - missing value type", &profileName, &deviceName, &resourceName, nil, nil, true}, + {"Invalid - bad value type", &profileName, &deviceName, &resourceName, &badValueType, nil, true}, + {"Valid binary", &profileName, &deviceName, &resourceName, &binaryValueType, &mediaType, false}, + {"Invalid binary - empty MediaType", &profileName, &deviceName, &resourceName, &binaryValueType, &emptyMediaType, true}, + {"Invalid binary - missing MediaType", &profileName, &deviceName, &resourceName, &binaryValueType, nil, true}, + } + + for _, testCase := range tests { + t.Run(testCase.Name, func(t *testing.T) { + params := make(map[string]string) + if testCase.ProfileName != nil { + params[ProfileName] = *testCase.ProfileName + } + if testCase.DeviceName != nil { + params[DeviceName] = *testCase.DeviceName + } + if testCase.ResourceName != nil { + params[ResourceName] = *testCase.ResourceName + } + if testCase.ValueType != nil { + params[ValueType] = *testCase.ValueType + } + if testCase.MediaType != nil { + params[MediaType] = *testCase.MediaType + } + + transform := configurable.PushToCore(params) + assert.Equal(t, testCase.ExpectNil, transform == nil) + }) + } +} diff --git a/internal/app/service.go b/internal/app/service.go index 36dad9899..bf8fb8a09 100644 --- a/internal/app/service.go +++ b/internal/app/service.go @@ -28,11 +28,9 @@ import ( "sync" "syscall" - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients" - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/coredata" "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/logger" - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/notifications" "github.com/edgexfoundry/go-mod-core-contracts/v2/models" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2" clientInterfaces "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/interfaces" "github.com/edgexfoundry/go-mod-messaging/v2/pkg/types" "github.com/edgexfoundry/go-mod-registry/v2/registry" @@ -110,10 +108,10 @@ type contextGroup struct { // AddRoute allows you to leverage the existing webserver to add routes. func (svc *Service) AddRoute(route string, handler func(nethttp.ResponseWriter, *nethttp.Request), methods ...string) error { - if route == clients.ApiPingRoute || - route == clients.ApiConfigRoute || - route == clients.ApiMetricsRoute || - route == clients.ApiVersionRoute || + if route == v2.ApiPingRoute || + route == v2.ApiConfigRoute || + route == v2.ApiMetricsRoute || + route == v2.ApiVersionRoute || route == internal.ApiTriggerRoute { return errors.New("route is reserved") } @@ -471,7 +469,7 @@ func (svc *Service) RegistryClient() registry.Client { } // EventClient returns the Event client, which may be nil, from the dependency injection container -func (svc *Service) EventClient() coredata.EventClient { +func (svc *Service) EventClient() clientInterfaces.EventClient { return container.EventClientFrom(svc.dic.Get) } @@ -480,9 +478,29 @@ func (svc *Service) CommandClient() clientInterfaces.CommandClient { return container.CommandClientFrom(svc.dic.Get) } -// NotificationsClient returns the Notifications client, which may be nil, from the dependency injection container -func (svc *Service) NotificationsClient() notifications.NotificationsClient { - return container.NotificationsClientFrom(svc.dic.Get) +// DeviceServiceClient returns the DeviceService client, which may be nil, from the dependency injection container +func (svc *Service) DeviceServiceClient() clientInterfaces.DeviceServiceClient { + return container.DeviceServiceClientFrom(svc.dic.Get) +} + +// DeviceProfileClient returns the DeviceProfile client, which may be nil, from the dependency injection container +func (svc *Service) DeviceProfileClient() clientInterfaces.DeviceProfileClient { + return container.DeviceProfileClientFrom(svc.dic.Get) +} + +// DeviceClient returns the Device client, which may be nil, from the dependency injection container +func (svc *Service) DeviceClient() clientInterfaces.DeviceClient { + return container.DeviceClientFrom(svc.dic.Get) +} + +// NotificationClient returns the Notifications client, which may be nil, from the dependency injection container +func (svc *Service) NotificationClient() clientInterfaces.NotificationClient { + return container.NotificationClientFrom(svc.dic.Get) +} + +// SubscriptionClient returns the Subscription client, which may be nil, from the dependency injection container +func (svc *Service) SubscriptionClient() clientInterfaces.SubscriptionClient { + return container.SubscriptionClientFrom(svc.dic.Get) } func listParameters(parameters map[string]string) string { diff --git a/internal/app/service_test.go b/internal/app/service_test.go index 2f28b7e98..281d60524 100644 --- a/internal/app/service_test.go +++ b/internal/app/service_test.go @@ -30,6 +30,7 @@ import ( "github.com/edgexfoundry/app-functions-sdk-go/v2/internal/trigger/messagebus" "github.com/edgexfoundry/app-functions-sdk-go/v2/internal/webserver" "github.com/edgexfoundry/app-functions-sdk-go/v2/pkg/interfaces" + v2clients "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/http" bootstrapContainer "github.com/edgexfoundry/go-mod-bootstrap/v2/bootstrap/container" "github.com/edgexfoundry/go-mod-bootstrap/v2/di" @@ -42,6 +43,8 @@ import ( var lc logger.LoggingClient var dic *di.Container +var target *Service +var baseUrl = "http://localhost:" func TestMain(m *testing.M) { // No remote and no file results in STDOUT logging only @@ -55,6 +58,10 @@ func TestMain(m *testing.M) { }, }) + target = NewService("unitTest", nil, "") + target.dic = dic + target.lc = lc + m.Run() } @@ -552,3 +559,109 @@ func TestFindMatchingFunction(t *testing.T) { }) } } + +func TestService_EventClient(t *testing.T) { + actual := target.EventClient() + assert.Nil(t, actual) + + dic.Update(di.ServiceConstructorMap{ + container.EventClientName: func(get di.Get) interface{} { + return v2clients.NewEventClient(baseUrl + "59880") + }, + }) + + actual = target.EventClient() + assert.NotNil(t, actual) +} + +func TestService_CommandClient(t *testing.T) { + actual := target.CommandClient() + assert.Nil(t, actual) + + dic.Update(di.ServiceConstructorMap{ + container.CommandClientName: func(get di.Get) interface{} { + return v2clients.NewCommandClient(baseUrl + "59882") + }, + }) + + actual = target.CommandClient() + assert.NotNil(t, actual) +} + +func TestService_DeviceServiceClient(t *testing.T) { + actual := target.DeviceServiceClient() + assert.Nil(t, actual) + + dic.Update(di.ServiceConstructorMap{ + container.DeviceServiceClientName: func(get di.Get) interface{} { + return v2clients.NewDeviceServiceClient(baseUrl + "59881") + }, + }) + + actual = target.DeviceServiceClient() + assert.NotNil(t, actual) + +} + +func TestService_DeviceProfileClient(t *testing.T) { + actual := target.DeviceProfileClient() + assert.Nil(t, actual) + + dic.Update(di.ServiceConstructorMap{ + container.DeviceProfileClientName: func(get di.Get) interface{} { + return v2clients.NewDeviceProfileClient(baseUrl + "59881") + }, + }) + + actual = target.DeviceProfileClient() + assert.NotNil(t, actual) +} + +func TestService_DeviceClient(t *testing.T) { + actual := target.DeviceClient() + assert.Nil(t, actual) + + dic.Update(di.ServiceConstructorMap{ + container.DeviceClientName: func(get di.Get) interface{} { + return v2clients.NewDeviceClient(baseUrl + "59881") + }, + }) + + actual = target.DeviceClient() + assert.NotNil(t, actual) + +} + +func TestService_NotificationClient(t *testing.T) { + actual := target.NotificationClient() + assert.Nil(t, actual) + + dic.Update(di.ServiceConstructorMap{ + container.NotificationClientName: func(get di.Get) interface{} { + return v2clients.NewNotificationClient(baseUrl + "59860") + }, + }) + + actual = target.NotificationClient() + assert.NotNil(t, actual) + +} + +func TestService_SubscriptionClient(t *testing.T) { + actual := target.SubscriptionClient() + assert.Nil(t, actual) + + dic.Update(di.ServiceConstructorMap{ + container.SubscriptionClientName: func(get di.Get) interface{} { + return v2clients.NewSubscriptionClient(baseUrl + "59860") + }, + }) + + actual = target.SubscriptionClient() + assert.NotNil(t, actual) +} + +func TestService_LoggingClient(t *testing.T) { + actual := target.LoggingClient() + assert.NotNil(t, actual) +} diff --git a/internal/appfunction/context.go b/internal/appfunction/context.go index bbfbfc492..bd17bbae9 100644 --- a/internal/appfunction/context.go +++ b/internal/appfunction/context.go @@ -18,6 +18,7 @@ package appfunction import ( "context" + "errors" "fmt" "regexp" "strings" @@ -25,21 +26,13 @@ import ( bootstrapContainer "github.com/edgexfoundry/go-mod-bootstrap/v2/bootstrap/container" "github.com/edgexfoundry/go-mod-bootstrap/v2/di" - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/coredata" "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/logger" - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/notifications" "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/interfaces" - - "github.com/edgexfoundry/app-functions-sdk-go/v2/internal/bootstrap/container" - "github.com/edgexfoundry/app-functions-sdk-go/v2/pkg/util" - - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients" - "github.com/edgexfoundry/go-mod-core-contracts/v2/models" - "github.com/edgexfoundry/go-mod-core-contracts/v2/v2" "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos" - commonDTO "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/common" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/common" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/requests" - "github.com/google/uuid" + "github.com/edgexfoundry/app-functions-sdk-go/v2/internal/bootstrap/container" ) // NewContext creates, initializes and return a new Context with implements the interfaces.AppFunctionContext interface @@ -121,73 +114,6 @@ func (appContext *Context) RetryData() []byte { return appContext.retryData } -// PushToCoreData pushes the provided value as an event to CoreData using the device name and reading name that have been set. -// TODO: This function must be reworked for the new V2 Event Client -func (appContext *Context) PushToCoreData(deviceName string, readingName string, value interface{}) (*dtos.Event, error) { - lc := appContext.LoggingClient() - lc.Debug("Pushing to CoreData") - - if appContext.EventClient() == nil { - return nil, fmt.Errorf("unable to Push To CoreData: '%s' is missing from Clients configuration", clients.CoreDataServiceKey) - } - - now := time.Now().UnixNano() - val, err := util.CoerceType(value) - if err != nil { - return nil, err - } - - // Temporary use V1 Reading until V2 EventClient is available - // TODO: Change to use dtos.Reading - v1Reading := models.Reading{ - Value: string(val), - ValueType: v2.ValueTypeString, - Origin: now, - Device: deviceName, - Name: readingName, - } - - readings := make([]models.Reading, 0, 1) - readings = append(readings, v1Reading) - - // Temporary use V1 Event until V2 EventClient is available - // TODO: Change to use dtos.Event - v1Event := &models.Event{ - Device: deviceName, - Origin: now, - Readings: readings, - } - - correlation := uuid.New().String() - ctx := context.WithValue(context.Background(), clients.CorrelationHeader, correlation) - result, err := appContext.EventClient().Add(ctx, v1Event) // TODO: Update to use V2 EventClient - if err != nil { - return nil, err - } - v1Event.ID = result - - // TODO: Remove once V2 EventClient is available - v2Reading := dtos.BaseReading{ - Id: v1Reading.Id, - Origin: v1Reading.Origin, - DeviceName: v1Reading.Device, - ResourceName: v1Reading.Name, - ProfileName: "", - ValueType: v1Reading.ValueType, - SimpleReading: dtos.SimpleReading{Value: v1Reading.Value}, - } - - // TODO: Remove once V2 EventClient is available - v2Event := dtos.Event{ - Versionable: commonDTO.NewVersionable(), - Id: result, - DeviceName: v1Event.Device, - Origin: v1Event.Origin, - Readings: []dtos.BaseReading{v2Reading}, - } - return &v2Event, nil -} - // GetSecret returns the secret data from the secret store (secure or insecure) for the specified path. func (appContext *Context) GetSecret(path string, keys ...string) (map[string]string, error) { secretProvider := bootstrapContainer.SecretProviderFrom(appContext.dic.Get) @@ -206,7 +132,7 @@ func (appContext *Context) LoggingClient() logger.LoggingClient { } // EventClient returns the Event client, which may be nil, from the dependency injection container -func (appContext *Context) EventClient() coredata.EventClient { +func (appContext *Context) EventClient() interfaces.EventClient { return container.EventClientFrom(appContext.dic.Get) } @@ -215,9 +141,29 @@ func (appContext *Context) CommandClient() interfaces.CommandClient { return container.CommandClientFrom(appContext.dic.Get) } -// NotificationsClient returns the Notifications client, which may be nil, from the dependency injection container -func (appContext *Context) NotificationsClient() notifications.NotificationsClient { - return container.NotificationsClientFrom(appContext.dic.Get) +// DeviceServiceClient returns the DeviceService client, which may be nil, from the dependency injection container +func (appContext *Context) DeviceServiceClient() interfaces.DeviceServiceClient { + return container.DeviceServiceClientFrom(appContext.dic.Get) +} + +// DeviceProfileClient returns the DeviceProfile client, which may be nil, from the dependency injection container +func (appContext *Context) DeviceProfileClient() interfaces.DeviceProfileClient { + return container.DeviceProfileClientFrom(appContext.dic.Get) +} + +// DeviceClient returns the Device client, which may be nil, from the dependency injection container +func (appContext *Context) DeviceClient() interfaces.DeviceClient { + return container.DeviceClientFrom(appContext.dic.Get) +} + +// NotificationClient returns the Notification client, which may be nil, from the dependency injection container +func (appContext *Context) NotificationClient() interfaces.NotificationClient { + return container.NotificationClientFrom(appContext.dic.Get) +} + +// SubscriptionClient returns the Subscription client, which may be nil, from the dependency injection container +func (appContext *Context) SubscriptionClient() interfaces.SubscriptionClient { + return container.SubscriptionClientFrom(appContext.dic.Get) } // AddValue stores a value for access within other functions in pipeline @@ -230,6 +176,32 @@ func (appContext *Context) RemoveValue(key string) { delete(appContext.contextData, strings.ToLower(key)) } +// PushToCore pushes a new event to Core Data. +func (appContext *Context) PushToCore(event dtos.Event) (common.BaseWithIdResponse, error) { + client := appContext.EventClient() + if client == nil { + return common.BaseWithIdResponse{}, errors.New("EventClient not initialized. Core Metadata is missing from clients configuration") + } + + request := requests.NewAddEventRequest(event) + return client.Add(context.Background(), request) +} + +// GetDeviceResource retrieves the DeviceResource for given profileName and resourceName. +func (appContext *Context) GetDeviceResource(profileName string, resourceName string) (dtos.DeviceResource, error) { + client := appContext.DeviceProfileClient() + if client == nil { + return dtos.DeviceResource{}, errors.New("DeviceProfileClient not initialized. Core Metadata is missing from clients configuration") + } + + response, err := client.DeviceResourceByProfileNameAndResourceName(context.Background(), profileName, resourceName) + if err != nil { + return dtos.DeviceResource{}, err + } + + return response.Resource, nil +} + // GetValue attempts to retrieve a value stored in the context at the given key func (appContext *Context) GetValue(key string) (string, bool) { val, found := appContext.contextData[strings.ToLower(key)] @@ -262,12 +234,12 @@ func (appContext *Context) ApplyValues(format string) (string, error) { key := strings.TrimRight(strings.TrimLeft(placeholder, "{"), "}") - ctxval, found := appContext.GetValue(key) + value, found := appContext.GetValue(key) attempts[placeholder] = found if found { - result = strings.Replace(result, placeholder, ctxval, -1) + result = strings.Replace(result, placeholder, value, -1) } } diff --git a/internal/appfunction/context_test.go b/internal/appfunction/context_test.go index 3d9cefd2e..d0e31e304 100644 --- a/internal/appfunction/context_test.go +++ b/internal/appfunction/context_test.go @@ -18,48 +18,37 @@ package appfunction import ( "fmt" - "github.com/google/uuid" - "net/http" - "net/http/httptest" "os" "strings" "testing" "time" + "github.com/edgexfoundry/app-functions-sdk-go/v2/internal/bootstrap/container" + "github.com/edgexfoundry/go-mod-core-contracts/v2/clients" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/responses" + bootstrapContainer "github.com/edgexfoundry/go-mod-bootstrap/v2/bootstrap/container" "github.com/edgexfoundry/go-mod-bootstrap/v2/bootstrap/interfaces/mocks" "github.com/edgexfoundry/go-mod-bootstrap/v2/di" - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients" - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/coredata" "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/logger" - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/notifications" - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/urlclient/local" "github.com/edgexfoundry/go-mod-core-contracts/v2/v2" v2clients "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/http" + clientMocks "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/interfaces/mocks" "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos" "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/common" + "github.com/google/uuid" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - - "github.com/edgexfoundry/app-functions-sdk-go/v2/internal/bootstrap/container" ) var target *Context var dic *di.Container +var baseUrl = "http://localhost:" func TestMain(m *testing.M) { - dic = di.NewContainer(di.ServiceConstructorMap{ - container.EventClientName: func(get di.Get) interface{} { - return coredata.NewEventClient(local.New(clients.ApiEventRoute)) - }, - container.NotificationsClientName: func(get di.Get) interface{} { - return notifications.NewNotificationsClient(local.New(clients.ApiNotificationRoute)) - }, - container.CommandClientName: func(get di.Get) interface{} { - return v2clients.NewCommandClient(clients.ApiCommandRoute) - }, bootstrapContainer.LoggingClientInterfaceName: func(get di.Get) interface{} { return logger.NewMockClient() }, @@ -69,72 +58,109 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } -func TestContext_PushToCoreData(t *testing.T) { - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte("newId")) - if r.Method != http.MethodPost { - t.Errorf("expected http method is POST, active http method is : %s", r.Method) - } - url := clients.ApiEventRoute - if r.URL.EscapedPath() != url { - t.Errorf("expected uri path is %s, actual uri path is %s", url, r.URL.EscapedPath()) - } - })) - - defer ts.Close() +func TestContext_EventClient(t *testing.T) { + actual := target.EventClient() + assert.Nil(t, actual) - eventClient := coredata.NewEventClient(local.New(ts.URL + clients.ApiEventRoute)) dic.Update(di.ServiceConstructorMap{ container.EventClientName: func(get di.Get) interface{} { - return eventClient + return v2clients.NewEventClient(baseUrl + "59880") }, }) - expectedEvent := &dtos.Event{ - Versionable: common.NewVersionable(), - DeviceName: "device-name", - Readings: []dtos.BaseReading{ - { - DeviceName: "device-name", - ResourceName: "device-resource", - ValueType: v2.ValueTypeString, - SimpleReading: dtos.SimpleReading{ - Value: "value", - }, - }, - }, - } - actualEvent, err := target.PushToCoreData("device-name", "device-resource", "value") - require.NoError(t, err) - - assert.NotNil(t, actualEvent) - assert.Equal(t, expectedEvent.ApiVersion, actualEvent.ApiVersion) - assert.Equal(t, expectedEvent.DeviceName, actualEvent.DeviceName) - assert.True(t, len(expectedEvent.Readings) == 1) - assert.Equal(t, expectedEvent.Readings[0].DeviceName, actualEvent.Readings[0].DeviceName) - assert.Equal(t, expectedEvent.Readings[0].ResourceName, actualEvent.Readings[0].ResourceName) - assert.Equal(t, expectedEvent.Readings[0].Value, actualEvent.Readings[0].Value) - assert.Equal(t, expectedEvent.Readings[0].ValueType, actualEvent.Readings[0].ValueType) + actual = target.EventClient() + assert.NotNil(t, actual) } func TestContext_CommandClient(t *testing.T) { actual := target.CommandClient() + assert.Nil(t, actual) + + dic.Update(di.ServiceConstructorMap{ + container.CommandClientName: func(get di.Get) interface{} { + return v2clients.NewCommandClient(baseUrl + "59882") + }, + }) + + actual = target.CommandClient() assert.NotNil(t, actual) } -func TestContext_EventClient(t *testing.T) { - actual := target.EventClient() +func TestContext_DeviceServiceClient(t *testing.T) { + actual := target.DeviceServiceClient() + assert.Nil(t, actual) + + dic.Update(di.ServiceConstructorMap{ + container.DeviceServiceClientName: func(get di.Get) interface{} { + return v2clients.NewDeviceServiceClient(baseUrl + "59881") + }, + }) + + actual = target.DeviceServiceClient() assert.NotNil(t, actual) + } -func TestContext_LoggingClient(t *testing.T) { - actual := target.LoggingClient() +func TestContext_DeviceProfileClient(t *testing.T) { + actual := target.DeviceProfileClient() + assert.Nil(t, actual) + + dic.Update(di.ServiceConstructorMap{ + container.DeviceProfileClientName: func(get di.Get) interface{} { + return v2clients.NewDeviceProfileClient(baseUrl + "59881") + }, + }) + + actual = target.DeviceProfileClient() assert.NotNil(t, actual) } -func TestContext_NotificationsClient(t *testing.T) { - actual := target.NotificationsClient() +func TestContext_DeviceClient(t *testing.T) { + actual := target.DeviceClient() + assert.Nil(t, actual) + + dic.Update(di.ServiceConstructorMap{ + container.DeviceClientName: func(get di.Get) interface{} { + return v2clients.NewDeviceClient(baseUrl + "59881") + }, + }) + + actual = target.DeviceClient() + assert.NotNil(t, actual) + +} + +func TestContext_NotificationClient(t *testing.T) { + actual := target.NotificationClient() + assert.Nil(t, actual) + + dic.Update(di.ServiceConstructorMap{ + container.NotificationClientName: func(get di.Get) interface{} { + return v2clients.NewNotificationClient(baseUrl + "59860") + }, + }) + + actual = target.NotificationClient() + assert.NotNil(t, actual) + +} + +func TestContext_SubscriptionClient(t *testing.T) { + actual := target.SubscriptionClient() + assert.Nil(t, actual) + + dic.Update(di.ServiceConstructorMap{ + container.SubscriptionClientName: func(get di.Get) interface{} { + return v2clients.NewSubscriptionClient(baseUrl + "59860") + }, + }) + + actual = target.SubscriptionClient() + assert.NotNil(t, actual) +} + +func TestContext_LoggingClient(t *testing.T) { + actual := target.LoggingClient() assert.NotNil(t, actual) } @@ -386,3 +412,55 @@ func TestContext_ApplyValues_MissingPlaceholder(t *testing.T) { require.Equal(t, fmt.Sprintf("failed to replace all context placeholders in input ('%s-%s-{key3}' after replacements)", data["key1"], data["key2"]), err.Error()) require.Equal(t, "", res) } + +func TestContext_PushToCore(t *testing.T) { + mockClient := clientMocks.EventClient{} + mockClient.On("Add", mock.Anything, mock.Anything).Return(common.BaseWithIdResponse{}, nil) + dic.Update(di.ServiceConstructorMap{ + container.EventClientName: func(get di.Get) interface{} { + return &mockClient + }, + }) + + event := dtos.NewEvent("MyProfile", "MyDevice", "MyResource") + err := event.AddSimpleReading("MyResource", v2.ValueTypeInt32, int32(1234)) + require.NoError(t, err) + + _, err = target.PushToCore(event) + require.NoError(t, err) +} + +func TestContext_PushToCore_error(t *testing.T) { + dic.Update(di.ServiceConstructorMap{ + container.EventClientName: func(get di.Get) interface{} { + return nil + }, + }) + + _, err := target.PushToCore(dtos.Event{}) + require.Error(t, err) +} + +func TestContext_GetDeviceResource(t *testing.T) { + mockClient := clientMocks.DeviceProfileClient{} + mockClient.On("DeviceResourceByProfileNameAndResourceName", mock.Anything, mock.Anything, mock.Anything).Return(responses.DeviceResourceResponse{}, nil) + dic.Update(di.ServiceConstructorMap{ + container.DeviceProfileClientName: func(get di.Get) interface{} { + return &mockClient + }, + }) + + _, err := target.GetDeviceResource("MyProfile", "MyResource") + require.NoError(t, err) +} + +func TestContext_GetDeviceResource_Error(t *testing.T) { + dic.Update(di.ServiceConstructorMap{ + container.DeviceProfileClientName: func(get di.Get) interface{} { + return nil + }, + }) + + _, err := target.GetDeviceResource("MyProfile", "MyResource") + require.Error(t, err) +} diff --git a/internal/bootstrap/container/clients.go b/internal/bootstrap/container/clients.go index 851411167..376c86d5f 100644 --- a/internal/bootstrap/container/clients.go +++ b/internal/bootstrap/container/clients.go @@ -17,55 +17,89 @@ package container import ( "github.com/edgexfoundry/go-mod-bootstrap/v2/di" - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/coredata" - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/notifications" "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/interfaces" ) -// ValueDescriptorClientName contains the name of the ValueDescriptorClient's implementation in the DIC. -var ValueDescriptorClientName = di.TypeInstanceToName((*coredata.ValueDescriptorClient)(nil)) +// EventClientName contains the name of the EventClient's implementation in the DIC. +var EventClientName = di.TypeInstanceToName((*interfaces.EventClient)(nil)) -// ValueDescriptorClientFrom helper function queries the DIC and returns the ValueDescriptorClient's implementation. -func ValueDescriptorClientFrom(get di.Get) coredata.ValueDescriptorClient { - if get(ValueDescriptorClientName) == nil { +// EventClientFrom helper function queries the DIC and returns the EventClient's implementation. +func EventClientFrom(get di.Get) interfaces.EventClient { + if get(EventClientName) == nil { return nil } - return get(ValueDescriptorClientName).(coredata.ValueDescriptorClient) + return get(EventClientName).(interfaces.EventClient) } -// EventClientName contains the name of the EventClient's implementation in the DIC. -var EventClientName = di.TypeInstanceToName((*coredata.EventClient)(nil)) +// CommandClientName contains the name of the CommandClient's implementation in the DIC. +var CommandClientName = di.TypeInstanceToName((*interfaces.CommandClient)(nil)) -// ValueDescriptorClientFrom helper function queries the DIC and returns the ValueDescriptorClient's implementation. -func EventClientFrom(get di.Get) coredata.EventClient { - if get(EventClientName) == nil { +// CommandClientFrom helper function queries the DIC and returns the CommandClient's implementation. +func CommandClientFrom(get di.Get) interfaces.CommandClient { + if get(CommandClientName) == nil { return nil } - return get(EventClientName).(coredata.EventClient) + return get(CommandClientName).(interfaces.CommandClient) } -// NotificationsClientName contains the name of the NotificationsClientInfo's implementation in the DIC. -var NotificationsClientName = di.TypeInstanceToName((*notifications.NotificationsClient)(nil)) +// NotificationClientName contains the name of the NotificationClient's implementation in the DIC. +var NotificationClientName = di.TypeInstanceToName((*interfaces.NotificationClient)(nil)) -// NotificationsClientFrom helper function queries the DIC and returns the NotificationsClientInfo's implementation. -func NotificationsClientFrom(get di.Get) notifications.NotificationsClient { - if get(NotificationsClientName) == nil { +// NotificationClientFrom helper function queries the DIC and returns the NotificationClient's implementation. +func NotificationClientFrom(get di.Get) interfaces.NotificationClient { + if get(NotificationClientName) == nil { return nil } - return get(NotificationsClientName).(notifications.NotificationsClient) + return get(NotificationClientName).(interfaces.NotificationClient) } -// CommandClientName contains the name of the CommandClientInfo's implementation in the DIC. -var CommandClientName = di.TypeInstanceToName((*interfaces.CommandClient)(nil)) +// SubscriptionClientName contains the name of the SubscriptionClient's implementation in the DIC. +var SubscriptionClientName = di.TypeInstanceToName((*interfaces.SubscriptionClient)(nil)) -// NotificationsClientFrom helper function queries the DIC and returns the NotificationsClientInfo's implementation. -func CommandClientFrom(get di.Get) interfaces.CommandClient { - if get(CommandClientName) == nil { +// SubscriptionClientFrom helper function queries the DIC and returns the SubscriptionClient's implementation. +func SubscriptionClientFrom(get di.Get) interfaces.SubscriptionClient { + if get(SubscriptionClientName) == nil { return nil } - return get(CommandClientName).(interfaces.CommandClient) + return get(SubscriptionClientName).(interfaces.SubscriptionClient) +} + +// DeviceServiceClientName contains the name of the DeviceServiceClient's implementation in the DIC. +var DeviceServiceClientName = di.TypeInstanceToName((*interfaces.DeviceServiceClient)(nil)) + +// DeviceServiceClientFrom helper function queries the DIC and returns the DeviceServiceClient's implementation. +func DeviceServiceClientFrom(get di.Get) interfaces.DeviceServiceClient { + if get(DeviceServiceClientName) == nil { + return nil + } + + return get(DeviceServiceClientName).(interfaces.DeviceServiceClient) +} + +// DeviceProfileClientName contains the name of the DeviceProfileClient's implementation in the DIC. +var DeviceProfileClientName = di.TypeInstanceToName((*interfaces.DeviceProfileClient)(nil)) + +// DeviceProfileClientFrom helper function queries the DIC and returns the DeviceProfileClient's implementation. +func DeviceProfileClientFrom(get di.Get) interfaces.DeviceProfileClient { + if get(DeviceProfileClientName) == nil { + return nil + } + + return get(DeviceProfileClientName).(interfaces.DeviceProfileClient) +} + +// DeviceClientName contains the name of the DeviceClient's implementation in the DIC. +var DeviceClientName = di.TypeInstanceToName((*interfaces.DeviceClient)(nil)) + +// DeviceClientFrom helper function queries the DIC and returns the DeviceClient's implementation. +func DeviceClientFrom(get di.Get) interfaces.DeviceClient { + if get(DeviceClientName) == nil { + return nil + } + + return get(DeviceClientName).(interfaces.DeviceClient) } diff --git a/internal/bootstrap/handlers/clients.go b/internal/bootstrap/handlers/clients.go index e4595b838..6e0105c45 100644 --- a/internal/bootstrap/handlers/clients.go +++ b/internal/bootstrap/handlers/clients.go @@ -19,16 +19,13 @@ import ( "context" "sync" + "github.com/edgexfoundry/app-functions-sdk-go/v2/internal/bootstrap/container" + "github.com/edgexfoundry/go-mod-core-contracts/v2/clients" + "github.com/edgexfoundry/go-mod-bootstrap/v2/bootstrap/startup" "github.com/edgexfoundry/go-mod-bootstrap/v2/di" - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients" - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/coredata" - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/notifications" - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/urlclient/local" v2clients "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/http" "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/interfaces" - - "github.com/edgexfoundry/app-functions-sdk-go/v2/internal/bootstrap/container" ) // Clients contains references to dependencies required by the Clients bootstrap implementation. @@ -49,28 +46,33 @@ func (_ *Clients) BootstrapHandler( config := container.ConfigurationFrom(dic.Get) - var eventClient coredata.EventClient - var valueDescriptorClient coredata.ValueDescriptorClient + var eventClient interfaces.EventClient var commandClient interfaces.CommandClient - var notificationsClient notifications.NotificationsClient + var notificationClient interfaces.NotificationClient + var subscriptionClient interfaces.SubscriptionClient + var deviceServiceClient interfaces.DeviceServiceClient + var deviceProfileClient interfaces.DeviceProfileClient + var deviceClient interfaces.DeviceClient // Use of these client interfaces is optional, so they are not required to be configured. For instance if not // sending commands, then don't need to have the Command client in the configuration. - if _, ok := config.Clients[clients.CoreDataServiceKey]; ok { - eventClient = coredata.NewEventClient( - local.New(config.Clients[clients.CoreDataServiceKey].Url() + clients.ApiEventRoute)) + if val, ok := config.Clients[clients.CoreDataServiceKey]; ok { + eventClient = v2clients.NewEventClient(val.Url()) + } - valueDescriptorClient = coredata.NewValueDescriptorClient( - local.New(config.Clients[clients.CoreDataServiceKey].Url() + clients.ApiValueDescriptorRoute)) + if val, ok := config.Clients[clients.CoreCommandServiceKey]; ok { + commandClient = v2clients.NewCommandClient(val.Url()) } - if _, ok := config.Clients[clients.CoreCommandServiceKey]; ok { - commandClient = v2clients.NewCommandClient(config.Clients[clients.CoreCommandServiceKey].Url()) + if val, ok := config.Clients[clients.CoreMetaDataServiceKey]; ok { + deviceServiceClient = v2clients.NewDeviceServiceClient(val.Url()) + deviceProfileClient = v2clients.NewDeviceProfileClient(val.Url()) + deviceClient = v2clients.NewDeviceClient(val.Url()) } - if _, ok := config.Clients[clients.SupportNotificationsServiceKey]; ok { - notificationsClient = notifications.NewNotificationsClient( - local.New(config.Clients[clients.SupportNotificationsServiceKey].Url() + clients.ApiNotificationRoute)) + if val, ok := config.Clients[clients.SupportNotificationsServiceKey]; ok { + notificationClient = v2clients.NewNotificationClient(val.Url()) + subscriptionClient = v2clients.NewSubscriptionClient(val.Url()) } // Note that all the clients are optional so some or all these clients may be nil @@ -80,14 +82,23 @@ func (_ *Clients) BootstrapHandler( container.EventClientName: func(get di.Get) interface{} { return eventClient }, - container.ValueDescriptorClientName: func(get di.Get) interface{} { - return valueDescriptorClient - }, container.CommandClientName: func(get di.Get) interface{} { return commandClient }, - container.NotificationsClientName: func(get di.Get) interface{} { - return notificationsClient + container.DeviceServiceClientName: func(get di.Get) interface{} { + return deviceServiceClient + }, + container.DeviceProfileClientName: func(get di.Get) interface{} { + return deviceProfileClient + }, + container.DeviceClientName: func(get di.Get) interface{} { + return deviceClient + }, + container.NotificationClientName: func(get di.Get) interface{} { + return notificationClient + }, + container.SubscriptionClientName: func(get di.Get) interface{} { + return subscriptionClient }, }) diff --git a/internal/bootstrap/handlers/clients_test.go b/internal/bootstrap/handlers/clients_test.go index a411d335a..1fb7cbef6 100644 --- a/internal/bootstrap/handlers/clients_test.go +++ b/internal/bootstrap/handlers/clients_test.go @@ -58,13 +58,19 @@ func TestClientsBootstrapHandler(t *testing.T) { Protocol: "http", } + metadataClientInfo := config.ClientInfo{ + Host: "localhost", + Port: 59881, + Protocol: "http", + } + commandClientInfo := config.ClientInfo{ Host: "localhost", Port: 59882, Protocol: "http", } - notificationsClientInfo := config.ClientInfo{ + notificationClientInfo := config.ClientInfo{ Host: "localhost", Port: 59860, Protocol: "http", @@ -73,28 +79,32 @@ func TestClientsBootstrapHandler(t *testing.T) { startupTimer := startup.NewStartUpTimer("unit-test") tests := []struct { - Name string - CoreDataClientInfo *config.ClientInfo - CommandClientInfo *config.ClientInfo - NotificationsClientInfo *config.ClientInfo + Name string + CoreDataClientInfo *config.ClientInfo + CommandClientInfo *config.ClientInfo + MetadataClientInfo *config.ClientInfo + NotificationClientInfo *config.ClientInfo }{ { - Name: "All Clients", - CoreDataClientInfo: &coreDataClientInfo, - CommandClientInfo: &commandClientInfo, - NotificationsClientInfo: ¬ificationsClientInfo, + Name: "All Clients", + CoreDataClientInfo: &coreDataClientInfo, + CommandClientInfo: &commandClientInfo, + MetadataClientInfo: &metadataClientInfo, + NotificationClientInfo: ¬ificationClientInfo, }, { - Name: "No Clients", - CoreDataClientInfo: nil, - CommandClientInfo: nil, - NotificationsClientInfo: nil, + Name: "No Clients", + CoreDataClientInfo: nil, + CommandClientInfo: nil, + MetadataClientInfo: nil, + NotificationClientInfo: nil, }, { - Name: "Only Core Data Clients", - CoreDataClientInfo: &coreDataClientInfo, - CommandClientInfo: nil, - NotificationsClientInfo: nil, + Name: "Only Core Data Clients", + CoreDataClientInfo: &coreDataClientInfo, + CommandClientInfo: nil, + MetadataClientInfo: nil, + NotificationClientInfo: nil, }, } @@ -110,8 +120,12 @@ func TestClientsBootstrapHandler(t *testing.T) { configuration.Clients[clients.CoreCommandServiceKey] = commandClientInfo } - if test.NotificationsClientInfo != nil { - configuration.Clients[clients.SupportNotificationsServiceKey] = notificationsClientInfo + if test.MetadataClientInfo != nil { + configuration.Clients[clients.CoreMetaDataServiceKey] = metadataClientInfo + } + + if test.NotificationClientInfo != nil { + configuration.Clients[clients.SupportNotificationsServiceKey] = notificationClientInfo } dic.Update(di.ServiceConstructorMap{ @@ -124,16 +138,17 @@ func TestClientsBootstrapHandler(t *testing.T) { require.True(t, success) eventClient := container.EventClientFrom(dic.Get) - valueDescriptorClient := container.ValueDescriptorClientFrom(dic.Get) commandClient := container.CommandClientFrom(dic.Get) - notificationsClient := container.NotificationsClientFrom(dic.Get) + deviceServiceClient := container.DeviceServiceClientFrom(dic.Get) + deviceProfileClient := container.DeviceProfileClientFrom(dic.Get) + deviceClient := container.DeviceClientFrom(dic.Get) + notificationClient := container.NotificationClientFrom(dic.Get) + subscriptionClient := container.SubscriptionClientFrom(dic.Get) if test.CoreDataClientInfo != nil { assert.NotNil(t, eventClient) - assert.NotNil(t, valueDescriptorClient) } else { assert.Nil(t, eventClient) - assert.Nil(t, valueDescriptorClient) } if test.CommandClientInfo != nil { @@ -142,10 +157,22 @@ func TestClientsBootstrapHandler(t *testing.T) { assert.Nil(t, commandClient) } - if test.NotificationsClientInfo != nil { - assert.NotNil(t, notificationsClient) + if test.MetadataClientInfo != nil { + assert.NotNil(t, deviceServiceClient) + assert.NotNil(t, deviceProfileClient) + assert.NotNil(t, deviceClient) + } else { + assert.Nil(t, deviceServiceClient) + assert.Nil(t, deviceProfileClient) + assert.Nil(t, deviceClient) + } + + if test.NotificationClientInfo != nil { + assert.NotNil(t, notificationClient) + assert.NotNil(t, subscriptionClient) } else { - assert.Nil(t, notificationsClient) + assert.Nil(t, notificationClient) + assert.Nil(t, subscriptionClient) } }) } diff --git a/pkg/interfaces/context.go b/pkg/interfaces/context.go index 047d70f68..c57a91211 100644 --- a/pkg/interfaces/context.go +++ b/pkg/interfaces/context.go @@ -18,12 +18,10 @@ package interfaces import ( "time" - "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/interfaces" - - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/coredata" "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/logger" - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/notifications" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/interfaces" "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/common" ) const DEVICENAME = "devicename" @@ -71,17 +69,31 @@ type AppFunctionContext interface { LoggingClient() logger.LoggingClient // EventClient returns the Event client. Note if Core Data is not specified in the Clients configuration, // this will return nil. - EventClient() coredata.EventClient + EventClient() interfaces.EventClient // CommandClient returns the Command client. Note if Support Command is not specified in the Clients configuration, // this will return nil. CommandClient() interfaces.CommandClient - // NotificationsClient returns the Notifications client. Note if Support Notifications is not specified in the + // NotificationClient returns the Notification client. Note if Support Notifications is not specified in the + // Clients configuration, this will return nil. + NotificationClient() interfaces.NotificationClient + // SubscriptionClient returns the Subscription client. Note if Support Notifications is not specified in the + // Clients configuration, this will return nil. + SubscriptionClient() interfaces.SubscriptionClient + // DeviceServiceClient returns the DeviceService client. Note if Core Metadata is not specified in the + // Clients configuration, this will return nil. + DeviceServiceClient() interfaces.DeviceServiceClient + // DeviceProfileClient returns the DeviceProfile client. Note if Core Metadata is not specified in the + // Clients configuration, this will return nil. + DeviceProfileClient() interfaces.DeviceProfileClient + // DeviceClient returns the Device client. Note if Core Metadata is not specified in the // Clients configuration, this will return nil. - NotificationsClient() notifications.NotificationsClient - // PushToCoreData is a convenience function for adding new Event/Reading(s) to core data and - // back onto the EdgeX MessageBus. This function uses the Event client and will result in an error if - // Core Data is not specified in the Clients configuration - PushToCoreData(deviceName string, readingName string, value interface{}) (*dtos.Event, error) + DeviceClient() interfaces.DeviceClient + // PushToCore pushes a new event to Core Data. + PushToCore(event dtos.Event) (common.BaseWithIdResponse, error) + // GetDeviceResource retrieves the DeviceResource for given profileName and resourceName. + // Resources retrieved are cached so multiple calls for same profileName and resourceName don't result in multiple + // unneeded HTTP calls to Core Metadata + GetDeviceResource(profileName string, resourceName string) (dtos.DeviceResource, error) // AddValue stores a value for access within other functions in pipeline AddValue(key string, value string) // RemoveValue deletes a value stored in the context at the given key diff --git a/pkg/interfaces/mocks/AppFunctionContext.go b/pkg/interfaces/mocks/AppFunctionContext.go index 8a9eaae1b..b5c4e8ebb 100644 --- a/pkg/interfaces/mocks/AppFunctionContext.go +++ b/pkg/interfaces/mocks/AppFunctionContext.go @@ -3,8 +3,8 @@ package mocks import ( - command "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/command" - coredata "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/coredata" + clientsinterfaces "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/interfaces" + common "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/common" dtos "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos" @@ -12,8 +12,6 @@ import ( mock "github.com/stretchr/testify/mock" - notifications "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/notifications" - time "time" ) @@ -22,16 +20,42 @@ type AppFunctionContext struct { mock.Mock } +// AddValue provides a mock function with given fields: key, value +func (_m *AppFunctionContext) AddValue(key string, value string) { + _m.Called(key, value) +} + +// ApplyValues provides a mock function with given fields: format +func (_m *AppFunctionContext) ApplyValues(format string) (string, error) { + ret := _m.Called(format) + + var r0 string + if rf, ok := ret.Get(0).(func(string) string); ok { + r0 = rf(format) + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(format) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // CommandClient provides a mock function with given fields: -func (_m *AppFunctionContext) CommandClient() command.CommandClient { +func (_m *AppFunctionContext) CommandClient() clientsinterfaces.CommandClient { ret := _m.Called() - var r0 command.CommandClient - if rf, ok := ret.Get(0).(func() command.CommandClient); ok { + var r0 clientsinterfaces.CommandClient + if rf, ok := ret.Get(0).(func() clientsinterfaces.CommandClient); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(command.CommandClient) + r0 = ret.Get(0).(clientsinterfaces.CommandClient) } } @@ -52,22 +76,107 @@ func (_m *AppFunctionContext) CorrelationID() string { return r0 } +// DeviceClient provides a mock function with given fields: +func (_m *AppFunctionContext) DeviceClient() clientsinterfaces.DeviceClient { + ret := _m.Called() + + var r0 clientsinterfaces.DeviceClient + if rf, ok := ret.Get(0).(func() clientsinterfaces.DeviceClient); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(clientsinterfaces.DeviceClient) + } + } + + return r0 +} + +// DeviceProfileClient provides a mock function with given fields: +func (_m *AppFunctionContext) DeviceProfileClient() clientsinterfaces.DeviceProfileClient { + ret := _m.Called() + + var r0 clientsinterfaces.DeviceProfileClient + if rf, ok := ret.Get(0).(func() clientsinterfaces.DeviceProfileClient); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(clientsinterfaces.DeviceProfileClient) + } + } + + return r0 +} + +// DeviceServiceClient provides a mock function with given fields: +func (_m *AppFunctionContext) DeviceServiceClient() clientsinterfaces.DeviceServiceClient { + ret := _m.Called() + + var r0 clientsinterfaces.DeviceServiceClient + if rf, ok := ret.Get(0).(func() clientsinterfaces.DeviceServiceClient); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(clientsinterfaces.DeviceServiceClient) + } + } + + return r0 +} + // EventClient provides a mock function with given fields: -func (_m *AppFunctionContext) EventClient() coredata.EventClient { +func (_m *AppFunctionContext) EventClient() clientsinterfaces.EventClient { + ret := _m.Called() + + var r0 clientsinterfaces.EventClient + if rf, ok := ret.Get(0).(func() clientsinterfaces.EventClient); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(clientsinterfaces.EventClient) + } + } + + return r0 +} + +// GetAllValues provides a mock function with given fields: +func (_m *AppFunctionContext) GetAllValues() map[string]string { ret := _m.Called() - var r0 coredata.EventClient - if rf, ok := ret.Get(0).(func() coredata.EventClient); ok { + var r0 map[string]string + if rf, ok := ret.Get(0).(func() map[string]string); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(coredata.EventClient) + r0 = ret.Get(0).(map[string]string) } } return r0 } +// GetDeviceResource provides a mock function with given fields: profileName, resourceName +func (_m *AppFunctionContext) GetDeviceResource(profileName string, resourceName string) (dtos.DeviceResource, error) { + ret := _m.Called(profileName, resourceName) + + var r0 dtos.DeviceResource + if rf, ok := ret.Get(0).(func(string, string) dtos.DeviceResource); ok { + r0 = rf(profileName, resourceName) + } else { + r0 = ret.Get(0).(dtos.DeviceResource) + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, string) error); ok { + r1 = rf(profileName, resourceName) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetSecret provides a mock function with given fields: path, keys func (_m *AppFunctionContext) GetSecret(path string, keys ...string) (map[string]string, error) { _va := make([]interface{}, len(keys)) @@ -98,6 +207,27 @@ func (_m *AppFunctionContext) GetSecret(path string, keys ...string) (map[string return r0, r1 } +// GetValue provides a mock function with given fields: key +func (_m *AppFunctionContext) GetValue(key string) (string, bool) { + ret := _m.Called(key) + + var r0 string + if rf, ok := ret.Get(0).(func(string) string); ok { + r0 = rf(key) + } else { + r0 = ret.Get(0).(string) + } + + var r1 bool + if rf, ok := ret.Get(1).(func(string) bool); ok { + r1 = rf(key) + } else { + r1 = ret.Get(1).(bool) + } + + return r0, r1 +} + // InputContentType provides a mock function with given fields: func (_m *AppFunctionContext) InputContentType() string { ret := _m.Called() @@ -128,38 +258,36 @@ func (_m *AppFunctionContext) LoggingClient() logger.LoggingClient { return r0 } -// NotificationsClient provides a mock function with given fields: -func (_m *AppFunctionContext) NotificationsClient() notifications.NotificationsClient { +// NotificationClient provides a mock function with given fields: +func (_m *AppFunctionContext) NotificationClient() clientsinterfaces.NotificationClient { ret := _m.Called() - var r0 notifications.NotificationsClient - if rf, ok := ret.Get(0).(func() notifications.NotificationsClient); ok { + var r0 clientsinterfaces.NotificationClient + if rf, ok := ret.Get(0).(func() clientsinterfaces.NotificationClient); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(notifications.NotificationsClient) + r0 = ret.Get(0).(clientsinterfaces.NotificationClient) } } return r0 } -// PushToCoreData provides a mock function with given fields: deviceName, readingName, value -func (_m *AppFunctionContext) PushToCoreData(deviceName string, readingName string, value interface{}) (*dtos.Event, error) { - ret := _m.Called(deviceName, readingName, value) +// PushToCore provides a mock function with given fields: event +func (_m *AppFunctionContext) PushToCore(event dtos.Event) (common.BaseWithIdResponse, error) { + ret := _m.Called(event) - var r0 *dtos.Event - if rf, ok := ret.Get(0).(func(string, string, interface{}) *dtos.Event); ok { - r0 = rf(deviceName, readingName, value) + var r0 common.BaseWithIdResponse + if rf, ok := ret.Get(0).(func(dtos.Event) common.BaseWithIdResponse); ok { + r0 = rf(event) } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*dtos.Event) - } + r0 = ret.Get(0).(common.BaseWithIdResponse) } var r1 error - if rf, ok := ret.Get(1).(func(string, string, interface{}) error); ok { - r1 = rf(deviceName, readingName, value) + if rf, ok := ret.Get(1).(func(dtos.Event) error); ok { + r1 = rf(event) } else { r1 = ret.Error(1) } @@ -167,6 +295,11 @@ func (_m *AppFunctionContext) PushToCoreData(deviceName string, readingName stri return r0, r1 } +// RemoveValue provides a mock function with given fields: key +func (_m *AppFunctionContext) RemoveValue(key string) { + _m.Called(key) +} + // ResponseContentType provides a mock function with given fields: func (_m *AppFunctionContext) ResponseContentType() string { ret := _m.Called() @@ -225,3 +358,19 @@ func (_m *AppFunctionContext) SetResponseData(data []byte) { func (_m *AppFunctionContext) SetRetryData(data []byte) { _m.Called(data) } + +// SubscriptionClient provides a mock function with given fields: +func (_m *AppFunctionContext) SubscriptionClient() clientsinterfaces.SubscriptionClient { + ret := _m.Called() + + var r0 clientsinterfaces.SubscriptionClient + if rf, ok := ret.Get(0).(func() clientsinterfaces.SubscriptionClient); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(clientsinterfaces.SubscriptionClient) + } + } + + return r0 +} diff --git a/pkg/interfaces/mocks/ApplicationService.go b/pkg/interfaces/mocks/ApplicationService.go index 74e7672cc..d3c600fed 100644 --- a/pkg/interfaces/mocks/ApplicationService.go +++ b/pkg/interfaces/mocks/ApplicationService.go @@ -3,19 +3,16 @@ package mocks import ( - coredata "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/coredata" - interfaces2 "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/interfaces" - http "net/http" + clientsinterfaces "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/interfaces" + interfaces "github.com/edgexfoundry/app-functions-sdk-go/v2/pkg/interfaces" logger "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/logger" mock "github.com/stretchr/testify/mock" - notifications "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/notifications" - registry "github.com/edgexfoundry/go-mod-registry/v2/registry" ) @@ -78,15 +75,63 @@ func (_m *ApplicationService) ApplicationSettings() map[string]string { } // CommandClient provides a mock function with given fields: -func (_m *ApplicationService) CommandClient() interfaces2.CommandClient { +func (_m *ApplicationService) CommandClient() clientsinterfaces.CommandClient { + ret := _m.Called() + + var r0 clientsinterfaces.CommandClient + if rf, ok := ret.Get(0).(func() clientsinterfaces.CommandClient); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(clientsinterfaces.CommandClient) + } + } + + return r0 +} + +// DeviceClient provides a mock function with given fields: +func (_m *ApplicationService) DeviceClient() clientsinterfaces.DeviceClient { ret := _m.Called() - var r0 interfaces2.CommandClient - if rf, ok := ret.Get(0).(func() interfaces2.CommandClient); ok { + var r0 clientsinterfaces.DeviceClient + if rf, ok := ret.Get(0).(func() clientsinterfaces.DeviceClient); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(interfaces2.CommandClient) + r0 = ret.Get(0).(clientsinterfaces.DeviceClient) + } + } + + return r0 +} + +// DeviceProfileClient provides a mock function with given fields: +func (_m *ApplicationService) DeviceProfileClient() clientsinterfaces.DeviceProfileClient { + ret := _m.Called() + + var r0 clientsinterfaces.DeviceProfileClient + if rf, ok := ret.Get(0).(func() clientsinterfaces.DeviceProfileClient); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(clientsinterfaces.DeviceProfileClient) + } + } + + return r0 +} + +// DeviceServiceClient provides a mock function with given fields: +func (_m *ApplicationService) DeviceServiceClient() clientsinterfaces.DeviceServiceClient { + ret := _m.Called() + + var r0 clientsinterfaces.DeviceServiceClient + if rf, ok := ret.Get(0).(func() clientsinterfaces.DeviceServiceClient); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(clientsinterfaces.DeviceServiceClient) } } @@ -94,15 +139,15 @@ func (_m *ApplicationService) CommandClient() interfaces2.CommandClient { } // EventClient provides a mock function with given fields: -func (_m *ApplicationService) EventClient() coredata.EventClient { +func (_m *ApplicationService) EventClient() clientsinterfaces.EventClient { ret := _m.Called() - var r0 coredata.EventClient - if rf, ok := ret.Get(0).(func() coredata.EventClient); ok { + var r0 clientsinterfaces.EventClient + if rf, ok := ret.Get(0).(func() clientsinterfaces.EventClient); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(coredata.EventClient) + r0 = ret.Get(0).(clientsinterfaces.EventClient) } } @@ -269,16 +314,16 @@ func (_m *ApplicationService) MakeItStop() { _m.Called() } -// NotificationsClient provides a mock function with given fields: -func (_m *ApplicationService) NotificationsClient() notifications.NotificationsClient { +// NotificationClient provides a mock function with given fields: +func (_m *ApplicationService) NotificationClient() clientsinterfaces.NotificationClient { ret := _m.Called() - var r0 notifications.NotificationsClient - if rf, ok := ret.Get(0).(func() notifications.NotificationsClient); ok { + var r0 clientsinterfaces.NotificationClient + if rf, ok := ret.Get(0).(func() clientsinterfaces.NotificationClient); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(notifications.NotificationsClient) + r0 = ret.Get(0).(clientsinterfaces.NotificationClient) } } @@ -348,3 +393,19 @@ func (_m *ApplicationService) StoreSecret(path string, secretData map[string]str return r0 } + +// SubscriptionClient provides a mock function with given fields: +func (_m *ApplicationService) SubscriptionClient() clientsinterfaces.SubscriptionClient { + ret := _m.Called() + + var r0 clientsinterfaces.SubscriptionClient + if rf, ok := ret.Get(0).(func() clientsinterfaces.SubscriptionClient); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(clientsinterfaces.SubscriptionClient) + } + } + + return r0 +} diff --git a/pkg/interfaces/service.go b/pkg/interfaces/service.go index c22fe52b3..c96fd1dfd 100644 --- a/pkg/interfaces/service.go +++ b/pkg/interfaces/service.go @@ -18,11 +18,8 @@ package interfaces import ( "net/http" - "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/interfaces" - - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/coredata" "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/logger" - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/notifications" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/interfaces" "github.com/edgexfoundry/go-mod-registry/v2/registry" bootstrapInterfaces "github.com/edgexfoundry/go-mod-bootstrap/v2/bootstrap/interfaces" @@ -101,14 +98,26 @@ type ApplicationService interface { LoggingClient() logger.LoggingClient // EventClient returns the Event client. Note if Core Data is not specified in the Clients configuration, // this will return nil. - EventClient() coredata.EventClient + EventClient() interfaces.EventClient // CommandClient returns the Command client. Note if Support Command is not specified in the Clients configuration, // this will return nil. CommandClient() interfaces.CommandClient - // NotificationsClient returns the Notifications client. Note if Support Notifications is not specified in the + // NotificationClient returns the Notification client. Note if Support Notifications is not specified in the + // Clients configuration, this will return nil. + NotificationClient() interfaces.NotificationClient + // SubscriptionClient returns the Subscription client. Note if Support Notifications is not specified in the + // Clients configuration, this will return nil. + SubscriptionClient() interfaces.SubscriptionClient + // DeviceServiceClient returns the DeviceService client. Note if Core Metadata is not specified in the + // Clients configuration, this will return nil. + DeviceServiceClient() interfaces.DeviceServiceClient + // DeviceProfileClient returns the DeviceProfile client. Note if Core Metadata is not specified in the + // Clients configuration, this will return nil. + DeviceProfileClient() interfaces.DeviceProfileClient + // DeviceClient returns the Device client. Note if Core Metadata is not specified in the // Clients configuration, this will return nil. - NotificationsClient() notifications.NotificationsClient - // RegistryClient() returns the Registry client. Note the registry must been enable, otherwise this will return nil. + DeviceClient() interfaces.DeviceClient + // RegistryClient returns the Registry client. Note the registry must been enable, otherwise this will return nil. // Useful if service needs to add additional health checks or needs to get endpoint of another registered service RegistryClient() registry.Client // LoadConfigurablePipeline loads the function pipeline from configuration. diff --git a/pkg/transforms/batch_test.go b/pkg/transforms/batch_test.go index 2c5a7478e..862df93d5 100644 --- a/pkg/transforms/batch_test.go +++ b/pkg/transforms/batch_test.go @@ -29,7 +29,7 @@ var dataToBatch = [3]string{"Test1", "Test2", "Test3"} func TestBatchNoData(t *testing.T) { bs, _ := NewBatchByCount(1) - continuePipeline, err := bs.Batch(context, nil) + continuePipeline, err := bs.Batch(ctx, nil) assert.False(t, continuePipeline) assert.Equal(t, "No Data Received", err.(error).Error()) @@ -38,28 +38,28 @@ func TestBatchInCountMode(t *testing.T) { bs, _ := NewBatchByCount(3) - continuePipeline1, _ := bs.Batch(context, []byte(dataToBatch[0])) + continuePipeline1, _ := bs.Batch(ctx, []byte(dataToBatch[0])) assert.False(t, continuePipeline1) assert.Len(t, bs.batchData.all(), 1, "Should have 1 record") - continuePipeline2, _ := bs.Batch(context, []byte(dataToBatch[0])) + continuePipeline2, _ := bs.Batch(ctx, []byte(dataToBatch[0])) assert.False(t, continuePipeline2) assert.Len(t, bs.batchData.all(), 2, "Should have 2 records") - continuePipeline3, result3 := bs.Batch(context, []byte(dataToBatch[0])) + continuePipeline3, result3 := bs.Batch(ctx, []byte(dataToBatch[0])) assert.True(t, continuePipeline3) assert.Len(t, result3, 3, "Should have 3 records") assert.Len(t, bs.batchData.all(), 0, "Records should have been cleared") - continuePipeline4, _ := bs.Batch(context, []byte(dataToBatch[0])) + continuePipeline4, _ := bs.Batch(ctx, []byte(dataToBatch[0])) assert.False(t, continuePipeline4) assert.Len(t, bs.batchData.all(), 1, "Should have 1 record") - continuePipeline5, _ := bs.Batch(context, []byte(dataToBatch[0])) + continuePipeline5, _ := bs.Batch(ctx, []byte(dataToBatch[0])) assert.False(t, continuePipeline5) assert.Len(t, bs.batchData.all(), 2, "Should have 2 records") - continuePipeline6, result4 := bs.Batch(context, []byte(dataToBatch[0])) + continuePipeline6, result4 := bs.Batch(ctx, []byte(dataToBatch[0])) assert.True(t, continuePipeline6) assert.Len(t, result4, 3, "Should have 3 records") assert.Len(t, bs.batchData.all(), 0, "Records should have been cleared") @@ -82,7 +82,7 @@ func TestBatchInTimeAndCountMode_TimeElapsed(t *testing.T) { // batch time interval has elapsed. In the mean time the other go func have to execute // before the batch time interval has elapsed, so the sleep above has to be less than the // batch time interval. - continuePipeline1, result := bs.Batch(context, []byte(dataToBatch[0])) + continuePipeline1, result := bs.Batch(ctx, []byte(dataToBatch[0])) assert.True(t, continuePipeline1) if continuePipeline1 { assert.Equal(t, 3, len(result.([][]byte))) @@ -92,13 +92,13 @@ func TestBatchInTimeAndCountMode_TimeElapsed(t *testing.T) { }() go func() { wgFirst.Wait() - continuePipeline2, _ := bs.Batch(context, []byte(dataToBatch[0])) + continuePipeline2, _ := bs.Batch(ctx, []byte(dataToBatch[0])) assert.False(t, continuePipeline2) wgAll.Done() }() go func() { wgFirst.Wait() - continuePipeline3, _ := bs.Batch(context, []byte(dataToBatch[0])) + continuePipeline3, _ := bs.Batch(ctx, []byte(dataToBatch[0])) assert.False(t, continuePipeline3) wgAll.Done() }() @@ -120,7 +120,7 @@ func TestBatchInTimeAndCountMode_CountMet(t *testing.T) { time.Sleep(time.Second * 10) wgFirst.Done() }() - continuePipeline1, _ := bs.Batch(context, []byte(dataToBatch[0])) + continuePipeline1, _ := bs.Batch(ctx, []byte(dataToBatch[0])) assert.False(t, continuePipeline1) wgAll.Done() }() @@ -130,14 +130,14 @@ func TestBatchInTimeAndCountMode_CountMet(t *testing.T) { time.Sleep(time.Second * 10) wgSecond.Done() }() - continuePipeline2, _ := bs.Batch(context, []byte(dataToBatch[0])) + continuePipeline2, _ := bs.Batch(ctx, []byte(dataToBatch[0])) assert.False(t, continuePipeline2) wgAll.Done() }() go func() { wgFirst.Wait() wgSecond.Wait() - continuePipeline3, result := bs.Batch(context, []byte(dataToBatch[0])) + continuePipeline3, result := bs.Batch(ctx, []byte(dataToBatch[0])) assert.True(t, continuePipeline3) assert.Equal(t, 3, len(result.([][]byte))) assert.Nil(t, bs.batchData.all(), "Should have 0 records") @@ -159,21 +159,21 @@ func TestBatchInTimeMode(t *testing.T) { wgFirst.Done() }() - continuePipeline1, result := bs.Batch(context, []byte(dataToBatch[0])) + continuePipeline1, result := bs.Batch(ctx, []byte(dataToBatch[0])) assert.True(t, continuePipeline1) assert.Equal(t, 3, len(result.([][]byte))) wgAll.Done() }() go func() { wgFirst.Wait() - continuePipeline2, result := bs.Batch(context, []byte(dataToBatch[0])) + continuePipeline2, result := bs.Batch(ctx, []byte(dataToBatch[0])) assert.False(t, continuePipeline2) assert.Nil(t, result) wgAll.Done() }() go func() { wgFirst.Wait() - continuePipeline3, _ := bs.Batch(context, []byte(dataToBatch[0])) + continuePipeline3, _ := bs.Batch(ctx, []byte(dataToBatch[0])) assert.False(t, continuePipeline3) wgAll.Done() }() diff --git a/pkg/transforms/compression_test.go b/pkg/transforms/compression_test.go index 941da2657..dc26bc061 100644 --- a/pkg/transforms/compression_test.go +++ b/pkg/transforms/compression_test.go @@ -38,7 +38,7 @@ const ( func TestGzip(t *testing.T) { comp := NewCompression() - continuePipeline, result := comp.CompressWithGZIP(context, []byte(clearString)) + continuePipeline, result := comp.CompressWithGZIP(ctx, []byte(clearString)) assert.True(t, continuePipeline) compressed, err := base64.StdEncoding.DecodeString(string(result.([]byte))) @@ -54,16 +54,16 @@ func TestGzip(t *testing.T) { require.NoError(t, err) require.Equal(t, clearString, string(decoded)) - continuePipeline2, result2 := comp.CompressWithGZIP(context, []byte(clearString)) + continuePipeline2, result2 := comp.CompressWithGZIP(ctx, []byte(clearString)) assert.True(t, continuePipeline2) assert.Equal(t, result.([]byte), result2.([]byte)) - assert.Equal(t, context.ResponseContentType(), clients.ContentTypeText) + assert.Equal(t, ctx.ResponseContentType(), clients.ContentTypeText) } func TestZlib(t *testing.T) { comp := NewCompression() - continuePipeline, result := comp.CompressWithZLIB(context, []byte(clearString)) + continuePipeline, result := comp.CompressWithZLIB(ctx, []byte(clearString)) assert.True(t, continuePipeline) require.NotNil(t, result) @@ -80,10 +80,10 @@ func TestZlib(t *testing.T) { require.NoError(t, err) require.Equal(t, clearString, string(decoded)) - continuePipeline2, result2 := comp.CompressWithZLIB(context, []byte(clearString)) + continuePipeline2, result2 := comp.CompressWithZLIB(ctx, []byte(clearString)) assert.True(t, continuePipeline2) assert.Equal(t, result.([]byte), result2.([]byte)) - assert.Equal(t, context.ResponseContentType(), clients.ContentTypeText) + assert.Equal(t, ctx.ResponseContentType(), clients.ContentTypeText) } var result []byte @@ -94,7 +94,7 @@ func BenchmarkGzip(b *testing.B) { var enc interface{} for i := 0; i < b.N; i++ { - _, enc = comp.CompressWithGZIP(context, []byte(clearString)) + _, enc = comp.CompressWithGZIP(ctx, []byte(clearString)) } b.SetBytes(int64(len(enc.([]byte)))) result = enc.([]byte) @@ -106,7 +106,7 @@ func BenchmarkZlib(b *testing.B) { var enc interface{} for i := 0; i < b.N; i++ { - _, enc = comp.CompressWithZLIB(context, []byte(clearString)) + _, enc = comp.CompressWithZLIB(ctx, []byte(clearString)) } b.SetBytes(int64(len(enc.([]byte)))) result = enc.([]byte) diff --git a/pkg/transforms/conversion_test.go b/pkg/transforms/conversion_test.go index 4b7d261a2..36b977f90 100644 --- a/pkg/transforms/conversion_test.go +++ b/pkg/transforms/conversion_test.go @@ -33,17 +33,17 @@ func TestTransformToXML(t *testing.T) { expectedResult := `device10` conv := NewConversion() - continuePipeline, result := conv.TransformToXML(context, eventIn) + continuePipeline, result := conv.TransformToXML(ctx, eventIn) assert.NotNil(t, result) assert.True(t, continuePipeline) - assert.Equal(t, clients.ContentTypeXML, context.ResponseContentType()) + assert.Equal(t, clients.ContentTypeXML, ctx.ResponseContentType()) assert.Equal(t, expectedResult, result.(string)) } func TestTransformToXMLNoData(t *testing.T) { conv := NewConversion() - continuePipeline, result := conv.TransformToXML(context, nil) + continuePipeline, result := conv.TransformToXML(ctx, nil) assert.Equal(t, "No Event Received", result.(error).Error()) assert.False(t, continuePipeline) @@ -51,7 +51,7 @@ func TestTransformToXMLNoData(t *testing.T) { func TestTransformToXMLNotAnEvent(t *testing.T) { conv := NewConversion() - continuePipeline, result := conv.TransformToXML(context, "") + continuePipeline, result := conv.TransformToXML(ctx, "") assert.Equal(t, "Unexpected type received", result.(error).Error()) assert.False(t, continuePipeline) @@ -65,17 +65,17 @@ func TestTransformToJSON(t *testing.T) { } expectedResult := `{"apiVersion":"","id":"","deviceName":"device1","profileName":"","sourceName":"","origin":0,"readings":null}` conv := NewConversion() - continuePipeline, result := conv.TransformToJSON(context, eventIn) + continuePipeline, result := conv.TransformToJSON(ctx, eventIn) assert.NotNil(t, result) assert.True(t, continuePipeline) - assert.Equal(t, clients.ContentTypeJSON, context.ResponseContentType()) + assert.Equal(t, clients.ContentTypeJSON, ctx.ResponseContentType()) assert.Equal(t, expectedResult, result.(string)) } func TestTransformToJSONNoEvent(t *testing.T) { conv := NewConversion() - continuePipeline, result := conv.TransformToJSON(context, nil) + continuePipeline, result := conv.TransformToJSON(ctx, nil) assert.Equal(t, "No Event Received", result.(error).Error()) assert.False(t, continuePipeline) @@ -84,7 +84,7 @@ func TestTransformToJSONNoEvent(t *testing.T) { func TestTransformToJSONNotAnEvent(t *testing.T) { conv := NewConversion() - continuePipeline, result := conv.TransformToJSON(context, "") + continuePipeline, result := conv.TransformToJSON(ctx, "") require.EqualError(t, result.(error), "Unexpected type received") assert.False(t, continuePipeline) } diff --git a/pkg/transforms/coredata.go b/pkg/transforms/coredata.go index 6cc3b2744..3e421124e 100644 --- a/pkg/transforms/coredata.go +++ b/pkg/transforms/coredata.go @@ -13,39 +13,84 @@ // See the License for the specific language governing permissions and // limitations under the License. // + package transforms import ( + "context" "errors" "github.com/edgexfoundry/app-functions-sdk-go/v2/pkg/interfaces" "github.com/edgexfoundry/app-functions-sdk-go/v2/pkg/util" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/requests" ) type CoreData struct { - DeviceName string - ReadingName string + profileName string + deviceName string + resourceName string + valueType string + mediaType string +} + +// NewCoreDataSimpleReading Is provided to interact with CoreData to add a simple reading +func NewCoreDataSimpleReading(profileName string, deviceName string, resourceName string, valueType string) *CoreData { + coreData := &CoreData{ + profileName: profileName, + deviceName: deviceName, + resourceName: resourceName, + valueType: valueType, + } + return coreData } -// NewCoreData Is provided to interact with CoreData -func NewCoreData() *CoreData { - coreData := &CoreData{} +// NewCoreDataBinaryReading Is provided to interact with CoreData to add a binary reading +func NewCoreDataBinaryReading(profileName string, deviceName string, resourceName string, mediaType string) *CoreData { + coreData := &CoreData{ + profileName: profileName, + deviceName: deviceName, + resourceName: resourceName, + valueType: v2.ValueTypeBinary, + mediaType: mediaType, + } return coreData } // PushToCoreData pushes the provided value as an event to CoreData using the device name and reading name that have been set. If validation is turned on in // CoreServices then your deviceName and readingName must exist in the CoreMetadata and be properly registered in EdgeX. func (cdc *CoreData) PushToCoreData(ctx interfaces.AppFunctionContext, data interface{}) (bool, interface{}) { + ctx.LoggingClient().Info("Pushing To CoreData...") + if data == nil { - return false, errors.New("No Data Received") + return false, errors.New("PushToCoreData - No Data Received") } - val, err := util.CoerceType(data) - if err != nil { - return false, err + client := ctx.EventClient() + if client == nil { + return false, errors.New("EventClient not initialized. Core Data is missing from clients configuration") + } + + event := dtos.NewEvent(cdc.profileName, cdc.deviceName, cdc.resourceName) + if cdc.valueType == v2.ValueTypeBinary { + reading, err := util.CoerceType(data) + if err != nil { + return false, err + } + event.AddBinaryReading(cdc.resourceName, reading, cdc.mediaType) + } else if cdc.valueType == v2.ValueTypeString { + reading, err := util.CoerceType(data) + if err != nil { + return false, err + } + event.AddSimpleReading(cdc.resourceName, cdc.valueType, string(reading)) + } else { + event.AddSimpleReading(cdc.resourceName, cdc.valueType, data) } - result, err := ctx.PushToCoreData(cdc.DeviceName, cdc.ReadingName, val) + request := requests.NewAddEventRequest(event) + result, err := client.Add(context.Background(), request) if err != nil { return false, err } diff --git a/pkg/transforms/coredata_test.go b/pkg/transforms/coredata_test.go index bc69a7b3f..c55d3f68c 100644 --- a/pkg/transforms/coredata_test.go +++ b/pkg/transforms/coredata_test.go @@ -18,26 +18,23 @@ package transforms import ( "testing" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2" "github.com/stretchr/testify/assert" ) func TestPushToCore_ShouldFailPipelineOnError(t *testing.T) { - coreData := NewCoreData() - coreData.DeviceName = "my-device" - coreData.ReadingName = "my-device-resource" - continuePipeline, result := coreData.PushToCoreData(context, "something") + coreData := NewCoreDataSimpleReading("MyProfile", "MyDevice", "MyResource", v2.ValueTypeInt32) + continuePipeline, result := coreData.PushToCoreData(ctx, "something") assert.NotNil(t, result) assert.False(t, continuePipeline) } func TestPushToCore_NoData(t *testing.T) { - coreData := NewCoreData() - coreData.DeviceName = "my-device" - coreData.ReadingName = "my-device-resource" - continuePipeline, result := coreData.PushToCoreData(context, nil) + coreData := NewCoreDataSimpleReading("MyProfile", "MyDevice", "MyResource", v2.ValueTypeInt32) + continuePipeline, result := coreData.PushToCoreData(ctx, nil) assert.NotNil(t, result) - assert.Equal(t, "No Data Received", result.(error).Error()) + assert.Equal(t, "PushToCoreData - No Data Received", result.(error).Error()) assert.False(t, continuePipeline) } diff --git a/pkg/transforms/encryption_test.go b/pkg/transforms/encryption_test.go index 0d595a195..d77a531bd 100644 --- a/pkg/transforms/encryption_test.go +++ b/pkg/transforms/encryption_test.go @@ -78,13 +78,13 @@ func pkcs5Trimming(encrypt []byte) []byte { func TestNewEncryption(t *testing.T) { enc := NewEncryption(aesData.Key, aesData.InitVector) - continuePipeline, encrypted := enc.EncryptWithAES(context, []byte(plainString)) + continuePipeline, encrypted := enc.EncryptWithAES(ctx, []byte(plainString)) assert.True(t, continuePipeline) decrypted := aesDecrypt(encrypted.([]byte), aesData) assert.Equal(t, plainString, string(decrypted)) - assert.Equal(t, context.ResponseContentType(), clients.ContentTypeText) + assert.Equal(t, ctx.ResponseContentType(), clients.ContentTypeText) } func TestNewEncryptionWithSecrets(t *testing.T) { @@ -102,13 +102,13 @@ func TestNewEncryptionWithSecrets(t *testing.T) { enc := NewEncryptionWithSecrets(secretPath, secretName, aesData.InitVector) - continuePipeline, encrypted := enc.EncryptWithAES(context, []byte(plainString)) + continuePipeline, encrypted := enc.EncryptWithAES(ctx, []byte(plainString)) assert.True(t, continuePipeline) decrypted := aesDecrypt(encrypted.([]byte), aesData) assert.Equal(t, plainString, string(decrypted)) - assert.Equal(t, context.ResponseContentType(), clients.ContentTypeText) + assert.Equal(t, ctx.ResponseContentType(), clients.ContentTypeText) } func TestAESNoData(t *testing.T) { @@ -120,7 +120,7 @@ func TestAESNoData(t *testing.T) { enc := NewEncryption(aesData.Key, aesData.InitVector) - continuePipeline, result := enc.EncryptWithAES(context, nil) + continuePipeline, result := enc.EncryptWithAES(ctx, nil) assert.False(t, continuePipeline) assert.Error(t, result.(error), "expect an error") } diff --git a/pkg/transforms/filter_test.go b/pkg/transforms/filter_test.go index 2cc7d76bb..8a136fc9f 100644 --- a/pkg/transforms/filter_test.go +++ b/pkg/transforms/filter_test.go @@ -76,11 +76,11 @@ func TestFilter_FilterByProfileName(t *testing.T) { expectedContinue := !test.ExpectedNilResult if test.EventIn == nil { - continuePipeline, result := filter.FilterByProfileName(context, nil) + continuePipeline, result := filter.FilterByProfileName(ctx, nil) assert.EqualError(t, result.(error), "FilterByProfileName: no Event Received") assert.False(t, continuePipeline) } else { - continuePipeline, result := filter.FilterByProfileName(context, *test.EventIn) + continuePipeline, result := filter.FilterByProfileName(ctx, *test.EventIn) assert.Equal(t, expectedContinue, continuePipeline) assert.Equal(t, test.ExpectedNilResult, result == nil) if result != nil && test.EventIn != nil { @@ -126,11 +126,11 @@ func TestFilter_FilterByDeviceName(t *testing.T) { expectedContinue := !test.ExpectedNilResult if test.EventIn == nil { - continuePipeline, result := filter.FilterByDeviceName(context, nil) + continuePipeline, result := filter.FilterByDeviceName(ctx, nil) assert.EqualError(t, result.(error), "FilterByDeviceName: no Event Received") assert.False(t, continuePipeline) } else { - continuePipeline, result := filter.FilterByDeviceName(context, *test.EventIn) + continuePipeline, result := filter.FilterByDeviceName(ctx, *test.EventIn) assert.Equal(t, expectedContinue, continuePipeline) assert.Equal(t, test.ExpectedNilResult, result == nil) if result != nil && test.EventIn != nil { @@ -176,11 +176,11 @@ func TestFilter_FilterBySourceName(t *testing.T) { expectedContinue := !test.ExpectedNilResult if test.EventIn == nil { - continuePipeline, result := filter.FilterBySourceName(context, nil) + continuePipeline, result := filter.FilterBySourceName(ctx, nil) assert.EqualError(t, result.(error), "FilterBySourceName: no Event Received") assert.False(t, continuePipeline) } else { - continuePipeline, result := filter.FilterBySourceName(context, *test.EventIn) + continuePipeline, result := filter.FilterBySourceName(ctx, *test.EventIn) assert.Equal(t, expectedContinue, continuePipeline) assert.Equal(t, test.ExpectedNilResult, result == nil) if result != nil && test.EventIn != nil { @@ -256,11 +256,11 @@ func TestFilter_FilterByResourceName(t *testing.T) { expectedContinue := !test.ExpectedNilResult if test.EventIn == nil { - continuePipeline, result := filter.FilterByResourceName(context, nil) + continuePipeline, result := filter.FilterByResourceName(ctx, nil) assert.EqualError(t, result.(error), "FilterByResourceName: no Event Received") assert.False(t, continuePipeline) } else { - continuePipeline, result := filter.FilterByResourceName(context, *test.EventIn) + continuePipeline, result := filter.FilterByResourceName(ctx, *test.EventIn) assert.Equal(t, expectedContinue, continuePipeline) assert.Equal(t, test.ExpectedNilResult, result == nil) if result != nil { diff --git a/pkg/transforms/http_test.go b/pkg/transforms/http_test.go index f315e1fb9..2cd147f81 100644 --- a/pkg/transforms/http_test.go +++ b/pkg/transforms/http_test.go @@ -108,8 +108,8 @@ func TestHTTPPostPut(t *testing.T) { for _, test := range tests { t.Run(test.Name, func(t *testing.T) { - context.AddValue("test", "foo") - context.SetRetryData(nil) + ctx.AddValue("test", "foo") + ctx.SetRetryData(nil) methodUsed = "" sender := NewHTTPSender(`http://`+targetUrl.Host+test.Path, "", test.PersistOnFail) sender.returnInputData = test.ReturnInputData @@ -118,9 +118,9 @@ func TestHTTPPostPut(t *testing.T) { var resultData interface{} if test.ExpectedMethod == http.MethodPost { - continueExecuting, resultData = sender.HTTPPost(context, msgStr) + continueExecuting, resultData = sender.HTTPPost(ctx, msgStr) } else { - continueExecuting, resultData = sender.HTTPPut(context, msgStr) + continueExecuting, resultData = sender.HTTPPut(ctx, msgStr) } assert.Equal(t, test.ExpectedContinueExecuting, continueExecuting) @@ -132,9 +132,9 @@ func TestHTTPPostPut(t *testing.T) { assert.NotEqual(t, msgStr, resultData) } } - assert.Equal(t, test.RetryDataSet, context.RetryData() != nil) + assert.Equal(t, test.RetryDataSet, ctx.RetryData() != nil) assert.Equal(t, test.ExpectedMethod, methodUsed) - context.RemoveValue("test") + ctx.RemoveValue("test") }) } } @@ -214,7 +214,7 @@ func TestHTTPPostPutWithSecrets(t *testing.T) { for _, test := range tests { t.Run(test.Name, func(t *testing.T) { - context.AddValue("test", "foo") + ctx.AddValue("test", "foo") methodUsed = "" sender := NewHTTPSenderWithSecretHeader( `http://`+targetUrl.Host+test.Path, @@ -228,9 +228,9 @@ func TestHTTPPostPutWithSecrets(t *testing.T) { var err interface{} if test.ExpectedMethod == http.MethodPost { - continuePipeline, err = sender.HTTPPost(context, msgStr) + continuePipeline, err = sender.HTTPPost(ctx, msgStr) } else { - continuePipeline, err = sender.HTTPPut(context, msgStr) + continuePipeline, err = sender.HTTPPut(ctx, msgStr) } assert.Equal(t, test.ExpectToContinue, continuePipeline) @@ -238,14 +238,14 @@ func TestHTTPPostPutWithSecrets(t *testing.T) { require.EqualError(t, err.(error), test.ExpectedErrorMessage) } assert.Equal(t, test.ExpectedMethod, methodUsed) - context.RemoveValue("test") + ctx.RemoveValue("test") }) } } func TestHTTPPostNoParameterPassed(t *testing.T) { sender := NewHTTPSender("", "", false) - continuePipeline, result := sender.HTTPPost(context, nil) + continuePipeline, result := sender.HTTPPost(ctx, nil) assert.False(t, continuePipeline, "Pipeline should stop") assert.Error(t, result.(error), "Result should be an error") @@ -254,7 +254,7 @@ func TestHTTPPostNoParameterPassed(t *testing.T) { func TestHTTPPutNoParameterPassed(t *testing.T) { sender := NewHTTPSender("", "", false) - continuePipeline, result := sender.HTTPPut(context, nil) + continuePipeline, result := sender.HTTPPut(ctx, nil) assert.False(t, continuePipeline, "Pipeline should stop") assert.Error(t, result.(error), "Result should be an error") @@ -265,7 +265,7 @@ func TestHTTPPostInvalidParameter(t *testing.T) { sender := NewHTTPSender("", "", false) // Channels are not marshalable to JSON and generate an error data := make(chan int) - continuePipeline, result := sender.HTTPPost(context, data) + continuePipeline, result := sender.HTTPPost(ctx, data) assert.False(t, continuePipeline, "Pipeline should stop") assert.Error(t, result.(error), "Result should be an error") @@ -277,7 +277,7 @@ func TestHTTPPutInvalidParameter(t *testing.T) { sender := NewHTTPSender("", "", false) // Channels are not marshalable to JSON and generate an error data := make(chan int) - continuePipeline, result := sender.HTTPPut(context, data) + continuePipeline, result := sender.HTTPPut(ctx, data) assert.False(t, continuePipeline, "Pipeline should stop") assert.Error(t, result.(error), "Result should be an error") diff --git a/pkg/transforms/jsonlogic_test.go b/pkg/transforms/jsonlogic_test.go index fd7a5a64c..8d6b25d30 100644 --- a/pkg/transforms/jsonlogic_test.go +++ b/pkg/transforms/jsonlogic_test.go @@ -27,7 +27,7 @@ import ( func TestJSONLogicSimple(t *testing.T) { jsonLogic := NewJSONLogic(`{"==": [1, 1]}`) - continuePipeline, result := jsonLogic.Evaluate(context, "{}") + continuePipeline, result := jsonLogic.Evaluate(ctx, "{}") assert.NotNil(t, result) assert.True(t, continuePipeline) @@ -41,7 +41,7 @@ func TestJSONLogicAdvanced(t *testing.T) { ] }`) data := `{ "temp" : 100, "sensor" : { "type" : "temperature" } }` - continuePipeline, result := jsonLogic.Evaluate(context, data) + continuePipeline, result := jsonLogic.Evaluate(ctx, data) assert.NotNil(t, result) assert.True(t, continuePipeline) @@ -52,7 +52,7 @@ func TestJSONLogicMalformedJSONRule(t *testing.T) { //missing quote jsonLogic := NewJSONLogic(`{"==: [1, 1]}`) - continuePipeline, result := jsonLogic.Evaluate(context, `{}`) + continuePipeline, result := jsonLogic.Evaluate(ctx, `{}`) assert.NotNil(t, result) assert.False(t, continuePipeline) @@ -63,7 +63,7 @@ func TestJSONLogicValidJSONBadRule(t *testing.T) { //missing quote jsonLogic := NewJSONLogic(`{"notAnOperator": [1, 1]}`) - continuePipeline, result := jsonLogic.Evaluate(context, `{}`) + continuePipeline, result := jsonLogic.Evaluate(ctx, `{}`) assert.NotNil(t, result) assert.False(t, continuePipeline) @@ -75,7 +75,7 @@ func TestJSONLogicNoData(t *testing.T) { //missing quote jsonLogic := NewJSONLogic(`{"notAnOperator": [1, 1]}`) - continuePipeline, result := jsonLogic.Evaluate(context, nil) + continuePipeline, result := jsonLogic.Evaluate(ctx, nil) assert.NotNil(t, result) assert.False(t, continuePipeline) @@ -86,7 +86,7 @@ func TestJSONLogicNonJSONData(t *testing.T) { //missing quote jsonLogic := NewJSONLogic(`{"==": [1, 1]}`) - continuePipeline, result := jsonLogic.Evaluate(context, "iAmNotJson") + continuePipeline, result := jsonLogic.Evaluate(ctx, "iAmNotJson") assert.NotNil(t, result) assert.False(t, continuePipeline) diff --git a/pkg/transforms/mqttsecret_test.go b/pkg/transforms/mqttsecret_test.go index 2d1e92605..8ac634f7b 100644 --- a/pkg/transforms/mqttsecret_test.go +++ b/pkg/transforms/mqttsecret_test.go @@ -27,25 +27,25 @@ import ( ) func TestMQTTSecretSender_setRetryDataPersistFalse(t *testing.T) { - context.SetRetryData(nil) + ctx.SetRetryData(nil) sender := NewMQTTSecretSender(MQTTSecretConfig{}, false) sender.mqttConfig = MQTTSecretConfig{} - sender.setRetryData(context, []byte("data")) - assert.Nil(t, context.RetryData()) + sender.setRetryData(ctx, []byte("data")) + assert.Nil(t, ctx.RetryData()) } func TestMQTTSecretSender_setRetryDataPersistTrue(t *testing.T) { - context.SetRetryData(nil) + ctx.SetRetryData(nil) sender := NewMQTTSecretSender(MQTTSecretConfig{}, true) sender.mqttConfig = MQTTSecretConfig{} - sender.setRetryData(context, []byte("data")) - assert.Equal(t, []byte("data"), context.RetryData()) + sender.setRetryData(ctx, []byte("data")) + assert.Equal(t, []byte("data"), ctx.RetryData()) } func TestMQTTSecretSender_MQTTSendNodata(t *testing.T) { sender := NewMQTTSecretSender(MQTTSecretConfig{}, true) sender.mqttConfig = MQTTSecretConfig{} - continuePipeline, result := sender.MQTTSend(context, nil) + continuePipeline, result := sender.MQTTSend(ctx, nil) require.False(t, continuePipeline) require.Error(t, result.(error)) } diff --git a/pkg/transforms/responsedata_test.go b/pkg/transforms/responsedata_test.go index 856936aec..d17cb5be6 100644 --- a/pkg/transforms/responsedata_test.go +++ b/pkg/transforms/responsedata_test.go @@ -31,12 +31,12 @@ func TestSetResponseDataString(t *testing.T) { expected := getExpectedEventXml(t) target := NewResponseData() - continuePipeline, result := target.SetResponseData(context, expected) + continuePipeline, result := target.SetResponseData(ctx, expected) assert.True(t, continuePipeline) assert.NotNil(t, result) - actual := string(context.ResponseData()) + actual := string(ctx.ResponseData()) assert.Equal(t, expected, actual) } @@ -44,11 +44,11 @@ func TestSetResponseDataBytes(t *testing.T) { expected := []byte(getExpectedEventXml(t)) target := NewResponseData() - continuePipeline, result := target.SetResponseData(context, expected) + continuePipeline, result := target.SetResponseData(ctx, expected) assert.True(t, continuePipeline) assert.NotNil(t, result) - actual := string(context.ResponseData()) + actual := string(ctx.ResponseData()) assert.Equal(t, string(expected), actual) } @@ -61,17 +61,17 @@ func TestSetResponseDataEvent(t *testing.T) { expected, _ := json.Marshal(eventIn) - continuePipeline, result := target.SetResponseData(context, eventIn) + continuePipeline, result := target.SetResponseData(ctx, eventIn) assert.True(t, continuePipeline) assert.NotNil(t, result) - actual := string(context.ResponseData()) + actual := string(ctx.ResponseData()) assert.Equal(t, string(expected), actual) } func TestSetResponseDataNoData(t *testing.T) { target := NewResponseData() - continuePipeline, result := target.SetResponseData(context, nil) + continuePipeline, result := target.SetResponseData(ctx, nil) assert.Nil(t, result) assert.False(t, continuePipeline) } @@ -80,7 +80,7 @@ func TestSetResponseDataBadType(t *testing.T) { target := NewResponseData() // Channels are not marshalable to JSON and generate an error - continuePipeline, result := target.SetResponseData(context, make(chan int)) + continuePipeline, result := target.SetResponseData(ctx, make(chan int)) assert.False(t, continuePipeline) require.NotNil(t, result) assert.Contains(t, result.(error).Error(), "passed in data must be of type") diff --git a/pkg/transforms/tags_test.go b/pkg/transforms/tags_test.go index d055e6f37..e02d04860 100644 --- a/pkg/transforms/tags_test.go +++ b/pkg/transforms/tags_test.go @@ -70,9 +70,9 @@ func TestTags_AddTags(t *testing.T) { target := NewTags(testCase.TagsToAdd) if testCase.FunctionInput != nil { - continuePipeline, result = target.AddTags(context, testCase.FunctionInput) + continuePipeline, result = target.AddTags(ctx, testCase.FunctionInput) } else { - continuePipeline, result = target.AddTags(context, nil) + continuePipeline, result = target.AddTags(ctx, nil) } if testCase.ErrorExpected { diff --git a/pkg/transforms/testmain_test.go b/pkg/transforms/testmain_test.go index 4eb1cbb78..41c607e2b 100644 --- a/pkg/transforms/testmain_test.go +++ b/pkg/transforms/testmain_test.go @@ -26,19 +26,17 @@ import ( bootstrapContainer "github.com/edgexfoundry/go-mod-bootstrap/v2/bootstrap/container" "github.com/edgexfoundry/go-mod-bootstrap/v2/di" - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients" - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/coredata" "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/logger" - "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/urlclient/local" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/http" ) var lc logger.LoggingClient var dic *di.Container -var context *appfunction.Context +var ctx *appfunction.Context func TestMain(m *testing.M) { lc = logger.NewMockClient() - eventClient := coredata.NewEventClient(local.New("http://test" + clients.ApiEventRoute)) + eventClient := http.NewEventClient("http://test") config := &common.ConfigurationStruct{} @@ -54,7 +52,7 @@ func TestMain(m *testing.M) { }, }) - context = appfunction.NewContext("123", dic, "") + ctx = appfunction.NewContext("123", dic, "") os.Exit(m.Run()) }