fix: refresh action cache and classify auth failures
This commit is contained in:
+70
-7
@@ -141,6 +141,7 @@ func TestGetDeviceInfoParsesSpecAndCaches(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var pythonCache struct {
|
||||
Version int `json:"version"`
|
||||
Properties []struct {
|
||||
Method cacheMethod `json:"method"`
|
||||
} `json:"properties"`
|
||||
@@ -148,7 +149,7 @@ func TestGetDeviceInfoParsesSpecAndCaches(t *testing.T) {
|
||||
Method cacheMethod `json:"method"`
|
||||
} `json:"actions"`
|
||||
}
|
||||
if err := json.Unmarshal(cacheData, &pythonCache); err != nil || pythonCache.Properties[0].Method.SIID != 2 || pythonCache.Properties[0].Method.PIID != 1 || pythonCache.Actions[0].Method.SIID != 2 || pythonCache.Actions[0].Method.AIID != 1 {
|
||||
if err := json.Unmarshal(cacheData, &pythonCache); err != nil || pythonCache.Version != 2 || pythonCache.Properties[0].Method.SIID != 2 || pythonCache.Properties[0].Method.PIID != 1 || pythonCache.Actions[0].Method.SIID != 2 || pythonCache.Actions[0].Method.AIID != 1 {
|
||||
t.Fatalf("Python-compatible cache = %#v, %v", pythonCache, err)
|
||||
}
|
||||
testServer.fixture = nil
|
||||
@@ -186,7 +187,7 @@ func TestPythonDeviceInfoCacheSupportsOperations(t *testing.T) {
|
||||
"properties": [{"name":"power","description":"Power","type":"bool","rw":"rw","method":{"siid":7,"piid":8}}],
|
||||
"actions": [{"name":"toggle","description":"Toggle","method":{"siid":9,"aiid":10}}]
|
||||
}`
|
||||
testServer := newDeviceTestServer(t, nil, []string{
|
||||
testServer := newDeviceTestServer(t, loadSpecFixture(t), []string{
|
||||
`{"homelist":[{"id":"10","uid":1}]}`,
|
||||
`{"device_info":[{"did":"a","name":"Lamp","model":"test.light.v1"}],"has_more":false}`,
|
||||
`[{"did":"a","siid":7,"piid":8,"value":true,"code":0}]`,
|
||||
@@ -213,9 +214,9 @@ func TestPythonDeviceInfoCacheSupportsOperations(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for index, want := range []map[string]any{
|
||||
{"siid": float64(7), "piid": float64(8)},
|
||||
{"siid": float64(7), "piid": float64(8)},
|
||||
{"siid": float64(9), "aiid": float64(10)},
|
||||
{"siid": float64(2), "piid": float64(1)},
|
||||
{"siid": float64(2), "piid": float64(1)},
|
||||
{"siid": float64(2), "aiid": float64(1)},
|
||||
} {
|
||||
params := testServer.requests[index+2]["params"]
|
||||
var request map[string]any
|
||||
@@ -230,8 +231,68 @@ func TestPythonDeviceInfoCacheSupportsOperations(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if testServer.specCalls != 0 {
|
||||
t.Fatalf("spec calls = %d, want 0", testServer.specCalls)
|
||||
if testServer.specCalls != 1 {
|
||||
t.Fatalf("spec calls = %d, want 1", testServer.specCalls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOldDeviceInfoCacheRefreshesActionInputs(t *testing.T) {
|
||||
for _, version := range []int{0, 1} {
|
||||
t.Run(fmt.Sprintf("version %d", version), func(t *testing.T) {
|
||||
testServer := newDeviceTestServer(t, loadSpecFixture(t), nil)
|
||||
cacheDir := t.TempDir()
|
||||
cache := fmt.Sprintf(`{
|
||||
"version":%d,
|
||||
"name":"Old Lamp",
|
||||
"model":"test.light.v1",
|
||||
"properties":[{"name":"power","type":"bool","rw":"rw","siid":2,"piid":1}],
|
||||
"actions":[{"name":"toggle","siid":2,"aiid":1}]
|
||||
}`, version)
|
||||
if err := os.WriteFile(filepath.Join(cacheDir, "test.light.v1.json"), []byte(cache), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
info, err := GetDeviceInfo(context.Background(), testServer.server.Client(), "test.light.v1", cacheDir)
|
||||
if err != nil || testServer.specCalls != 1 || len(info.Actions) == 0 || len(info.Actions[0].Inputs) != 2 {
|
||||
t.Fatalf("GetDeviceInfo() = %#v, %v, calls=%d", info, err, testServer.specCalls)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersion2DeviceInfoCacheTrustsActionWithoutInputs(t *testing.T) {
|
||||
testServer := newDeviceTestServer(t, nil, nil)
|
||||
cacheDir := t.TempDir()
|
||||
const cache = `{
|
||||
"version":2,
|
||||
"name":"Cached Lamp",
|
||||
"model":"test.light.v1",
|
||||
"properties":[{"name":"power","type":"bool","rw":"rw","siid":2,"piid":1}],
|
||||
"actions":[{"name":"toggle","siid":2,"aiid":1}]
|
||||
}`
|
||||
if err := os.WriteFile(filepath.Join(cacheDir, "test.light.v1.json"), []byte(cache), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
info, err := GetDeviceInfo(context.Background(), testServer.server.Client(), "test.light.v1", cacheDir)
|
||||
if err != nil || testServer.specCalls != 0 || len(info.Actions) != 1 || len(info.Actions[0].Inputs) != 0 {
|
||||
t.Fatalf("GetDeviceInfo() = %#v, %v, calls=%d", info, err, testServer.specCalls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStaleDeviceInfoCacheRefreshFailureIncludesBothErrors(t *testing.T) {
|
||||
testServer := newDeviceTestServer(t, []byte("unavailable"), nil)
|
||||
testServer.status = http.StatusServiceUnavailable
|
||||
cacheDir := t.TempDir()
|
||||
cachePath := filepath.Join(cacheDir, "test.light.v1.json")
|
||||
const cache = `{"version":1,"model":"test.light.v1","properties":[],"actions":[]}`
|
||||
if err := os.WriteFile(cachePath, []byte(cache), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err := GetDeviceInfo(context.Background(), testServer.server.Client(), "test.light.v1", cacheDir)
|
||||
if err == nil || !strings.Contains(err.Error(), "cache stale") || !strings.Contains(err.Error(), "refresh failed") || !strings.Contains(err.Error(), "503") {
|
||||
t.Fatalf("error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,6 +331,7 @@ func TestInvalidDeviceInfoCacheRefreshesAndOverwrites(t *testing.T) {
|
||||
|
||||
func TestDecodeDeviceInfoRejectsNonexistentActionInput(t *testing.T) {
|
||||
const cache = `{
|
||||
"version":2,
|
||||
"model":"test.light.v1",
|
||||
"properties":[{"name":"power","description":"Power","type":"bool","rw":"rw","siid":2,"piid":1}],
|
||||
"actions":[{"name":"toggle","siid":2,"aiid":1,"inputs":[{"name":"missing","type":"bool","rw":"rw","siid":2,"piid":99}]}]
|
||||
@@ -282,6 +344,7 @@ func TestDecodeDeviceInfoRejectsNonexistentActionInput(t *testing.T) {
|
||||
|
||||
func TestDecodeDeviceInfoCanonicalizesActionInputMetadata(t *testing.T) {
|
||||
const cache = `{
|
||||
"version":2,
|
||||
"model":"test.light.v1",
|
||||
"properties":[{"name":"power","description":"Power","type":"bool","rw":"rw","value-list":[{"value":0,"description":"Off"},{"value":1,"description":"On"}],"siid":2,"piid":1}],
|
||||
"actions":[{"name":"toggle","siid":2,"aiid":1,"inputs":[{"name":"forged","description":"Forged","type":"string","rw":"w","range":[1,9,1],"siid":2,"piid":1}]}]
|
||||
|
||||
Reference in New Issue
Block a user