Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bridge: updates for tests #464

Merged
merged 7 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
2 changes: 1 addition & 1 deletion .github/workflows/build-with-cfg.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ inputs.go-version || '^1.20' }}
go-version: ${{ inputs.go-version || '^1.22' }}
check-latest: true

- run: |
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ jobs:
matrix:
include:
# test build of oldest supported go version
- name: go1.20
go-version: "~1.20"
- name: go1.22
go-version: "~1.22"
uses: ./.github/workflows/build-with-cfg.yml
with:
go-version: ${{ matrix.go-version }}
4 changes: 2 additions & 2 deletions .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ jobs:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Go 1.20+
- name: Set up Go 1.22+
uses: actions/setup-go@v5
with:
go-version: "^1.20" # The Go version to download (if necessary) and use.
go-version: "^1.22" # The Go version to download (if necessary) and use.
check-latest: true
cache: false

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test-with-cfg.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ jobs:
- name: Shallow checkout
uses: actions/checkout@v4

- name: Set up Go 1.20+
- name: Set up Go 1.22+
uses: actions/setup-go@v5
with:
go-version: "^1.20"
go-version: "^1.22"
check-latest: true

- run: go version
Expand Down
2 changes: 1 addition & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -163,4 +163,4 @@ issues:
# fix: true

run:
go: "1.20"
go: "1.22"
46 changes: 35 additions & 11 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ CERT_TOOL_SIGN_ALG ?= ECDSA-SHA256
# supported values: P256, P384, P521
CERT_TOOL_ELLIPTIC_CURVE ?= P256
DEVSIM_IMAGE ?= ghcr.io/iotivity/iotivity-lite/cloud-server-discovery-resource-observable-debug:vnext
HUB_TEST_DEVICE_IMAGE = ghcr.io/plgd-dev/hub/test-cloud-server:main
# HUB_TEST_DEVICE_IMAGE = ghcr.io/plgd-dev/hub/test-cloud-server:main
HUB_TEST_DEVICE_IMAGE = ghcr.io/plgd-dev/hub/test-cloud-server:vnext-pr1274
jkralik marked this conversation as resolved.
Show resolved Hide resolved

default: build

Expand Down Expand Up @@ -123,7 +124,34 @@ test: env build-testcontainer
-v $(TMP_PATH):/tmp \
$(SERVICE_NAME):$(VERSION_TAG) -test.parallel 1 -test.v -test.coverprofile=/tmp/coverage.txt

test-bridge:
test-bridge/clean:
pkill -KILL bridge-device || :
rm -rf $(TMP_PATH)/bridge || :

define SET-BRIDGE-DEVICE-CONFIG
yq -i '.apis.coap.externalAddresses=["127.0.0.1:15683","[::1]:15683"]' $(1)
yq -i '.cloud.enabled=true' $(1)
yq -i '.cloud.cloudID="$(CLOUD_SID)"' $(1)
yq -i '.cloud.tls.caPoolPath="$(2)/data/certs/root_ca.crt"' $(1)
yq -i '.cloud.tls.keyPath="$(2)/data/certs/external/coap-gateway.key"' $(1)
yq -i '.cloud.tls.certPath="$(2)/data/certs/external/coap-gateway.crt"' $(1)
yq -i '.numGeneratedBridgedDevices=3' $(1)
yq -i '.numResourcesPerDevice=0' $(1)
yq -i '.thingDescription.enabled=true' $(1)
yq -i '.thingDescription.file="$(2)/bridge/bridge-device.jsonld"' $(1)
endef

# config-docker.yaml -> copy of configuration with paths valid inside docker container
# config-test.yaml -> copy of configuration with paths valid on host machine
test-bridge/env: test-bridge/clean
mkdir -p $(TMP_PATH)/bridge
cp ./cmd/bridge-device/bridge-device.jsonld $(TMP_PATH)/bridge
cp ./cmd/bridge-device/config.yaml $(TMP_PATH)/bridge/config-docker.yaml
$(call SET-BRIDGE-DEVICE-CONFIG,$(TMP_PATH)/bridge/config-docker.yaml,)
cp $(TMP_PATH)/bridge/config-docker.yaml $(TMP_PATH)/bridge/config-test.yaml
$(call SET-BRIDGE-DEVICE-CONFIG,$(TMP_PATH)/bridge/config-test.yaml,$(TMP_PATH))

test-bridge: test-bridge/env
sudo rm -rf $(TMP_PATH)/data || :
mkdir -p $(TMP_PATH)/data
# pull image
Expand All @@ -141,15 +169,10 @@ test-bridge:
$(HUB_TEST_DEVICE_IMAGE)

# start device
rm -rf $(TMP_PATH)/bridge || :
mkdir -p $(TMP_PATH)/bridge
go build -C ./test/bridge-device -cover -o ./bridge-device
go build -C ./cmd/bridge-device -cover -o ./bridge-device
pkill -KILL bridge-device || :
CLOUD_SID=$(CLOUD_SID) CA_POOL=$(TMP_PATH)/data/certs/root_ca.crt \
CERT_FILE=$(TMP_PATH)/data/certs/external/coap-gateway.crt \
KEY_FILE=$(TMP_PATH)/data/certs/external/coap-gateway.key \
GOCOVERDIR=$(TMP_PATH)/bridge \
./test/bridge-device/bridge-device &
./cmd/bridge-device/bridge-device -config $(TMP_PATH)/bridge/config-test.yaml &

# run tests
docker run \
Expand All @@ -161,9 +184,11 @@ test-bridge:
--env COAP_GATEWAY_CLOUD_ID="$(CLOUD_SID)" \
--env TEST_DEVICE_NAME="bridged-device-0" \
--env TEST_DEVICE_TYPE="bridged" \
--env TEST_BRIDGE_DEVICE_CONFIG="/bridge/config-docker.yaml" \
--env GRPC_GATEWAY_TEST_DISABLED=1 \
--env IOTIVITY_LITE_TEST_RUN="(TestOffboard|TestOffboardWithoutSignIn|TestOffboardWithRepeat|TestRepublishAfterRefresh)$$" \
-v $(TMP_PATH):/tmp \
-v $(TMP_PATH)/bridge:/bridge \
-v $(TMP_PATH)/data:/data \
$(HUB_TEST_DEVICE_IMAGE)

Expand All @@ -175,11 +200,10 @@ test-bridge:
done
go tool covdata textfmt -i=$(TMP_PATH)/bridge -o $(TMP_PATH)/bridge.coverage.txt

clean:
clean: test-bridge/clean
docker rm -f devsim-net-host || :
docker rm -f hub-device-tests-environment || :
docker rm -f hub-device-tests || :
pkill -KILL bridge-device || :
sudo rm -rf .tmp/*

.PHONY: build-testcontainer build certificates clean env test unit-test
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The **client** enables interaction with devices in a local network:

## Requirements

- Go 1.20 or higher
- Go 1.22 or higher

## Installation OCF Client

Expand Down
128 changes: 0 additions & 128 deletions bridge/device/thingDescription/manager.go
Original file line number Diff line number Diff line change
@@ -1,35 +1,19 @@
package thingDescription

import (
"net/url"
"reflect"
"sync/atomic"

"github.com/fredbi/uri"
"github.com/google/uuid"
"github.com/plgd-dev/device/v2/bridge/net"
"github.com/plgd-dev/device/v2/bridge/resources"
"github.com/plgd-dev/device/v2/pkg/eventloop"
"github.com/plgd-dev/device/v2/schema"
"github.com/plgd-dev/go-coap/v3/message"
"github.com/plgd-dev/go-coap/v3/message/pool"
"github.com/plgd-dev/go-coap/v3/pkg/sync"
"github.com/web-of-things-open-source/thingdescription-go/thingDescription"
)

var (
SecurityNoSec = "nosec_sc"
SecurityDefinitions = map[string]thingDescription.SecurityScheme{
SecurityNoSec: {
Scheme: "nosec",
},
}
HTTPSWWWW3Org2022WotTdV11 = thingDescription.HTTPSWWWW3Org2022WotTdV11
Context = thingDescription.ThingContext{
Enum: &HTTPSWWWW3Org2022WotTdV11,
}
)

// Resource to avoid import cycle also it is same as in Device package to avoid wrapping it
type Resource = interface {
Close()
Expand Down Expand Up @@ -117,115 +101,3 @@ func (t *Manager) NotifySubscriptions(td thingDescription.ThingDescription) {
default:
}
}

func supportedOperationToTDOperation(ops resources.SupportedOperation) []string {
tdOps := make([]string, 0, 3)
if ops.HasOperation(resources.SupportedOperationRead) {
tdOps = append(tdOps, string(thingDescription.Readproperty))
}
if ops.HasOperation(resources.SupportedOperationWrite) {
tdOps = append(tdOps, string(thingDescription.Writeproperty))
}
if ops.HasOperation(resources.SupportedOperationObserve) {
tdOps = append(tdOps, string(thingDescription.Observeproperty), string(thingDescription.Unobserveproperty))
}
if len(tdOps) == 0 {
return nil
}
return tdOps
}

func boolToPtr(v bool) *bool {
if !v {
return nil
}
return &v
}

func stringToPtr(v string) *string {
if v == "" {
return nil
}
return &v
}

func createForms(deviceID uuid.UUID, href string, supportedOperations resources.SupportedOperation, setForm bool) []thingDescription.FormElementProperty {
if !setForm {
return nil
}
ops := supportedOperationToTDOperation(supportedOperations)
if len(ops) > 0 {
hrefStr := href
if deviceID != uuid.Nil {
hrefStr += "?di=" + deviceID.String()
}
href, err := url.Parse(hrefStr)
if err == nil {
return []thingDescription.FormElementProperty{
{
ContentType: stringToPtr(message.AppCBOR.String()),
Op: &thingDescription.FormElementPropertyOp{
StringArray: ops,
},
Href: *href,
},
}
}
}
return nil
}

func PatchPropertyElement(prop thingDescription.PropertyElement, deviceID uuid.UUID, resource Resource, setForm bool) thingDescription.PropertyElement {
ops := resource.SupportsOperations()
observable := ops.HasOperation(resources.SupportedOperationObserve)
isReadOnly := ops.HasOperation(resources.SupportedOperationRead) && !ops.HasOperation(resources.SupportedOperationWrite)
isWriteOnly := ops.HasOperation(resources.SupportedOperationWrite) && !ops.HasOperation(resources.SupportedOperationRead)
resourceTypes := resource.GetResourceTypes()

prop.Type = &thingDescription.TypeDeclaration{
StringArray: resourceTypes,
}
prop.Observable = boolToPtr(observable)
prop.ReadOnly = boolToPtr(isReadOnly)
prop.WriteOnly = boolToPtr(isWriteOnly)
prop.Observable = boolToPtr(observable)
prop.Forms = createForms(deviceID, resource.GetHref(), ops, setForm)
return prop
}

func PatchThingDescription(td thingDescription.ThingDescription, device Device, endpoint string, getPropertyElement func(resourceHref string, resource Resource) (thingDescription.PropertyElement, bool)) thingDescription.ThingDescription {
if td.Context == nil {
td.Context = &Context
}
id, err := uri.Parse("urn:uuid:" + device.GetID().String())
if err == nil {
td.ID = id
}
td.Title = device.GetName()
if endpoint != "" {
// base
u, err := url.Parse(endpoint)
if err == nil {
td.Base = *u
}
// security
td.Security = &thingDescription.TypeDeclaration{
String: &SecurityNoSec,
}
// securityDefinitions
td.SecurityDefinitions = SecurityDefinitions
}

device.Range(func(resourceHref string, resource Resource) bool {
pe, ok := getPropertyElement(resourceHref, resource)
if !ok {
return true
}
if td.Properties == nil {
td.Properties = make(map[string]thingDescription.PropertyElement)
}
td.Properties[resourceHref] = pe
return true
})
return td
}
Loading
Loading