File: test_network_state.py

package info (click to toggle)
zigpy-znp 0.14.2%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,116 kB
  • sloc: python: 14,241; makefile: 6
file content (152 lines) | stat: -rw-r--r-- 5,076 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import logging
from unittest import mock

import pytest
from zigpy.exceptions import FormationFailure

import zigpy_znp.types as t
import zigpy_znp.commands as c
from zigpy_znp.types.nvids import ExNvIds, OsalNvIds

from ..conftest import (
    ALL_DEVICES,
    FORMED_DEVICES,
    BaseZStack1CC2531,
    FormedZStack3CC2531,
    FormedLaunchpadCC26X2R1,
)


@pytest.mark.parametrize("to_device", ALL_DEVICES)
@pytest.mark.parametrize("from_device", FORMED_DEVICES)
async def test_state_transfer(from_device, to_device, make_connected_znp):
    formed_znp, _ = await make_connected_znp(server_cls=from_device)

    await formed_znp.load_network_info()
    await formed_znp.disconnect()

    empty_znp, _ = await make_connected_znp(server_cls=to_device)

    await empty_znp.write_network_info(
        network_info=formed_znp.network_info,
        node_info=formed_znp.node_info,
    )
    await empty_znp.load_network_info()

    # Z-Stack 1 devices can't have some security info read out
    if issubclass(from_device, BaseZStack1CC2531):
        assert formed_znp.network_info == empty_znp.network_info.replace(
            stack_specific={},
            metadata=formed_znp.network_info.metadata,
        )
    elif issubclass(to_device, BaseZStack1CC2531):
        assert (
            formed_znp.network_info.replace(
                stack_specific={},
                metadata=empty_znp.network_info.metadata,
            )
            == empty_znp.network_info
        )
    else:
        assert formed_znp.network_info == empty_znp.network_info.replace(
            metadata=formed_znp.network_info.metadata
        )

    assert formed_znp.node_info == empty_znp.node_info.replace(
        version=formed_znp.node_info.version,
        model=formed_znp.node_info.model,
        manufacturer=formed_znp.node_info.manufacturer,
    )


@pytest.mark.parametrize("device", [FormedZStack3CC2531])
async def test_broken_cc2531_load_state(device, make_connected_znp, caplog):
    znp, znp_server = await make_connected_znp(server_cls=device)

    # "Bad" TCLK seed is a TCLK from Z-Stack 1 with the first 16 bytes overwritten
    znp_server._nvram[ExNvIds.LEGACY][
        OsalNvIds.TCLK_SEED
    ] += b"liance092\x00\x00\x00\x00\x00\x00\x00"

    caplog.set_level(logging.ERROR)
    await znp.load_network_info()
    assert "inconsistent" in caplog.text

    await znp.disconnect()


@pytest.mark.parametrize("device", [FormedZStack3CC2531])
async def test_state_write_tclk_zstack3(device, make_connected_znp, caplog):
    formed_znp, _ = await make_connected_znp(server_cls=device)

    await formed_znp.load_network_info()
    await formed_znp.disconnect()

    empty_znp, _ = await make_connected_znp(server_cls=device)

    caplog.set_level(logging.WARNING)
    await empty_znp.write_network_info(
        network_info=formed_znp.network_info.replace(
            tc_link_key=formed_znp.network_info.tc_link_key.replace(
                # Non-standard TCLK
                key=t.KeyData.convert("AA:BB:CC:DD:AA:BB:CC:DD:AA:BB:CC:DD:AA:BB:CC:DD")
            )
        ),
        node_info=formed_znp.node_info,
    )
    assert "TC link key is configured at build time in Z-Stack 3" in caplog.text

    await empty_znp.load_network_info()

    # TCLK was not changed
    assert formed_znp.network_info == empty_znp.network_info


@pytest.mark.parametrize("device", ALL_DEVICES)
async def test_write_settings_fast(device, make_connected_znp):
    formed_znp, _ = await make_connected_znp(server_cls=FormedLaunchpadCC26X2R1)
    await formed_znp.load_network_info()
    await formed_znp.disconnect()

    znp, _ = await make_connected_znp(server_cls=device)

    formed_znp.network_info.stack_specific["form_quickly"] = True

    with mock.patch("zigpy_znp.znp.security.write_devices") as mock_write_devices:
        await znp.write_network_info(
            network_info=formed_znp.network_info,
            node_info=formed_znp.node_info,
        )

    # We don't waste time writing device info
    assert len(mock_write_devices.mock_awaits) == 0


@pytest.mark.parametrize("device", FORMED_DEVICES)
async def test_formation_failure_on_corrupted_nvram(device, make_connected_znp):
    formed_znp, _ = await make_connected_znp(server_cls=FormedLaunchpadCC26X2R1)
    await formed_znp.load_network_info()
    await formed_znp.disconnect()

    znp, znp_server = await make_connected_znp(server_cls=device)

    # Instead of accepting the write, fail
    write_reset_rsp = znp_server.reply_once_to(
        request=c.SYS.OSALNVWriteExt.Req(
            Id=OsalNvIds.STARTUP_OPTION,
            Offset=0,
            Value=t.ShortBytes(
                (t.StartupOptions.ClearState | t.StartupOptions.ClearConfig).serialize()
            ),
        ),
        responses=[c.SYS.OSALNVWriteExt.Rsp(Status=t.Status.NV_OPER_FAILED)],
        override=True,
    )

    with pytest.raises(FormationFailure):
        await znp.write_network_info(
            network_info=formed_znp.network_info,
            node_info=formed_znp.node_info,
        )

    await write_reset_rsp