You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2023/05/17 10:32:32 UTC

[plc4x] branch develop updated (320c7095c1 -> 7de8439f1d)

This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a change to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git


    from 320c7095c1 build(plc4x): output command error in case of missing version [skip ci]
     new a7ca651288 test(plc4go/spi): add test for DefaultPlcConsumerRegistration
     new a69ada6faa refactor(plc4go): streamline imports
     new 7de8439f1d fix(plc4go/spi): gracefully handle tag names not found on ReadResponse.

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 plc4go/examples/ads/write/Write.go                 |  97 ++++-----
 plc4go/internal/ads/Discoverer.go                  |  12 +-
 plc4go/internal/ads/Reader.go                      |  23 ++-
 .../knxnetip/ConnectionDriverSpecificOperations.go |  16 +-
 plc4go/internal/knxnetip/Reader.go                 |   6 +-
 plc4go/internal/knxnetip/Subscriber.go             |   6 +-
 plc4go/internal/simulated/Device_test.go           |  75 +++----
 .../model/DefaultPlcConsumerRegistration_test.go   | 146 +++++++++++++
 plc4go/spi/model/DefaultPlcReadResponse.go         |  19 +-
 plc4go/spi/model/DefaultPlcReadResponse_test.go    | 226 +++++++++++++++++++++
 plc4go/spi/model/render_test.go                    |  10 +-
 11 files changed, 511 insertions(+), 125 deletions(-)
 create mode 100644 plc4go/spi/model/DefaultPlcConsumerRegistration_test.go
 create mode 100644 plc4go/spi/model/DefaultPlcReadResponse_test.go


[plc4x] 02/03: refactor(plc4go): streamline imports

Posted by sr...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit a69ada6faa9ca58a22a5b481993a7bf48a24f33c
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Wed May 17 12:28:37 2023 +0200

    refactor(plc4go): streamline imports
---
 plc4go/examples/ads/write/Write.go                 | 97 +++++++++++-----------
 plc4go/internal/ads/Discoverer.go                  | 12 +--
 plc4go/internal/ads/Reader.go                      | 23 ++---
 .../knxnetip/ConnectionDriverSpecificOperations.go | 16 ++--
 plc4go/internal/knxnetip/Reader.go                 |  6 +-
 plc4go/internal/knxnetip/Subscriber.go             |  6 +-
 plc4go/internal/simulated/Device_test.go           | 75 ++++++++---------
 7 files changed, 119 insertions(+), 116 deletions(-)

diff --git a/plc4go/examples/ads/write/Write.go b/plc4go/examples/ads/write/Write.go
index b0f1de3fe2..c91042b6c4 100644
--- a/plc4go/examples/ads/write/Write.go
+++ b/plc4go/examples/ads/write/Write.go
@@ -24,8 +24,9 @@ import (
 
 	plc4go "github.com/apache/plc4x/plc4go/pkg/api"
 	"github.com/apache/plc4x/plc4go/pkg/api/drivers"
-	values2 "github.com/apache/plc4x/plc4go/pkg/api/values"
-	"github.com/apache/plc4x/plc4go/spi/values"
+	apiValues "github.com/apache/plc4x/plc4go/pkg/api/values"
+	spiValues "github.com/apache/plc4x/plc4go/spi/values"
+
 	"github.com/rs/zerolog/log"
 )
 
@@ -42,53 +43,53 @@ func main() {
 	dateAndTime, _ := time.Parse("2014-11-12T11:45:26.371Z", "1996-05-06T15:36:30")
 
 	// Prepare the data structure for a custom type.
-	children := map[string]values2.PlcValue{}
-	children["hurz_BOOL"] = values.NewPlcBOOL(true)
-	children["hurz_BYTE"] = values.NewPlcBYTE(1)
-	children["hurz_WORD"] = values.NewPlcWORD(2)
-	children["hurz_DWORD"] = values.NewPlcDWORD(3)
-	children["hurz_LWORD"] = values.NewPlcLWORD(4)
-	children["hurz_SINT"] = values.NewPlcSINT(5)
-	children["hurz_USINT"] = values.NewPlcUSINT(6)
-	children["hurz_INT"] = values.NewPlcINT(7)
-	children["hurz_UINT"] = values.NewPlcUINT(8)
-	children["hurz_DINT"] = values.NewPlcDINT(9)
-	children["hurz_UDINT"] = values.NewPlcUDINT(10)
-	children["hurz_LINT"] = values.NewPlcLINT(11)
-	children["hurz_ULINT"] = values.NewPlcULINT(12)
-	children["hurz_REAL"] = values.NewPlcREAL(13.0)
-	children["hurz_LREAL"] = values.NewPlcLREAL(14.0)
-	children["hurz_STRING"] = values.NewPlcSTRING("hurz")
-	children["hurz_WSTRING"] = values.NewPlcWSTRING("wolf")
-	children["hurz_TIME"] = values.NewPlcTIME(duration)
-	children["hurz_LTIME"] = values.NewPlcLTIME(lduration)
-	children["hurz_DATE"] = values.NewPlcDATE(date)
-	children["hurz_TIME_OF_DAY"] = values.NewPlcTIME_OF_DAY(timeOfDay)
-	children["hurz_DATE_AND_TIME"] = values.NewPlcDATE_AND_TIME(dateAndTime)
+	children := map[string]apiValues.PlcValue{}
+	children["hurz_BOOL"] = spiValues.NewPlcBOOL(true)
+	children["hurz_BYTE"] = spiValues.NewPlcBYTE(1)
+	children["hurz_WORD"] = spiValues.NewPlcWORD(2)
+	children["hurz_DWORD"] = spiValues.NewPlcDWORD(3)
+	children["hurz_LWORD"] = spiValues.NewPlcLWORD(4)
+	children["hurz_SINT"] = spiValues.NewPlcSINT(5)
+	children["hurz_USINT"] = spiValues.NewPlcUSINT(6)
+	children["hurz_INT"] = spiValues.NewPlcINT(7)
+	children["hurz_UINT"] = spiValues.NewPlcUINT(8)
+	children["hurz_DINT"] = spiValues.NewPlcDINT(9)
+	children["hurz_UDINT"] = spiValues.NewPlcUDINT(10)
+	children["hurz_LINT"] = spiValues.NewPlcLINT(11)
+	children["hurz_ULINT"] = spiValues.NewPlcULINT(12)
+	children["hurz_REAL"] = spiValues.NewPlcREAL(13.0)
+	children["hurz_LREAL"] = spiValues.NewPlcLREAL(14.0)
+	children["hurz_STRING"] = spiValues.NewPlcSTRING("hurz")
+	children["hurz_WSTRING"] = spiValues.NewPlcWSTRING("wolf")
+	children["hurz_TIME"] = spiValues.NewPlcTIME(duration)
+	children["hurz_LTIME"] = spiValues.NewPlcLTIME(lduration)
+	children["hurz_DATE"] = spiValues.NewPlcDATE(date)
+	children["hurz_TIME_OF_DAY"] = spiValues.NewPlcTIME_OF_DAY(timeOfDay)
+	children["hurz_DATE_AND_TIME"] = spiValues.NewPlcDATE_AND_TIME(dateAndTime)
 	writeRequest, err := connection.GetConnection().WriteRequestBuilder().
-		AddTagAddress("value-bool", "MAIN.hurz_BOOL", values.NewPlcBOOL(true)).                   // 1
-		AddTagAddress("value-byte", "MAIN.hurz_BYTE", values.NewPlcBYTE(42)).                     // 1
-		AddTagAddress("value-word", "MAIN.hurz_WORD", values.NewPlcWORD(42424)).                  // 2
-		AddTagAddress("value-dword", "MAIN.hurz_DWORD", values.NewPlcDWORD(4242442424)).          // 4
-		AddTagAddress("value-lword", "MAIN.hurz_LWORD", values.NewPlcLWORD(4242442424242424242)). // 8
-		AddTagAddress("value-sint", "MAIN.hurz_SINT", values.NewPlcSINT(-42)).                    // 1
-		AddTagAddress("value-usint", "MAIN.hurz_USINT", values.NewPlcUSINT(42)).                  // 1
-		AddTagAddress("value-int", "MAIN.hurz_INT", values.NewPlcINT(-2424)).                     // 2
-		AddTagAddress("value-uint", "MAIN.hurz_UINT", values.NewPlcUINT(42424)).                  // 2
-		AddTagAddress("value-dint", "MAIN.hurz_DINT", values.NewPlcDINT(-242442424)).             // 4
-		AddTagAddress("value-udint", "MAIN.hurz_UDINT", values.NewPlcUDINT(4242442424)).          // 4
-		AddTagAddress("value-lint", "MAIN.hurz_LINT", values.NewPlcLINT(-4242442424242424242)).   // 8
-		AddTagAddress("value-ulint", "MAIN.hurz_ULINT", values.NewPlcULINT(4242442424242424242)). // 8
-		AddTagAddress("value-real", "MAIN.hurz_REAL", values.NewPlcREAL(3.14159265359)).          // 4
-		AddTagAddress("value-lreal", "MAIN.hurz_LREAL", values.NewPlcLREAL(2.71828182846)).       // 8
-		AddTagAddress("value-string", "MAIN.hurz_STRING", values.NewPlcSTRING("hurz")).           // 4
-		AddTagAddress("value-wstring", "MAIN.hurz_WSTRING", values.NewPlcWSTRING("wolf")).        // 8
-		AddTagAddress("value-time", "MAIN.hurz_TIME", values.NewPlcTIME(duration)).
-		AddTagAddress("value-ltime", "MAIN.hurz_LTIME", values.NewPlcLTIME(lduration)).
-		AddTagAddress("value.date", "MAIN.hurz_DATE", values.NewPlcDATE(date)).
-		AddTagAddress("value-time-of-day", "MAIN.hurz_TIME_OF_DAY", values.NewPlcTIME_OF_DAY(timeOfDay)).
-		AddTagAddress("value-date-and-time", "MAIN.hurz_DATE_AND_TIME", values.NewPlcDATE_AND_TIME(dateAndTime)).
-		AddTagAddress("value-struct", "MAIN.hurz_Struct", values.NewPlcStruct(children)).
+		AddTagAddress("value-bool", "MAIN.hurz_BOOL", spiValues.NewPlcBOOL(true)).                   // 1
+		AddTagAddress("value-byte", "MAIN.hurz_BYTE", spiValues.NewPlcBYTE(42)).                     // 1
+		AddTagAddress("value-word", "MAIN.hurz_WORD", spiValues.NewPlcWORD(42424)).                  // 2
+		AddTagAddress("value-dword", "MAIN.hurz_DWORD", spiValues.NewPlcDWORD(4242442424)).          // 4
+		AddTagAddress("value-lword", "MAIN.hurz_LWORD", spiValues.NewPlcLWORD(4242442424242424242)). // 8
+		AddTagAddress("value-sint", "MAIN.hurz_SINT", spiValues.NewPlcSINT(-42)).                    // 1
+		AddTagAddress("value-usint", "MAIN.hurz_USINT", spiValues.NewPlcUSINT(42)).                  // 1
+		AddTagAddress("value-int", "MAIN.hurz_INT", spiValues.NewPlcINT(-2424)).                     // 2
+		AddTagAddress("value-uint", "MAIN.hurz_UINT", spiValues.NewPlcUINT(42424)).                  // 2
+		AddTagAddress("value-dint", "MAIN.hurz_DINT", spiValues.NewPlcDINT(-242442424)).             // 4
+		AddTagAddress("value-udint", "MAIN.hurz_UDINT", spiValues.NewPlcUDINT(4242442424)).          // 4
+		AddTagAddress("value-lint", "MAIN.hurz_LINT", spiValues.NewPlcLINT(-4242442424242424242)).   // 8
+		AddTagAddress("value-ulint", "MAIN.hurz_ULINT", spiValues.NewPlcULINT(4242442424242424242)). // 8
+		AddTagAddress("value-real", "MAIN.hurz_REAL", spiValues.NewPlcREAL(3.14159265359)).          // 4
+		AddTagAddress("value-lreal", "MAIN.hurz_LREAL", spiValues.NewPlcLREAL(2.71828182846)).       // 8
+		AddTagAddress("value-string", "MAIN.hurz_STRING", spiValues.NewPlcSTRING("hurz")).           // 4
+		AddTagAddress("value-wstring", "MAIN.hurz_WSTRING", spiValues.NewPlcWSTRING("wolf")).        // 8
+		AddTagAddress("value-time", "MAIN.hurz_TIME", spiValues.NewPlcTIME(duration)).
+		AddTagAddress("value-ltime", "MAIN.hurz_LTIME", spiValues.NewPlcLTIME(lduration)).
+		AddTagAddress("value.date", "MAIN.hurz_DATE", spiValues.NewPlcDATE(date)).
+		AddTagAddress("value-time-of-day", "MAIN.hurz_TIME_OF_DAY", spiValues.NewPlcTIME_OF_DAY(timeOfDay)).
+		AddTagAddress("value-date-and-time", "MAIN.hurz_DATE_AND_TIME", spiValues.NewPlcDATE_AND_TIME(dateAndTime)).
+		AddTagAddress("value-struct", "MAIN.hurz_Struct", spiValues.NewPlcStruct(children)).
 		Build()
 	if err != nil {
 		panic(err)
diff --git a/plc4go/internal/ads/Discoverer.go b/plc4go/internal/ads/Discoverer.go
index 79fafd40ae..f31e51c0e4 100644
--- a/plc4go/internal/ads/Discoverer.go
+++ b/plc4go/internal/ads/Discoverer.go
@@ -30,13 +30,13 @@ import (
 	"time"
 
 	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
-	"github.com/apache/plc4x/plc4go/pkg/api/values"
+	apiValues "github.com/apache/plc4x/plc4go/pkg/api/values"
 	"github.com/apache/plc4x/plc4go/protocols/ads/discovery/readwrite/model"
 	driverModel "github.com/apache/plc4x/plc4go/protocols/ads/readwrite/model"
 	"github.com/apache/plc4x/plc4go/spi"
 	spiModel "github.com/apache/plc4x/plc4go/spi/model"
 	"github.com/apache/plc4x/plc4go/spi/options"
-	values2 "github.com/apache/plc4x/plc4go/spi/values"
+	spiValues "github.com/apache/plc4x/plc4go/spi/values"
 	"github.com/rs/zerolog/log"
 )
 
@@ -199,15 +199,15 @@ func (d *Discoverer) Discover(ctx context.Context, callback func(event apiModel.
 				// TODO: Check if this is legit, or if we can get the information from somewhere.
 				opts["targetAmsPort"] = []string{"851"}
 
-				attributes := make(map[string]values.PlcValue)
-				attributes["hostName"] = values2.NewPlcSTRING(hostNameBlock.GetHostName().GetText())
+				attributes := make(map[string]apiValues.PlcValue)
+				attributes["hostName"] = spiValues.NewPlcSTRING(hostNameBlock.GetHostName().GetText())
 				if versionBlock != nil {
 					versionData := versionBlock.GetVersionData()
 					patchVersion := (int(versionData[3])&0xFF)<<8 | (int(versionData[2]) & 0xFF)
-					attributes["twinCatVersion"] = values2.NewPlcSTRING(fmt.Sprintf("%d.%d.%d", int(versionData[0])&0xFF, int(versionData[1])&0xFF, patchVersion))
+					attributes["twinCatVersion"] = spiValues.NewPlcSTRING(fmt.Sprintf("%d.%d.%d", int(versionData[0])&0xFF, int(versionData[1])&0xFF, patchVersion))
 				}
 				if fingerprintBlock != nil {
-					attributes["fingerprint"] = values2.NewPlcSTRING(string(fingerprintBlock.GetData()))
+					attributes["fingerprint"] = spiValues.NewPlcSTRING(string(fingerprintBlock.GetData()))
 				}
 				// TODO: Find out how to handle the OS Data
 
diff --git a/plc4go/internal/ads/Reader.go b/plc4go/internal/ads/Reader.go
index a4edefa115..326edc4f89 100644
--- a/plc4go/internal/ads/Reader.go
+++ b/plc4go/internal/ads/Reader.go
@@ -27,11 +27,12 @@ import (
 
 	"github.com/apache/plc4x/plc4go/internal/ads/model"
 	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
-	"github.com/apache/plc4x/plc4go/pkg/api/values"
+	apiValues "github.com/apache/plc4x/plc4go/pkg/api/values"
 	driverModel "github.com/apache/plc4x/plc4go/protocols/ads/readwrite/model"
 	spiModel "github.com/apache/plc4x/plc4go/spi/model"
 	"github.com/apache/plc4x/plc4go/spi/utils"
-	internalValues "github.com/apache/plc4x/plc4go/spi/values"
+	spiValues "github.com/apache/plc4x/plc4go/spi/values"
+
 	"github.com/pkg/errors"
 	"github.com/rs/zerolog/log"
 )
@@ -116,7 +117,7 @@ func (m *Connection) singleRead(ctx context.Context, readRequest apiModel.PlcRea
 
 		rb := utils.NewReadBufferByteBased(response.GetData(), utils.WithByteOrderForReadBufferByteBased(binary.LittleEndian))
 		responseCodes := map[string]apiModel.PlcResponseCode{}
-		plcValues := map[string]values.PlcValue{}
+		plcValues := map[string]apiValues.PlcValue{}
 		for _, tagName := range readRequest.GetTagNames() {
 			log.Debug().Msgf("get a tag from request with name %s", tagName)
 			// Try to parse the value
@@ -214,7 +215,7 @@ func (m *Connection) multiRead(ctx context.Context, readRequest apiModel.PlcRead
 
 	// Read in the response codes first.
 	responseCodes := map[string]apiModel.PlcResponseCode{}
-	plcValues := map[string]values.PlcValue{}
+	plcValues := map[string]apiValues.PlcValue{}
 	for _, tagName := range readRequest.GetTagNames() {
 		returnCodeValue, err := rb.ReadUint32("returnCode", 32)
 		if err != nil {
@@ -227,7 +228,7 @@ func (m *Connection) multiRead(ctx context.Context, readRequest apiModel.PlcRead
 		}
 	}
 
-	// Parse the plc values for those items that were ok.
+	// Parse the plc apiValues for those items that were ok.
 	for _, tagName := range readRequest.GetTagNames() {
 		if responseCodes[tagName] != apiModel.PlcResponseCode_OK {
 			continue
@@ -254,7 +255,7 @@ func (m *Connection) multiRead(ctx context.Context, readRequest apiModel.PlcRead
 	)
 }
 
-func (m *Connection) parsePlcValue(dataType driverModel.AdsDataTypeTableEntry, arrayInfo []driverModel.AdsDataTypeArrayInfo, rb utils.ReadBufferByteBased) (values.PlcValue, error) {
+func (m *Connection) parsePlcValue(dataType driverModel.AdsDataTypeTableEntry, arrayInfo []driverModel.AdsDataTypeArrayInfo, rb utils.ReadBufferByteBased) (apiValues.PlcValue, error) {
 	// Decode the data according to the information from the request
 	// Based on the AdsDataTypeTableEntry in tag.DataType() parse the data
 	if len(arrayInfo) > 0 {
@@ -265,7 +266,7 @@ func (m *Connection) parsePlcValue(dataType driverModel.AdsDataTypeTableEntry, a
 		if !ok {
 			return nil, fmt.Errorf("couldn't resolve array item type %s", arrayItemTypeName)
 		}
-		var plcValues []values.PlcValue
+		var plcValues []apiValues.PlcValue
 		for i := uint32(0); i < curArrayInfo.GetNumElements(); i++ {
 			restArrayInfo := arrayInfo[1:]
 			plcValue, err := m.parsePlcValue(arrayItemType, restArrayInfo, rb)
@@ -274,10 +275,10 @@ func (m *Connection) parsePlcValue(dataType driverModel.AdsDataTypeTableEntry, a
 			}
 			plcValues = append(plcValues, plcValue)
 		}
-		return internalValues.NewPlcList(plcValues), nil
+		return spiValues.NewPlcList(plcValues), nil
 	} else if len(dataType.GetChildren()) > 0 {
 		// This is a Struct type.
-		plcValues := map[string]values.PlcValue{}
+		plcValues := map[string]apiValues.PlcValue{}
 		startPos := uint32(rb.GetPos())
 		curPos := uint32(0)
 		for _, child := range dataType.GetChildren() {
@@ -299,11 +300,11 @@ func (m *Connection) parsePlcValue(dataType driverModel.AdsDataTypeTableEntry, a
 			plcValues[childName] = childValue
 			curPos = uint32(rb.GetPos()) - startPos
 		}
-		return internalValues.NewPlcStruct(plcValues), nil
+		return spiValues.NewPlcStruct(plcValues), nil
 	} else {
 		// This is a primitive type.
 		valueType, stringLength := m.getPlcValueForAdsDataTypeTableEntry(dataType)
-		if valueType == values.NULL {
+		if valueType == apiValues.NULL {
 			return nil, errors.New(fmt.Sprintf("error converting %s into plc4x plc-value type", dataType.GetDataTypeName()))
 		}
 		adsValueType, ok := driverModel.PlcValueTypeByName(valueType.String())
diff --git a/plc4go/internal/knxnetip/ConnectionDriverSpecificOperations.go b/plc4go/internal/knxnetip/ConnectionDriverSpecificOperations.go
index 5e551225eb..54bb0bc1e6 100644
--- a/plc4go/internal/knxnetip/ConnectionDriverSpecificOperations.go
+++ b/plc4go/internal/knxnetip/ConnectionDriverSpecificOperations.go
@@ -28,7 +28,7 @@ import (
 	"github.com/apache/plc4x/plc4go/pkg/api/values"
 	driverModel "github.com/apache/plc4x/plc4go/protocols/knxnetip/readwrite/model"
 	"github.com/apache/plc4x/plc4go/spi/utils"
-	values2 "github.com/apache/plc4x/plc4go/spi/values"
+	spiValues "github.com/apache/plc4x/plc4go/spi/values"
 	"github.com/pkg/errors"
 	"github.com/rs/zerolog/log"
 )
@@ -434,12 +434,12 @@ func (m *Connection) DeviceReadPropertyDescriptor(ctx context.Context, targetAdd
 		}
 
 		val := map[string]values.PlcValue{}
-		val["writable"] = values2.NewPlcBOOL(propertyDescriptionResponse.GetWriteEnabled())
-		val["dataType"] = values2.NewPlcSTRING(propertyDescriptionResponse.GetPropertyDataType().Name())
-		val["maxElements"] = values2.NewPlcUINT(propertyDescriptionResponse.GetMaxNrOfElements())
-		val["readLevel"] = values2.NewPlcSTRING(propertyDescriptionResponse.GetReadLevel().String())
-		val["writeLevel"] = values2.NewPlcSTRING(propertyDescriptionResponse.GetWriteLevel().String())
-		str := values2.NewPlcStruct(val)
+		val["writable"] = spiValues.NewPlcBOOL(propertyDescriptionResponse.GetWriteEnabled())
+		val["dataType"] = spiValues.NewPlcSTRING(propertyDescriptionResponse.GetPropertyDataType().Name())
+		val["maxElements"] = spiValues.NewPlcUINT(propertyDescriptionResponse.GetMaxNrOfElements())
+		val["readLevel"] = spiValues.NewPlcSTRING(propertyDescriptionResponse.GetReadLevel().String())
+		val["writeLevel"] = spiValues.NewPlcSTRING(propertyDescriptionResponse.GetWriteLevel().String())
+		str := spiValues.NewPlcStruct(val)
 		sendResponse(&str, 1, nil)
 	}()
 
@@ -544,7 +544,7 @@ func (m *Connection) DeviceReadMemory(ctx context.Context, targetAddress driverM
 		}
 		if len(results) > 1 {
 			var plcList values.PlcValue
-			plcList = values2.NewPlcList(results)
+			plcList = spiValues.NewPlcList(results)
 			sendResponse(plcList, 1, nil)
 		} else if len(results) == 1 {
 			sendResponse(results[0], 1, nil)
diff --git a/plc4go/internal/knxnetip/Reader.go b/plc4go/internal/knxnetip/Reader.go
index 2fe1a23097..f9c0d7921d 100644
--- a/plc4go/internal/knxnetip/Reader.go
+++ b/plc4go/internal/knxnetip/Reader.go
@@ -30,7 +30,7 @@ import (
 	driverModel "github.com/apache/plc4x/plc4go/protocols/knxnetip/readwrite/model"
 	spiModel "github.com/apache/plc4x/plc4go/spi/model"
 	"github.com/apache/plc4x/plc4go/spi/utils"
-	internalValues "github.com/apache/plc4x/plc4go/spi/values"
+	spiValues "github.com/apache/plc4x/plc4go/spi/values"
 
 	"github.com/pkg/errors"
 	"github.com/rs/zerolog/log"
@@ -220,7 +220,7 @@ func (m Reader) readGroupAddress(ctx context.Context, tag GroupAddressTag) (apiM
 		} else {
 			// If we don't have any tag-type information, add the raw data
 			if tag.GetTagType() == nil {
-				values[stringAddress] = internalValues.NewPlcRawByteArray(int8s)
+				values[stringAddress] = spiValues.NewPlcRawByteArray(int8s)
 			} else {
 				// Decode the data according to the tags type
 				rb := utils.NewReadBufferByteBased(int8s)
@@ -252,7 +252,7 @@ func (m Reader) readGroupAddress(ctx context.Context, tag GroupAddressTag) (apiM
 		return apiModel.PlcResponseCode_OK, values[stringAddress]
 	} else if len(rawAddresses) > 1 {
 		// Add it to the result
-		return apiModel.PlcResponseCode_OK, internalValues.NewPlcStruct(values)
+		return apiModel.PlcResponseCode_OK, spiValues.NewPlcStruct(values)
 	} else {
 		// Add it to the result
 		return apiModel.PlcResponseCode_NOT_FOUND, nil
diff --git a/plc4go/internal/knxnetip/Subscriber.go b/plc4go/internal/knxnetip/Subscriber.go
index ae9da83cf2..7527563667 100644
--- a/plc4go/internal/knxnetip/Subscriber.go
+++ b/plc4go/internal/knxnetip/Subscriber.go
@@ -29,7 +29,7 @@ import (
 	driverModel "github.com/apache/plc4x/plc4go/protocols/knxnetip/readwrite/model"
 	spiModel "github.com/apache/plc4x/plc4go/spi/model"
 	"github.com/apache/plc4x/plc4go/spi/utils"
-	values2 "github.com/apache/plc4x/plc4go/spi/values"
+	spiValues "github.com/apache/plc4x/plc4go/spi/values"
 )
 
 type Subscriber struct {
@@ -146,7 +146,7 @@ func (m *Subscriber) handleValueChange(destinationAddress []byte, payload []byte
 					if !rb.HasMore(1) {
 						rb.Reset(0)
 					}
-					plcValue := values2.NewPlcRawByteArray(rb.GetBytes())
+					plcValue := spiValues.NewPlcRawByteArray(rb.GetBytes())
 					plcValueList = append(plcValueList, plcValue)
 				} else {
 					plcValue, err2 := driverModel.KnxDatapointParseWithBuffer(context.Background(), rb, elementType)
@@ -164,7 +164,7 @@ func (m *Subscriber) handleValueChange(destinationAddress []byte, payload []byte
 				if len(plcValueList) == 1 {
 					plcValues[tagName] = plcValueList[0]
 				} else {
-					plcValues[tagName] = values2.NewPlcList(plcValueList)
+					plcValues[tagName] = spiValues.NewPlcList(plcValueList)
 				}
 			}
 			event := NewSubscriptionEvent(tags, types, intervals, responseCodes, addresses, plcValues)
diff --git a/plc4go/internal/simulated/Device_test.go b/plc4go/internal/simulated/Device_test.go
index 0c262048ff..e1ddec33e5 100644
--- a/plc4go/internal/simulated/Device_test.go
+++ b/plc4go/internal/simulated/Device_test.go
@@ -23,16 +23,17 @@ import (
 	"github.com/stretchr/testify/assert"
 	"testing"
 
-	"github.com/apache/plc4x/plc4go/pkg/api/values"
-	"github.com/apache/plc4x/plc4go/protocols/simulated/readwrite/model"
-	values2 "github.com/apache/plc4x/plc4go/spi/values"
+	apiValues "github.com/apache/plc4x/plc4go/pkg/api/values"
+	readWriteModel "github.com/apache/plc4x/plc4go/protocols/simulated/readwrite/model"
+	spiValues "github.com/apache/plc4x/plc4go/spi/values"
+
 	"github.com/rs/zerolog/log"
 )
 
 func TestDevice_Get(t1 *testing.T) {
 	type fields struct {
 		Name  string
-		State map[simulatedTag]*values.PlcValue
+		State map[simulatedTag]*apiValues.PlcValue
 	}
 	type args struct {
 		field        simulatedTag
@@ -42,42 +43,42 @@ func TestDevice_Get(t1 *testing.T) {
 		name   string
 		fields fields
 		args   args
-		want   *values.PlcValue
+		want   *apiValues.PlcValue
 	}{
 		{
 			name: "simple state",
 			fields: fields{
 				Name: "hurz",
-				State: map[simulatedTag]*values.PlcValue{
-					NewSimulatedTag(TagState, "boolTag", model.SimulatedDataTypeSizes_BOOL, 1): ToReference(values2.NewPlcBOOL(true)),
+				State: map[simulatedTag]*apiValues.PlcValue{
+					NewSimulatedTag(TagState, "boolTag", readWriteModel.SimulatedDataTypeSizes_BOOL, 1): ToReference(spiValues.NewPlcBOOL(true)),
 				},
 			},
 			args: args{
-				field:        NewSimulatedTag(TagState, "boolTag", model.SimulatedDataTypeSizes_BOOL, 1),
+				field:        NewSimulatedTag(TagState, "boolTag", readWriteModel.SimulatedDataTypeSizes_BOOL, 1),
 				verifyOutput: true,
 			},
-			want: ToReference(values2.NewPlcBOOL(true)),
+			want: ToReference(spiValues.NewPlcBOOL(true)),
 		},
 		{
 			name: "simple random",
 			fields: fields{
 				Name:  "hurz",
-				State: map[simulatedTag]*values.PlcValue{},
+				State: map[simulatedTag]*apiValues.PlcValue{},
 			},
 			args: args{
-				field:        NewSimulatedTag(TagRandom, "boolTag", model.SimulatedDataTypeSizes_BOOL, 1),
+				field:        NewSimulatedTag(TagRandom, "boolTag", readWriteModel.SimulatedDataTypeSizes_BOOL, 1),
 				verifyOutput: false,
 			},
-			want: ToReference(values2.NewPlcBOOL(true)),
+			want: ToReference(spiValues.NewPlcBOOL(true)),
 		},
 		{
 			name: "simple stdout",
 			fields: fields{
 				Name:  "hurz",
-				State: map[simulatedTag]*values.PlcValue{},
+				State: map[simulatedTag]*apiValues.PlcValue{},
 			},
 			args: args{
-				field:        NewSimulatedTag(TagStdOut, "boolTag", model.SimulatedDataTypeSizes_BOOL, 1),
+				field:        NewSimulatedTag(TagStdOut, "boolTag", readWriteModel.SimulatedDataTypeSizes_BOOL, 1),
 				verifyOutput: false,
 			},
 			want: nil,
@@ -103,13 +104,13 @@ func TestDevice_Get(t1 *testing.T) {
 }
 
 /*
- * When first playing around with random values I only got "false" values.
- * So I added this test in order to verify I'm actually getting random values.
+ * When first playing around with random apiValues I only got "false" apiValues.
+ * So I added this test in order to verify I'm actually getting random apiValues.
  */
 func TestDevice_Random(t1 *testing.T) {
 	type fields struct {
 		Name  string
-		State map[simulatedTag]*values.PlcValue
+		State map[simulatedTag]*apiValues.PlcValue
 	}
 	type args struct {
 		field   simulatedTag
@@ -119,19 +120,19 @@ func TestDevice_Random(t1 *testing.T) {
 		name   string
 		fields fields
 		args   args
-		want   *values.PlcValue
+		want   *apiValues.PlcValue
 	}{
 		{
 			name: "simple random",
 			fields: fields{
 				Name:  "hurz",
-				State: map[simulatedTag]*values.PlcValue{},
+				State: map[simulatedTag]*apiValues.PlcValue{},
 			},
 			args: args{
-				field:   NewSimulatedTag(TagRandom, "boolTag", model.SimulatedDataTypeSizes_BOOL, 1),
+				field:   NewSimulatedTag(TagRandom, "boolTag", readWriteModel.SimulatedDataTypeSizes_BOOL, 1),
 				numRuns: 1000,
 			},
-			want: ToReference(values2.NewPlcBOOL(true)),
+			want: ToReference(spiValues.NewPlcBOOL(true)),
 		},
 	}
 	for _, tt := range tests {
@@ -152,9 +153,9 @@ func TestDevice_Random(t1 *testing.T) {
 				}
 			}
 			if numTrue == 0 || numFalse == 0 {
-				t1.Errorf("Random doesn't seem to work. In %d runs I got %d true and %d false values", tt.args.numRuns, numTrue, numFalse)
+				t1.Errorf("Random doesn't seem to work. In %d runs I got %d true and %d false apiValues", tt.args.numRuns, numTrue, numFalse)
 			} else {
-				log.Info().Msgf("In %d runs I got %d true and %d false values", tt.args.numRuns, numTrue, numFalse)
+				log.Info().Msgf("In %d runs I got %d true and %d false apiValues", tt.args.numRuns, numTrue, numFalse)
 			}
 		})
 	}
@@ -163,11 +164,11 @@ func TestDevice_Random(t1 *testing.T) {
 func TestDevice_Set(t1 *testing.T) {
 	type fields struct {
 		Name  string
-		State map[simulatedTag]*values.PlcValue
+		State map[simulatedTag]*apiValues.PlcValue
 	}
 	type args struct {
 		field         simulatedTag
-		value         *values.PlcValue
+		value         *apiValues.PlcValue
 		shouldBeSaved bool
 	}
 	tests := []struct {
@@ -179,11 +180,11 @@ func TestDevice_Set(t1 *testing.T) {
 			name: "simple state",
 			fields: fields{
 				Name:  "hurz",
-				State: map[simulatedTag]*values.PlcValue{},
+				State: map[simulatedTag]*apiValues.PlcValue{},
 			},
 			args: args{
-				field:         NewSimulatedTag(TagState, "boolTag", model.SimulatedDataTypeSizes_BOOL, 1),
-				value:         ToReference(values2.NewPlcBOOL(true)),
+				field:         NewSimulatedTag(TagState, "boolTag", readWriteModel.SimulatedDataTypeSizes_BOOL, 1),
+				value:         ToReference(spiValues.NewPlcBOOL(true)),
 				shouldBeSaved: true,
 			},
 		},
@@ -191,11 +192,11 @@ func TestDevice_Set(t1 *testing.T) {
 			name: "simple random",
 			fields: fields{
 				Name:  "hurz",
-				State: map[simulatedTag]*values.PlcValue{},
+				State: map[simulatedTag]*apiValues.PlcValue{},
 			},
 			args: args{
-				field:         NewSimulatedTag(TagRandom, "boolTag", model.SimulatedDataTypeSizes_BOOL, 1),
-				value:         ToReference(values2.NewPlcBOOL(true)),
+				field:         NewSimulatedTag(TagRandom, "boolTag", readWriteModel.SimulatedDataTypeSizes_BOOL, 1),
+				value:         ToReference(spiValues.NewPlcBOOL(true)),
 				shouldBeSaved: false,
 			},
 		},
@@ -203,11 +204,11 @@ func TestDevice_Set(t1 *testing.T) {
 			name: "simple stdout",
 			fields: fields{
 				Name:  "hurz",
-				State: map[simulatedTag]*values.PlcValue{},
+				State: map[simulatedTag]*apiValues.PlcValue{},
 			},
 			args: args{
-				field:         NewSimulatedTag(TagStdOut, "boolTag", model.SimulatedDataTypeSizes_BOOL, 1),
-				value:         ToReference(values2.NewPlcBOOL(true)),
+				field:         NewSimulatedTag(TagStdOut, "boolTag", readWriteModel.SimulatedDataTypeSizes_BOOL, 1),
+				value:         ToReference(spiValues.NewPlcBOOL(true)),
 				shouldBeSaved: false,
 			},
 		},
@@ -238,7 +239,7 @@ func TestDevice_Set(t1 *testing.T) {
 func TestDevice_getRandomValue(t1 *testing.T) {
 	type fields struct {
 		Name  string
-		State map[simulatedTag]*values.PlcValue
+		State map[simulatedTag]*apiValues.PlcValue
 	}
 	type args struct {
 		field simulatedTag
@@ -247,7 +248,7 @@ func TestDevice_getRandomValue(t1 *testing.T) {
 		name   string
 		fields fields
 		args   args
-		want   *values.PlcValue
+		want   *apiValues.PlcValue
 	}{
 		// TODO: Add test cases.
 	}
@@ -284,6 +285,6 @@ func TestNewDevice(t *testing.T) {
 	}
 }
 
-func ToReference(value values.PlcValue) *values.PlcValue {
+func ToReference(value apiValues.PlcValue) *apiValues.PlcValue {
 	return &value
 }


[plc4x] 01/03: test(plc4go/spi): add test for DefaultPlcConsumerRegistration

Posted by sr...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit a7ca651288794c0f292451f86e6f260260c6c9ff
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Wed May 17 12:17:48 2023 +0200

    test(plc4go/spi): add test for DefaultPlcConsumerRegistration
---
 .../model/DefaultPlcConsumerRegistration_test.go   | 146 +++++++++++++++++++++
 1 file changed, 146 insertions(+)

diff --git a/plc4go/spi/model/DefaultPlcConsumerRegistration_test.go b/plc4go/spi/model/DefaultPlcConsumerRegistration_test.go
new file mode 100644
index 0000000000..6ad2d7fabb
--- /dev/null
+++ b/plc4go/spi/model/DefaultPlcConsumerRegistration_test.go
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ *   https://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 model
+
+import (
+	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
+	"github.com/apache/plc4x/plc4go/spi"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
+	"testing"
+)
+
+func TestDefaultPlcConsumerRegistration_GetConsumerId(t *testing.T) {
+	type fields struct {
+		consumerId    int
+		consumer      apiModel.PlcSubscriptionEventConsumer
+		plcSubscriber spi.PlcSubscriber
+		handles       []apiModel.PlcSubscriptionHandle
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   int
+	}{
+		{
+			name: "get it",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DefaultPlcConsumerRegistration{
+				consumerId:    tt.fields.consumerId,
+				consumer:      tt.fields.consumer,
+				plcSubscriber: tt.fields.plcSubscriber,
+				handles:       tt.fields.handles,
+			}
+			assert.Equalf(t, tt.want, d.GetConsumerId(), "GetConsumerId()")
+		})
+	}
+}
+
+func TestDefaultPlcConsumerRegistration_GetSubscriptionHandles(t *testing.T) {
+	type fields struct {
+		consumerId    int
+		consumer      apiModel.PlcSubscriptionEventConsumer
+		plcSubscriber spi.PlcSubscriber
+		handles       []apiModel.PlcSubscriptionHandle
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   []apiModel.PlcSubscriptionHandle
+	}{
+		{
+			name: "get it",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DefaultPlcConsumerRegistration{
+				consumerId:    tt.fields.consumerId,
+				consumer:      tt.fields.consumer,
+				plcSubscriber: tt.fields.plcSubscriber,
+				handles:       tt.fields.handles,
+			}
+			assert.Equalf(t, tt.want, d.GetSubscriptionHandles(), "GetSubscriptionHandles()")
+		})
+	}
+}
+
+func TestDefaultPlcConsumerRegistration_Unregister(t *testing.T) {
+	type fields struct {
+		consumerId    int
+		consumer      apiModel.PlcSubscriptionEventConsumer
+		plcSubscriber spi.PlcSubscriber
+		handles       []apiModel.PlcSubscriptionHandle
+	}
+	tests := []struct {
+		name   string
+		fields fields
+	}{
+		{
+			name: "unregister it",
+			fields: fields{
+				plcSubscriber: func() spi.PlcSubscriber {
+					subscriber := NewMockPlcSubscriber(t)
+					subscriber.EXPECT().Unregister(mock.Anything).Return()
+					return subscriber
+				}(),
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DefaultPlcConsumerRegistration{
+				consumerId:    tt.fields.consumerId,
+				consumer:      tt.fields.consumer,
+				plcSubscriber: tt.fields.plcSubscriber,
+				handles:       tt.fields.handles,
+			}
+			d.Unregister()
+		})
+	}
+}
+
+func TestNewDefaultPlcConsumerRegistration(t *testing.T) {
+	type args struct {
+		plcSubscriber spi.PlcSubscriber
+		consumer      apiModel.PlcSubscriptionEventConsumer
+		handles       []apiModel.PlcSubscriptionHandle
+	}
+	tests := []struct {
+		name string
+		args args
+		want apiModel.PlcConsumerRegistration
+	}{
+		{
+			name: "create it",
+			want: &DefaultPlcConsumerRegistration{},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := NewDefaultPlcConsumerRegistration(tt.args.plcSubscriber, tt.args.consumer, tt.args.handles...).(*DefaultPlcConsumerRegistration)
+			tt.want.(*DefaultPlcConsumerRegistration).consumerId = got.consumerId
+			assert.Equalf(t, tt.want, got, "NewDefaultPlcConsumerRegistration(%v, func(), %v)", tt.args.plcSubscriber, tt.args.handles)
+		})
+	}
+}


[plc4x] 03/03: fix(plc4go/spi): gracefully handle tag names not found on ReadResponse.

Posted by sr...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 7de8439f1d098a0e84024d560752698f83bf0416
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Wed May 17 12:32:25 2023 +0200

    fix(plc4go/spi): gracefully handle tag names not found on ReadResponse.
---
 plc4go/spi/model/DefaultPlcReadResponse.go      |  19 +-
 plc4go/spi/model/DefaultPlcReadResponse_test.go | 226 ++++++++++++++++++++++++
 plc4go/spi/model/render_test.go                 |  10 +-
 3 files changed, 246 insertions(+), 9 deletions(-)

diff --git a/plc4go/spi/model/DefaultPlcReadResponse.go b/plc4go/spi/model/DefaultPlcReadResponse.go
index badb6c75b5..43f0f1b6a5 100644
--- a/plc4go/spi/model/DefaultPlcReadResponse.go
+++ b/plc4go/spi/model/DefaultPlcReadResponse.go
@@ -21,7 +21,8 @@ package model
 
 import (
 	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
-	"github.com/apache/plc4x/plc4go/pkg/api/values"
+	apiValues "github.com/apache/plc4x/plc4go/pkg/api/values"
+	spiValues "github.com/apache/plc4x/plc4go/spi/values"
 )
 
 //go:generate go run ../../tools/plc4xgenerator/gen.go -type=DefaultPlcReadResponse
@@ -30,7 +31,7 @@ type DefaultPlcReadResponse struct {
 	values  map[string]*ResponseItem
 }
 
-func NewDefaultPlcReadResponse(request apiModel.PlcReadRequest, responseCodes map[string]apiModel.PlcResponseCode, values map[string]values.PlcValue) apiModel.PlcReadResponse {
+func NewDefaultPlcReadResponse(request apiModel.PlcReadRequest, responseCodes map[string]apiModel.PlcResponseCode, values map[string]apiValues.PlcValue) apiModel.PlcReadResponse {
 	valueMap := map[string]*ResponseItem{}
 	for name, code := range responseCodes {
 		value := values[name]
@@ -66,9 +67,17 @@ func (d *DefaultPlcReadResponse) GetRequest() apiModel.PlcReadRequest {
 }
 
 func (d *DefaultPlcReadResponse) GetResponseCode(name string) apiModel.PlcResponseCode {
-	return d.values[name].GetCode()
+	item, ok := d.values[name]
+	if !ok {
+		return apiModel.PlcResponseCode_NOT_FOUND
+	}
+	return item.GetCode()
 }
 
-func (d *DefaultPlcReadResponse) GetValue(name string) values.PlcValue {
-	return d.values[name].GetValue()
+func (d *DefaultPlcReadResponse) GetValue(name string) apiValues.PlcValue {
+	item, ok := d.values[name]
+	if !ok {
+		return spiValues.PlcNull{}
+	}
+	return item.GetValue()
 }
diff --git a/plc4go/spi/model/DefaultPlcReadResponse_test.go b/plc4go/spi/model/DefaultPlcReadResponse_test.go
new file mode 100644
index 0000000000..33fd07fe4d
--- /dev/null
+++ b/plc4go/spi/model/DefaultPlcReadResponse_test.go
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ *   https://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 model
+
+import (
+	"testing"
+
+	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
+	apiValues "github.com/apache/plc4x/plc4go/pkg/api/values"
+	spiValues "github.com/apache/plc4x/plc4go/spi/values"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestDefaultPlcReadResponse_GetRequest(t *testing.T) {
+	type fields struct {
+		request apiModel.PlcReadRequest
+		values  map[string]*ResponseItem
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   apiModel.PlcReadRequest
+	}{
+		{
+			name: "get it",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DefaultPlcReadResponse{
+				request: tt.fields.request,
+				values:  tt.fields.values,
+			}
+			assert.Equalf(t, tt.want, d.GetRequest(), "GetRequest()")
+		})
+	}
+}
+
+func TestDefaultPlcReadResponse_GetResponseCode(t *testing.T) {
+	type fields struct {
+		request apiModel.PlcReadRequest
+		values  map[string]*ResponseItem
+	}
+	type args struct {
+		name string
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+		want   apiModel.PlcResponseCode
+	}{
+		{
+			name: "get it (not found)",
+			want: apiModel.PlcResponseCode_NOT_FOUND,
+		},
+		{
+			name: "get it",
+			fields: fields{
+				values: map[string]*ResponseItem{
+					"something": {
+						code: apiModel.PlcResponseCode_OK,
+					},
+				},
+			},
+			args: args{
+				name: "something",
+			},
+			want: apiModel.PlcResponseCode_OK,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DefaultPlcReadResponse{
+				request: tt.fields.request,
+				values:  tt.fields.values,
+			}
+			assert.Equalf(t, tt.want, d.GetResponseCode(tt.args.name), "GetResponseCode(%v)", tt.args.name)
+		})
+	}
+}
+
+func TestDefaultPlcReadResponse_GetTagNames(t *testing.T) {
+	type fields struct {
+		request apiModel.PlcReadRequest
+		values  map[string]*ResponseItem
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   []string
+	}{
+		{
+			name: "get it",
+			fields: fields{
+				request: NewDefaultPlcReadRequest(nil, []string{"tag1", "tag2"}, nil, nil),
+				values: map[string]*ResponseItem{
+					"tag1": nil,
+					"tag2": nil,
+				},
+			},
+			want: []string{"tag1", "tag2"},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DefaultPlcReadResponse{
+				request: tt.fields.request,
+				values:  tt.fields.values,
+			}
+			assert.Equalf(t, tt.want, d.GetTagNames(), "GetTagNames()")
+		})
+	}
+}
+
+func TestDefaultPlcReadResponse_GetValue(t *testing.T) {
+	type fields struct {
+		request apiModel.PlcReadRequest
+		values  map[string]*ResponseItem
+	}
+	type args struct {
+		name string
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+		want   apiValues.PlcValue
+	}{
+		{
+			name: "get it (not found)",
+			want: spiValues.PlcNull{},
+		},
+		{
+			name: "get it",
+			fields: fields{
+				values: map[string]*ResponseItem{
+					"something": {
+						code:  apiModel.PlcResponseCode_OK,
+						value: spiValues.NewPlcSTRING("yes"),
+					},
+				},
+			},
+			args: args{
+				name: "something",
+			},
+			want: spiValues.NewPlcSTRING("yes"),
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DefaultPlcReadResponse{
+				request: tt.fields.request,
+				values:  tt.fields.values,
+			}
+			assert.Equalf(t, tt.want, d.GetValue(tt.args.name), "GetValue(%v)", tt.args.name)
+		})
+	}
+}
+
+func TestDefaultPlcReadResponse_IsAPlcMessage(t *testing.T) {
+	type fields struct {
+		request apiModel.PlcReadRequest
+		values  map[string]*ResponseItem
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   bool
+	}{
+		{
+			name: "it is",
+			want: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DefaultPlcReadResponse{
+				request: tt.fields.request,
+				values:  tt.fields.values,
+			}
+			assert.Equalf(t, tt.want, d.IsAPlcMessage(), "IsAPlcMessage()")
+		})
+	}
+}
+
+func TestNewDefaultPlcReadResponse(t *testing.T) {
+	type args struct {
+		request       apiModel.PlcReadRequest
+		responseCodes map[string]apiModel.PlcResponseCode
+		values        map[string]apiValues.PlcValue
+	}
+	tests := []struct {
+		name string
+		args args
+		want apiModel.PlcReadResponse
+	}{
+		{
+			name: "create it",
+			want: &DefaultPlcReadResponse{values: map[string]*ResponseItem{}},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			assert.Equalf(t, tt.want, NewDefaultPlcReadResponse(tt.args.request, tt.args.responseCodes, tt.args.values), "NewDefaultPlcReadResponse(%v, %v, %v)", tt.args.request, tt.args.responseCodes, tt.args.values)
+		})
+	}
+}
diff --git a/plc4go/spi/model/render_test.go b/plc4go/spi/model/render_test.go
index 1608cac319..4d6eb82895 100644
--- a/plc4go/spi/model/render_test.go
+++ b/plc4go/spi/model/render_test.go
@@ -30,7 +30,7 @@ import (
 	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
 	apiValues "github.com/apache/plc4x/plc4go/pkg/api/values"
 	"github.com/apache/plc4x/plc4go/spi/utils"
-	spiValue "github.com/apache/plc4x/plc4go/spi/values"
+	spiValues "github.com/apache/plc4x/plc4go/spi/values"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -120,8 +120,8 @@ func TestRenderTestCustom(t *testing.T) {
 					"tagid2": NewMockPlcBrowseItem(t),
 				},
 				map[string]apiValues.PlcValue{
-					"tagid1": spiValue.PlcNull{},
-					"tagid2": spiValue.PlcNull{},
+					"tagid1": spiValues.PlcNull{},
+					"tagid2": spiValues.PlcNull{},
 					"tagid3": nil,
 				},
 			).(interface { // TODO: workaround
@@ -182,7 +182,9 @@ func TestRenderTestCustom(t *testing.T) {
 				"something",
 				"something",
 				url.URL{},
-				nil,
+				map[string][]string{
+					"something": {"else"},
+				},
 				"something",
 				nil,
 			).(interface { // TODO: workaround