Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@
//

edgeXBuildGoMod (
project: 'go-mod-core-contracts'
project: 'go-mod-core-contracts',
goVersion: '1.23'
)
1 change: 1 addition & 0 deletions clients/http/deviceprofile.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func NewDeviceProfileClientWithUrlCallback(baseUrlFunc clients.ClientBaseUrlFunc
return &DeviceProfileClient{
baseUrlFunc: baseUrlFunc,
authInjector: authInjector,
resourcesCache: make(map[string]responses.DeviceResourceResponse),
enableNameFieldEscape: enableNameFieldEscape,
}
}
Expand Down
10 changes: 9 additions & 1 deletion clients/http/deviceprofile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,20 @@ import (
"github.com/edgexfoundry/go-mod-core-contracts/v4/dtos/requests"
"github.com/edgexfoundry/go-mod-core-contracts/v4/dtos/responses"
edgexErrors "github.com/edgexfoundry/go-mod-core-contracts/v4/errors"

"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestNewDeviceProfileClientWithUrlCallback(t *testing.T) {
baseUrlFunc := func() (string, error) {
return "", nil
}
client := NewDeviceProfileClientWithUrlCallback(baseUrlFunc, &emptyAuthenticationInjector{}, true)
require.NotNil(t, client)
require.NotNil(t, client.(*DeviceProfileClient).resourcesCache)
}

func TestAddDeviceProfiles(t *testing.T) {
requestId := uuid.New().String()

Expand Down
48 changes: 47 additions & 1 deletion models/device.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
//
// Copyright (C) 2020-2024 IOTech Ltd
// Copyright (C) 2020-2025 IOTech Ltd
//
// SPDX-License-Identifier: Apache-2.0

package models

import "maps"

type Device struct {
DBTimestamp
Id string
Expand All @@ -26,6 +28,12 @@ type Device struct {
// ProtocolProperties contains the device connection information in key/value pair
type ProtocolProperties map[string]any

func (p ProtocolProperties) Clone() ProtocolProperties {
cloned := make(map[string]any)
maps.Copy(cloned, p)
return cloned
}

// AdminState controls the range of values which constitute valid administrative states for a device
type AdminState string

Expand All @@ -39,3 +47,41 @@ func AssignAdminState(dtoAdminState string) AdminState {

// OperatingState is an indication of the operations of the device.
type OperatingState string

func (device Device) Clone() Device {
cloned := Device{
DBTimestamp: device.DBTimestamp,
Id: device.Id,
Name: device.Name,
Parent: device.Parent,
Description: device.Description,
AdminState: device.AdminState,
OperatingState: device.OperatingState,
Location: device.Location,
ServiceName: device.ServiceName,
ProfileName: device.ProfileName,
}
if len(device.Protocols) > 0 {
cloned.Protocols = make(map[string]ProtocolProperties)
for k, v := range device.Protocols {
cloned.Protocols[k] = v.Clone()
}
}
if len(device.Labels) > 0 {
cloned.Labels = make([]string, len(device.Labels))
copy(cloned.Labels, device.Labels)
}
if len(device.AutoEvents) > 0 {
cloned.AutoEvents = make([]AutoEvent, len(device.AutoEvents))
copy(cloned.AutoEvents, device.AutoEvents)
}
if len(device.Tags) > 0 {
cloned.Tags = make(map[string]any)
maps.Copy(cloned.Tags, device.Tags)
}
if len(device.Properties) > 0 {
cloned.Properties = make(map[string]any)
maps.Copy(cloned.Properties, device.Properties)
}
return cloned
}
44 changes: 44 additions & 0 deletions models/device_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (C) 2025 IOTech Ltd

package models

import (
"github.com/stretchr/testify/assert"
"testing"
)

func TestDevice_Clone(t *testing.T) {
testDevice := Device{
DBTimestamp: DBTimestamp{},
Id: "ca93c8fa-9919-4ec5-85d3-f81b2b6a7bc1",
Name: "testDevice",
Parent: "testParent",
Description: "testDescription",
AdminState: Locked,
OperatingState: Up,
Protocols: map[string]ProtocolProperties{"other": map[string]any{"Address": "127.0.0.1"}},
Labels: []string{"label1", "label2"},
Location: map[string]any{"loc": "x.y.z"},
ServiceName: "testServiceName",
ProfileName: "testProfileName",
AutoEvents: []AutoEvent{
{
Interval: "10s",
OnChange: false,
OnChangeThreshold: 0.5,
SourceName: "testSourceName",
Retention: Retention{
MaxCap: 500,
MinCap: 100,
Duration: "1m",
},
},
},
Tags: map[string]any{"tag1": "val1", "tag2": "val2"},
Properties: map[string]any{
"foo": "bar",
},
}
clone := testDevice.Clone()
assert.Equal(t, testDevice, clone)
}
23 changes: 22 additions & 1 deletion models/devicecommand.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,35 @@
//
// Copyright (C) 2020-2023 IOTech Ltd
// Copyright (C) 2020-2025 IOTech Ltd
//
// SPDX-License-Identifier: Apache-2.0

package models

import "maps"

type DeviceCommand struct {
Name string
IsHidden bool
ReadWrite string
ResourceOperations []ResourceOperation
Tags map[string]any
}

func (dc DeviceCommand) Clone() DeviceCommand {
cloned := DeviceCommand{
Name: dc.Name,
IsHidden: dc.IsHidden,
ReadWrite: dc.ReadWrite,
}
if len(dc.ResourceOperations) > 0 {
cloned.ResourceOperations = make([]ResourceOperation, len(dc.ResourceOperations))
for i, op := range dc.ResourceOperations {
cloned.ResourceOperations[i] = op.Clone()
}
}
if len(dc.Tags) > 0 {
cloned.Tags = make(map[string]any)
maps.Copy(cloned.Tags, dc.Tags)
}
return cloned
}
31 changes: 30 additions & 1 deletion models/deviceprofile.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Copyright (C) 2020-2024 IOTech Ltd
// Copyright (C) 2020-2025 IOTech Ltd
//
// SPDX-License-Identifier: Apache-2.0

Expand All @@ -17,3 +17,32 @@ type DeviceProfile struct {
DeviceResources []DeviceResource
DeviceCommands []DeviceCommand
}

func (profile DeviceProfile) Clone() DeviceProfile {
cloned := DeviceProfile{
DBTimestamp: profile.DBTimestamp,
ApiVersion: profile.ApiVersion,
Description: profile.Description,
Id: profile.Id,
Name: profile.Name,
Manufacturer: profile.Manufacturer,
Model: profile.Model,
}
if len(profile.Labels) > 0 {
cloned.Labels = make([]string, len(profile.Labels))
copy(cloned.Labels, profile.Labels)
}
if len(profile.DeviceResources) > 0 {
cloned.DeviceResources = make([]DeviceResource, len(profile.DeviceResources))
for i := range profile.DeviceResources {
cloned.DeviceResources[i] = profile.DeviceResources[i].Clone()
}
}
if len(profile.DeviceCommands) > 0 {
cloned.DeviceCommands = make([]DeviceCommand, len(profile.DeviceCommands))
for i := range profile.DeviceCommands {
cloned.DeviceCommands[i] = profile.DeviceCommands[i].Clone()
}
}
return cloned
}
60 changes: 60 additions & 0 deletions models/deviceprofile_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (C) 2025 IOTech Ltd

package models

import (
"github.com/edgexfoundry/go-mod-core-contracts/v4/common"
"github.com/stretchr/testify/assert"
"testing"
)

func TestDeviceProfile_Clone(t *testing.T) {
testMinimum := -1.123
testMaximum := 1.123
testDeviceProfile := DeviceProfile{
DBTimestamp: DBTimestamp{},
ApiVersion: common.ApiVersion,
Description: "test description",
Id: "ca93c8fa-9919-4ec5-85d3-f81b2b6a7bc1",
Name: "TestProfile",
Manufacturer: "testManufacturer",
Model: "testModel",
Labels: []string{"label1", "label2"},
DeviceResources: []DeviceResource{{
Description: "test description",
Name: "TestDeviceResource",
IsHidden: false,
Properties: ResourceProperties{
ValueType: common.ValueTypeString, Minimum: &testMinimum, Maximum: &testMaximum},
Attributes: map[string]any{
"foo": "bar",
},
Tags: map[string]any{
"tag1": "val1",
},
}},
DeviceCommands: []DeviceCommand{{
Name: "TestDeviceCommand",
IsHidden: false,
ReadWrite: "RW",
ResourceOperations: []ResourceOperation{{
DeviceResource: "TestDeviceResource1",
DefaultValue: "",
Mappings: map[string]string{
"on": "true",
},
}, {
DeviceResource: "TestDeviceResource2",
DefaultValue: "",
Mappings: map[string]string{
"off": "false",
},
}},
Tags: map[string]any{
"tag3": "val3",
},
}},
}
clone := testDeviceProfile.Clone()
assert.Equal(t, testDeviceProfile, clone)
}
22 changes: 21 additions & 1 deletion models/deviceresource.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
//
// Copyright (C) 2020-2023 IOTech Ltd
// Copyright (C) 2020-2025 IOTech Ltd
//
// SPDX-License-Identifier: Apache-2.0

package models

import "maps"

type DeviceResource struct {
Description string
Name string
Expand All @@ -13,3 +15,21 @@ type DeviceResource struct {
Attributes map[string]interface{}
Tags map[string]any
}

func (dr DeviceResource) Clone() DeviceResource {
cloned := DeviceResource{
Description: dr.Description,
Name: dr.Name,
IsHidden: dr.IsHidden,
Properties: dr.Properties.Clone(),
}
if len(dr.Attributes) > 0 {
cloned.Attributes = make(map[string]any)
maps.Copy(cloned.Attributes, dr.Attributes)
}
if len(dr.Tags) > 0 {
cloned.Tags = make(map[string]any)
maps.Copy(cloned.Tags, dr.Tags)
}
return cloned
}
20 changes: 19 additions & 1 deletion models/discovereddevice.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
//
// Copyright (C) 2023 IOTech Ltd
// Copyright (C) 2023-2025 IOTech Ltd
//
// SPDX-License-Identifier: Apache-2.0

package models

import "maps"

type DiscoveredDevice struct {
ProfileName string
AdminState AdminState
AutoEvents []AutoEvent
Properties map[string]any
}

func (d DiscoveredDevice) Clone() DiscoveredDevice {
cloned := DiscoveredDevice{
ProfileName: d.ProfileName,
AdminState: d.AdminState,
}
if len(d.AutoEvents) > 0 {
cloned.AutoEvents = make([]AutoEvent, len(d.AutoEvents))
copy(cloned.AutoEvents, d.AutoEvents)
}
if len(d.Properties) > 0 {
cloned.Properties = make(map[string]any)
maps.Copy(cloned.Properties, d.Properties)
}
return cloned
}
Loading