diff --git a/v2/dtos/address.go b/v2/dtos/address.go index f7906b30..5f3e7505 100644 --- a/v2/dtos/address.go +++ b/v2/dtos/address.go @@ -50,6 +50,17 @@ type RESTAddress struct { HTTPMethod string `json:"httpMethod" validate:"required,oneof='GET' 'HEAD' 'POST' 'PUT' 'DELETE' 'TRACE' 'CONNECT'"` } +func NewRESTAddress(host string, port int, httpMethod string) Address { + return Address{ + Type: v2.REST, + Host: host, + Port: port, + RESTAddress: RESTAddress{ + HTTPMethod: httpMethod, + }, + } +} + type MQTTPubAddress struct { Publisher string `json:"publisher" validate:"required"` Topic string `json:"topic" validate:"required"` @@ -60,6 +71,18 @@ type MQTTPubAddress struct { ConnectTimeout int `json:"connectTimeout,omitempty"` } +func NewMQTTAddress(host string, port int, publisher string, topic string) Address { + return Address{ + Type: v2.MQTT, + Host: host, + Port: port, + MQTTPubAddress: MQTTPubAddress{ + Publisher: publisher, + Topic: topic, + }, + } +} + func ToAddressModel(a Address) models.Address { var address models.Address diff --git a/v2/dtos/intervalaction.go b/v2/dtos/intervalaction.go index e5e0deba..b96b459a 100644 --- a/v2/dtos/intervalaction.go +++ b/v2/dtos/intervalaction.go @@ -8,48 +8,40 @@ package dtos import ( "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/common" "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/models" + + "github.com/google/uuid" ) // IntervalAction and its properties are defined in the APIv2 specification: // https://app.swaggerhub.com/apis-docs/EdgeXFoundry1/support-scheduler/2.x#/IntervalAction type IntervalAction struct { common.Versionable `json:",inline"` - Created int64 `json:"created,omitempty"` - Modified int64 `json:"modified,omitempty"` - Id string `json:"id,omitempty" validate:"omitempty,uuid"` - Name string `json:"name" validate:"edgex-dto-none-empty-string,edgex-dto-rfc3986-unreserved-chars"` - IntervalName string `json:"intervalName" validate:"edgex-dto-none-empty-string,edgex-dto-rfc3986-unreserved-chars"` - Protocol string `json:"protocol,omitempty"` - Host string `json:"host,omitempty"` - Port int `json:"port,omitempty"` - Path string `json:"path,omitempty"` - Parameters string `json:"parameters,omitempty"` - HTTPMethod string `json:"httpMethod,omitempty" validate:"omitempty,oneof='GET' 'HEAD' 'POST' 'PUT' 'DELETE' 'TRACE' 'CONNECT'"` - User string `json:"user,omitempty"` - Password string `json:"password,omitempty"` - Publisher string `json:"publisher,omitempty"` - Target string `json:"target" validate:"edgex-dto-none-empty-string,edgex-dto-rfc3986-unreserved-chars"` - Topic string `json:"topic,omitempty"` + Created int64 `json:"created,omitempty"` + Modified int64 `json:"modified,omitempty"` + Id string `json:"id,omitempty" validate:"omitempty,uuid"` + Name string `json:"name" validate:"edgex-dto-none-empty-string,edgex-dto-rfc3986-unreserved-chars"` + IntervalName string `json:"intervalName" validate:"edgex-dto-none-empty-string,edgex-dto-rfc3986-unreserved-chars"` + Address Address `json:"address" validate:"required"` +} + +func NewIntervalAction(name string, intervalName string, address Address) IntervalAction { + return IntervalAction{ + Versionable: common.NewVersionable(), + Id: uuid.NewString(), + Name: name, + IntervalName: intervalName, + Address: address, + } } // UpdateIntervalAction and its properties are defined in the APIv2 specification: // https://app.swaggerhub.com/apis-docs/EdgeXFoundry1/support-scheduler/2.x#/UpdateIntervalAction type UpdateIntervalAction struct { common.Versionable `json:",inline"` - 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"` - IntervalName *string `json:"intervalName" validate:"edgex-dto-none-empty-string,edgex-dto-rfc3986-unreserved-chars"` - Protocol *string `json:"protocol,omitempty"` - Host *string `json:"host,omitempty"` - Port *int `json:"port,omitempty"` - Path *string `json:"path,omitempty"` - Parameters *string `json:"parameters,omitempty"` - HTTPMethod *string `json:"httpMethod,omitempty" validate:"omitempty,oneof='GET' 'HEAD' 'POST' 'PUT' 'DELETE' 'TRACE' 'CONNECT'"` - User *string `json:"user,omitempty"` - Password *string `json:"password,omitempty"` - Publisher *string `json:"publisher,omitempty"` - Target *string `json:"target,omitempty" validate:"omitempty,edgex-dto-none-empty-string,edgex-dto-rfc3986-unreserved-chars"` - Topic *string `json:"topic,omitempty"` + 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"` + IntervalName *string `json:"intervalName" validate:"edgex-dto-none-empty-string,edgex-dto-rfc3986-unreserved-chars"` + Address *Address `json:"address,omitempty"` } // ToIntervalActionModel transforms the IntervalAction DTO to the IntervalAction Model @@ -58,17 +50,7 @@ func ToIntervalActionModel(dto IntervalAction) models.IntervalAction { model.Id = dto.Id model.Name = dto.Name model.IntervalName = dto.IntervalName - model.Protocol = dto.Protocol - model.Host = dto.Host - model.Port = dto.Port - model.Path = dto.Path - model.Parameters = dto.Parameters - model.HTTPMethod = dto.HTTPMethod - model.User = dto.User - model.Password = dto.Password - model.Publisher = dto.Publisher - model.Target = dto.Target - model.Topic = dto.Topic + model.Address = ToAddressModel(dto.Address) return model } @@ -79,16 +61,6 @@ func FromIntervalActionModelToDTO(model models.IntervalAction) IntervalAction { dto.Id = model.Id dto.Name = model.Name dto.IntervalName = model.IntervalName - dto.Protocol = model.Protocol - dto.Host = model.Host - dto.Port = model.Port - dto.Path = model.Path - dto.Parameters = model.Parameters - dto.HTTPMethod = model.HTTPMethod - dto.User = model.User - dto.Password = model.Password - dto.Publisher = model.Publisher - dto.Target = model.Target - dto.Topic = model.Topic + dto.Address = FromAddressModelToDTO(model.Address) return dto } diff --git a/v2/dtos/requests/intervalaction.go b/v2/dtos/requests/intervalaction.go index 1b360e03..1a20996d 100644 --- a/v2/dtos/requests/intervalaction.go +++ b/v2/dtos/requests/intervalaction.go @@ -26,7 +26,14 @@ type AddIntervalActionRequest struct { // Validate satisfies the Validator interface func (request AddIntervalActionRequest) Validate() error { err := v2.Validate(request) - return err + if err != nil { + return errors.NewCommonEdgeXWrapper(err) + } + err = request.Action.Address.Validate() + if err != nil { + return errors.NewCommonEdgeXWrapper(err) + } + return nil } // UnmarshalJSON implements the Unmarshaler interface for the AddIntervalActionRequest type @@ -43,7 +50,7 @@ func (request *AddIntervalActionRequest) UnmarshalJSON(b []byte) error { // validate AddIntervalActionRequest DTO if err := request.Validate(); err != nil { - return err + return errors.NewCommonEdgeXWrapper(err) } return nil } @@ -68,7 +75,16 @@ type UpdateIntervalActionRequest struct { // Validate satisfies the Validator interface func (request UpdateIntervalActionRequest) Validate() error { err := v2.Validate(request) - return err + if err != nil { + return errors.NewCommonEdgeXWrapper(err) + } + if request.Action.Address != nil { + err = request.Action.Address.Validate() + if err != nil { + return errors.NewCommonEdgeXWrapper(err) + } + } + return nil } // UnmarshalJSON implements the Unmarshaler interface for the UpdateIntervalActionRequest type @@ -95,38 +111,8 @@ func ReplaceIntervalActionModelFieldsWithDTO(action *models.IntervalAction, patc if patch.IntervalName != nil { action.IntervalName = *patch.IntervalName } - if patch.Protocol != nil { - action.Protocol = *patch.Protocol - } - if patch.Host != nil { - action.Host = *patch.Host - } - if patch.Port != nil { - action.Port = *patch.Port - } - if patch.Path != nil { - action.Path = *patch.Path - } - if patch.Parameters != nil { - action.Parameters = *patch.Parameters - } - if patch.HTTPMethod != nil { - action.HTTPMethod = *patch.HTTPMethod - } - if patch.User != nil { - action.User = *patch.User - } - if patch.Password != nil { - action.Password = *patch.Password - } - if patch.Publisher != nil { - action.Publisher = *patch.Publisher - } - if patch.Target != nil { - action.Target = *patch.Target - } - if patch.Topic != nil { - action.Topic = *patch.Topic + if patch.Address != nil { + action.Address = dtos.ToAddressModel(*patch.Address) } } diff --git a/v2/dtos/requests/intervalaction_test.go b/v2/dtos/requests/intervalaction_test.go index 1d9f3335..234f2a1f 100644 --- a/v2/dtos/requests/intervalaction_test.go +++ b/v2/dtos/requests/intervalaction_test.go @@ -9,6 +9,7 @@ import ( "encoding/json" "testing" + "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/common" "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/models" @@ -18,18 +19,9 @@ import ( ) func addIntervalActionRequestData() AddIntervalActionRequest { - return AddIntervalActionRequest{ - BaseRequest: common.BaseRequest{ - RequestId: ExampleUUID, - Versionable: common.NewVersionable(), - }, - Action: dtos.IntervalAction{ - Versionable: common.NewVersionable(), - Name: TestIntervalActionName, - IntervalName: TestIntervalName, - Target: TestTarget, - }, - } + address := dtos.NewRESTAddress(TestHost, TestPort, TestHTTPMethod) + dto := dtos.NewIntervalAction(TestIntervalActionName, TestIntervalName, address) + return NewAddIntervalActionRequest(dto) } func updateIntervalActionRequestData() UpdateIntervalActionRequest { @@ -46,34 +38,14 @@ func updateIntervalActionData() dtos.UpdateIntervalAction { testId := ExampleUUID testName := TestIntervalActionName testIntervalName := TestIntervalName - testProtocol := TestProtocol - testHost := TestHost - testPort := TestPort - testPath := TestPath - testParameters := TestParameter - testHTTPMethod := TestHTTPMethod - testUser := TestUser - testPassword := TestPassword - testPublisher := TestPublisher - testTarget := TestTarget - testTopic := TestTopic dto := dtos.UpdateIntervalAction{} dto.Versionable = common.NewVersionable() dto.Id = &testId dto.Name = &testName dto.IntervalName = &testIntervalName - dto.Protocol = &testProtocol - dto.Host = &testHost - dto.Port = &testPort - dto.Path = &testPath - dto.Parameters = &testParameters - dto.HTTPMethod = &testHTTPMethod - dto.User = &testUser - dto.Password = &testPassword - dto.Publisher = &testPublisher - dto.Target = &testTarget - dto.Topic = &testTopic + address := dtos.NewRESTAddress(TestHost, TestPort, TestHTTPMethod) + dto.Address = &address return dto } @@ -89,13 +61,24 @@ func TestAddIntervalActionRequest_Validate(t *testing.T) { noIntervalActionName.Action.Name = emptyString noIntervalName := addIntervalActionRequestData() noIntervalName.Action.IntervalName = emptyString - noTarget := addIntervalActionRequestData() - noTarget.Action.Target = emptyString intervalNameWithUnreservedChars := addIntervalActionRequestData() intervalNameWithUnreservedChars.Action.Name = nameWithUnreservedChars intervalNameWithReservedChars := addIntervalActionRequestData() intervalNameWithReservedChars.Action.Name = "name!.~_001" + invalidNoAddressType := addIntervalActionRequestData() + invalidNoAddressType.Action.Address.Type = "" + invalidNoAddressHTTPMethod := addIntervalActionRequestData() + invalidNoAddressHTTPMethod.Action.Address.HTTPMethod = "" + invalidNoAddressMQTTPublisher := addIntervalActionRequestData() + invalidNoAddressMQTTPublisher.Action.Address.Type = v2.MQTT + invalidNoAddressMQTTPublisher.Action.Address.Topic = TestTopic + invalidNoAddressMQTTPublisher.Action.Address.Publisher = "" + invalidNoAddressMQTTTopic := addIntervalActionRequestData() + invalidNoAddressMQTTTopic.Action.Address.Type = v2.MQTT + invalidNoAddressMQTTTopic.Action.Address.Publisher = TestPublisher + invalidNoAddressMQTTTopic.Action.Address.Topic = "" + tests := []struct { name string IntervalAction AddIntervalActionRequest @@ -108,7 +91,10 @@ func TestAddIntervalActionRequest_Validate(t *testing.T) { {"invalid AddIntervalActionRequest, Request Id is not an uuid", invalidReqId, true}, {"invalid AddIntervalActionRequest, no IntervalActionName", noIntervalActionName, true}, {"invalid AddIntervalActionRequest, no IntervalActionName", noIntervalName, true}, - {"invalid AddIntervalActionRequest, no Target", noTarget, true}, + {"invalid AddIntervalActionRequest, no address type", invalidNoAddressType, true}, + {"invalid AddIntervalActionRequest, no address http method", invalidNoAddressHTTPMethod, true}, + {"invalid AddIntervalActionRequest, no address MQTT publisher", invalidNoAddressMQTTPublisher, true}, + {"invalid AddIntervalActionRequest, no address MQTT topic", invalidNoAddressMQTTTopic, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -121,7 +107,7 @@ func TestAddIntervalActionRequest_Validate(t *testing.T) { func TestAddIntervalAction_UnmarshalJSON(t *testing.T) { valid := addIntervalActionRequestData() - jsonData, _ := json.Marshal(addIntervalActionRequestData()) + jsonData, _ := json.Marshal(valid) tests := []struct { name string expected AddIntervalActionRequest @@ -150,9 +136,10 @@ func TestAddIntervalActionReqToIntervalActionModels(t *testing.T) { requests := []AddIntervalActionRequest{addIntervalActionRequestData()} expectedIntervalActionModel := []models.IntervalAction{ { + Id: requests[0].Action.Id, Name: TestIntervalActionName, IntervalName: TestIntervalName, - Target: TestTarget, + Address: dtos.ToAddressModel(requests[0].Action.Address), }, } resultModels := AddIntervalActionReqToIntervalActionModels(requests) @@ -208,6 +195,19 @@ func TestUpdateIntervalActionRequest_Validate(t *testing.T) { invalidEmptyIntervalName := valid invalidEmptyIntervalName.Action.IntervalName = &emptyString + invalidNoAddressType := updateIntervalActionRequestData() + invalidNoAddressType.Action.Address.Type = "" + invalidNoAddressHttpMethod := updateIntervalActionRequestData() + invalidNoAddressHttpMethod.Action.Address.HTTPMethod = "" + invalidNoAddressMQTTPublisher := updateIntervalActionRequestData() + invalidNoAddressMQTTPublisher.Action.Address.Type = v2.MQTT + invalidNoAddressMQTTPublisher.Action.Address.Topic = TestTopic + invalidNoAddressMQTTPublisher.Action.Address.Publisher = "" + invalidNoAddressMQTTTopic := updateIntervalActionRequestData() + invalidNoAddressMQTTTopic.Action.Address.Type = v2.MQTT + invalidNoAddressMQTTTopic.Action.Address.Publisher = TestPublisher + invalidNoAddressMQTTTopic.Action.Address.Topic = "" + tests := []struct { name string req UpdateIntervalActionRequest @@ -222,6 +222,11 @@ func TestUpdateIntervalActionRequest_Validate(t *testing.T) { {"valid, only name", validOnlyName, false}, {"invalid, empty name", invalidEmptyName, true}, {"invalid, empty interval name", invalidEmptyIntervalName, true}, + + {"invalid, no address type", invalidNoAddressType, true}, + {"invalid, no address HTTP method", invalidNoAddressHttpMethod, true}, + {"invalid, no address MQTT publisher", invalidNoAddressMQTTPublisher, true}, + {"invalid, no address MQTT Topic", invalidNoAddressMQTTPublisher, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -243,17 +248,7 @@ func TestUpdateIntervalActionRequest_UnmarshalJSON_NilField(t *testing.T) { require.NoError(t, err) // Nil field checking is used to update with patch - assert.Nil(t, req.Action.Protocol) - assert.Nil(t, req.Action.Host) - assert.Nil(t, req.Action.Port) - assert.Nil(t, req.Action.Path) - assert.Nil(t, req.Action.HTTPMethod) - assert.Nil(t, req.Action.Parameters) - assert.Nil(t, req.Action.User) - assert.Nil(t, req.Action.Password) - assert.Nil(t, req.Action.Publisher) - assert.Nil(t, req.Action.Target) - assert.Nil(t, req.Action.Topic) + assert.Nil(t, req.Action.Address) } func TestReplaceIntervalActionModelFieldsWithDTO(t *testing.T) { @@ -265,17 +260,8 @@ func TestReplaceIntervalActionModelFieldsWithDTO(t *testing.T) { ReplaceIntervalActionModelFieldsWithDTO(&interval, patch) + expectedAddress := dtos.ToAddressModel(*patch.Address) assert.Equal(t, TestIntervalActionName, interval.Name) assert.Equal(t, TestIntervalName, interval.IntervalName) - assert.Equal(t, TestProtocol, interval.Protocol) - assert.Equal(t, TestHost, interval.Host) - assert.Equal(t, TestPort, interval.Port) - assert.Equal(t, TestPath, interval.Path) - assert.Equal(t, TestParameter, interval.Parameters) - assert.Equal(t, TestHTTPMethod, interval.HTTPMethod) - assert.Equal(t, TestUser, interval.User) - assert.Equal(t, TestPassword, interval.Password) - assert.Equal(t, TestPublisher, interval.Publisher) - assert.Equal(t, TestTarget, interval.Target) - assert.Equal(t, TestTopic, interval.Topic) + assert.Equal(t, expectedAddress, interval.Address) } diff --git a/v2/models/intervalaction.go b/v2/models/intervalaction.go index 5836292e..2f7a4925 100644 --- a/v2/models/intervalaction.go +++ b/v2/models/intervalaction.go @@ -13,15 +13,5 @@ type IntervalAction struct { Id string Name string IntervalName string - Protocol string - Host string - Port int - Path string - Parameters string - HTTPMethod string - User string - Password string - Publisher string - Target string - Topic string + Address Address }