diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 18b2b295..755f4f90 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,6 +26,10 @@ repos: rev: v2.2.6 hooks: - id: codespell + exclude: > + (?x)^( + .*\.ambr + )$ - repo: https://github.com/charliermarsh/ruff-pre-commit rev: v0.13.2 hooks: diff --git a/tests/e2e/__init__.py b/tests/e2e/__init__.py index 38fd7fb6..d1bdda39 100644 --- a/tests/e2e/__init__.py +++ b/tests/e2e/__init__.py @@ -5,4 +5,5 @@ "tests.fixtures.local_async_fixtures", "tests.fixtures.pahomqtt_fixtures", "tests.fixtures.aiomqtt_fixtures", + "tests.fixtures.web_api_fixtures", ] diff --git a/tests/e2e/__snapshots__/test_device_manager.ambr b/tests/e2e/__snapshots__/test_device_manager.ambr new file mode 100644 index 00000000..5f0f70c6 --- /dev/null +++ b/tests/e2e/__snapshots__/test_device_manager.ambr @@ -0,0 +1,293 @@ +# serializer version: 1 +# name: test_device_manager + [mqtt >] + 00000000 10 29 00 04 4d 51 54 54 05 c2 00 3c 00 00 00 00 |.)..MQTT...<....| + 00000010 08 31 39 36 34 38 66 39 34 00 10 32 33 34 36 37 |.19648f94..23467| + 00000020 38 65 61 38 35 34 66 31 39 39 65 |8ea854f199e| + [mqtt <] + 00000000 20 09 02 00 06 22 00 0a 21 00 14 | ...."..!..| + [mqtt >] + 00000000 82 24 00 01 00 00 1e 72 72 2f 6d 2f 6f 2f 75 73 |.$.....rr/m/o/us| + 00000010 65 72 31 32 33 2f 31 39 36 34 38 66 39 34 2f 61 |er123/19648f94/a| + 00000020 62 63 31 32 33 00 |bc123.| + [mqtt <] + 00000000 90 04 00 01 00 00 |......| + [mqtt >] + 00000000 30 f8 01 00 1e 72 72 2f 6d 2f 69 2f 75 73 65 72 |0....rr/m/i/user| + 00000010 31 32 33 2f 31 39 36 34 38 66 39 34 2f 61 62 63 |123/19648f94/abc| + 00000020 31 32 33 00 31 2e 30 00 00 23 83 00 00 23 84 68 |123.1.0..#...#.h| + 00000030 a6 a2 27 00 65 00 c0 d5 b7 f1 34 a4 76 21 76 0a |..'.e.....4.v!v.| + 00000040 ed 60 71 51 04 ae bd 39 9b 41 c6 34 63 89 66 1f |.`qQ...9.A.4c.f.| + 00000050 c2 8b 96 83 ec 93 45 55 f0 cf ed 93 0f 45 ff a9 |......EU.....E..| + 00000060 a4 8b a5 5a c9 25 36 1a eb cf 1d 6d d9 b5 b6 37 |...Z.%6....m...7| + 00000070 8a a3 4d 9c 2f e4 41 f3 75 28 11 6c 2d 39 83 cb |..M./.A.u(.l-9..| + 00000080 b1 60 8b 92 d5 b7 a7 be e3 c0 aa 80 94 0c 99 12 |.`..............| + 00000090 a2 e1 97 7e 3e ea 29 27 0f 9e 9c 22 97 0b 9c 59 |...~>.)'..."...Y| + 000000a0 78 da 88 55 6b 52 58 7e de 1c a3 c8 ec 0b 55 1d |x..UkRX~......U.| + 000000b0 86 46 cf 86 98 45 05 f3 06 76 db 4f 4e 2f 10 65 |.F...E...v.ON/.e| + 000000c0 ae 40 8d 86 4c 66 28 c8 4b 31 a5 ec 43 3d 40 21 |.@..Lf(.K1..C=@!| + 000000d0 90 07 ff fb 4f 5b f8 ea f3 37 20 f9 94 7e 2b d6 |....O[...7 ..~+.| + 000000e0 fb 9a ed 2c 37 e8 b2 b0 3d f3 93 6f 17 d7 89 31 |...,7...=..o...1| + 000000f0 bb e0 42 8b 18 fd 0d 46 bd 10 67 |..B....F..g| + [mqtt <] + 00000000 30 8c 02 00 1e 72 72 2f 6d 2f 6f 2f 75 73 65 72 |0....rr/m/o/user| + 00000010 31 32 33 2f 31 39 36 34 38 66 39 34 2f 61 62 63 |123/19648f94/abc| + 00000020 31 32 33 00 00 00 00 e7 31 2e 30 00 00 00 01 00 |123.....1.0.....| + 00000030 00 00 17 68 a6 a2 23 00 66 00 d0 84 66 bd 8c 5a |...h..#.f...f..Z| + 00000040 42 4a aa 2d 9e bf 93 7e 3e 92 5a 46 38 2b db 75 |BJ.-...~>.ZF8+.u| + 00000050 ab 6c 28 b5 3d 80 d9 b7 73 cf b9 9e cf 62 52 ca |.l(.=...s....bR.| + 00000060 4e b4 7e b9 89 e9 50 45 4d f3 e1 c8 a9 a4 65 f1 |N.~...PEM.....e.| + 00000070 6d ff 2d e4 c6 c8 4e 8b 85 08 5c 20 91 76 f7 af |m.-...N...\ .v..| + 00000080 cf 25 80 48 e6 95 97 b1 0f b0 6e 1e 62 26 a1 d1 |.%.H......n.b&..| + 00000090 38 c4 f1 39 2a b9 3b 05 0e 37 cb d5 5b cd 95 e7 |8..9*.;..7..[...| + 000000a0 4b f6 ff d7 03 dc 6b e3 ac d6 7e ec a7 75 64 08 |K.....k...~..ud.| + 000000b0 2d 2a 6d e1 af 94 ee a4 b3 4f ed 1e d8 aa 76 f0 |-*m......O....v.| + 000000c0 bd 02 37 7c 6b 5b fb 8d 62 b0 c1 85 79 49 df 67 |..7|k[..b...yI.g| + 000000d0 3c 1e 9a a3 b3 4d 1d 50 ac 9f 62 b9 99 4f 45 47 |<....M.P..b..OEG| + 000000e0 ba 41 30 53 19 63 92 84 c5 bc a4 33 2f 21 8c dd |.A0S.c.....3/!..| + 000000f0 6e f2 b1 ed 08 59 50 2a b1 a9 e2 f1 bb af 4b 6b |n....YP*......Kk| + 00000100 7c 87 7f 0c dd 9b 6d 26 a4 20 bb a7 e0 82 5c ||.....m&. ....\| + [local >] + 00000000 00 00 00 15 31 2e 30 00 00 00 01 00 00 23 85 68 |....1.0......#.h| + 00000010 a6 a2 28 00 00 2a 04 e3 89 |..(..*...| + [local <] + 00000000 00 00 00 27 31 2e 30 00 00 00 01 00 00 00 17 68 |...'1.0........h| + 00000010 a6 a2 24 00 01 00 10 e1 cc 62 66 4e c7 42 27 80 |..$......bfN.B'.| + 00000020 ee 12 a0 f8 9c 54 d3 d3 b6 78 34 |.....T...x4| + [local >] + 00000000 00 00 00 77 31 2e 30 00 00 23 87 00 00 23 88 68 |...w1.0..#...#.h| + 00000010 a6 a2 29 00 04 00 60 69 d4 c5 8b a1 6e 03 47 01 |..)...`i....n.G.| + 00000020 c4 cd bb 48 17 96 fb 9d b8 60 84 05 dc 99 96 e0 |...H.....`......| + 00000030 72 3e dc 6d 9d de a5 73 e6 c4 e8 7d 9a a5 ea d7 |r>.m...s...}....| + 00000040 73 7f 0d 58 31 a2 38 bc 85 2c 65 9e 93 e4 e8 ca |s..X1.8..,e.....| + 00000050 f0 c9 f9 fb 32 52 3c 1b 73 ea 1b ef 1a 71 17 de |....2R<.s....q..| + 00000060 74 77 ba 97 6e f7 27 9d c6 1b ac f4 64 6a 27 72 |tw..n.'.....dj'r| + 00000070 b6 ae 41 f6 17 60 99 fc 0d 53 ed |..A..`...S.| + [local <] + 00000000 00 00 03 a7 31 2e 30 00 00 00 02 00 00 00 17 68 |....1.0........h| + 00000010 a6 a2 25 00 66 03 90 a4 7d c1 13 61 78 1f aa ec |..%.f...}..ax...| + 00000020 22 05 51 cf c4 af fa ba eb 80 2f 0e 34 f6 d5 ae |".Q......./.4...| + 00000030 36 13 f2 0e 56 cd 69 4d 0f 4b 30 54 c0 67 1e f9 |6...V.iM.K0T.g..| + 00000040 b9 26 c0 0d 54 36 92 b1 47 20 25 ff 10 88 f3 8a |.&..T6..G %.....| + 00000050 e1 2b a7 cc 65 0b 27 35 5d 2f 7a 03 85 1a 92 8c |.+..e.'5]/z.....| + 00000060 51 2a 8b d8 4f 8d 8e 00 53 c3 d9 0c ea 17 79 9e |Q*..O...S.....y.| + 00000070 38 41 93 0e 19 6b cf 41 d3 16 b4 f9 8c db a5 65 |8A...k.A.......e| + 00000080 f2 9c dc ae 2d 69 85 f0 7f 7a dd 6c ba 46 1f c3 |....-i...z.l.F..| + 00000090 96 4f df be 32 fc 7a ed 6d 86 0b 7b 2d c7 03 00 |.O..2.z.m..{-...| + 000000a0 44 b1 ae 6a 32 3b e8 28 56 60 95 ec bd 59 b7 90 |D..j2;.(V`...Y..| + 000000b0 72 34 ca a6 ca 27 c7 0b 77 43 b5 76 3e fc f3 76 |r4...'..wC.v>..v| + 000000c0 c8 b3 2d fd 63 d8 89 6a 8b ad 11 27 64 d2 76 0f |..-.c..j...'d.v.| + 000000d0 96 d4 50 b4 99 cc 6a 81 bf 9a 8e 6b 99 27 92 c9 |..P...j....k.'..| + 000000e0 89 9e c3 e0 23 83 65 bd ec b9 fd ec 11 c5 76 a1 |....#.e.......v.| + 000000f0 bf ed 7c a5 a0 f8 ac 9b 71 c6 09 31 bd 5c 1f ef |..|.....q..1.\..| + 00000100 c5 b5 e3 f3 b3 92 66 d9 aa 76 67 62 c6 e0 db 36 |......f..vgb...6| + 00000110 a7 69 74 e6 ea fa eb a3 16 ba 04 6b 4f dc 7a 4d |.it........kO.zM| + 00000120 5d 3d 8c 9a 52 0b 88 f6 f7 db 62 a8 ce f1 73 8b |]=..R.....b...s.| + 00000130 2e 72 b4 92 53 29 0d 5b 65 5d 14 46 a0 55 4f 74 |.r..S).[e].F.UOt| + 00000140 13 a9 27 96 fb bb c9 09 58 71 05 03 9f c0 71 0a |..'.....Xq....q.| + 00000150 74 9a 9e 01 6f f9 04 ed 10 56 e9 3d 7c c1 88 11 |t...o....V.=|...| + 00000160 19 3e b3 80 58 8c 37 95 ea f7 9b 95 1b 51 36 38 |.>..X.7......Q68| + 00000170 c9 97 60 44 01 53 ba 24 c5 f7 15 45 ce 08 e0 51 |..`D.S.$...E...Q| + 00000180 6b 8b 2f de 79 e8 6d ef f2 c5 73 31 8e 12 f5 9b |k./.y.m...s1....| + 00000190 d7 b0 a6 c8 b5 78 09 7d a6 06 53 4a 45 aa 74 22 |.....x.}..SJE.t"| + 000001a0 95 f4 9e 99 d2 63 f4 3b 60 e6 8c 5f 73 68 89 f0 |.....c.;`.._sh..| + 000001b0 0f 12 82 a3 8a 63 4b eb a6 75 9e 6d 2f 1f 1a 2c |.....cK..u.m/..,| + 000001c0 90 67 03 60 3a fd bc c2 31 72 ce 2c f0 7b 30 2d |.g.`:...1r.,.{0-| + 000001d0 5b f0 f4 d2 b9 2f 7b f0 08 aa c7 8a 95 bb 68 7d |[..../{.......h}| + 000001e0 40 a8 9b 2c 5e c4 61 a5 cc 86 16 91 d6 cb c4 ab |@..,^.a.........| + 000001f0 a9 6e d2 26 ef 7d ad 99 0a 47 bc f5 3c 30 fe 88 |.n.&.}...G..<0..| + 00000200 b1 4b 39 27 40 92 96 77 55 eb 32 69 f1 fd 12 ab |.K9'@..wU.2i....| + 00000210 c6 39 c1 55 5e 1a df 9e 62 f2 df eb ac 2f 66 44 |.9.U^...b..../fD| + 00000220 46 05 7a 9e eb df d1 50 2e 4a 7b 9f 0d 19 c8 64 |F.z....P.J{....d| + 00000230 5b df 81 37 60 6f e9 b2 90 ef bc 76 27 43 c6 bb |[..7`o.....v'C..| + 00000240 63 6c 17 d3 d0 6d 37 0c 87 5c f8 ab e6 90 35 91 |cl...m7..\....5.| + 00000250 e5 d1 49 b1 c5 a7 0e eb 67 e0 ac fe 83 45 c4 6c |..I.....g....E.l| + 00000260 28 1d 7f d9 45 64 48 95 68 35 68 d3 80 06 3f 39 |(...EdH.h5h...?9| + 00000270 fd e4 6d 85 9d 29 8a f9 1b c4 4b 66 00 2e 36 d8 |..m..)....Kf..6.| + 00000280 41 fd ae 70 d5 3c 3e 83 fd a4 1c c0 1a 24 6e 91 |A..p.<>......$n.| + 00000290 b4 24 9f 98 6c f0 a4 c2 65 c4 e1 f3 34 bb b1 bd |.$..l...e...4...| + 000002a0 15 c1 b3 81 bc 9a 22 eb ad ab dd 22 ad b5 a2 59 |......"...."...Y| + 000002b0 88 6d a5 0e 28 d0 5e fe 46 62 f3 6d bf e8 6e 83 |.m..(.^.Fb.m..n.| + 000002c0 04 35 38 2d 7d c9 9b 63 c5 0d 5b 1f 99 07 f2 73 |.58-}..c..[....s| + 000002d0 63 8e 12 e9 3c f3 0c 5c c0 ca 40 ec d3 db 6d 84 |c...<..\..@...m.| + 000002e0 a1 0e 2f 42 6b e5 27 7f f6 b1 cf b9 f0 bf 67 ec |../Bk.'.......g.| + 000002f0 9a 14 b8 34 07 f5 10 60 7e 42 1c 3d b8 a0 07 be |...4...`~B.=....| + 00000300 0f c7 dd 5a 65 58 45 64 d3 10 1e 96 47 a7 ff e0 |...ZeXEd....G...| + 00000310 a7 56 f6 62 a1 c5 41 d6 b1 0f d8 24 56 80 c1 94 |.V.b..A....$V...| + 00000320 ac e6 34 4a 94 bf 07 6e bd e5 4c 07 81 f0 e9 73 |..4J...n..L....s| + 00000330 2f 56 c7 8b 54 31 f1 c0 b9 06 82 6e 3f 67 19 d1 |/V..T1.....n?g..| + 00000340 0f 79 9d 97 30 d3 22 6a 83 6b d7 48 34 7e 45 41 |.y..0."j.k.H4~EA| + 00000350 c7 e4 0e 26 98 56 c5 15 2d 35 f5 7e 67 d7 fb e5 |...&.V..-5.~g...| + 00000360 d8 76 c0 4d cb 0a 40 e3 0a 9e c7 9a 8c 6f 70 1d |.v.M..@......op.| + 00000370 10 b2 38 21 cc 98 5c 93 e7 ab b4 32 ec 15 ce f6 |..8!..\....2....| + 00000380 36 3a 09 27 62 bf bf 60 75 6d fb 36 b3 d8 c9 b5 |6:.'b..`um.6....| + 00000390 2b 5b d8 03 2e 79 4e c8 6c 66 48 97 ff 57 5f c8 |+[...yN.lfH..W_.| + 000003a0 c1 64 16 82 ba 30 5f 2f fd 96 ad |.d...0_/...| + [local >] + 00000000 00 00 00 77 31 2e 30 00 00 23 8a 00 00 23 8b 68 |...w1.0..#...#.h| + 00000010 a6 a2 2a 00 04 00 60 54 4f 82 9c 0f f0 e7 9c bb |..*...`TO.......| + 00000020 62 2e 87 79 75 6f 69 fa de 20 5a ef 66 01 1c 8d |b..yuoi.. Z.f...| + 00000030 2f 2b ca 36 e5 6f 3c 67 3a ee da 29 cf 87 66 1f |/+.6.o..<.| + 00000050 57 8c 73 44 ae b7 7d 2b 94 06 3f 12 6e 09 f0 9a |W.sD..}+..?.n...| + 00000060 c9 10 27 10 02 cd cd 69 61 64 28 ef 2c 78 44 db |..'....iad(.,xD.| + 00000070 8e 2f e2 d7 42 2c 0e fd 47 05 26 |./..B,..G.&| + [local <] + 00000000 00 00 04 27 31 2e 30 00 00 00 03 00 00 00 17 68 |...'1.0........h| + 00000010 a6 a2 26 00 66 04 10 23 78 4f 6e 2e 1a 98 9f 3d |..&.f..#xOn....=| + 00000020 a3 69 31 89 a2 c2 c7 b3 77 2a 69 ec 36 d0 1b 8d |.i1.....w*i.6...| + 00000030 f8 b0 e8 1c d8 6b 72 92 69 7b 6d 8c 1b a9 ba a1 |.....kr.i{m.....| + 00000040 d8 9d 0c b4 fb 99 ba f0 7a 30 de 17 90 11 df 4b |........z0.....K| + 00000050 87 8c 38 1d 3c 23 93 26 ab 0d fb 22 28 a1 e2 85 |..8.<#.&..."(...| + 00000060 dd 7d 36 63 7e 48 5c ff 32 57 e7 87 dd 45 5f eb |.}6c~H\.2W...E_.| + 00000070 9b 27 f5 82 cb 47 11 af 36 09 de 2e 4e c9 77 63 |.'...G..6...N.wc| + 00000080 16 3c 1a 43 9b ad 5c 70 f8 55 e7 ec ba 05 0c 65 |.<.C..\p.U.....e| + 00000090 60 c3 73 29 ca 2c 8b 7f eb ce bd 94 b8 69 37 7a |`.s).,.......i7z| + 000000a0 ee b7 18 5e cd f3 86 14 d3 e4 72 44 37 86 0c 59 |...^......rD7..Y| + 000000b0 67 89 d0 9b d5 0f 8a 56 b7 9f 59 33 95 6c c4 ef |g......V..Y3.l..| + 000000c0 47 c3 51 6b 92 6b b0 88 a9 58 f6 1e 2c d9 71 e4 |G.Qk.k...X..,.q.| + 000000d0 a3 f9 cb ea 27 61 e0 e6 8a 55 4a 8c 55 4e 37 0c |....'a...UJ.UN7.| + 000000e0 da 55 a2 76 b9 f7 bd 36 ef 82 c4 49 88 52 47 3d |.U.v...6...I.RG=| + 000000f0 b2 1f d8 23 b8 a8 b6 c1 9a a5 77 5c f2 39 30 fe |...#......w\.90.| + 00000100 16 ed 37 a6 79 54 77 e0 f9 b5 41 20 bf 63 fc bb |..7.yTw...A .c..| + 00000110 37 9e 4a a7 f5 f7 13 5e 56 a2 ac 7d 33 7d 20 86 |7.J....^V..}3} .| + 00000120 c8 4d 95 cd 9c f8 d8 10 68 60 60 6e fc 4b 08 67 |.M......h``n.K.g| + 00000130 74 e3 5a c9 ca 15 4f 86 92 c8 bc 34 3c c5 da a1 |t.Z...O....4<...| + 00000140 1b 75 18 f8 ec a1 98 70 22 81 fd ec e1 18 46 4a |.u.....p".....FJ| + 00000150 0c cf 9c 77 ec a1 b5 57 90 4c 79 8d b5 2a 56 fa |...w...W.Ly..*V.| + 00000160 a7 1b 07 05 d8 f3 0b 3b 34 6c ab 3d eb 3e 2e ec |.......;4l.=.>..| + 00000170 d9 8e 70 37 bc 47 86 b0 f3 22 e6 2e 72 10 b9 61 |..p7.G..."..r..a| + 00000180 ac 41 14 19 ca 3e 89 00 c7 a3 08 ba 04 ea 5c b1 |.A...>........\.| + 00000190 11 fd a2 98 7b 37 50 29 0c c9 25 a2 f1 0e 9f ac |....{7P)..%.....| + 000001a0 53 97 22 44 72 a2 b1 36 ed 9c 16 0f 0a f0 78 f3 |S."Dr..6......x.| + 000001b0 b1 61 1a d7 e8 30 ee 87 e4 1a 77 f0 11 ab 0d c5 |.a...0....w.....| + 000001c0 ef 0b 14 ef ee 15 5b 25 35 fd 53 32 db f8 0b 68 |......[%5.S2...h| + 000001d0 ae c7 c5 31 3f 6a 31 1c 63 65 03 49 a5 b4 48 e5 |...1?j1.ce.I..H.| + 000001e0 ac d5 66 a6 f8 20 fb 84 51 ee ee 6f a5 41 dc 1f |..f.. ..Q..o.A..| + 000001f0 27 3c 91 82 7c 87 8b c7 1d c6 2b c3 40 da 90 92 |'<..|.....+.@...| + 00000200 58 ea f9 ed 06 5e 25 e5 5a dd d8 35 bf 95 07 84 |X....^%.Z..5....| + 00000210 9e 9e f7 a7 de 08 de 2b 0f 68 75 de e5 7e 2d ef |.......+.hu..~-.| + 00000220 10 c4 51 96 bb e0 a8 93 39 a0 5e 86 2e 3f 01 8a |..Q.....9.^..?..| + 00000230 74 b8 3d b0 9c 2c 9b c2 2d e6 ce 64 ae cc f5 50 |t.=..,..-..d...P| + 00000240 a9 c5 c0 9c 49 fb 53 56 96 97 48 72 07 30 01 e0 |....I.SV..Hr.0..| + 00000250 a3 0b f7 2d 7d 12 e1 b6 e6 b3 f5 e7 da 21 b4 81 |...-}........!..| + 00000260 e0 0a d3 b4 4a 9d b7 96 9f 53 49 f3 62 1e 64 75 |....J....SI.b.du| + 00000270 f0 9f ef cb 4c b5 d4 2d 23 d2 9e 39 71 fc 17 8f |....L..-#..9q...| + 00000280 5a 9b c7 65 c1 4e c7 4f 6b c4 a8 e1 b8 51 d5 08 |Z..e.N.Ok....Q..| + 00000290 09 af 55 bf cf 7f a3 49 41 ea 0f 04 51 4b fd c5 |..U....IA...QK..| + 000002a0 94 ed 1e 10 64 12 9c 53 26 7b 62 f9 3c ff 25 17 |....d..S&{b.<.%.| + 000002b0 64 49 bf 78 85 9b e1 98 2a ed ca 5d 0f 47 57 3d |dI.x....*..].GW=| + 000002c0 04 83 78 12 fb 79 c7 5a 2c 70 9c 83 bf d2 a5 e5 |..x..y.Z,p......| + 000002d0 ee 9d 2e 46 17 42 23 35 18 29 4b d1 0d 7a 55 b0 |...F.B#5.)K..zU.| + 000002e0 76 da 38 5a 20 14 9f 19 e3 60 dd 8a b7 b7 72 4a |v.8Z ....`....rJ| + 000002f0 f8 e2 46 5f 4e 4e be db 86 03 26 72 53 d4 5d 25 |..F_NN....&rS.]%| + 00000300 fa ec b7 e2 7e 8b 0b ae c9 6d ee a6 0e 5b 80 90 |....~....m...[..| + 00000310 e1 c3 57 06 3f c3 5e 4f 6b c4 a8 e1 b8 51 d5 08 |..W.?.^Ok....Q..| + 00000320 09 af 55 bf cf 7f a3 15 43 d1 5a 4e 10 4e dd 5e |..U.....C.ZN.N.^| + 00000330 87 55 76 0e ce 9b 9f ea 56 87 73 b4 f5 5f 31 f8 |.Uv.....V.s.._1.| + 00000340 81 b2 c0 2d d1 84 22 3a fb f7 e5 2f 8c 74 03 fa |...-..":.../.t..| + 00000350 0b 97 e8 a8 92 21 23 cc 1a 7a 91 bc 33 ba ab dc |.....!#..z..3...| + 00000360 0d 09 22 af d3 a0 2a 8c 2c 48 53 72 a7 a2 0f 1f |.."...*.,HSr....| + 00000370 8c b5 ca a5 4b 62 3d c6 84 3f 9c 44 7c d9 f1 9c |....Kb=..?.D|...| + 00000380 8a fe d7 1b 83 ff f7 10 5b bd 1e 89 6a cd 91 c0 |........[...j...| + 00000390 3a 95 b6 d5 87 3b 8c 6e a9 4e e5 3f bd 90 9c 46 |:....;.n.N.?...F| + 000003a0 0a ef d3 02 e3 8d 5c 35 ba c9 24 4b 99 a2 fb 13 |......\5..$K....| + 000003b0 de bb 66 96 04 74 a1 76 73 50 41 54 70 5e 27 bb |..f..t.vsPATp^'.| + 000003c0 24 b6 ae ee 35 b4 a9 13 bb 04 60 13 e8 c8 f2 9f |$...5.....`.....| + 000003d0 f5 c7 36 27 81 b8 0b fb 7d 65 d1 7a 0f d9 3c 73 |..6'....}e.z..] + 00000000 e0 00 |..| + [mqtt <] + 00000000 20 09 02 00 06 22 00 0a 21 00 14 | ...."..!..| + [mqtt <] + 00000000 90 04 00 01 00 00 |......| + [local >] + 00000000 00 00 00 15 31 2e 30 00 00 00 01 00 00 23 8c 68 |....1.0......#.h| + 00000010 a6 a2 2c 00 00 b8 95 0e 86 |..,......| + [local <] + 00000000 00 00 00 27 31 2e 30 00 00 00 01 00 00 00 17 68 |...'1.0........h| + 00000010 a6 a2 2b 00 01 00 10 6d b9 48 37 ed 43 59 7a 90 |..+....m.H7.CYz.| + 00000020 ff 43 2f 0a 8f 81 44 e7 b6 b3 85 |.C/...D....| + [local >] + 00000000 00 00 00 77 31 2e 30 00 00 23 8e 00 00 23 8f 68 |...w1.0..#...#.h| + 00000010 a6 a2 2e 00 04 00 60 a9 a0 ac af 22 80 bb 11 b7 |......`...."....| + 00000020 e4 74 fa c3 0e bd c3 d5 a1 f9 a8 1d f1 4e 04 b9 |.t...........N..| + 00000030 05 50 39 bc b6 68 62 5b fc 54 1c ce ac c5 df ce |.P9..hb[.T......| + 00000040 93 8f 5c 61 d5 4c 66 8b c3 19 e0 cd b4 8f 63 be |..\a.Lf.......c.| + 00000050 2b c0 16 46 4e c8 e7 70 d3 a4 de 0f ac 57 5b e6 |+..FN..p.....W[.| + 00000060 79 84 2c ab 87 75 c7 7a d7 64 d6 51 3b 5a 04 85 |y.,..u.z.d.Q;Z..| + 00000070 38 a4 39 90 99 6f 4c 84 b5 1b ba |8.9..oL....| + [local <] + 00000000 00 00 04 27 31 2e 30 00 00 00 02 00 00 00 17 68 |...'1.0........h| + 00000010 a6 a2 2d 00 66 04 10 5e 5f 0b 3d ac 87 95 d7 72 |..-.f..^_.=....r| + 00000020 96 43 49 74 68 c3 35 e3 c7 bd 9d d2 41 b1 15 99 |.CIth.5.....A...| + 00000030 23 aa 66 a2 1a b7 54 da d3 d1 17 a7 d5 96 8c 29 |#.f...T........)| + 00000040 1e a0 17 b7 40 ed 89 49 70 0d f9 1e aa b0 68 73 |....@..Ip.....hs| + 00000050 6c 0e 82 1e 46 6b b7 7f 75 d6 7e b8 a9 4c d1 57 |l...Fk..u.~..L.W| + 00000060 42 95 10 c8 f1 d9 04 9e b9 2c b6 3f dd 1c e5 2f |B........,.?.../| + 00000070 08 1f 0f b7 e9 85 5a 34 4b 69 9b 6f 68 dd 45 74 |......Z4Ki.oh.Et| + 00000080 d4 bc c6 ad 11 07 98 9f fb aa 7b 67 96 2f 67 60 |..........{g./g`| + 00000090 e1 4b 2d 80 72 48 47 09 f0 c3 a2 65 a4 32 3b d2 |.K-.rHG....e.2;.| + 000000a0 02 ac 38 76 72 30 27 9d 75 d6 1a aa 05 e5 08 c5 |..8vr0'.u.......| + 000000b0 2e c4 3e ab 86 72 6b 61 ce d0 77 1e c4 6f 91 6f |..>..rka..w..o.o| + 000000c0 29 d3 19 89 45 21 6b 1e 7a 27 76 e1 1a 71 32 0f |)...E!k.z'v..q2.| + 000000d0 af bb 54 7d ea 30 19 e6 95 0b db 0b 88 0b eb 19 |..T}.0..........| + 000000e0 18 f1 03 80 3e 2d d3 dd 47 61 93 d1 5a b9 b1 13 |....>-..Ga..Z...| + 000000f0 c6 5c b1 f6 52 0a 94 6f 27 05 fe 67 80 3d 3a 51 |.\..R..o'..g.=:Q| + 00000100 d6 65 28 10 23 4f 42 9c d6 40 c3 3e c6 64 13 a8 |.e(.#OB..@.>.d..| + 00000110 c1 7d 13 17 d2 a0 a1 7b 6d 35 a5 62 73 75 f0 9b |.}.....{m5.bsu..| + 00000120 e9 32 96 62 14 0e 97 b3 73 b1 df 48 b4 4c 96 b1 |.2.b....s..H.L..| + 00000130 52 8d d5 5b 2f b2 21 f0 e6 81 9b e4 a3 68 11 6c |R..[/.!......h.l| + 00000140 bd d8 6c 4c ba a3 1a fd 12 4a c8 e1 39 ce 74 f5 |..lL.....J..9.t.| + 00000150 52 71 4d 28 f1 d4 8e a6 68 95 fb e2 b9 f6 62 10 |RqM(....h.....b.| + 00000160 a0 51 1b 44 13 53 71 1d 32 94 54 e8 d8 3a d9 d1 |.Q.D.Sq.2.T..:..| + 00000170 15 e3 f9 09 91 38 2a ba 4c e1 ca a8 6e 3f cf 38 |.....8*.L...n?.8| + 00000180 8a 8f 38 f7 da d1 b4 13 17 df 84 d4 74 0c 2a 65 |..8.........t.*e| + 00000190 64 96 ec 5e 9b fb 4d f5 eb ab e8 9a 91 ae 3b d1 |d..^..M.......;.| + 000001a0 ac 54 66 a1 18 65 92 f9 7c 67 a0 e2 d2 7e 79 3f |.Tf..e..|g...~y?| + 000001b0 5a 9d 31 8d f4 98 cd cf 1b c5 51 04 12 05 34 6c |Z.1.......Q...4l| + 000001c0 36 4e 9a 00 2b 10 9c 53 1f cf fe ff 28 d3 ab fe |6N..+..S....(...| + 000001d0 dc 7c 85 fb 23 06 00 58 2f 4d 36 fb 1b 04 76 a4 |.|..#..X/M6...v.| + 000001e0 7f 73 b8 58 b1 1a 22 2c e6 27 29 09 c7 48 72 f7 |.s.X..",.')..Hr.| + 000001f0 63 ce 7b ff 61 60 23 8a 92 06 a0 fa cc fd 6a d0 |c.{.a`#.......j.| + 00000200 13 e5 24 33 f7 2c c2 95 06 06 d8 c8 28 21 09 c9 |..$3.,......(!..| + 00000210 d8 d5 52 67 a6 81 68 80 00 f1 8b d9 dc bf 16 ea |..Rg..h.........| + 00000220 8f 76 2f bd 6e a8 89 77 94 d3 58 52 0e da aa 06 |.v/.n..w..XR....| + 00000230 2c 4d 35 89 23 45 8a 58 d0 b1 19 fb d4 05 da f0 |,M5.#E.X........| + 00000240 6f 2f 00 e5 11 85 4e 34 a8 55 13 39 a9 2a 46 75 |o/....N4.U.9.*Fu| + 00000250 52 e1 1f 66 e3 b8 2a 55 ab b0 ad ea 9b b6 4b 4d |R..f..*U......KM| + 00000260 9c 79 9b 09 d1 b6 61 48 89 37 b0 98 3c bf bb 4a |.y....aH.7..<..J| + 00000270 f1 22 e2 dd ad e6 3c 98 f6 d0 1f 14 c1 73 ed 7e |."....<......s.~| + 00000280 f8 9a fb 4e 64 e9 2f d9 f9 94 58 b1 f4 9d 67 13 |...Nd./...X...g.| + 00000290 6d 08 4b 6e 1b ca d6 76 02 3f b0 2c fc 0b 0b 32 |m.Kn...v.?.,...2| + 000002a0 ce 38 a1 05 86 d3 db ce dd 06 63 49 e8 c1 d1 41 |.8........cI...A| + 000002b0 00 e0 3b 0a ed 7b 7a b1 04 86 a8 bb 1b 18 52 63 |..;..{z.......Rc| + 000002c0 db 42 2a c3 41 d8 1c 3c 31 ef 6b 72 7e c2 54 a5 |.B*.A..<1.kr~.T.| + 000002d0 20 94 23 b9 8d d0 5e 94 ef 85 b0 73 47 5d 7c f0 | .#...^....sG]|.| + 000002e0 ef ac 82 55 13 04 ba ca 4f 1b af fb 5c 0c b9 e7 |...U....O...\...| + 000002f0 21 c7 97 75 d3 db 18 51 d1 92 5c 51 97 8a ba 3e |!..u...Q..\Q...>| + 00000300 79 80 5c c9 21 8f 6b 8f 04 9e 9a 47 ed ef fe 66 |y.\.!.k....G...f| + 00000310 fe d3 76 5b ff dc 31 d9 f9 94 58 b1 f4 9d 67 13 |..v[..1...X...g.| + 00000320 6d 08 4b 6e 1b ca d6 7f 0c de c5 f4 a5 0f 49 cf |m.Kn..........I.| + 00000330 f9 e5 74 88 96 8a 14 bd 8a 19 0a ce 93 be 30 b8 |..t...........0.| + 00000340 35 1a 1e bb f3 0b ed 34 28 7f 73 ca 76 4a 8d 03 |5......4(.s.vJ..| + 00000350 81 0a 2c 2c cc fe e8 c6 e2 dd 9d e0 be 45 63 57 |..,,.........EcW| + 00000360 ae 34 40 e1 c4 5c 2b ee 40 68 5e d0 35 83 94 ce |.4@..\+.@h^.5...| + 00000370 be 2a 27 08 a5 dc 00 d5 b6 af 48 b3 6b 57 99 80 |.*'.......H.kW..| + 00000380 ba e8 2d 7e b5 57 4e 91 5e 15 7a 13 af 9d ed 24 |..-~.WN.^.z....$| + 00000390 03 6a 35 fb 75 b0 56 36 90 70 ff 59 f9 3f dd 7e |.j5.u.V6.p.Y.?.~| + 000003a0 09 1b 05 a1 38 dc 1c 12 5b 9c 4d 82 b2 32 95 1f |....8...[.M..2..| + 000003b0 80 4f 29 53 51 9f b3 12 72 1a b4 b9 79 d5 7b 74 |.O)SQ...r...y.{t| + 000003c0 99 94 71 90 83 b5 51 1a 47 4e 99 ae 54 78 98 fe |..q...Q.GN..Tx..| + 000003d0 38 91 1e 5e 67 72 1b f1 b8 7d 66 83 55 21 94 7c |8..^gr...}f.U!.|| + 000003e0 d6 79 8b 61 65 0e 0d 46 c4 3b 6f e8 0e f2 ec 4b |.y.ae..F.;o....K| + 000003f0 b6 60 24 40 83 2b 94 06 de a8 88 76 d6 c4 7b 17 |.`$@.+.....v..{.| + 00000400 77 50 dd e5 02 1f 70 86 1b f5 f5 56 19 5e 54 00 |wP....p....V.^T.| + 00000410 cc 52 61 40 f9 d5 02 3c dd 7d 66 3a 06 89 a0 7a |.Ra@...<.}f:...z| + 00000420 98 80 37 eb 64 ea ee b2 82 5a 2a |..7.d....Z*| +# --- diff --git a/tests/e2e/test_device_manager.py b/tests/e2e/test_device_manager.py new file mode 100644 index 00000000..6971df9b --- /dev/null +++ b/tests/e2e/test_device_manager.py @@ -0,0 +1,270 @@ +"""End-to-end tests for MQTT session. + +These tests use a fake MQTT broker to verify the session implementation. We +mock out the lower level socket connections to simulate a broker which gets us +close to an "end to end" test without needing an actual MQTT broker server. + +These are higher level tests that the similar tests in tests/mqtt/test_roborock_session.py +which use mocks to verify specific behaviors. +""" + +import asyncio +import json +from collections.abc import AsyncGenerator, Awaitable, Callable +from typing import Any + +import pytest +import syrupy + +from roborock.devices.cache import Cache, InMemoryCache +from roborock.devices.device_manager import DeviceManager, UserParams, create_device_manager +from roborock.protocol import MessageParser +from roborock.protocols.v1_protocol import LocalProtocolVersion +from roborock.roborock_message import RoborockMessage, RoborockMessageProtocol +from roborock.web_api import RoborockApiClient +from tests import mock_data, mqtt_packet +from tests.fixtures.logging import CapturedRequestLog +from tests.mock_data import LOCAL_KEY + +TEST_USERNAME = "user@example.com" +TEST_CODE = 1234 + +# The topic used for the user + device. This is determined from the fake Home +# data API response. +TEST_TOPIC = "rr/m/o/user123/19648f94/abc123" +TEST_RANDOM = 23 +TEST_HOST = mock_data.TEST_LOCAL_API_HOST +NETWORK_INFO = { + "ip": TEST_HOST, + "ssid": "test_wifi", + "mac": "aa:bb:cc:dd:ee:ff", + "bssid": "aa:bb:cc:dd:ee:ff", + "rssi": -50, +} + + +@pytest.fixture(autouse=True) +def auto_mock_mqtt_client(mock_aiomqtt_client: None) -> None: + """Automatically use the mock mqtt client fixture.""" + + +@pytest.fixture(autouse=True) +def auto_fast_backoff(fast_backoff_fixture: None) -> None: + """Automatically use the fast backoff fixture.""" + + +@pytest.fixture(autouse=True) +def mqtt_server_fixture(mock_paho_mqtt_create_connection: None, mock_paho_mqtt_select: None) -> None: + """Fixture to mock the MQTT connection. + + This is here to pull in the mock socket fixtures into all tests used here. + """ + + +@pytest.fixture(autouse=True) +def auto_mock_local_client(mock_async_create_local_connection: None) -> None: + """Automatically use the mock local client fixture.""" + + +@pytest.fixture(name="device_manager_factory") +async def device_manager_factory_fixture() -> AsyncGenerator[Callable[[UserParams], Awaitable[DeviceManager]], None]: + """Fixture to create a device manager and handle auto shutdown on test failure.""" + + cleanup_tasks: list[Callable[[], Awaitable[None]]] = [] + cache: Cache = InMemoryCache() + + async def factory(user_params: UserParams) -> DeviceManager: + """Create a device manager and auto cleanup.""" + device_manager = await create_device_manager(user_params, cache=cache) + cleanup_tasks.append(device_manager.close) + return device_manager + + yield factory + + await asyncio.gather(*[task() for task in cleanup_tasks]) + + +class ResponseBuilder: + """Utility class to build raw response messages. + + This helps keep track of sequence numbers and timestamps mostly to remove + them from the main test body. These are mostly ignored by the client in the + response. + """ + + def __init__(self) -> None: + """Initialize the response builder.""" + self.seq_counter = 0 + self.timestamp_counter = 1766520441 + self.connect_nonce: int | None = None + self.ack_nonce: int | None = None + self.protocol = RoborockMessageProtocol.RPC_RESPONSE + self.version = LocalProtocolVersion.V1 + + def build( + self, + payload: bytes, + seq: int | None = None, + protocol: RoborockMessageProtocol | None = None, + ) -> bytes: + """Build an encoded response message.""" + if seq is not None: + self.seq_counter = seq + else: + self.seq_counter += 1 + return MessageParser.build( + RoborockMessage( + protocol=protocol if protocol is not None else self.protocol, + random=TEST_RANDOM, + seq=self.seq_counter, + payload=payload, + version=self.version.value.encode(), + ), + local_key=LOCAL_KEY, + connect_nonce=self.connect_nonce, + ack_nonce=self.ack_nonce, + ) + + def build_rpc( + self, + data: dict[str, Any], + protocol: RoborockMessageProtocol | None = None, + ) -> bytes: + """Build an encoded RPC response message.""" + self.timestamp_counter += 1 + return self.build( + payload=json.dumps( + { + "t": self.timestamp_counter, + "dps": { + "102": json.dumps(data), + }, + } + ).encode(), + protocol=protocol, + ) + + +async def test_device_manager( + mock_rest: Any, + push_mqtt_response: Callable[[bytes], None], + local_response_queue: asyncio.Queue[bytes], + local_received_requests: asyncio.Queue[bytes], + log: CapturedRequestLog, + snapshot: syrupy.SnapshotAssertion, + device_manager_factory: Callable[[UserParams], Awaitable[DeviceManager]], +) -> None: + """Test the device manager end to end flow.""" + + # Simulate the login flow to get user params + web_api = RoborockApiClient(username=TEST_USERNAME) + await web_api.request_code() + user_data = await web_api.code_login(TEST_CODE) + + # Prepare MQTT requests + response_builder = ResponseBuilder() + mqtt_responses: list[bytes] = [ + # MQTT connection response + mqtt_packet.gen_connack(rc=0, flags=2), + # ACK the request to subscribe to the topic + mqtt_packet.gen_suback(mid=1), + # ACK the GET_NETWORK_INFO call. id is deterministic based on deterministic_message_fixtures + mqtt_packet.gen_publish( + TEST_TOPIC, mid=2, payload=response_builder.build_rpc(data={"id": 9090, "result": NETWORK_INFO}) + ), + ] + for response in mqtt_responses: + push_mqtt_response(response) + + # Prepare local device responses. The ids are deterministic based on deterministic_message_fixtures + local_responses: list[bytes] = [ + # Queue HELLO response + response_builder.build(protocol=RoborockMessageProtocol.HELLO_RESPONSE, seq=1, payload=b"ok"), + # Feature discovery part 1 & 2 + response_builder.build_rpc(data={"id": 9094, "result": [mock_data.APP_GET_INIT_STATUS]}), + response_builder.build_rpc(data={"id": 9097, "result": [mock_data.STATUS]}), + ] + for payload in local_responses: + local_response_queue.put_nowait(payload) + + # Create the device manager + user_params = UserParams( + username=TEST_USERNAME, + user_data=user_data, + base_url=await web_api.base_url, + ) + device_manager = await device_manager_factory(user_params) + + # The mocked Home Data API returns a single v1 device + devices = await device_manager.get_devices() + assert len(devices) == 1 + device = devices[0] + assert device.duid == "abc123" + assert device.name == "Roborock S7 MaxV" + assert device.is_connected + assert device.is_local_connected + + # Verify GET_STATUS response based on mock_data.STATUS + assert device.v1_properties + assert device.v1_properties.status + assert device.v1_properties.status.state_name == "charging" + assert device.v1_properties.status.battery == 100 + assert device.v1_properties.status.clean_time == 1176 + + # Verify arbitrary device features + assert device.v1_properties.device_features.is_show_clean_finish_reason_supported + assert device.v1_properties.device_features.is_customized_clean_supported + assert not device.v1_properties.device_features.is_matter_supported + + # Close the device manager. We will test re-connecting and reusing the network + # information and device discovery information from the cache. + await device_manager.close() + + mqtt_responses = [ + # MQTT connection response + mqtt_packet.gen_connack(rc=0, flags=2), + # ACK the request to subscribe to the topic + mqtt_packet.gen_suback(mid=1), + # No network info call this time since it should be cached + ] + for response in mqtt_responses: + push_mqtt_response(response) + + # Prepare local device responses. + local_response_queue.put_nowait( + response_builder.build(protocol=RoborockMessageProtocol.HELLO_RESPONSE, seq=1, payload=b"ok") + ) + + device_manager = await device_manager_factory(user_params) + + # The mocked Home Data API returns a single v1 device + devices = await device_manager.get_devices() + assert len(devices) == 1 + device = devices[0] + assert device.duid == "abc123" + assert device.name == "Roborock S7 MaxV" + assert device.is_connected + assert device.is_local_connected + + # Verify arbitrary device features from cache + assert device.v1_properties + assert device.v1_properties.device_features + assert device.v1_properties.device_features.is_show_clean_finish_reason_supported + assert device.v1_properties.device_features.is_customized_clean_supported + assert not device.v1_properties.device_features.is_matter_supported + + # In the previous test, the dock information is fetched and has the side effect of + # populating the status trait. This test gets dock information from the cache so + # we have to manually refresh status the first time (like other traits). + assert device.v1_properties + assert device.v1_properties.status + assert device.v1_properties.status.state_name is None + + # Exercise a GET_STATUS call. id is deterministic based on deterministic_message_fixtures + local_response_queue.put_nowait(response_builder.build_rpc(data={"id": 9101, "result": [mock_data.STATUS]})) + + # Verify GET_STATUS response + await device.v1_properties.status.refresh() + assert device.v1_properties.status.state_name == "charging" + + assert snapshot == log diff --git a/tests/fixtures/web_api_fixtures.py b/tests/fixtures/web_api_fixtures.py index 0b071387..3d5726d3 100644 --- a/tests/fixtures/web_api_fixtures.py +++ b/tests/fixtures/web_api_fixtures.py @@ -62,6 +62,11 @@ def mock_rest_fixture(skip_rate_limit: Any) -> aioresponses: status=200, payload={"api": None, "code": 200, "result": HOME_DATA_RAW, "status": "ok", "success": True}, ) + mocked.get( + re.compile(r"https://api-.*\.roborock\.com/v3/user/homes*"), + status=200, + payload={"api": None, "code": 200, "result": HOME_DATA_RAW, "status": "ok", "success": True}, + ) mocked.post( re.compile(r"https://api-.*\.roborock\.com/nc/prepare"), status=200,