From f8890694ba2443089107554beff12780e39f030e Mon Sep 17 00:00:00 2001 From: Chris Hung Date: Thu, 16 Mar 2023 14:31:54 +0800 Subject: [PATCH] feat!: add 'discoveredDevice' for discovered device fields BREAKING CHANGE: add 'discoveredDevice' field which includes serviceName, profileName,adminState,autoEvents and properties for discovered device closes #813 Signed-off-by: Chris Hung --- dtos/discovereddevice.go | 55 ++++++++++++++++++++ dtos/provisionwatcher.go | 39 +++++--------- dtos/provisionwatcher_test.go | 10 ++-- dtos/requests/provisionwatcher.go | 29 ++++++----- dtos/requests/provisionwatcher_test.go | 71 +++++++++++++++----------- models/discovereddevice.go | 14 +++++ models/provisionwatcher.go | 7 +-- 7 files changed, 145 insertions(+), 80 deletions(-) create mode 100644 dtos/discovereddevice.go create mode 100644 models/discovereddevice.go diff --git a/dtos/discovereddevice.go b/dtos/discovereddevice.go new file mode 100644 index 00000000..8821d249 --- /dev/null +++ b/dtos/discovereddevice.go @@ -0,0 +1,55 @@ +// +// Copyright (C) 2023 IOTech Ltd +// +// SPDX-License-Identifier: Apache-2.0 + +package dtos + +import "github.com/edgexfoundry/go-mod-core-contracts/v3/models" + +type DiscoveredDevice struct { + ProfileName string `json:"profileName" yaml:"profileName" validate:"required,edgex-dto-none-empty-string,edgex-dto-rfc3986-unreserved-chars"` + ServiceName string `json:"serviceName" yaml:"serviceName" validate:"required,edgex-dto-none-empty-string,edgex-dto-rfc3986-unreserved-chars"` + AdminState string `json:"adminState" yaml:"adminState" validate:"oneof='LOCKED' 'UNLOCKED'"` + AutoEvents []AutoEvent `json:"autoEvents,omitempty" yaml:"autoEvents,omitempty" validate:"dive"` + Properties map[string]any `json:"properties,omitempty" yaml:"properties,omitempty"` +} + +type UpdateDiscoveredDevice struct { + ProfileName *string `json:"profileName" validate:"omitempty,edgex-dto-none-empty-string,edgex-dto-rfc3986-unreserved-chars"` + ServiceName *string `json:"serviceName" validate:"omitempty,edgex-dto-none-empty-string,edgex-dto-rfc3986-unreserved-chars"` + AdminState *string `json:"adminState" validate:"omitempty,oneof='LOCKED' 'UNLOCKED'"` + AutoEvents []AutoEvent `json:"autoEvents" validate:"dive"` + Properties map[string]any `json:"properties"` +} + +func ToDiscoveredDeviceModel(dto DiscoveredDevice) models.DiscoveredDevice { + return models.DiscoveredDevice{ + ProfileName: dto.ProfileName, + ServiceName: dto.ServiceName, + AdminState: models.AdminState(dto.AdminState), + AutoEvents: ToAutoEventModels(dto.AutoEvents), + Properties: dto.Properties, + } +} + +func FromDiscoveredDeviceModelToDTO(d models.DiscoveredDevice) DiscoveredDevice { + return DiscoveredDevice{ + ProfileName: d.ProfileName, + ServiceName: d.ServiceName, + AdminState: string(d.AdminState), + AutoEvents: FromAutoEventModelsToDTOs(d.AutoEvents), + Properties: d.Properties, + } +} + +func FromDiscoveredDeviceModelToUpdateDTO(d models.DiscoveredDevice) UpdateDiscoveredDevice { + adminState := string(d.AdminState) + return UpdateDiscoveredDevice{ + ProfileName: &d.ProfileName, + ServiceName: &d.ServiceName, + AdminState: &adminState, + AutoEvents: FromAutoEventModelsToDTOs(d.AutoEvents), + Properties: d.Properties, + } +} diff --git a/dtos/provisionwatcher.go b/dtos/provisionwatcher.go index 49355746..d27da3c2 100644 --- a/dtos/provisionwatcher.go +++ b/dtos/provisionwatcher.go @@ -18,26 +18,20 @@ type ProvisionWatcher struct { Labels []string `json:"labels,omitempty" yaml:"labels,omitempty"` Identifiers map[string]string `json:"identifiers" yaml:"identifiers" validate:"gt=0,dive,keys,required,endkeys,required"` BlockingIdentifiers map[string][]string `json:"blockingIdentifiers,omitempty" yaml:"blockingIdentifiers,omitempty"` - ProfileName string `json:"profileName" yaml:"profileName" validate:"required,edgex-dto-none-empty-string,edgex-dto-rfc3986-unreserved-chars"` - ServiceName string `json:"serviceName" yaml:"serviceName" validate:"required,edgex-dto-none-empty-string,edgex-dto-rfc3986-unreserved-chars"` AdminState string `json:"adminState" yaml:"adminState" validate:"oneof='LOCKED' 'UNLOCKED'"` - AutoEvents []AutoEvent `json:"autoEvents,omitempty" yaml:"autoEvents,omitempty" validate:"dive"` - Properties map[string]any `json:"properties,omitempty" yaml:"properties,omitempty"` + DiscoveredDevice DiscoveredDevice `json:"discoveredDevice" yaml:"discoveredDevice" validate:"dive"` } // UpdateProvisionWatcher and its properties are defined in the APIv2 specification: // https://app.swaggerhub.com/apis-docs/EdgeXFoundry1/core-metadata/2.1.0#/UpdateProvisionWatcher type UpdateProvisionWatcher struct { - Id *string `json:"id" validate:"required_without=Name,edgex-dto-uuid"` - Name *string `json:"name" validate:"required_without=Id,edgex-dto-none-empty-string,edgex-dto-rfc3986-unreserved-chars"` - Labels []string `json:"labels"` - Identifiers map[string]string `json:"identifiers" validate:"omitempty,gt=0,dive,keys,required,endkeys,required"` - BlockingIdentifiers map[string][]string `json:"blockingIdentifiers"` - ProfileName *string `json:"profileName" validate:"omitempty,edgex-dto-none-empty-string,edgex-dto-rfc3986-unreserved-chars"` - ServiceName *string `json:"serviceName" validate:"omitempty,edgex-dto-none-empty-string,edgex-dto-rfc3986-unreserved-chars"` - AdminState *string `json:"adminState" validate:"omitempty,oneof='LOCKED' 'UNLOCKED'"` - AutoEvents []AutoEvent `json:"autoEvents" validate:"dive"` - Properties map[string]any `json:"properties"` + Id *string `json:"id" validate:"required_without=Name,edgex-dto-uuid"` + Name *string `json:"name" validate:"required_without=Id,edgex-dto-none-empty-string,edgex-dto-rfc3986-unreserved-chars"` + Labels []string `json:"labels"` + Identifiers map[string]string `json:"identifiers" validate:"omitempty,gt=0,dive,keys,required,endkeys,required"` + BlockingIdentifiers map[string][]string `json:"blockingIdentifiers"` + AdminState *string `json:"adminState" validate:"omitempty,oneof='LOCKED' 'UNLOCKED'"` + DiscoveredDevice UpdateDiscoveredDevice `json:"discoveredDevice"` } // ToProvisionWatcherModel transforms the ProvisionWatcher DTO to the ProvisionWatcher model @@ -49,11 +43,8 @@ func ToProvisionWatcherModel(dto ProvisionWatcher) models.ProvisionWatcher { Labels: dto.Labels, Identifiers: dto.Identifiers, BlockingIdentifiers: dto.BlockingIdentifiers, - ProfileName: dto.ProfileName, - ServiceName: dto.ServiceName, AdminState: models.AdminState(dto.AdminState), - AutoEvents: ToAutoEventModels(dto.AutoEvents), - Properties: dto.Properties, + DiscoveredDevice: ToDiscoveredDeviceModel(dto.DiscoveredDevice), } } @@ -66,11 +57,8 @@ func FromProvisionWatcherModelToDTO(pw models.ProvisionWatcher) ProvisionWatcher Labels: pw.Labels, Identifiers: pw.Identifiers, BlockingIdentifiers: pw.BlockingIdentifiers, - ProfileName: pw.ProfileName, - ServiceName: pw.ServiceName, AdminState: string(pw.AdminState), - AutoEvents: FromAutoEventModelsToDTOs(pw.AutoEvents), - Properties: pw.Properties, + DiscoveredDevice: FromDiscoveredDeviceModelToDTO(pw.DiscoveredDevice), } } @@ -80,14 +68,11 @@ func FromProvisionWatcherModelToUpdateDTO(pw models.ProvisionWatcher) UpdateProv dto := UpdateProvisionWatcher{ Id: &pw.Id, Name: &pw.Name, - ProfileName: &pw.ProfileName, - ServiceName: &pw.ServiceName, - AdminState: &adminState, - AutoEvents: FromAutoEventModelsToDTOs(pw.AutoEvents), Labels: pw.Labels, Identifiers: pw.Identifiers, BlockingIdentifiers: pw.BlockingIdentifiers, - Properties: pw.Properties, + AdminState: &adminState, + DiscoveredDevice: FromDiscoveredDeviceModelToUpdateDTO(pw.DiscoveredDevice), } return dto } diff --git a/dtos/provisionwatcher_test.go b/dtos/provisionwatcher_test.go index 5c771718..5cf8aa81 100644 --- a/dtos/provisionwatcher_test.go +++ b/dtos/provisionwatcher_test.go @@ -1,5 +1,5 @@ // -// Copyright (C) 2021 IOTech Ltd +// Copyright (C) 2021-2023 IOTech Ltd // // SPDX-License-Identifier: Apache-2.0 @@ -21,8 +21,10 @@ func TestFromProvisionWatcherModelToUpdateDTO(t *testing.T) { assert.Equal(t, model.Labels, dto.Labels) assert.Nil(t, model.Identifiers, dto.Identifiers) assert.Nil(t, model.BlockingIdentifiers, dto.BlockingIdentifiers) - assert.Equal(t, model.ProfileName, *dto.ProfileName) - assert.Equal(t, model.ServiceName, *dto.ServiceName) assert.EqualValues(t, model.AdminState, *dto.AdminState) - assert.Equal(t, model.Properties, dto.Properties) + assert.Equal(t, model.DiscoveredDevice.ProfileName, *dto.DiscoveredDevice.ProfileName) + assert.Equal(t, model.DiscoveredDevice.ServiceName, *dto.DiscoveredDevice.ServiceName) + assert.EqualValues(t, model.DiscoveredDevice.AdminState, *dto.DiscoveredDevice.AdminState) + assert.Zero(t, model.DiscoveredDevice.AutoEvents) + assert.Equal(t, model.DiscoveredDevice.Properties, dto.DiscoveredDevice.Properties) } diff --git a/dtos/requests/provisionwatcher.go b/dtos/requests/provisionwatcher.go index f30e80c2..5159adde 100644 --- a/dtos/requests/provisionwatcher.go +++ b/dtos/requests/provisionwatcher.go @@ -1,5 +1,5 @@ // -// Copyright (C) 2021 IOTech Ltd +// Copyright (C) 2021-2023 IOTech Ltd // // SPDX-License-Identifier: Apache-2.0 @@ -24,7 +24,7 @@ type AddProvisionWatcherRequest struct { } // Validate satisfies the Validator interface -func (pw AddProvisionWatcherRequest) Validate() error { +func (pw *AddProvisionWatcherRequest) Validate() error { err := common.Validate(pw) return err } @@ -66,7 +66,7 @@ type UpdateProvisionWatcherRequest struct { } // Validate satisfies the Validator interface -func (pw UpdateProvisionWatcherRequest) Validate() error { +func (pw *UpdateProvisionWatcherRequest) Validate() error { err := common.Validate(pw) return err } @@ -101,20 +101,23 @@ func ReplaceProvisionWatcherModelFieldsWithDTO(pw *models.ProvisionWatcher, patc if patch.BlockingIdentifiers != nil { pw.BlockingIdentifiers = patch.BlockingIdentifiers } - if patch.ProfileName != nil { - pw.ProfileName = *patch.ProfileName - } - if patch.ServiceName != nil { - pw.ServiceName = *patch.ServiceName - } if patch.AdminState != nil { pw.AdminState = models.AdminState(*patch.AdminState) } - if patch.AutoEvents != nil { - pw.AutoEvents = dtos.ToAutoEventModels(patch.AutoEvents) + if patch.DiscoveredDevice.ProfileName != nil { + pw.DiscoveredDevice.ProfileName = *patch.DiscoveredDevice.ProfileName + } + if patch.DiscoveredDevice.ServiceName != nil { + pw.DiscoveredDevice.ServiceName = *patch.DiscoveredDevice.ServiceName + } + if patch.DiscoveredDevice.AdminState != nil { + pw.DiscoveredDevice.AdminState = models.AdminState(*patch.DiscoveredDevice.AdminState) + } + if patch.DiscoveredDevice.AutoEvents != nil { + pw.DiscoveredDevice.AutoEvents = dtos.ToAutoEventModels(patch.DiscoveredDevice.AutoEvents) } - if patch.Properties != nil { - pw.Properties = patch.Properties + if patch.DiscoveredDevice.Properties != nil { + pw.DiscoveredDevice.Properties = patch.DiscoveredDevice.Properties } } diff --git a/dtos/requests/provisionwatcher_test.go b/dtos/requests/provisionwatcher_test.go index d6443ed2..e6d7845b 100644 --- a/dtos/requests/provisionwatcher_test.go +++ b/dtos/requests/provisionwatcher_test.go @@ -1,5 +1,5 @@ // -// Copyright (C) 2021 IOTech Ltd +// Copyright (C) 2021-2023 IOTech Ltd // // SPDX-License-Identifier: Apache-2.0 @@ -37,10 +37,13 @@ var testAddProvisionWatcher = AddProvisionWatcherRequest{ Labels: testProvisionWatcherLabels, Identifiers: testIdentifiers, BlockingIdentifiers: testBlockingIdentifiers, - ServiceName: TestDeviceServiceName, - ProfileName: TestDeviceProfileName, AdminState: models.Locked, - AutoEvents: testAutoEvents, + DiscoveredDevice: dtos.DiscoveredDevice{ + ProfileName: TestDeviceProfileName, + ServiceName: TestDeviceServiceName, + AdminState: models.Locked, + AutoEvents: testAutoEvents, + }, }, } @@ -64,10 +67,11 @@ func mockUpdateProvisionWatcher() dtos.UpdateProvisionWatcher { d.Labels = testProvisionWatcherLabels d.Identifiers = testIdentifiers d.BlockingIdentifiers = testBlockingIdentifiers - d.ServiceName = &testDeviceServiceName - d.ProfileName = &testProfileName d.AdminState = &testAdminState - d.AutoEvents = testAutoEvents + d.DiscoveredDevice.ServiceName = &testDeviceServiceName + d.DiscoveredDevice.ProfileName = &testProfileName + d.DiscoveredDevice.AdminState = &testAdminState + d.DiscoveredDevice.AutoEvents = testAutoEvents return d } @@ -94,19 +98,19 @@ func TestAddProvisionWatcherRequest_Validate(t *testing.T) { "key": "", } noServiceName := testAddProvisionWatcher - noServiceName.ProvisionWatcher.ServiceName = emptyString + noServiceName.ProvisionWatcher.DiscoveredDevice.ServiceName = emptyString noProfileName := testAddProvisionWatcher - noProfileName.ProvisionWatcher.ProfileName = emptyString + noProfileName.ProvisionWatcher.DiscoveredDevice.ProfileName = emptyString invalidFrequency := testAddProvisionWatcher - invalidFrequency.ProvisionWatcher.AutoEvents = []dtos.AutoEvent{ + invalidFrequency.ProvisionWatcher.DiscoveredDevice.AutoEvents = []dtos.AutoEvent{ {SourceName: "TestDevice", Interval: "-1", OnChange: true}, } noAutoEventFrequency := testAddProvisionWatcher - noAutoEventFrequency.ProvisionWatcher.AutoEvents = []dtos.AutoEvent{ + noAutoEventFrequency.ProvisionWatcher.DiscoveredDevice.AutoEvents = []dtos.AutoEvent{ {SourceName: "TestDevice", OnChange: true}, } noAutoEventResource := testAddProvisionWatcher - noAutoEventResource.ProvisionWatcher.AutoEvents = []dtos.AutoEvent{ + noAutoEventResource.ProvisionWatcher.DiscoveredDevice.AutoEvents = []dtos.AutoEvent{ {Interval: "300ms", OnChange: true}, } @@ -181,11 +185,14 @@ func TestAddProvisionWatcherReqToProvisionWatcherModels(t *testing.T) { BlockingIdentifiers: map[string][]string{ "port": {"397", "398", "399"}, }, - ServiceName: TestDeviceServiceName, - ProfileName: TestDeviceProfileName, - AdminState: models.Locked, - AutoEvents: []models.AutoEvent{ - {SourceName: "TestDevice", Interval: "300ms", OnChange: true}, + AdminState: models.Locked, + DiscoveredDevice: models.DiscoveredDevice{ + ProfileName: TestDeviceProfileName, + ServiceName: TestDeviceServiceName, + AdminState: models.Locked, + AutoEvents: []models.AutoEvent{ + {SourceName: "TestDevice", Interval: "300ms", OnChange: true}, + }, }, }, } @@ -229,20 +236,20 @@ func TestUpdateProvisionWatcherRequest_Validate(t *testing.T) { invalidEmptyIdentifiers.ProvisionWatcher.Identifiers = emptyMap // ServiceName validNilServiceName := valid - validNilServiceName.ProvisionWatcher.ServiceName = nil + validNilServiceName.ProvisionWatcher.DiscoveredDevice.ServiceName = nil invalidEmptyServiceName := valid - invalidEmptyServiceName.ProvisionWatcher.ServiceName = &emptyString + invalidEmptyServiceName.ProvisionWatcher.DiscoveredDevice.ServiceName = &emptyString // ProfileName validNilProfileName := valid - validNilProfileName.ProvisionWatcher.ProfileName = nil + validNilProfileName.ProvisionWatcher.DiscoveredDevice.ProfileName = nil invalidEmptyProfileName := valid - invalidEmptyProfileName.ProvisionWatcher.ProfileName = &emptyString + invalidEmptyProfileName.ProvisionWatcher.DiscoveredDevice.ProfileName = &emptyString invalidState := "invalid state" invalidAdminState := valid invalidAdminState.ProvisionWatcher.AdminState = &invalidState invalidFrequency := valid - invalidFrequency.ProvisionWatcher.AutoEvents = testAutoEventsWithInvalidFrequency + invalidFrequency.ProvisionWatcher.DiscoveredDevice.AutoEvents = testAutoEventsWithInvalidFrequency tests := []struct { name string @@ -297,11 +304,11 @@ func TestUpdateProvisionWatcherRequest_UnmarshalJSON_NilField(t *testing.T) { assert.Nil(t, req.ProvisionWatcher.Labels) assert.Nil(t, req.ProvisionWatcher.Identifiers) assert.Nil(t, req.ProvisionWatcher.BlockingIdentifiers) - assert.Nil(t, req.ProvisionWatcher.ServiceName) - assert.Nil(t, req.ProvisionWatcher.ProfileName) + assert.Nil(t, req.ProvisionWatcher.DiscoveredDevice.ServiceName) + assert.Nil(t, req.ProvisionWatcher.DiscoveredDevice.ProfileName) assert.Nil(t, req.ProvisionWatcher.AdminState) - assert.Nil(t, req.ProvisionWatcher.AutoEvents) - assert.Nil(t, req.ProvisionWatcher.Properties) + assert.Nil(t, req.ProvisionWatcher.DiscoveredDevice.AutoEvents) + assert.Nil(t, req.ProvisionWatcher.DiscoveredDevice.Properties) } func TestUpdateProvisionWatcherRequest_UnmarshalJSON_EmptySlice(t *testing.T) { @@ -312,7 +319,9 @@ func TestUpdateProvisionWatcherRequest_UnmarshalJSON_EmptySlice(t *testing.T) { "apiVersion" : "v2", "name":"test-watcher", "labels":[], - "autoEvents":[] + "discoveredDevice":{ + "autoEvents":[] + } } }` var req UpdateProvisionWatcherRequest @@ -322,7 +331,7 @@ func TestUpdateProvisionWatcherRequest_UnmarshalJSON_EmptySlice(t *testing.T) { require.NoError(t, err) // Empty slice is used to remove the data assert.NotNil(t, req.ProvisionWatcher.Labels) - assert.NotNil(t, req.ProvisionWatcher.AutoEvents) + assert.NotNil(t, req.ProvisionWatcher.DiscoveredDevice.AutoEvents) } func TestReplaceProvisionWatcherModelFieldsWithDTO(t *testing.T) { @@ -337,8 +346,8 @@ func TestReplaceProvisionWatcherModelFieldsWithDTO(t *testing.T) { assert.Equal(t, testProvisionWatcherLabels, provisionWatcher.Labels) assert.Equal(t, testIdentifiers, provisionWatcher.Identifiers) assert.Equal(t, testBlockingIdentifiers, provisionWatcher.BlockingIdentifiers) - assert.Equal(t, TestDeviceServiceName, provisionWatcher.ServiceName) - assert.Equal(t, TestDeviceProfileName, provisionWatcher.ProfileName) + assert.Equal(t, TestDeviceServiceName, provisionWatcher.DiscoveredDevice.ServiceName) + assert.Equal(t, TestDeviceProfileName, provisionWatcher.DiscoveredDevice.ProfileName) assert.Equal(t, models.AdminState(models.Locked), provisionWatcher.AdminState) - assert.Equal(t, dtos.ToAutoEventModels(testAutoEvents), provisionWatcher.AutoEvents) + assert.Equal(t, dtos.ToAutoEventModels(testAutoEvents), provisionWatcher.DiscoveredDevice.AutoEvents) } diff --git a/models/discovereddevice.go b/models/discovereddevice.go new file mode 100644 index 00000000..4241b553 --- /dev/null +++ b/models/discovereddevice.go @@ -0,0 +1,14 @@ +// +// Copyright (C) 2023 IOTech Ltd +// +// SPDX-License-Identifier: Apache-2.0 + +package models + +type DiscoveredDevice struct { + ProfileName string + ServiceName string + AdminState AdminState + AutoEvents []AutoEvent + Properties map[string]any +} diff --git a/models/provisionwatcher.go b/models/provisionwatcher.go index a492bd5d..5eb66d34 100644 --- a/models/provisionwatcher.go +++ b/models/provisionwatcher.go @@ -1,5 +1,5 @@ // -// Copyright (C) 2021 IOTech Ltd +// Copyright (C) 2021-2023 IOTech Ltd // // SPDX-License-Identifier: Apache-2.0 @@ -15,9 +15,6 @@ type ProvisionWatcher struct { Labels []string Identifiers map[string]string BlockingIdentifiers map[string][]string - ProfileName string - ServiceName string AdminState AdminState - AutoEvents []AutoEvent - Properties map[string]any + DiscoveredDevice DiscoveredDevice }