fix: preserve batch result compatibility
This commit is contained in:
@@ -767,18 +767,12 @@ func (device *Device) GetMany(ctx context.Context, names []string) ([]DeviceProp
|
|||||||
identity := propertyIdentity{did: request.DID, siid: request.SIID, piid: request.PIID}
|
identity := propertyIdentity{did: request.DID, siid: request.SIID, piid: request.PIID}
|
||||||
name := names[start+index]
|
name := names[start+index]
|
||||||
if _, duplicate := duplicateIdentities[identity]; duplicate {
|
if _, duplicate := duplicateIdentities[identity]; duplicate {
|
||||||
results[start+index] = DevicePropertyResult{
|
results[start+index] = DevicePropertyResult{Name: name, Code: PropertyResultCodeDuplicate}
|
||||||
Name: name,
|
|
||||||
Err: fmt.Errorf("get properties protocol error: duplicate identity (%s,%d,%d)", request.DID, request.SIID, request.PIID),
|
|
||||||
}
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
result, ok := byIdentity[identity]
|
result, ok := byIdentity[identity]
|
||||||
if !ok {
|
if !ok {
|
||||||
results[start+index] = DevicePropertyResult{
|
results[start+index] = DevicePropertyResult{Name: name, Code: PropertyResultCodeMissing}
|
||||||
Name: name,
|
|
||||||
Err: fmt.Errorf("get properties protocol error: missing identity (%s,%d,%d)", request.DID, request.SIID, request.PIID),
|
|
||||||
}
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
results[start+index] = DevicePropertyResult{Name: name, Value: result.Value, Code: result.Code}
|
results[start+index] = DevicePropertyResult{Name: name, Value: result.Value, Code: result.Code}
|
||||||
|
|||||||
+27
-21
@@ -18,6 +18,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ = DevicePropertyResult{"x", nil, 0}
|
||||||
|
|
||||||
type deviceTestServer struct {
|
type deviceTestServer struct {
|
||||||
t *testing.T
|
t *testing.T
|
||||||
fixture []byte
|
fixture []byte
|
||||||
@@ -625,51 +627,55 @@ func TestDeviceGetManyMatchesIdentityAndPreservesBusinessErrors(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeviceGetManyPreservesPartialResultsForInvalidResponseIdentities(t *testing.T) {
|
func TestDeviceGetManyClassifiesMissingAndDuplicateResults(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
response string
|
response string
|
||||||
wantErrs []string
|
want []DevicePropertyResult
|
||||||
}{
|
}{
|
||||||
{name: "missing", response: `[{"did":"a","siid":2,"piid":1,"value":true,"code":0}]`, wantErrs: []string{"", "missing identity"}},
|
{
|
||||||
{name: "duplicate and missing", response: `[{"did":"a","siid":2,"piid":1,"value":true,"code":0},{"did":"a","siid":2,"piid":1,"value":false,"code":0}]`, wantErrs: []string{"duplicate identity", "missing identity"}},
|
name: "missing",
|
||||||
|
response: `[{"did":"a","siid":2,"piid":1,"value":true,"code":0}]`,
|
||||||
|
want: []DevicePropertyResult{{"power", true, 0}, {"brightness", nil, PropertyResultCodeMissing}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "duplicate",
|
||||||
|
response: `[{"did":"a","siid":2,"piid":1,"value":true,"code":0},{"did":"a","siid":2,"piid":1,"value":false,"code":0},{"did":"a","siid":2,"piid":2,"value":5,"code":0}]`,
|
||||||
|
want: []DevicePropertyResult{{"power", nil, PropertyResultCodeDuplicate}, {"brightness", json.Number("5"), 0}},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
device := fixtureDeviceWithResults(t, []string{test.response}, 0)
|
device := fixtureDeviceWithResults(t, []string{test.response}, 0)
|
||||||
results, err := device.GetMany(context.Background(), []string{"power", "brightness"})
|
results, err := device.GetMany(context.Background(), []string{"power", "brightness"})
|
||||||
if err != nil || len(results) != 2 {
|
if err != nil || !reflect.DeepEqual(results, test.want) {
|
||||||
t.Fatalf("GetMany() = %#v, %v", results, err)
|
t.Fatalf("GetMany() = %#v, %v, want %#v, nil", results, err, test.want)
|
||||||
}
|
|
||||||
for index, wantErr := range test.wantErrs {
|
|
||||||
if results[index].Name != []string{"power", "brightness"}[index] {
|
|
||||||
t.Fatalf("result %d name = %q", index, results[index].Name)
|
|
||||||
}
|
|
||||||
if wantErr == "" {
|
|
||||||
if results[index].Err != nil || results[index].Value != true {
|
|
||||||
t.Fatalf("result %d = %#v, want successful power result", index, results[index])
|
|
||||||
}
|
|
||||||
} else if results[index].Err == nil || !strings.Contains(results[index].Err.Error(), wantErr) {
|
|
||||||
t.Fatalf("result %d error = %v, want %q", index, results[index].Err, wantErr)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeviceGetManyRejectsExtraResponseIdentity(t *testing.T) {
|
func TestDeviceGetManyRejectsExtraResult(t *testing.T) {
|
||||||
device := fixtureDeviceWithResults(t, []string{`[
|
device := fixtureDeviceWithResults(t, []string{`[
|
||||||
{"did":"a","siid":2,"piid":1,"value":true,"code":0},
|
{"did":"a","siid":2,"piid":1,"value":true,"code":0},
|
||||||
{"did":"a","siid":2,"piid":2,"value":5,"code":0},
|
{"did":"a","siid":2,"piid":2,"value":5,"code":0},
|
||||||
{"did":"other","siid":9,"piid":9,"value":1,"code":0}
|
{"did":"other","siid":9,"piid":9,"value":1,"code":0}
|
||||||
]`}, 0)
|
]`}, 0)
|
||||||
|
|
||||||
results, err := device.GetMany(context.Background(), []string{"power", "brightness"})
|
results, err := device.GetMany(context.Background(), []string{"power", "brightness"})
|
||||||
if err == nil || results != nil || !strings.Contains(err.Error(), "protocol") {
|
if err == nil || results != nil || !strings.Contains(err.Error(), "protocol") {
|
||||||
t.Fatalf("GetMany() = %#v, %v, want nil protocol error", results, err)
|
t.Fatalf("GetMany() = %#v, %v, want nil protocol error", results, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDeviceGetManyReturnsTransportError(t *testing.T) {
|
||||||
|
device, testServer := fixtureDeviceWithServer(t, nil)
|
||||||
|
testServer.server.Close()
|
||||||
|
|
||||||
|
results, err := device.GetMany(context.Background(), []string{"power", "brightness"})
|
||||||
|
if err == nil || results != nil {
|
||||||
|
t.Fatalf("GetMany() = %#v, %v, want nil transport error", results, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
func TestDeviceGetManyValidatesBeforeNetwork(t *testing.T) {
|
func TestDeviceGetManyValidatesBeforeNetwork(t *testing.T) {
|
||||||
device, testServer := fixtureDeviceWithServer(t, nil)
|
device, testServer := fixtureDeviceWithServer(t, nil)
|
||||||
tests := [][]string{{"power", "power"}, {"power", "missing"}, {"power", "write-only"}}
|
tests := [][]string{{"power", "power"}, {"power", "missing"}, {"power", "write-only"}}
|
||||||
@@ -723,7 +729,7 @@ func TestDeviceGetManyWaitsOnceWithPartialProtocolErrors(t *testing.T) {
|
|||||||
started := time.Now()
|
started := time.Now()
|
||||||
results, err := device.GetMany(context.Background(), []string{"power", "brightness"})
|
results, err := device.GetMany(context.Background(), []string{"power", "brightness"})
|
||||||
elapsed := time.Since(started)
|
elapsed := time.Since(started)
|
||||||
if err != nil || len(results) != 2 || results[1].Err == nil {
|
if err != nil || len(results) != 2 || results[1].Code != PropertyResultCodeMissing {
|
||||||
t.Fatalf("GetMany() = %#v, %v", results, err)
|
t.Fatalf("GetMany() = %#v, %v", results, err)
|
||||||
}
|
}
|
||||||
if elapsed < 30*time.Millisecond || elapsed >= 75*time.Millisecond {
|
if elapsed < 30*time.Millisecond || elapsed >= 75*time.Millisecond {
|
||||||
|
|||||||
@@ -5,9 +5,17 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// PropertyResultCodeMissing classifies a missing GetMany result locally and is never returned by upstream.
|
||||||
|
PropertyResultCodeMissing int = math.MinInt32
|
||||||
|
// PropertyResultCodeDuplicate classifies duplicate GetMany results locally and is never returned by upstream.
|
||||||
|
PropertyResultCodeDuplicate int = math.MinInt32 + 1
|
||||||
|
)
|
||||||
|
|
||||||
type Home struct {
|
type Home struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
@@ -163,7 +171,6 @@ type DevicePropertyResult struct {
|
|||||||
Name string
|
Name string
|
||||||
Value any
|
Value any
|
||||||
Code int
|
Code int
|
||||||
Err error `json:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ActionRequest struct {
|
type ActionRequest struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user