-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Create a common Address struct for V2 API (#525)
* feat: Create a common Addressable struct for V2 API Create a common Addressable struct for different endpoint protocols Signed-off-by: weichou <[email protected]> * feat: Modify MQTT Addressable Rename and add fields Signed-off-by: weichou <[email protected]> * refactor: Refactor Addressable and add test - Rename Addressable to Address - Remove BaseAddress DTO because the json unmarshal func can't identify repeat fields - Add test for json unmarshalling and validation Close #523 Signed-off-by: weichou <[email protected]> * refactor: Rename MqttPubAddress to MQTTPubAddress Fix #523 Signed-off-by: weichou <[email protected]>
- Loading branch information
1 parent
3caf778
commit eae89da
Showing
4 changed files
with
296 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
// | ||
// Copyright (C) 2021 IOTech Ltd | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package dtos | ||
|
||
import ( | ||
"github.com/edgexfoundry/go-mod-core-contracts/v2/errors" | ||
"github.com/edgexfoundry/go-mod-core-contracts/v2/v2" | ||
"github.com/edgexfoundry/go-mod-core-contracts/v2/v2/models" | ||
) | ||
|
||
type Address struct { | ||
Type string `json:"type" validate:"oneof='REST' 'MQTT'"` | ||
|
||
Host string `json:"host" validate:"required"` | ||
Port int `json:"port" validate:"required"` | ||
|
||
RESTAddress `json:",inline" validate:"-"` | ||
MQTTPubAddress `json:",inline" validate:"-"` | ||
} | ||
|
||
// Validate satisfies the Validator interface | ||
func (a *Address) Validate() error { | ||
err := v2.Validate(a) | ||
if err != nil { | ||
return errors.NewCommonEdgeX(errors.KindContractInvalid, "invalid Address.", err) | ||
} | ||
switch a.Type { | ||
case v2.REST: | ||
err = v2.Validate(a.RESTAddress) | ||
if err != nil { | ||
return errors.NewCommonEdgeX(errors.KindContractInvalid, "invalid RESTAddress.", err) | ||
} | ||
break | ||
case v2.MQTT: | ||
err = v2.Validate(a.MQTTPubAddress) | ||
if err != nil { | ||
return errors.NewCommonEdgeX(errors.KindContractInvalid, "invalid MQTTPubAddress.", err) | ||
} | ||
break | ||
} | ||
return nil | ||
} | ||
|
||
type RESTAddress struct { | ||
Path string `json:"path,omitempty"` | ||
QueryParameters string `json:"queryParameters,omitempty"` | ||
HTTPMethod string `json:"httpMethod" validate:"required,oneof='GET' 'HEAD' 'POST' 'PUT' 'DELETE' 'TRACE' 'CONNECT'"` | ||
} | ||
|
||
type MQTTPubAddress struct { | ||
Publisher string `json:"publisher" validate:"required"` | ||
Topic string `json:"topic" validate:"required"` | ||
QoS int `json:"qos,omitempty"` | ||
KeepAlive int `json:"keepAlive,omitempty"` | ||
Retained bool `json:"retained,omitempty"` | ||
AutoReconnect bool `json:"autoReconnect,omitempty"` | ||
ConnectTimeout int `json:"connectTimeout,omitempty"` | ||
} | ||
|
||
func ToAddressModel(a Address) models.Address { | ||
var address models.Address | ||
|
||
switch a.Type { | ||
case v2.REST: | ||
address = models.RESTAddress{ | ||
BaseAddress: models.BaseAddress{ | ||
Type: a.Type, Host: a.Host, Port: a.Port, | ||
}, | ||
Path: a.RESTAddress.Path, | ||
QueryParameters: a.RESTAddress.QueryParameters, | ||
HTTPMethod: a.RESTAddress.HTTPMethod, | ||
} | ||
break | ||
case v2.MQTT: | ||
address = models.MQTTPubAddress{ | ||
BaseAddress: models.BaseAddress{ | ||
Type: a.Type, Host: a.Host, Port: a.Port, | ||
}, | ||
Publisher: a.MQTTPubAddress.Publisher, | ||
Topic: a.MQTTPubAddress.Topic, | ||
QoS: a.QoS, | ||
KeepAlive: a.KeepAlive, | ||
Retained: a.Retained, | ||
AutoReconnect: a.AutoReconnect, | ||
ConnectTimeout: a.ConnectTimeout, | ||
} | ||
break | ||
} | ||
return address | ||
} | ||
|
||
func FromAddressModelToDTO(address models.Address) Address { | ||
dto := Address{ | ||
Type: address.GetBaseAddress().Type, | ||
Host: address.GetBaseAddress().Host, | ||
Port: address.GetBaseAddress().Port, | ||
} | ||
|
||
switch a := address.(type) { | ||
case models.RESTAddress: | ||
dto.RESTAddress = RESTAddress{ | ||
Path: a.Path, | ||
QueryParameters: a.QueryParameters, | ||
HTTPMethod: a.HTTPMethod, | ||
} | ||
break | ||
case models.MQTTPubAddress: | ||
dto.MQTTPubAddress = MQTTPubAddress{ | ||
Publisher: a.Publisher, | ||
Topic: a.Topic, | ||
QoS: a.QoS, | ||
KeepAlive: a.KeepAlive, | ||
Retained: a.Retained, | ||
AutoReconnect: a.AutoReconnect, | ||
ConnectTimeout: a.ConnectTimeout, | ||
} | ||
break | ||
} | ||
return dto | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
// | ||
// Copyright (C) 2021 IOTech Ltd | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package dtos | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/edgexfoundry/go-mod-core-contracts/v2/v2" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
const ( | ||
testHost = "testHost" | ||
testPort = 123 | ||
testPath = "testPath" | ||
testQueryParameters = "testQueryParameters" | ||
testHTTPMethod = "GET" | ||
testPublisher = "testPublisher" | ||
testTopic = "testTopic" | ||
) | ||
|
||
var testRESTAddress = Address{ | ||
Type: v2.REST, | ||
Host: testHost, | ||
Port: testPort, | ||
RESTAddress: RESTAddress{ | ||
Path: testPath, | ||
QueryParameters: testQueryParameters, | ||
HTTPMethod: testHTTPMethod, | ||
}, | ||
} | ||
|
||
var testMQTTPubAddress = Address{ | ||
Type: v2.MQTT, | ||
Host: testHost, | ||
Port: testPort, | ||
MQTTPubAddress: MQTTPubAddress{ | ||
Publisher: testPublisher, | ||
Topic: testTopic, | ||
}, | ||
} | ||
|
||
func TestAddress_UnmarshalJSON(t *testing.T) { | ||
restJsonStr := fmt.Sprintf( | ||
`{"type":"%s","host":"%s","port":%d,"path":"%s","queryParameters":"%s","httpMethod":"%s"}`, | ||
testRESTAddress.Type, testRESTAddress.Host, testRESTAddress.Port, | ||
testRESTAddress.Path, testRESTAddress.QueryParameters, testRESTAddress.HTTPMethod, | ||
) | ||
mqttJsonStr := fmt.Sprintf( | ||
`{"type":"%s","host":"%s","port":%d,"Publisher":"%s","Topic":"%s"}`, | ||
testMQTTPubAddress.Type, testMQTTPubAddress.Host, testMQTTPubAddress.Port, | ||
testMQTTPubAddress.Publisher, testMQTTPubAddress.Topic, | ||
) | ||
|
||
type args struct { | ||
data []byte | ||
} | ||
tests := []struct { | ||
name string | ||
expected Address | ||
data []byte | ||
wantErr bool | ||
}{ | ||
{"unmarshal RESTAddress with success", testRESTAddress, []byte(restJsonStr), false}, | ||
{"unmarshal MQTTPubAddress with success", testMQTTPubAddress, []byte(mqttJsonStr), false}, | ||
{"unmarshal invalid Address, empty data", Address{}, []byte{}, true}, | ||
{"unmarshal invalid Address, string data", Address{}, []byte("Invalid address"), true}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
var result Address | ||
err := json.Unmarshal(tt.data, &result) | ||
if tt.wantErr { | ||
require.Error(t, err) | ||
} else { | ||
require.NoError(t, err) | ||
assert.Equal(t, tt.expected, result, "Unmarshal did not result in expected Address.", err) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestAddress_Validate(t *testing.T) { | ||
validRest := testRESTAddress | ||
noRestHttpMethod := testRESTAddress | ||
noRestHttpMethod.HTTPMethod = "" | ||
|
||
validMQTT := testMQTTPubAddress | ||
noMQTTPublisher := testMQTTPubAddress | ||
noMQTTPublisher.Publisher = "" | ||
noMQTTTopic := testMQTTPubAddress | ||
noMQTTTopic.Topic = "" | ||
tests := []struct { | ||
name string | ||
dto Address | ||
expectError bool | ||
}{ | ||
{"valid RESTAddress", validRest, false}, | ||
{"invalid RESTAddress, no HTTP method", noRestHttpMethod, true}, | ||
{"valid MQTTPubAddress", validMQTT, false}, | ||
{"invalid MQTTPubAddress, no MQTT publisher", noMQTTPublisher, true}, | ||
{"invalid MQTTPubAddress, no MQTT Topic", noMQTTTopic, true}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
err := tt.dto.Validate() | ||
if tt.expectError { | ||
require.Error(t, err) | ||
} else { | ||
require.NoError(t, err) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// | ||
// Copyright (C) 2021 IOTech Ltd | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package models | ||
|
||
type Address interface { | ||
GetBaseAddress() BaseAddress | ||
} | ||
|
||
// BaseAddress is a base struct contains the common fields, such as type, host, port, and so on. | ||
type BaseAddress struct { | ||
// Type is used to identify the Address type, i.e., REST or MQTT | ||
Type string | ||
|
||
// Common properties | ||
Host string | ||
Port int | ||
} | ||
|
||
// RESTAddress is a REST specific struct | ||
type RESTAddress struct { | ||
BaseAddress | ||
Path string | ||
QueryParameters string | ||
HTTPMethod string | ||
} | ||
|
||
func (a RESTAddress) GetBaseAddress() BaseAddress { return a.BaseAddress } | ||
|
||
// MQTTPubAddress is a MQTT specific struct | ||
type MQTTPubAddress struct { | ||
BaseAddress | ||
Publisher string | ||
Topic string | ||
QoS int | ||
KeepAlive int | ||
Retained bool | ||
AutoReconnect bool | ||
ConnectTimeout int | ||
} | ||
|
||
func (a MQTTPubAddress) GetBaseAddress() BaseAddress { return a.BaseAddress } |