From 620e36bb5f190aa30041152538c7183ea4578d70 Mon Sep 17 00:00:00 2001 From: Allen Porter Date: Tue, 23 Dec 2025 12:23:05 -0800 Subject: [PATCH 1/3] chore: Add an end to end device manager test --- tests/e2e/__init__.py | 1 + .../__snapshots__/test_device_manager.ambr | 203 ++++++++++++++++ tests/e2e/test_device_manager.py | 223 ++++++++++++++++++ tests/fixtures/web_api_fixtures.py | 5 + 4 files changed, 432 insertions(+) create mode 100644 tests/e2e/__snapshots__/test_device_manager.ambr create mode 100644 tests/e2e/test_device_manager.py 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..374aa9d5 --- /dev/null +++ b/tests/e2e/__snapshots__/test_device_manager.ambr @@ -0,0 +1,203 @@ +# 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.. 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 pixtures into all tests used here. + """ + + +@pytest.fixture +def auto_deterministic_message_fixtures(deterministic_message_fixtures: None) -> None: + """Auto-use deterministic message fixtures for all tests in this module.""" + pass + + +@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]]] = [] + + async def factory(user_params: UserParams) -> DeviceManager: + """Create a device manager and auto cleanup.""" + device_manager = await create_device_manager(user_params) + 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 + + 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, From 54964d700f79b3c63cfffc315ba6c44662662d0e Mon Sep 17 00:00:00 2001 From: Allen Porter Date: Tue, 23 Dec 2025 17:07:00 -0800 Subject: [PATCH 2/3] chore: Add end to end tests of the device cache Use the existing test to also exercise the cache by closing the device manager and reconnecting. --- .pre-commit-config.yaml | 4 + .../__snapshots__/test_device_manager.ambr | 90 +++++++++++++++++++ tests/e2e/test_device_manager.py | 63 +++++++++++-- 3 files changed, 149 insertions(+), 8 deletions(-) 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/__snapshots__/test_device_manager.ambr b/tests/e2e/__snapshots__/test_device_manager.ambr index 374aa9d5..5f0f70c6 100644 --- a/tests/e2e/__snapshots__/test_device_manager.ambr +++ b/tests/e2e/__snapshots__/test_device_manager.ambr @@ -200,4 +200,94 @@ 00000400 22 54 f5 8f 15 f6 5f 5c 0b f2 7e 71 34 7d d1 12 |"T...._\..~q4}..| 00000410 5c 4c 83 4b d3 d1 37 b7 01 d4 00 04 13 e7 40 c4 |\L.K..7.......@.| 00000420 0d ff 46 6d ef 57 d3 05 18 3d 90 |..Fm.W...=.| + [mqtt >] + 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 index 7237e158..6971df9b 100644 --- a/tests/e2e/test_device_manager.py +++ b/tests/e2e/test_device_manager.py @@ -16,6 +16,7 @@ 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 @@ -56,16 +57,10 @@ def auto_fast_backoff(fast_backoff_fixture: None) -> None: 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 pixtures into all tests used here. + This is here to pull in the mock socket fixtures into all tests used here. """ -@pytest.fixture -def auto_deterministic_message_fixtures(deterministic_message_fixtures: None) -> None: - """Auto-use deterministic message fixtures for all tests in this module.""" - pass - - @pytest.fixture(autouse=True) def auto_mock_local_client(mock_async_create_local_connection: None) -> None: """Automatically use the mock local client fixture.""" @@ -76,10 +71,11 @@ async def device_manager_factory_fixture() -> AsyncGenerator[Callable[[UserParam """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) + device_manager = await create_device_manager(user_params, cache=cache) cleanup_tasks.append(device_manager.close) return device_manager @@ -220,4 +216,55 @@ async def test_device_manager( 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 From 8849074bab2665c9b50f7bad77b9d33db289513d Mon Sep 17 00:00:00 2001 From: Allen Porter Date: Wed, 24 Dec 2025 09:22:58 -0800 Subject: [PATCH 3/3] fix: Update device startup connection behavior Increase the timeout waiting for the initial device startup to happen to wait beyond the L01 fallback behavior. Before this chnage, the device returns and is not yet conected locally (the test fails) forcing MQTT requests. --- roborock/devices/device.py | 4 +- .../__snapshots__/test_device_manager.ambr | 212 +++++++++++++++++- tests/e2e/test_device_manager.py | 95 +++++++- 3 files changed, 300 insertions(+), 11 deletions(-) diff --git a/roborock/devices/device.py b/roborock/devices/device.py index e58bac9d..d7908c74 100644 --- a/roborock/devices/device.py +++ b/roborock/devices/device.py @@ -33,7 +33,9 @@ MIN_BACKOFF_INTERVAL = datetime.timedelta(seconds=10) MAX_BACKOFF_INTERVAL = datetime.timedelta(minutes=30) BACKOFF_MULTIPLIER = 1.5 -START_ATTEMPT_TIMEOUT = datetime.timedelta(seconds=5) +# Give time for the NETWORK_INFO fetch and V1 hello attempt +# and potential fallback to L01. +START_ATTEMPT_TIMEOUT = datetime.timedelta(seconds=15) DeviceReadyCallback = Callable[["RoborockDevice"], None] diff --git a/tests/e2e/__snapshots__/test_device_manager.ambr b/tests/e2e/__snapshots__/test_device_manager.ambr index 5f0f70c6..ccea0922 100644 --- a/tests/e2e/__snapshots__/test_device_manager.ambr +++ b/tests/e2e/__snapshots__/test_device_manager.ambr @@ -1,5 +1,215 @@ # serializer version: 1 -# name: test_device_manager +# name: test_l01_device + [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 b7 a3 2b 85 67 49 5e 90 85 |x..UkRX..+.gI^..| + 000000b0 d8 7a bb b3 c9 14 6c fb 42 1c 85 96 23 ff 30 02 |.z....l.B...#.0.| + 000000c0 78 20 1c 5b 96 e1 f2 ad f2 62 28 c2 8a 9f 97 79 |x .[.....b(....y| + 000000d0 f9 73 25 c4 66 98 e8 ea f3 37 20 f9 94 7e 2b d6 |.s%.f....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 62 2d 95 ca |..B....b-..| + [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 |.| + [local >] + 00000000 00 00 00 15 4c 30 31 00 00 00 01 00 00 23 85 68 |....L01......#.h| + 00000010 a6 a2 29 00 00 22 92 f7 02 |..).."...| + [local <] + 00000000 00 00 00 29 4c 30 31 00 00 00 01 00 00 00 17 68 |...)L01........h| + 00000010 a6 a2 24 00 01 00 12 c1 07 5b 52 43 96 97 c5 29 |..$......[RC...)| + 00000020 59 36 cc 5c 9c 8b f2 ab 8a f0 30 d7 a9 |Y6.\......0..| + [local >] + 00000000 00 00 00 86 4c 30 31 00 00 23 87 00 00 23 88 68 |....L01..#...#.h| + 00000010 a6 a2 2a 00 04 00 6f 62 62 b7 96 c7 51 5f a7 4b |..*...obb...Q_.K| + 00000020 92 8f ce 25 cb 15 55 28 7a 93 03 83 ec 3c d9 9b |...%..U(z....<..| + 00000030 e2 c0 34 22 93 c0 c6 9a ff b2 9a df c3 01 b3 ad |..4"............| + 00000040 f3 a4 7f 05 f5 9c c5 89 38 55 42 09 ad 60 56 88 |........8UB..`V.| + 00000050 b7 cb 6f 62 f2 6d 04 a3 39 1f 69 70 64 41 29 d8 |..ob.m..9.ipdA).| + 00000060 20 a8 b4 64 d0 ae 37 79 b4 85 44 bb 66 87 14 39 | ..d..7y..D.f..9| + 00000070 33 20 60 02 0f 4e b1 bf 87 8a 84 5a 29 44 e1 d5 |3 `..N.....Z)D..| + 00000080 40 a6 02 6a 67 81 63 37 eb 07 |@..jg.c7..| + [local <] + 00000000 00 00 03 b5 4c 30 31 00 00 00 02 00 00 00 17 68 |....L01........h| + 00000010 a6 a2 25 00 66 03 9e f6 bf 79 0a 3e 32 de 58 fa |..%.f....y.>2.X.| + 00000020 f1 b0 dd a2 47 f6 30 37 c6 c1 24 70 3d bd 9c 15 |....G.07..$p=...| + 00000030 1f 2e 64 c7 95 7a e4 4f 5d 0a c6 d6 7a 9f b9 ad |..d..z.O]...z...| + 00000040 10 75 e3 b5 ff 4c e0 b5 dd 20 34 53 6f 40 4d ef |.u...L... 4So@M.| + 00000050 9c fd c7 83 49 99 80 0b 29 c9 b0 e7 57 4f 7d 24 |....I...)...WO}$| + 00000060 3b 09 42 fb 78 1f cc 39 2e ff 05 e3 0a 19 7f be |;.B.x..9........| + 00000070 6e cc ee d4 fe 3a dc 92 00 9e 07 09 ae 74 fc 95 |n....:.......t..| + 00000080 8b 4e 87 73 40 da bc 06 40 62 e7 49 86 e8 03 36 |.N.s@...@b.I...6| + 00000090 01 21 84 47 2b 1c 5f 64 26 8a 3c 65 0f 83 91 86 |.!.G+._d&..Mv..Z| + 000002d0 e0 cf 61 65 3b d4 30 04 f1 9f c0 14 33 b4 dc a0 |..ae;.0.....3...| + 000002e0 6e cc b7 eb 7d 52 e0 e2 c7 87 7e 31 52 64 92 3f |n...}R....~1Rd.?| + 000002f0 5d 55 d8 92 d0 d9 c0 11 92 36 40 f1 cc 67 14 84 |]U.......6@..g..| + 00000300 2a 00 08 91 21 b5 c9 12 c0 56 34 57 d2 e8 ef 51 |*...!....V4W...Q| + 00000310 81 10 eb c9 d9 84 a3 38 6d b5 b7 2c b6 52 a5 d6 |.......8m..,.R..| + 00000320 c5 33 94 a7 ed 27 00 c1 2e e2 88 0f 73 16 59 06 |.3...'......s.Y.| + 00000330 47 aa 45 6e e1 c7 31 69 b8 87 ae 1d 8f 01 ab 38 |G.En..1i.......8| + 00000340 69 ba a0 48 a0 47 3b a4 8f bf ac 51 64 6d e8 6a |i..H.G;....Qdm.j| + 00000350 ce a4 0a 2f af 36 04 97 60 f7 98 da df 84 7b d2 |.../.6..`.....{.| + 00000360 c6 c4 ac 9e 7d d7 86 b8 61 2b 1f b7 8e 19 67 69 |....}...a+....gi| + 00000370 cf 4e 65 b0 e9 50 b2 19 23 9e 8b de 4f 08 87 d2 |.Ne..P..#...O...| + 00000380 14 64 53 b8 f1 34 a9 ce 34 d3 c4 81 64 c0 9f 43 |.dS..4..4...d..C| + 00000390 c2 c4 bb 0b b0 ae ed e7 3f 28 cd 90 dd f6 7e dd |........?(....~.| + 000003a0 f7 2a 36 ad a6 a3 e2 1c 5e 52 41 a7 da 02 1e b4 |.*6.....^RA.....| + 000003b0 b5 c6 bf 22 a1 9f 76 65 45 |..."..veE| + [local >] + 00000000 00 00 00 7d 4c 30 31 00 00 23 8a 00 00 23 8b 68 |...}L01..#...#.h| + 00000010 a6 a2 2b 00 04 00 66 20 60 4b 53 1e 12 de 76 a8 |..+...f `KS...v.| + 00000020 54 c9 45 0a 1f 8d ec 16 42 2c 16 30 9b 69 03 a8 |T.E.....B,.0.i..| + 00000030 28 76 60 ff cf 40 84 05 29 92 68 05 71 df b5 5f |(v`..@..).h.q.._| + 00000040 56 f6 f1 d1 05 89 8f 23 6c 02 56 38 a2 e8 5a 08 |V......#l.V8..Z.| + 00000050 02 bd 2b db b7 c8 ff 25 52 ac 76 52 50 e7 a3 24 |..+....%R.vRP..$| + 00000060 4d ee 52 b4 00 f9 e2 49 c7 23 4b bd 11 6e cd 31 |M.R....I.#K..n.1| + 00000070 32 b3 57 f0 68 3d f4 87 10 21 5d 5a 0f e7 5a b4 |2.W.h=...!]Z..Z.| + 00000080 55 |U| + [local <] + 00000000 00 00 04 2a 4c 30 31 00 00 00 03 00 00 00 17 68 |...*L01........h| + 00000010 a6 a2 26 00 66 04 13 ce 36 7e 30 29 16 38 0c d3 |..&.f...6~0).8..| + 00000020 b0 34 ac 93 71 51 2c 20 ac a7 fb fa b7 1d 24 98 |.4..qQ, ......$.| + 00000030 4f 23 6e 89 0c 21 07 b4 8b a1 5a 86 ab c8 8e 94 |O#n..!....Z.....| + 00000040 9b 0f fc 8d 57 bc 01 a8 8e 95 27 e3 6a 08 5f b6 |....W.....'.j._.| + 00000050 cc 78 7c 39 c5 07 44 ae 70 2b bb e2 0a 0f 90 e9 |.x|9..D.p+......| + 00000060 a2 00 c5 9f 06 f2 b0 a5 85 e8 59 c5 36 bd 87 83 |..........Y.6...| + 00000070 78 e4 ed 0d 48 1c 60 bc 7f d9 aa c7 e5 25 cb 1b |x...H.`......%..| + 00000080 24 c7 c6 d8 96 c7 5d c8 f7 e5 a9 03 c9 6b 52 3e |$.....]......kR>| + 00000090 43 56 0a 82 9f bb f8 3d 92 38 9d 65 d0 26 53 cf |CV.....=.8.e.&S.| + 000000a0 62 48 ae ce 77 df 70 4a 0f e1 fc c7 36 da e7 64 |bH..w.pJ....6..d| + 000000b0 1f b0 aa 07 a1 1a 46 78 55 ad b7 52 99 33 16 a7 |......FxU..R.3..| + 000000c0 ed f4 a6 a3 45 58 bc a9 c0 4e db 0d 8c 7e 23 a2 |....EX...N...~#.| + 000000d0 d1 08 34 49 e5 ba 3e df c1 e3 b7 a4 38 78 47 e2 |..4I..>.....8xG.| + 000000e0 21 5f 16 30 86 c3 14 f8 f6 16 f9 aa d9 7f f5 87 |!_.0............| + 000000f0 70 a1 d2 3b a6 55 63 fe 78 7f c5 f5 bf 6d 51 80 |p..;.Uc.x....mQ.| + 00000100 d1 d9 e6 ce 5f 93 16 8b f7 b2 02 41 62 a9 90 95 |...._......Ab...| + 00000110 1f a9 82 3b 9e 22 ed 84 c5 31 12 bc 2d 7b 52 05 |...;."...1..-{R.| + 00000120 eb c3 b8 e9 66 5e 59 cf cb 4f b1 39 6b 8a 61 b8 |....f^Y..O.9k.a.| + 00000130 48 f4 a8 de 92 5e 68 c5 01 36 65 3c 5c 60 83 93 |H....^h..6e<\`..| + 00000140 25 f1 d4 96 fa a1 e9 3e 22 18 c2 b5 27 1e bb 92 |%......>"...'...| + 00000150 06 3c 6a ee 3e 03 fb a3 73 fe 22 5c ca f4 90 95 |....s."\....| + 00000160 be cf 91 dd 1e 3f fe ef 5b ac a6 5d 23 f2 9a 28 |.....?..[..]#..(| + 00000170 20 79 ec b7 0c 4b cc a3 3c a6 02 ce 3c eb b9 93 | y...K..<...<...| + 00000180 60 5b bb ab ab 1a 86 1f d2 3a 63 38 12 d2 2c 15 |`[.......:c8..,.| + 00000190 5e f0 12 23 c0 86 93 b7 70 fc 29 2b 75 41 e5 43 |^..#....p.)+uA.C| + 000001a0 ad 64 64 33 4d f3 a9 7b f9 4c 79 62 b0 3a 22 d5 |.dd3M..{.Lyb.:".| + 000001b0 0c 22 ee 55 60 11 0d 30 f5 ac ac a6 42 ec 12 85 |.".U`..0....B...| + 000001c0 d4 7f d1 ba 11 d3 da 40 03 d6 d6 1b d6 35 72 77 |.......@.....5rw| + 000001d0 49 05 be e6 c8 c7 84 4c 25 0b 4d b6 1f 59 2b 09 |I......L%.M..Y+.| + 000001e0 d5 4a 59 f1 7d 19 70 a9 39 29 25 fd 0e d1 ad 5d |.JY.}.p.9)%....]| + 000001f0 6a 91 c3 61 c7 ad c1 ed 4f 47 8c 54 d7 27 25 ee |j..a....OG.T.'%.| + 00000200 77 30 2d 36 73 60 3a d1 9b 5b 8a 8f 52 be f3 f7 |w0-6s`:..[..R...| + 00000210 68 a3 f5 16 a6 c3 df 2d c0 93 15 4a f9 00 3b 7d |h......-...J..;}| + 00000220 29 8c c4 ab 25 a5 ea d3 03 fc 67 06 b3 d3 23 55 |)...%.....g...#U| + 00000230 ef 8c 03 84 e2 af 3c b9 22 f4 cf 9e 44 9f df 4a |......<."...D..J| + 00000240 95 7e 22 8a 92 29 ce 86 6f 0a 70 6d 7b 47 2e 99 |.~"..)..o.pm{G..| + 00000250 6f d5 46 a8 61 13 2c 00 cb 06 80 fa 6d 73 20 88 |o.F.a.,.....ms .| + 00000260 e5 ec 00 89 4d 38 93 5c 11 28 5a 0e e7 3c 21 18 |....M8.\.(Z.....p......| + 00000340 12 85 2a 27 5a 92 54 fe ec 6f 51 ee 9a d6 ec 5a |..*'Z.T..oQ....Z| + 00000350 60 3e 12 5e 4b 78 c2 60 c5 3e 06 c1 24 43 4f 31 |`>.^Kx.`.>..$CO1| + 00000360 1a 37 61 06 d7 b3 f4 a9 bd 5b 1f 4e cf d7 c9 81 |.7a......[.N....| + 00000370 1b 5e f5 94 af 10 55 b2 01 e6 89 a7 1d 68 df b2 |.^....U......h..| + 00000380 8c a6 9a 2b 36 5c e2 9c 4b 69 0e 2e 03 b6 e3 18 |...+6\..Ki......| + 00000390 4c ca 5e 4e e6 44 1b 1f e9 e0 7d 73 2e 72 ce 39 |L.^N.D....}s.r.9| + 000003a0 e3 12 90 89 12 eb 93 34 1a 11 4f d1 98 33 c0 41 |.......4..O..3.A| + 000003b0 f0 6b 5d 64 90 4a cc 5c f6 2f 46 a0 55 20 d7 36 |.k]d.J.\./F.U .6| + 000003c0 0c 92 1a 85 68 aa 44 73 1d d0 7c c4 ba 31 33 a0 |....h.Ds..|..13.| + 000003d0 43 00 0e b3 43 68 98 7b 3d f9 4f 7c e8 c4 30 9e |C...Ch.{=.O|..0.| + 000003e0 0c b8 c1 89 56 88 a1 1c 5b ff dd 92 2c ef bf 0e |....V...[...,...| + 000003f0 23 48 d2 bd 48 84 99 14 a7 e8 19 cc 50 5e 0a 05 |#H..H.......P^..| + 00000400 90 1a e0 25 1a 4b 55 74 fe 59 36 47 e3 e5 79 fd |...%.KUt.Y6G..y.| + 00000410 a0 9b 5e 72 8d 3e 57 69 0b 7c 21 80 2f a4 d5 12 |..^r.>Wi.|!./...| + 00000420 99 be 49 6e f3 0b 57 e5 a8 1e 88 b6 7b 48 |..In..W.....{H| +# --- +# name: test_v1_device [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| diff --git a/tests/e2e/test_device_manager.py b/tests/e2e/test_device_manager.py index 6971df9b..c6364819 100644 --- a/tests/e2e/test_device_manager.py +++ b/tests/e2e/test_device_manager.py @@ -16,6 +16,7 @@ import pytest import syrupy +from roborock.data.containers import UserData from roborock.devices.cache import Cache, InMemoryCache from roborock.devices.device_manager import DeviceManager, UserParams, create_device_manager from roborock.protocol import MessageParser @@ -104,14 +105,10 @@ def __init__(self) -> None: 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 + self.seq_counter += 1 return MessageParser.build( RoborockMessage( protocol=protocol if protocol is not None else self.protocol, @@ -145,7 +142,7 @@ def build_rpc( ) -async def test_device_manager( +async def test_v1_device( mock_rest: Any, push_mqtt_response: Callable[[bytes], None], local_response_queue: asyncio.Queue[bytes], @@ -154,7 +151,7 @@ async def test_device_manager( snapshot: syrupy.SnapshotAssertion, device_manager_factory: Callable[[UserParams], Awaitable[DeviceManager]], ) -> None: - """Test the device manager end to end flow.""" + """Test the device manager end to end flow with a v1 device.""" # Simulate the login flow to get user params web_api = RoborockApiClient(username=TEST_USERNAME) @@ -177,9 +174,10 @@ async def test_device_manager( push_mqtt_response(response) # Prepare local device responses. The ids are deterministic based on deterministic_message_fixtures + response_builder.seq_counter = 0 local_responses: list[bytes] = [ # Queue HELLO response - response_builder.build(protocol=RoborockMessageProtocol.HELLO_RESPONSE, seq=1, payload=b"ok"), + response_builder.build(protocol=RoborockMessageProtocol.HELLO_RESPONSE, 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]}), @@ -231,8 +229,9 @@ async def test_device_manager( push_mqtt_response(response) # Prepare local device responses. + response_builder.seq_counter = 0 local_response_queue.put_nowait( - response_builder.build(protocol=RoborockMessageProtocol.HELLO_RESPONSE, seq=1, payload=b"ok") + response_builder.build(protocol=RoborockMessageProtocol.HELLO_RESPONSE, payload=b"ok") ) device_manager = await device_manager_factory(user_params) @@ -268,3 +267,81 @@ async def test_device_manager( assert device.v1_properties.status.state_name == "charging" assert snapshot == log + + +async def test_l01_device( + 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 with a l01 device.""" + # Prepare MQTT requests + mqtt_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=mqtt_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_response_builder = ResponseBuilder() + local_response_builder.version = LocalProtocolVersion.L01 + local_response_builder.connect_nonce = 9093 + local_responses: list[bytes] = [ + # Initial V01 Hello request will fail and cause a retry with L01 + b"\x00", + # Queue HELLO response with L01 + local_response_builder.build(protocol=RoborockMessageProtocol.HELLO_RESPONSE, payload=b"ok"), + ] + # Feature discovery requests are sent with an ack nonce based on the random sent in HELLO_RESPONSE + local_response_builder.ack_nonce = TEST_RANDOM + local_responses.extend( + [ + local_response_builder.build_rpc(data={"id": 9094, "result": [mock_data.APP_GET_INIT_STATUS]}), + local_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=UserData.from_dict(mock_data.USER_DATA), + base_url=mock_data.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 + + assert snapshot == log