157 lines
5.7 KiB
Go
157 lines
5.7 KiB
Go
|
//
|
||
|
// Copyright (C) 2023-2025 IOTech Ltd
|
||
|
//
|
||
|
// SPDX-License-Identifier: Apache-2.0
|
||
|
|
||
|
package messaging
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"encoding/json"
|
||
|
"errors"
|
||
|
"os"
|
||
|
"sync"
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
bootstrapContainer "github.com/edgexfoundry/go-mod-bootstrap/v4/bootstrap/container"
|
||
|
"github.com/edgexfoundry/go-mod-bootstrap/v4/di"
|
||
|
loggerMocks "github.com/edgexfoundry/go-mod-core-contracts/v4/clients/logger/mocks"
|
||
|
"github.com/edgexfoundry/go-mod-core-contracts/v4/common"
|
||
|
"github.com/edgexfoundry/go-mod-core-contracts/v4/dtos"
|
||
|
"github.com/edgexfoundry/go-mod-core-contracts/v4/dtos/requests"
|
||
|
"github.com/edgexfoundry/go-mod-core-contracts/v4/models"
|
||
|
messagingMocks "github.com/edgexfoundry/go-mod-messaging/v4/messaging/mocks"
|
||
|
"github.com/edgexfoundry/go-mod-messaging/v4/pkg/types"
|
||
|
"github.com/google/uuid"
|
||
|
"github.com/stretchr/testify/assert"
|
||
|
"github.com/stretchr/testify/mock"
|
||
|
"github.com/stretchr/testify/require"
|
||
|
|
||
|
"github.com/edgexfoundry/device-sdk-go/v4/internal/config"
|
||
|
"github.com/edgexfoundry/device-sdk-go/v4/internal/container"
|
||
|
"github.com/edgexfoundry/device-sdk-go/v4/pkg/interfaces/mocks"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
testDeviceName = "testDevice"
|
||
|
testServiceName = "testService"
|
||
|
testProfileName = "testProfile"
|
||
|
testProtocolName = "testProtocol"
|
||
|
)
|
||
|
|
||
|
func TestDeviceValidation(t *testing.T) {
|
||
|
var wg sync.WaitGroup
|
||
|
expectedRequestId := uuid.NewString()
|
||
|
expectedCorrelationId := uuid.NewString()
|
||
|
expectedRequestTopic := common.BuildTopic(common.DefaultBaseTopic, testServiceName, common.ValidateDeviceSubscribeTopic)
|
||
|
expectedResponseTopic := common.BuildTopic(common.DefaultBaseTopic, common.ResponseTopic, testServiceName, expectedRequestId)
|
||
|
expectedDevice := dtos.Device{
|
||
|
Name: testDeviceName,
|
||
|
AdminState: models.Locked,
|
||
|
OperatingState: models.Up,
|
||
|
ServiceName: testServiceName,
|
||
|
ProfileName: testProfileName,
|
||
|
Protocols: map[string]dtos.ProtocolProperties{
|
||
|
testProtocolName: {"key": "value"},
|
||
|
},
|
||
|
}
|
||
|
expectedAddDeviceRequest := requests.NewAddDeviceRequest(expectedDevice)
|
||
|
expectedAddDeviceRequestBytes, err := json.Marshal(expectedAddDeviceRequest)
|
||
|
require.NoError(t, err)
|
||
|
validationFailedDevice := expectedDevice
|
||
|
validationFailedDevice.Name = "validationFailedDevice"
|
||
|
validationFailedDeviceRequest := requests.NewAddDeviceRequest(validationFailedDevice)
|
||
|
validationFailedDeviceRequestBytes, err := json.Marshal(validationFailedDeviceRequest)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
mockLogger := &loggerMocks.LoggingClient{}
|
||
|
mockLogger.On("Infof", mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
||
|
mockLogger.On("Debugf", mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
||
|
mockLogger.On("Errorf", mock.Anything, mock.Anything).Return(nil)
|
||
|
|
||
|
mockDriver := &mocks.ProtocolDriver{}
|
||
|
mockDriver.On("ValidateDevice", dtos.ToDeviceModel(expectedDevice)).Return(nil)
|
||
|
mockDriver.On("ValidateDevice", dtos.ToDeviceModel(validationFailedDevice)).Return(errors.New("validation failed"))
|
||
|
|
||
|
dic := di.NewContainer(di.ServiceConstructorMap{
|
||
|
container.ConfigurationName: func(get di.Get) any {
|
||
|
return &config.ConfigurationStruct{}
|
||
|
},
|
||
|
container.ProtocolDriverName: func(get di.Get) any {
|
||
|
return mockDriver
|
||
|
},
|
||
|
container.DeviceServiceName: func(get di.Get) any {
|
||
|
return &models.DeviceService{Name: testServiceName}
|
||
|
},
|
||
|
bootstrapContainer.LoggingClientInterfaceName: func(get di.Get) any {
|
||
|
return mockLogger
|
||
|
},
|
||
|
})
|
||
|
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
request any
|
||
|
expectedError bool
|
||
|
withEnv bool
|
||
|
}{
|
||
|
{"valid with env - device validation succeed", expectedAddDeviceRequestBytes, false, true},
|
||
|
{"valid with env - device validation failed", validationFailedDeviceRequestBytes, true, true},
|
||
|
{"invalid with env - message payload is not AddDeviceRequest", []byte("invalid"), true, true},
|
||
|
{"valid - device validation succeed", expectedAddDeviceRequest, false, false},
|
||
|
{"valid - device validation failed", validationFailedDeviceRequest, true, false},
|
||
|
{"invalid - message payload is not AddDeviceRequest", []byte("invalid"), true, false},
|
||
|
}
|
||
|
for _, tt := range tests {
|
||
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
if tt.withEnv {
|
||
|
_ = os.Setenv("EDGEX_MSG_BASE64_PAYLOAD", common.ValueTrue)
|
||
|
defer os.Setenv("EDGEX_MSG_BASE64_PAYLOAD", common.ValueFalse)
|
||
|
}
|
||
|
mockMessaging := &messagingMocks.MessageClient{}
|
||
|
mockMessaging.On("Subscribe", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
|
||
|
topics := args.Get(0).([]types.TopicChannel)
|
||
|
require.Len(t, topics, 1)
|
||
|
require.Equal(t, expectedRequestTopic, topics[0].Topic)
|
||
|
wg.Add(1)
|
||
|
go func() {
|
||
|
defer wg.Done()
|
||
|
topics[0].Messages <- types.MessageEnvelope{
|
||
|
RequestID: expectedRequestId,
|
||
|
CorrelationID: expectedCorrelationId,
|
||
|
ReceivedTopic: expectedRequestTopic,
|
||
|
ContentType: common.ContentTypeJSON,
|
||
|
Payload: tt.request,
|
||
|
}
|
||
|
time.Sleep(time.Second * 1)
|
||
|
}()
|
||
|
}).Return(nil)
|
||
|
mockMessaging.On("Publish", mock.Anything, expectedResponseTopic).Run(func(args mock.Arguments) {
|
||
|
response := args.Get(0).(types.MessageEnvelope)
|
||
|
assert.Equal(t, expectedRequestId, response.RequestID)
|
||
|
if tt.expectedError {
|
||
|
assert.Equal(t, 1, response.ErrorCode)
|
||
|
assert.NotEmpty(t, response.Payload)
|
||
|
assert.Equal(t, common.ContentTypeText, response.ContentType)
|
||
|
} else {
|
||
|
assert.Equal(t, expectedCorrelationId, response.CorrelationID)
|
||
|
assert.Equal(t, 0, response.ErrorCode)
|
||
|
assert.Empty(t, response.Payload)
|
||
|
assert.Equal(t, common.ContentTypeJSON, response.ContentType)
|
||
|
}
|
||
|
}).Return(nil)
|
||
|
|
||
|
dic.Update(di.ServiceConstructorMap{
|
||
|
bootstrapContainer.MessagingClientName: func(get di.Get) any {
|
||
|
return mockMessaging
|
||
|
},
|
||
|
})
|
||
|
err := SubscribeDeviceValidation(context.Background(), dic)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
wg.Wait()
|
||
|
mockMessaging.AssertExpectations(t)
|
||
|
})
|
||
|
}
|
||
|
}
|