Skip to content

Commit

Permalink
feat: Add unit tests for provision refactor, update to latest Load fu…
Browse files Browse the repository at this point in the history
…nction

Signed-off-by: Elizabeth J Lee <elizabeth.j.lee@intel.com>
  • Loading branch information
ejlee3 committed Jul 18, 2023
1 parent d09a2ea commit 2c47d96
Show file tree
Hide file tree
Showing 9 changed files with 444 additions and 56 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.20

require (
github.com/OneOfOne/xxhash v1.2.8
github.com/edgexfoundry/go-mod-bootstrap/v3 v3.1.0-dev.5
github.com/edgexfoundry/go-mod-bootstrap/v3 v3.1.0-dev.6
github.com/edgexfoundry/go-mod-core-contracts/v3 v3.1.0-dev.2
github.com/edgexfoundry/go-mod-messaging/v3 v3.1.0-dev.10
github.com/google/uuid v1.3.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/eclipse/paho.mqtt.golang v1.4.3 h1:2kwcUGn8seMUfWndX0hGbvH8r7crgcJguQNCyp70xik=
github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE=
github.com/edgexfoundry/go-mod-bootstrap/v3 v3.1.0-dev.5 h1:KdAEhHb1ETPLfhnrz/pKra7usnv6PVwXJBmHE+yUa4U=
github.com/edgexfoundry/go-mod-bootstrap/v3 v3.1.0-dev.5/go.mod h1:EHev55Vr5Xyhz1IbVbVngo+i0E1Cbb/Qia7ocHqE4qE=
github.com/edgexfoundry/go-mod-bootstrap/v3 v3.1.0-dev.6 h1:FzX0WfQU3frA4agk5/4OGJknHocUclSEmWsGkMFCVwY=
github.com/edgexfoundry/go-mod-bootstrap/v3 v3.1.0-dev.6/go.mod h1:EHev55Vr5Xyhz1IbVbVngo+i0E1Cbb/Qia7ocHqE4qE=
github.com/edgexfoundry/go-mod-configuration/v3 v3.1.0-dev.3 h1:xWyraOW+RtFwIO+DnCWBKoaa5w1ZX8vRf91zBa2Ll8c=
github.com/edgexfoundry/go-mod-configuration/v3 v3.1.0-dev.3/go.mod h1:yaxBuJh45+VxXX+nSt/Q+1gGEk4/BDe9edYWm8aEtfg=
github.com/edgexfoundry/go-mod-core-contracts/v3 v3.1.0-dev.2 h1:H3ls1vyxCv6pigZ/RZlRhj9lUTQq7CiT5/dnZRsgVmQ=
Expand Down
20 changes: 10 additions & 10 deletions internal/provision/devices.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ func LoadDevices(path string, dic *di.Container) errors.EdgeX {
}
if parsedUrl.Scheme == "http" || parsedUrl.Scheme == "https" {
secretProvider := bootstrapContainer.SecretProviderFrom(dic.Get)
edgexErr := loadDevicesFromUri(lc, path, serviceName, secretProvider, addDevicesReq)
edgexErr := loadDevicesFromUri(path, serviceName, secretProvider, lc, addDevicesReq)
if edgexErr != nil {
return edgexErr
}
} else {
edgexErr := loadDevicesFromFile(lc, path, serviceName, addDevicesReq)
edgexErr := loadDevicesFromFile(path, serviceName, lc, addDevicesReq)
if edgexErr != nil {
return edgexErr
}
Expand Down Expand Up @@ -92,7 +92,7 @@ func LoadDevices(path string, dic *di.Container) errors.EdgeX {
return nil
}

func loadDevicesFromFile(lc logger.LoggingClient, path string, serviceName string, addDevicesReq []requests.AddDeviceRequest) errors.EdgeX {
func loadDevicesFromFile(path string, serviceName string, lc logger.LoggingClient, addDevicesReq []requests.AddDeviceRequest) errors.EdgeX {
absPath, err := filepath.Abs(path)
if err != nil {
return errors.NewCommonEdgeX(errors.KindServerError, "failed to create absolute path", err)
Expand All @@ -111,18 +111,18 @@ func loadDevicesFromFile(lc logger.LoggingClient, path string, serviceName strin

for _, file := range files {
fullPath := filepath.Join(absPath, file.Name())
addDevicesReq = processDevices(lc, fullPath, serviceName, nil, addDevicesReq)
addDevicesReq = processDevices(fullPath, serviceName, nil, lc, addDevicesReq)
}
return nil
}

func loadDevicesFromUri(lc logger.LoggingClient, inputUri string, serviceName string, secretProvider interfaces.SecretProvider, addDevicesReq []requests.AddDeviceRequest) errors.EdgeX {
func loadDevicesFromUri(inputUri string, serviceName string, secretProvider interfaces.SecretProvider, lc logger.LoggingClient, addDevicesReq []requests.AddDeviceRequest) errors.EdgeX {
parsedUrl, err := url.Parse(inputUri)
if err != nil {
return errors.NewCommonEdgeX(errors.KindServerError, "could not parse uri for Provision Watcher", err)
return errors.NewCommonEdgeX(errors.KindServerError, "could not parse uri for Device", err)
}

bytes, err := file.Load(inputUri, timeout, secretProvider)
bytes, err := file.Load(inputUri, secretProvider, lc)
if err != nil {
return errors.NewCommonEdgeX(errors.KindServerError, fmt.Sprintf("failed to read uri %s", parsedUrl.Redacted()), err)
}
Expand Down Expand Up @@ -151,14 +151,14 @@ func loadDevicesFromUri(lc logger.LoggingClient, inputUri string, serviceName st
lc.Error("could not join uri path for device %s: %v", file, err)
continue
}
addDevicesReq = processDevices(lc, fullPath, serviceName, nil, addDevicesReq)
addDevicesReq = processDevices(fullPath, serviceName, secretProvider, lc, addDevicesReq)
}
return nil
}

func processDevices(lc logger.LoggingClient, fullPath string, serviceName string, secretProvider interfaces.SecretProvider, addDevicesReq []requests.AddDeviceRequest) []requests.AddDeviceRequest {
func processDevices(fullPath string, serviceName string, secretProvider interfaces.SecretProvider, lc logger.LoggingClient, addDevicesReq []requests.AddDeviceRequest) []requests.AddDeviceRequest {
var devices []dtos.Device
content, err := file.Load(fullPath, timeout, secretProvider)
content, err := file.Load(fullPath, secretProvider, lc)
if err != nil {
lc.Errorf("Failed to read %s: %v", fullPath, err)
return addDevicesReq
Expand Down
41 changes: 41 additions & 0 deletions internal/provision/devices_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// -*- Mode: Go; indent-tabs-mode: t -*-
//
// # Copyright (C) 2023 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
package provision

import (
"github.com/edgexfoundry/device-sdk-go/v3/internal/cache"
"github.com/edgexfoundry/go-mod-bootstrap/v3/bootstrap/interfaces"
"github.com/edgexfoundry/go-mod-core-contracts/v3/clients/logger"
"github.com/edgexfoundry/go-mod-core-contracts/v3/dtos/requests"
"github.com/stretchr/testify/assert"
"path"
"testing"
)

func Test_processDevices(t *testing.T) {
tests := []struct {
name string
path string
secretProvider interfaces.SecretProvider
expectedNumProfiles int
}{
{"valid load device from file", path.Join("..", "..", "example", "cmd", "device-simple", "res", "devices", "simple-device.yml"), nil, 1},
{"valid load device from uri", "https://github.com/raw/edgexfoundry/device-sdk-go/main/example/cmd/device-simple/res/devices/simple-device.yml", nil, 1},
{"invalid load device empty path", "", nil, 0},
{"invalid load device from file", path.Join("..", "..", "example", "cmd", "device-simple", "res", "devices", "bogus.yml"), nil, 0},
{"invalid load device invalid uri", "https://github.com/raw/edgexfoundry/device-sdk-go/main/example/cmd/device-simple/res/devices/bogus.yml", nil, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var addDeviceRequests []requests.AddDeviceRequest
lc := logger.MockLogger{}
dic, _ := NewMockDIC()
cache.InitCache(TestDeviceService, TestDeviceService, dic)
addDeviceRequests = processDevices(tt.path, TestDeviceService, tt.secretProvider, lc, addDeviceRequests)
assert.Equal(t, tt.expectedNumProfiles, len(addDeviceRequests))
})
}
}
119 changes: 119 additions & 0 deletions internal/provision/mockdic_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// -*- Mode: Go; indent-tabs-mode: t -*-
//
// # Copyright (C) 2023 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
package provision

import (
"context"
"github.com/edgexfoundry/device-sdk-go/v3/internal/config"
"github.com/edgexfoundry/device-sdk-go/v3/internal/container"
bootstrapContainer "github.com/edgexfoundry/go-mod-bootstrap/v3/bootstrap/container"
"github.com/edgexfoundry/go-mod-bootstrap/v3/di"
clientMocks "github.com/edgexfoundry/go-mod-core-contracts/v3/clients/interfaces/mocks"
"github.com/edgexfoundry/go-mod-core-contracts/v3/clients/logger"
"github.com/edgexfoundry/go-mod-core-contracts/v3/dtos"
"github.com/edgexfoundry/go-mod-core-contracts/v3/dtos/responses"
"github.com/edgexfoundry/go-mod-core-contracts/v3/models"
)

const (
TestDeviceService = "testDeviceService"
TestDeviceWithTags = "testDeviceWithTags"
TestDeviceWithoutTags = "testDeviceWithoutTags"
TestProfile = "testProfile"
TestDeviceResourceWithTags = "testResourceWithTags"
TestDeviceResourceWithoutTags = "testResourceWithoutTags"
TestDeviceCommandWithTags = "testCommandWithTags"
TestDeviceCommandWithoutTags = "testCommandWithoutTags"
TestResourceTagName = "testResourceTagName"
TestResourceTagValue = "testResourceTagValue"
TestCommandTagName = "testCommandTagName"
TestCommandTagValue = "testCommandTagValue"
TestDeviceTagName = "testDeviceTagName"
TestDeviceTagValue = "testDeviceTagValue"
TestDuplicateTagName = "testDuplicateTagName"
)

var profile = responses.DeviceProfileResponse{
Profile: dtos.DeviceProfile{
DeviceProfileBasicInfo: dtos.DeviceProfileBasicInfo{Name: TestProfile},
DeviceResources: []dtos.DeviceResource{
{
Name: TestDeviceResourceWithTags,
Tags: dtos.Tags{
TestResourceTagName: TestResourceTagValue,
},
},
{
Name: TestDeviceResourceWithoutTags,
},
},
DeviceCommands: []dtos.DeviceCommand{
{
Name: TestDeviceCommandWithTags,
Tags: dtos.Tags{
TestCommandTagName: TestCommandTagValue,
TestDuplicateTagName: TestCommandTagValue,
},
},
{
Name: TestDeviceCommandWithoutTags,
},
},
},
}

func NewMockDIC() (*di.Container, *clientMocks.DeviceProfileClient) {
configuration := &config.ConfigurationStruct{
Device: config.DeviceInfo{MaxCmdOps: 1},
}
deviceService := &models.DeviceService{Name: TestDeviceService}

devices := responses.MultiDevicesResponse{
Devices: []dtos.Device{
{
Name: TestDeviceWithTags,
ProfileName: TestProfile,
Tags: dtos.Tags{
TestDeviceTagName: TestDeviceTagValue,
TestDuplicateTagName: TestDeviceTagValue,
},
},
{
Name: TestDeviceWithoutTags,
ProfileName: TestProfile,
},
},
}
dcMock := &clientMocks.DeviceClient{}
dcMock.On("DevicesByServiceName", context.Background(), TestDeviceService, 0, -1).Return(devices, nil)

dpcMock := &clientMocks.DeviceProfileClient{}
dpcMock.On("DeviceProfileByName", context.Background(), TestProfile).Return(profile, nil)

pwcMock := &clientMocks.ProvisionWatcherClient{}
pwcMock.On("ProvisionWatchersByServiceName", context.Background(), TestDeviceService, 0, -1).Return(responses.MultiProvisionWatchersResponse{}, nil)

return di.NewContainer(di.ServiceConstructorMap{
container.ConfigurationName: func(get di.Get) interface{} {
return configuration
},
container.DeviceServiceName: func(get di.Get) any {
return deviceService
},
bootstrapContainer.LoggingClientInterfaceName: func(get di.Get) interface{} {
return logger.NewMockClient()
},
bootstrapContainer.DeviceClientName: func(get di.Get) interface{} {
return dcMock
},
bootstrapContainer.DeviceProfileClientName: func(get di.Get) interface{} {
return dpcMock
},
bootstrapContainer.ProvisionWatcherClientName: func(get di.Get) interface{} {
return pwcMock
},
}), dpcMock
}
45 changes: 22 additions & 23 deletions internal/provision/profiles.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,23 @@ import (
"context"
"encoding/json"
"fmt"
bootstrapContainer "github.com/edgexfoundry/go-mod-bootstrap/v3/bootstrap/container"
"github.com/edgexfoundry/go-mod-bootstrap/v3/bootstrap/file"
bootstrapInterfaces "github.com/edgexfoundry/go-mod-bootstrap/v3/bootstrap/interfaces"
"github.com/edgexfoundry/go-mod-bootstrap/v3/di"
"github.com/edgexfoundry/go-mod-core-contracts/v3/clients/interfaces"
"github.com/edgexfoundry/go-mod-core-contracts/v3/clients/logger"
"net/url"
"os"
"path"
"path/filepath"
"strings"
"time"

bootstrapContainer "github.com/edgexfoundry/go-mod-bootstrap/v3/bootstrap/container"
"github.com/edgexfoundry/go-mod-bootstrap/v3/di"
"github.com/edgexfoundry/go-mod-core-contracts/v3/common"
"github.com/edgexfoundry/go-mod-core-contracts/v3/dtos"
"github.com/edgexfoundry/go-mod-core-contracts/v3/dtos/requests"
"github.com/edgexfoundry/go-mod-core-contracts/v3/errors"
"github.com/google/uuid"
"gopkg.in/yaml.v3"
"net/url"
"os"
"path"
"path/filepath"
"strings"

"github.com/edgexfoundry/device-sdk-go/v3/internal/cache"
)
Expand All @@ -55,12 +53,12 @@ func LoadProfiles(path string, dic *di.Container) errors.EdgeX {

if parsedUrl.Scheme == "http" || parsedUrl.Scheme == "https" {
secretProvider := bootstrapContainer.SecretProviderFrom(dic.Get)
edgexErr := loadProfilesFromUri(lc, path, dpc, secretProvider, addProfilesReq)
edgexErr := loadProfilesFromUri(path, dpc, secretProvider, lc, addProfilesReq)
if edgexErr != nil {
return edgexErr
}
} else {
edgexErr := loadProfilesFromFile(lc, path, dpc, addProfilesReq)
edgexErr := loadProfilesFromFile(path, dpc, lc, addProfilesReq)
if edgexErr != nil {
return edgexErr
}
Expand All @@ -74,7 +72,7 @@ func LoadProfiles(path string, dic *di.Container) errors.EdgeX {
return edgexErr
}

func loadProfilesFromFile(lc logger.LoggingClient, path string, dpc interfaces.DeviceProfileClient, addProfilesReq []requests.DeviceProfileRequest) errors.EdgeX {
func loadProfilesFromFile(path string, dpc interfaces.DeviceProfileClient, lc logger.LoggingClient, addProfilesReq []requests.DeviceProfileRequest) errors.EdgeX {
var edgexErr errors.EdgeX
absPath, err := filepath.Abs(path)
if err != nil {
Expand All @@ -94,17 +92,22 @@ func loadProfilesFromFile(lc logger.LoggingClient, path string, dpc interfaces.D

for _, file := range files {
fullPath := filepath.Join(absPath, file.Name())
addProfilesReq, edgexErr = processProfiles(lc, fullPath, nil, dpc, addProfilesReq)
addProfilesReq, edgexErr = processProfiles(fullPath, nil, lc, dpc, addProfilesReq)
if edgexErr != nil {
return nil
}
}
return nil
}

func loadProfilesFromUri(lc logger.LoggingClient, inputUri string, dpc interfaces.DeviceProfileClient, secretProvider bootstrapInterfaces.SecretProvider, addProfilesReq []requests.DeviceProfileRequest) errors.EdgeX {
func loadProfilesFromUri(inputUri string, dpc interfaces.DeviceProfileClient, secretProvider bootstrapInterfaces.SecretProvider, lc logger.LoggingClient, addProfilesReq []requests.DeviceProfileRequest) errors.EdgeX {
var edgexErr errors.EdgeX
bytes, err := file.Load(inputUri, timeout, secretProvider)
parsedUrl, err := url.Parse(inputUri)
if err != nil {
return errors.NewCommonEdgeX(errors.KindServerError, "could not parse uri for Profile", err)
}

bytes, err := file.Load(inputUri, secretProvider, lc)
if err != nil {
return errors.NewCommonEdgeX(errors.KindServerError, "failed to read directory", err)
}
Expand All @@ -116,17 +119,13 @@ func loadProfilesFromUri(lc logger.LoggingClient, inputUri string, dpc interface
var files []string
err = json.Unmarshal(bytes, &files)
if err != nil {
return errors.NewCommonEdgeX(errors.KindServerError, "could not unmarshal Provision Watcher contents", err)
return errors.NewCommonEdgeX(errors.KindServerError, "could not unmarshal Profile contents", err)
}
if len(files) == 0 {
return nil
}

baseUrl, _ := path.Split(inputUri)
parsedUrl, err := url.Parse(inputUri)
if err != nil {
return errors.NewCommonEdgeX(errors.KindServerError, "could not parse uri for Provision Watcher", err)
}
lc.Infof("Loading pre-defined profiles from %s(%d files found)", parsedUrl.Redacted(), len(files))

for _, file := range files {
Expand All @@ -135,17 +134,17 @@ func loadProfilesFromUri(lc logger.LoggingClient, inputUri string, dpc interface
lc.Error("could not join uri path for profile %s: %v", file, err)
continue
}
addProfilesReq, edgexErr = processProfiles(lc, fullPath, secretProvider, dpc, addProfilesReq)
addProfilesReq, edgexErr = processProfiles(fullPath, secretProvider, lc, dpc, addProfilesReq)
if edgexErr != nil {
return edgexErr
}
}
return nil
}

func processProfiles(lc logger.LoggingClient, path string, secretProvider bootstrapInterfaces.SecretProvider, dpc interfaces.DeviceProfileClient, addProfilesReq []requests.DeviceProfileRequest) ([]requests.DeviceProfileRequest, errors.EdgeX) {
func processProfiles(path string, secretProvider bootstrapInterfaces.SecretProvider, lc logger.LoggingClient, dpc interfaces.DeviceProfileClient, addProfilesReq []requests.DeviceProfileRequest) ([]requests.DeviceProfileRequest, errors.EdgeX) {
var profile dtos.DeviceProfile
bytes, err := file.Load(path, 10*time.Second, secretProvider)
bytes, err := file.Load(path, secretProvider, lc)
if err != nil {
lc.Errorf("Failed to read %s: %v", path, err)
return addProfilesReq, nil
Expand Down
Loading

0 comments on commit 2c47d96

Please sign in to comment.