Skip to content

Commit

Permalink
Fix issues and add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Danielius1922 committed Jan 19, 2024
1 parent a63d60b commit 2b14143
Show file tree
Hide file tree
Showing 32 changed files with 959 additions and 197 deletions.
5 changes: 3 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"-race",
"-v",
"-cover",
"-coverpkg=./...",
],
"go.testEnvVars": {
"ROOT_CA_CRT": "${workspaceFolder}/.tmp/pki_certs/cloudca.pem",
Expand All @@ -15,7 +16,7 @@
"IDENTITY_KEY": "${workspaceFolder}/.tmp/pki_certs/identitykey.pem",
},
"files.watcherExclude": {
"**/plgd-dev/device/v2/**": true
},
"**/plgd-dev/device/v2/**": true
},
"go.testTimeout": "600s",
}
10 changes: 9 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ build-testcontainer:

build: build-testcontainer

ROOT_CA_CRT = $(CERT_PATH)/cloudca.pem
ROOT_CA_KEY = $(CERT_PATH)/cloudcakey.pem
INTERMEDIATE_CA_CRT = $(CERT_PATH)/intermediatecacrt.pem
INTERMEDIATE_CA_KEY = $(CERT_PATH)/intermediatecakey.pem
MFG_CRT = $(CERT_PATH)/mfgcrt.pem
MFG_KEY = $(CERT_PATH)/mfgkey.pem

certificates:
mkdir -p $(CERT_PATH)
chmod 0777 $(CERT_PATH)
Expand Down Expand Up @@ -64,8 +71,9 @@ env: clean certificates

unit-test: certificates
mkdir -p $(TMP_PATH)
ROOT_CA_CRT="$(ROOT_CA_CRT)" MFG_CRT="$(MFG_CRT)" MFG_KEY="$(MFG_KEY)" INTERMEDIATE_CA_CRT="$(INTERMEDIATE_CA_CRT)" INTERMEDIATE_CA_KEY=$(INTERMEDIATE_CA_KEY) go test -race -v ./bridge/... -coverpkg=./... -covermode=atomic -coverprofile=$(TMP_PATH)/bridge.coverage.txt
go test -race -v ./schema/... -covermode=atomic -coverprofile=$(TMP_PATH)/schema.coverage.txt
ROOT_CA_CRT="$(CERT_PATH)/cloudca.pem" ROOT_CA_KEY="$(CERT_PATH)/cloudcakey.pem" go test -race -v ./pkg/... -covermode=atomic -coverprofile=$(TMP_PATH)/pkg.coverage.txt
ROOT_CA_CRT="$(ROOT_CA_CRT)" ROOT_CA_KEY="$(CERT_PATH)/cloudcakey.pem" go test -race -v ./pkg/... -covermode=atomic -coverprofile=$(TMP_PATH)/pkg.coverage.txt

test: env build-testcontainer
docker run \
Expand Down
19 changes: 11 additions & 8 deletions bridge/device/cloud/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,9 @@ func (c *Manager) resetCredentials(ctx context.Context, signOff bool) {
c.creds = CoapSignUpResponse{}
c.signedIn = false
c.resourcesPublished = false
c.close()
if err := c.close(); err != nil {
log.Printf("cannot close connection: %v\n", err)
}
c.save()
}

Expand Down Expand Up @@ -299,19 +301,18 @@ func (c *Manager) close() error {
}
client := c.client
c.client = nil
err := client.Close()
return err
return client.Close()
}

func (c *Manager) dial(ctx context.Context) error {
if c.client != nil && c.client.Context().Err() == nil {
return nil
}
c.close()
_ = c.close()
cfg := c.getCloudConfiguration()
tlsConfig := &tls.Config{
// TODO: set RootCAs from configuration
InsecureSkipVerify: true,
InsecureSkipVerify: true, //nolint:gosec
}
ep := schema.Endpoint{
URI: cfg.URL,
Expand All @@ -334,7 +335,9 @@ func (c *Manager) dial(ctx context.Context) error {
}),
options.WithKeepAlive(2, time.Second*10, func(c *client.Conn) {
log.Printf("keepalive timeout\n")
c.Close()
if errC := c.Close(); errC != nil {
log.Printf("cannot close connection: %v\n", errC)
}
}))
if err != nil {
return fmt.Errorf("cannot dial to %v: %w", addr.String(), err)
Expand Down Expand Up @@ -430,7 +433,7 @@ func (c *Manager) signOff(ctx context.Context) error {
}
// signIn / refresh token fails
if ctx.Err() != nil {
return nil
return ctx.Err()
}
req, err := c.newSignOffReq(ctx)
if err != nil {
Expand Down Expand Up @@ -678,7 +681,7 @@ func (c *Manager) connect(ctx context.Context) error {
}
err := r(ctx)
if err != nil {
c.close()
_ = c.close()
return err
}
}
Expand Down
68 changes: 68 additions & 0 deletions bridge/device/device_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/****************************************************************************
*
* Copyright (c) 2024 plgd.dev s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License"),
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************/

package device_test

import (
"testing"

"github.com/google/uuid"
bridgeDevice "github.com/plgd-dev/device/v2/bridge/device"
"github.com/stretchr/testify/require"
)

func TestConfigValidate(t *testing.T) {
tests := []struct {
name string
cfg bridgeDevice.Config
wantError bool
}{
{
name: "Valid Configuration",
cfg: bridgeDevice.Config{
ProtocolIndependentID: uuid.New(),
ID: uuid.New(),
Name: "ValidName",
},
},
{
name: "Valid Configuration with empty ID and Name",
cfg: bridgeDevice.Config{
ProtocolIndependentID: uuid.New(),
},
},
{
name: "Invalid ProtocolIndependentID",
cfg: bridgeDevice.Config{
ID: uuid.New(),
},
wantError: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.cfg.Validate()
if tt.wantError {
require.Error(t, err)
return
}
require.NoError(t, err)
})
}
}
175 changes: 175 additions & 0 deletions bridge/getResource_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/****************************************************************************
*
* Copyright (c) 2024 plgd.dev s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License"),
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************/

package bridge_test

import (
"context"
"fmt"
"testing"
"time"

"github.com/google/uuid"
"github.com/plgd-dev/device/v2/bridge/resources"
bridgeTest "github.com/plgd-dev/device/v2/bridge/test"
"github.com/plgd-dev/device/v2/client"
"github.com/plgd-dev/device/v2/client/core"
"github.com/plgd-dev/device/v2/pkg/net/coap"
"github.com/plgd-dev/device/v2/schema/device"
"github.com/plgd-dev/device/v2/schema/interfaces"
testClient "github.com/plgd-dev/device/v2/test/client"
"github.com/plgd-dev/go-coap/v3/message/codes"
"github.com/stretchr/testify/require"
)

func withDeviceID(deviceID string) client.ResourceQueryOption {
return client.WithQuery(fmt.Sprintf("di=%v", deviceID))
}

func TestGetResource(t *testing.T) {
s := bridgeTest.NewBridgeService(t)
deviceID1 := uuid.New().String()
d1 := bridgeTest.NewBridgedDevice(t, s, false, deviceID1)
deviceID2 := uuid.New().String()
d2 := bridgeTest.NewBridgedDevice(t, s, false, deviceID2)
defer func() {
s.DeleteAndCloseDevice(d2.GetID())
s.DeleteAndCloseDevice(d1.GetID())
}()

failRes := resources.NewResource("/fail",
nil,
nil,
[]string{"oic.d.virtual", "oic.d.test"},
[]string{interfaces.OC_IF_BASELINE, interfaces.OC_IF_R},
)
d1.AddResource(failRes)

cleanup := bridgeTest.RunBridgeService(s)
defer cleanup()

type args struct {
deviceID string
href string
opts []client.GetOption
}
tests := []struct {
name string
args args
want coap.DetailedResponse[interface{}]
wantErr bool
}{
{
name: "valid",
args: args{
deviceID: d1.GetID().String(),
href: device.ResourceURI,
opts: []client.GetOption{
client.WithDiscoveryConfiguration(core.DefaultDiscoveryConfiguration()),
withDeviceID(d1.GetID().String()),
},
},
want: coap.DetailedResponse[interface{}]{
Code: codes.Content,
Body: map[interface{}]interface{}{
"di": d1.GetID().String(),
"piid": d1.GetProtocolIndependentID().String(),
"n": d1.GetName(),
},
},
},
{
name: "valid with interface",
args: args{
deviceID: d2.GetID().String(),
href: device.ResourceURI,
opts: []client.GetOption{
client.WithInterface(interfaces.OC_IF_BASELINE),
withDeviceID(d2.GetID().String()),
},
},

want: coap.DetailedResponse[interface{}]{
Code: codes.Content,
Body: map[interface{}]interface{}{
"di": d2.GetID().String(),
"piid": d2.GetProtocolIndependentID().String(),
"n": d2.GetName(),
"if": []interface{}{interfaces.OC_IF_BASELINE, interfaces.OC_IF_R},
"rt": []interface{}{"oic.d.virtual", "oic.wk.d"},
},
},
},
{
name: "invalid href",
args: args{
deviceID: d1.GetID().String(),
href: "/invalid/href",
opts: []client.GetOption{
withDeviceID(d1.GetID().String()),
},
},
wantErr: true,
},
{
name: "invalid deviceID",
args: args{
deviceID: "notfound",
href: device.ResourceURI,
opts: []client.GetOption{
withDeviceID(d1.GetID().String()),
},
},
wantErr: true,
},
{
name: "invalid get handler",
args: args{
deviceID: d1.GetID().String(),
href: failRes.GetHref(),
opts: []client.GetOption{
withDeviceID(d1.GetID().String()),
},
},
wantErr: true,
},
}

c, err := testClient.NewTestSecureClient()
require.NoError(t, err)
defer func() {
errC := c.Close(context.Background())
require.NoError(t, errC)
}()

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*4)
defer cancel()
var got coap.DetailedResponse[interface{}]
err := c.GetResource(ctx, tt.args.deviceID, tt.args.href, &got, tt.args.opts...)
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
got.ETag = nil
require.Equal(t, tt.want, got)
})
}
}
10 changes: 4 additions & 6 deletions bridge/net/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"fmt"
"io"
"log"
"math"
gonet "net"
"strconv"
"strings"
Expand Down Expand Up @@ -63,6 +62,8 @@ type Net struct {
mux *mux.Router
}

const DefaultMaxMessageSize = 2 * 1024 * 1024

func (cfg *Config) Validate() error {
if cfg.ExternalAddress == "" {
return fmt.Errorf("externalAddress is required")
Expand All @@ -81,11 +82,8 @@ func (cfg *Config) Validate() error {
if port == 0 {
return fmt.Errorf("invalid externalAddress: port cannot be 0")
}
if port > math.MaxUint16 {
return fmt.Errorf("invalid externalAddress: port cannot be greater than %v", math.MaxUint16)
}
if cfg.MaxMessageSize == 0 {
cfg.MaxMessageSize = 2 * 1024 * 1024
cfg.MaxMessageSize = DefaultMaxMessageSize
}

cfg.externalAddressPort = portStr
Expand Down Expand Up @@ -126,7 +124,7 @@ func initConnectivity(listenAddress string) (*net.UDPConn, *net.UDPConn, error)
}
if !anySet {
_ = mcastListener.Close()
return nil, nil, fmt.Errorf("cannot JoinGroup(%v): %v", a, err)
return nil, nil, fmt.Errorf("cannot JoinGroup(%v): %w", a, err)
}

err = mcastListener.SetMulticastLoopback(true)
Expand Down
Loading

0 comments on commit 2b14143

Please sign in to comment.