mirror of
https://github.com/rstrouse/ESPSomfy-RTS.git
synced 2026-10-31 13:52:15 +01:00
test: record protocol 2 fixtures from a device
hello, the schema and a whole sync as the device sent them, recorded with pytest test/e2e --record. Remote addresses, rolling codes, names, the server id, hostname and SSID are replaced with fake values while recording, since with an address and its rolling code anyone could forge frames for a real installation's shades. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
10521cf78d
commit
d869bb53d5
4 changed files with 1593 additions and 2 deletions
|
|
@ -100,8 +100,36 @@ def test_resync_sends_it_all_again(connect, schema):
|
||||||
assert "T" not in f["d"]
|
assert "T" not in f["d"]
|
||||||
|
|
||||||
|
|
||||||
|
# What a recording must not keep from a real installation: the remote
|
||||||
|
# addresses and rolling codes would let anyone forge frames for its shades.
|
||||||
|
SCRUBBED = {"remoteAddress", "lastRollingCode", "sourceAddress", "startingAddress", "repeaters",
|
||||||
|
"name", "serverId", "hostname", "ssid"}
|
||||||
|
|
||||||
|
|
||||||
|
def scrub(value, schema, counter):
|
||||||
|
"""Fake values of the same kind in place of anything identifying."""
|
||||||
|
if isinstance(value, list):
|
||||||
|
return [scrub(v, schema, counter) for v in value]
|
||||||
|
if not isinstance(value, dict):
|
||||||
|
return value
|
||||||
|
out = {}
|
||||||
|
for key, v in value.items():
|
||||||
|
name = schema.fields.get(key, (key,))[0]
|
||||||
|
if name in SCRUBBED:
|
||||||
|
counter[0] += 1
|
||||||
|
if isinstance(v, list):
|
||||||
|
v = [0x100000 + counter[0] * 16 + i for i in range(len(v))]
|
||||||
|
elif isinstance(v, str):
|
||||||
|
v = "%s %u" % (name, counter[0])
|
||||||
|
else:
|
||||||
|
v = 0x100000 + counter[0]
|
||||||
|
out[key] = scrub(v, schema, counter)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
def test_record_fixtures(connect, recording):
|
def test_record_fixtures(connect, recording):
|
||||||
"""With --record, saves hello and a whole first sync for the other suites."""
|
"""With --record, saves hello and a whole first sync for the other suites,
|
||||||
|
with the installation's identifying values replaced."""
|
||||||
if not recording:
|
if not recording:
|
||||||
return
|
return
|
||||||
c = connect()
|
c = connect()
|
||||||
|
|
@ -111,8 +139,12 @@ def test_record_fixtures(connect, recording):
|
||||||
hello = json.loads(c.raw[0])
|
hello = json.loads(c.raw[0])
|
||||||
with open(os.path.join(FIXTURES, "hello.json"), "w", encoding="utf-8") as f:
|
with open(os.path.join(FIXTURES, "hello.json"), "w", encoding="utf-8") as f:
|
||||||
json.dump(hello, f, indent=1)
|
json.dump(hello, f, indent=1)
|
||||||
|
counter = [0]
|
||||||
|
frames = [json.loads(r) for r in c.raw[1:]]
|
||||||
|
for frame in frames:
|
||||||
|
frame["d"] = scrub(frame["d"], schema, counter)
|
||||||
with open(os.path.join(FIXTURES, "sync.json"), "w", encoding="utf-8") as f:
|
with open(os.path.join(FIXTURES, "sync.json"), "w", encoding="utf-8") as f:
|
||||||
json.dump([json.loads(r) for r in c.raw[1:]], f, indent=1)
|
json.dump(frames, f, indent=1)
|
||||||
expanded = {
|
expanded = {
|
||||||
"hash": hello["d"]["sh"],
|
"hash": hello["d"]["sh"],
|
||||||
"types": {str(k): v for k, v in sorted(schema.types.items())},
|
"types": {str(k): v for k, v in sorted(schema.types.items())},
|
||||||
|
|
|
||||||
8
test/fixtures/proto2/hello.json
vendored
Normal file
8
test/fixtures/proto2/hello.json
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"v": 2,
|
||||||
|
"t": 1,
|
||||||
|
"d": {
|
||||||
|
"fw": "v3.0.14",
|
||||||
|
"sh": "8198c564"
|
||||||
|
}
|
||||||
|
}
|
||||||
510
test/fixtures/proto2/schema.json
vendored
Normal file
510
test/fixtures/proto2/schema.json
vendored
Normal file
|
|
@ -0,0 +1,510 @@
|
||||||
|
{
|
||||||
|
"hash": "8198c564",
|
||||||
|
"types": {
|
||||||
|
"1": "hello",
|
||||||
|
"2": "reply",
|
||||||
|
"3": "next",
|
||||||
|
"4": "sync",
|
||||||
|
"5": "syncEnd",
|
||||||
|
"6": "subscribe",
|
||||||
|
"7": "unsubscribe",
|
||||||
|
"128": "shadeState",
|
||||||
|
"129": "shade",
|
||||||
|
"130": "shadeRemoved",
|
||||||
|
"131": "group",
|
||||||
|
"132": "groupState",
|
||||||
|
"133": "groupRemoved",
|
||||||
|
"134": "room",
|
||||||
|
"135": "roomRemoved",
|
||||||
|
"136": "roomOrder",
|
||||||
|
"137": "shadeOrder",
|
||||||
|
"138": "groupOrder",
|
||||||
|
"139": "shadeCommand",
|
||||||
|
"140": "memory",
|
||||||
|
"141": "wifi",
|
||||||
|
"142": "ethernet",
|
||||||
|
"143": "frame",
|
||||||
|
"144": "frequencyScan",
|
||||||
|
"145": "repeaters"
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"D": {
|
||||||
|
"name": "downTime",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"E": {
|
||||||
|
"name": "errors",
|
||||||
|
"kind": "l",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"F": {
|
||||||
|
"name": "fields",
|
||||||
|
"kind": "l",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"G": {
|
||||||
|
"name": "groups",
|
||||||
|
"kind": "l",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"M": {
|
||||||
|
"name": "myTiltPos",
|
||||||
|
"kind": "i",
|
||||||
|
"default": -1
|
||||||
|
},
|
||||||
|
"Q": {
|
||||||
|
"name": "feeds",
|
||||||
|
"kind": "l",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"R": {
|
||||||
|
"name": "rooms",
|
||||||
|
"kind": "l",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"S": {
|
||||||
|
"name": "shades",
|
||||||
|
"kind": "l",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"T": {
|
||||||
|
"name": "types",
|
||||||
|
"kind": "l",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"U": {
|
||||||
|
"name": "upTime",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"X": {
|
||||||
|
"name": "repeaters",
|
||||||
|
"kind": "l",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"Y": {
|
||||||
|
"name": "tiltTime",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"Z": {
|
||||||
|
"name": "status",
|
||||||
|
"kind": "o",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"a": {
|
||||||
|
"name": "remoteAddress",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"bl": {
|
||||||
|
"name": "bitLength",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 56
|
||||||
|
},
|
||||||
|
"bt": {
|
||||||
|
"name": "bits",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"c": {
|
||||||
|
"name": "lastRollingCode",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"ch": {
|
||||||
|
"name": "channel",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"cm": {
|
||||||
|
"name": "command",
|
||||||
|
"kind": "s",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"co": {
|
||||||
|
"name": "connected",
|
||||||
|
"kind": "b",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"cp": {
|
||||||
|
"name": "chipModel",
|
||||||
|
"kind": "s",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"ct": {
|
||||||
|
"name": "connType",
|
||||||
|
"kind": "s",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"d": {
|
||||||
|
"name": "direction",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"e": {
|
||||||
|
"name": "code",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"ek": {
|
||||||
|
"name": "encKey",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"f": {
|
||||||
|
"name": "flags",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"fc": {
|
||||||
|
"name": "flipCommands",
|
||||||
|
"kind": "b",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"fd": {
|
||||||
|
"name": "fullDuplex",
|
||||||
|
"kind": "b",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"fe": {
|
||||||
|
"name": "feed",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"fp": {
|
||||||
|
"name": "flipPosition",
|
||||||
|
"kind": "b",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"fq": {
|
||||||
|
"name": "frequency",
|
||||||
|
"kind": "n",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"fr": {
|
||||||
|
"name": "freeHeap",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"fw": {
|
||||||
|
"name": "fw",
|
||||||
|
"kind": "s",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"g": {
|
||||||
|
"name": "groupId",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"gd": {
|
||||||
|
"name": "gpioDown",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"gl": {
|
||||||
|
"name": "gpioLLTrigger",
|
||||||
|
"kind": "b",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"gm": {
|
||||||
|
"name": "gpioMy",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"gu": {
|
||||||
|
"name": "gpioUp",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"h": {
|
||||||
|
"name": "header",
|
||||||
|
"kind": "o",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"hn": {
|
||||||
|
"name": "hostname",
|
||||||
|
"kind": "s",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"hs": {
|
||||||
|
"name": "hwsync",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"i": {
|
||||||
|
"name": "paired",
|
||||||
|
"kind": "b",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"ig": {
|
||||||
|
"name": "inGroup",
|
||||||
|
"kind": "b",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"is": {
|
||||||
|
"name": "ids",
|
||||||
|
"kind": "l",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"k": {
|
||||||
|
"name": "ok",
|
||||||
|
"kind": "b",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"li": {
|
||||||
|
"name": "light",
|
||||||
|
"kind": "b",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"lk": {
|
||||||
|
"name": "linkedRemotes",
|
||||||
|
"kind": "l",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"lp": {
|
||||||
|
"name": "loopRate",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"ls": {
|
||||||
|
"name": "linkedShades",
|
||||||
|
"kind": "l",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"lx": {
|
||||||
|
"name": "loopMaxUs",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"m": {
|
||||||
|
"name": "myPos",
|
||||||
|
"kind": "i",
|
||||||
|
"default": -1
|
||||||
|
},
|
||||||
|
"md": {
|
||||||
|
"name": "model",
|
||||||
|
"kind": "s",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"mn": {
|
||||||
|
"name": "minHeap",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"mx": {
|
||||||
|
"name": "maxHeap",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"n": {
|
||||||
|
"name": "name",
|
||||||
|
"kind": "s",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"o": {
|
||||||
|
"name": "sortOrder",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"p": {
|
||||||
|
"name": "position",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"pr": {
|
||||||
|
"name": "proto",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"pu": {
|
||||||
|
"name": "pulses",
|
||||||
|
"kind": "l",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"q": {
|
||||||
|
"name": "tiltPosition",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"r": {
|
||||||
|
"name": "roomId",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"rp": {
|
||||||
|
"name": "repeats",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 1
|
||||||
|
},
|
||||||
|
"rs": {
|
||||||
|
"name": "rssi",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"rw": {
|
||||||
|
"name": "rawCmd",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"s": {
|
||||||
|
"name": "shadeId",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"sa": {
|
||||||
|
"name": "startingAddress",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"sc": {
|
||||||
|
"name": "scanning",
|
||||||
|
"kind": "b",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"sd": {
|
||||||
|
"name": "ssid",
|
||||||
|
"kind": "s",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"sg": {
|
||||||
|
"name": "strength",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"sh": {
|
||||||
|
"name": "schemaHash",
|
||||||
|
"kind": "s",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"sm": {
|
||||||
|
"name": "simMy",
|
||||||
|
"kind": "b",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"so": {
|
||||||
|
"name": "source",
|
||||||
|
"kind": "s",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"sp": {
|
||||||
|
"name": "speed",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"sr": {
|
||||||
|
"name": "sourceAddress",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"ss": {
|
||||||
|
"name": "sunSensor",
|
||||||
|
"kind": "b",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"st": {
|
||||||
|
"name": "shadeType",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"sv": {
|
||||||
|
"name": "serverId",
|
||||||
|
"kind": "s",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"t": {
|
||||||
|
"name": "target",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"tf": {
|
||||||
|
"name": "testFreq",
|
||||||
|
"kind": "n",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"name": "totalHeap",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"tr": {
|
||||||
|
"name": "testRssi",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"u": {
|
||||||
|
"name": "tiltTarget",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"up": {
|
||||||
|
"name": "uptime",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"va": {
|
||||||
|
"name": "valid",
|
||||||
|
"kind": "b",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"w": {
|
||||||
|
"name": "tiltDirection",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"x": {
|
||||||
|
"name": "desc",
|
||||||
|
"kind": "s",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"xg": {
|
||||||
|
"name": "maxGroups",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"xl": {
|
||||||
|
"name": "maxLinkedRemotes",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"xm": {
|
||||||
|
"name": "maxGroupedShades",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"xr": {
|
||||||
|
"name": "maxRooms",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"xs": {
|
||||||
|
"name": "maxShades",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"y": {
|
||||||
|
"name": "tiltType",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"z": {
|
||||||
|
"name": "stepSize",
|
||||||
|
"kind": "i",
|
||||||
|
"default": 100
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"1": "badRequest",
|
||||||
|
"2": "unknownOp",
|
||||||
|
"3": "unauthorized",
|
||||||
|
"4": "notFound",
|
||||||
|
"5": "busy",
|
||||||
|
"6": "radioUnavailable",
|
||||||
|
"7": "internal"
|
||||||
|
},
|
||||||
|
"feeds": {
|
||||||
|
"1": "frames",
|
||||||
|
"2": "frequencyScan"
|
||||||
|
}
|
||||||
|
}
|
||||||
1041
test/fixtures/proto2/sync.json
vendored
Normal file
1041
test/fixtures/proto2/sync.json
vendored
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue