File: test_nvram.py

package info (click to toggle)
zigpy-znp 0.14.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,112 kB
  • sloc: python: 14,241; makefile: 6
file content (158 lines) | stat: -rw-r--r-- 5,435 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
153
154
155
156
157
158
import json
import logging

import pytest

import zigpy_znp.types as t
import zigpy_znp.commands as c
from zigpy_znp.types.nvids import NWK_NVID_TABLES, ExNvIds, OsalNvIds
from zigpy_znp.tools.nvram_read import main as nvram_read
from zigpy_znp.tools.nvram_reset import main as nvram_reset
from zigpy_znp.tools.nvram_write import main as nvram_write

from ..conftest import ALL_DEVICES, BaseZStack1CC2531, FormedLaunchpadCC26X2R1


def dump_nvram(znp):
    obj = {}

    for item_id, items in znp._nvram.items():
        item_id = ExNvIds(item_id)
        item = obj[item_id.name] = {}

        for sub_id, value in items.items():
            # Unnamed pass right through
            if item_id != ExNvIds.LEGACY:
                item[f"0x{sub_id:04X}"] = value.hex()
                continue

            try:
                # Table entries are named differently
                start, end = next(
                    ((s, e) for s, e in NWK_NVID_TABLES.items() if s <= sub_id <= e)
                )
                item[f"{start.name}+{sub_id - start}"] = value.hex()
            except StopIteration:
                item[OsalNvIds(sub_id).name] = value.hex()

    return obj


@pytest.mark.parametrize("device", ALL_DEVICES)
async def test_nvram_read(device, make_znp_server, tmp_path, mocker):
    znp_server = make_znp_server(server_cls=device)

    # Make one reaaally long, requiring multiple writes to read it
    znp_server._nvram[ExNvIds.LEGACY][OsalNvIds.HAS_CONFIGURED_ZSTACK3] = b"\xFF" * 300

    # Make a few secure but unreadable
    if issubclass(device, BaseZStack1CC2531):
        # Normal NVID
        znp_server._nvram[ExNvIds.LEGACY][OsalNvIds.TCLK_SEED] = b"\xFF" * 32

        # Part of a table
        znp_server._nvram[ExNvIds.LEGACY][OsalNvIds.LEGACY_TCLK_TABLE_START] = b"\xFF"

    # XXX: this is not a great way to do it but deepcopy won't work here
    old_nvram_repr = repr(znp_server._nvram)

    backup_file = tmp_path / "backup.json"
    await nvram_read([znp_server._port_path, "-o", str(backup_file)])

    # No NVRAM was modified during the read
    assert repr(znp_server._nvram) == old_nvram_repr

    # Remove the item since it won't be present in the backup
    if issubclass(device, BaseZStack1CC2531):
        del znp_server._nvram[ExNvIds.LEGACY][OsalNvIds.TCLK_SEED]
        del znp_server._nvram[ExNvIds.LEGACY][OsalNvIds.LEGACY_TCLK_TABLE_START]

    # The backup JSON written to disk should be an exact copy
    assert json.loads(backup_file.read_text()) == dump_nvram(znp_server)

    znp_server.close()


@pytest.mark.parametrize("device", ALL_DEVICES)
async def test_nvram_write(device, make_znp_server, tmp_path, mocker):
    znp_server = make_znp_server(server_cls=device)

    # Prevent the reset from occurring so NVRAM state isn't affected during "startup"
    version = znp_server.version_replier(None)
    znp_server.reply_to(
        c.SYS.ResetReq.Req(partial=True),
        responses=[
            c.SYS.ResetInd.Callback(
                Reason=t.ResetReason.PowerUp,
                TransportRev=version.TransportRev,
                ProductId=version.ProductId,
                MajorRel=version.MajorRel,
                MinorRel=version.MinorRel,
                MaintRel=version.MaintRel,
            )
        ],
        override=True,
    )

    # Create a dummy backup
    backup = dump_nvram(znp_server)

    # Change some values
    backup["LEGACY"]["HAS_CONFIGURED_ZSTACK1"] = "ff"

    # Make one with a long value
    backup["LEGACY"]["HAS_CONFIGURED_ZSTACK3"] = "ffee" * 400

    backup_file = tmp_path / "backup.json"
    backup_file.write_text(json.dumps(backup))

    # And clear out all of our NVRAM
    znp_server._nvram = {ExNvIds.LEGACY: {}}

    # This has a differing length
    znp_server._nvram[ExNvIds.LEGACY][OsalNvIds.HAS_CONFIGURED_ZSTACK1] = b"\xEE\xEE"

    # This already exists
    znp_server._nvram[ExNvIds.LEGACY][OsalNvIds.HAS_CONFIGURED_ZSTACK3] = b"\xBB"

    await nvram_write([znp_server._port_path, "-i", str(backup_file)])

    nvram_obj = dump_nvram(znp_server)

    # XXX: should we check that the NVRAMs are *identical*, or that every item in the
    #      backup was completely restored?
    for item_id, sub_ids in backup.items():
        for sub_id, value in sub_ids.items():
            assert nvram_obj[item_id][sub_id] == value

    znp_server.close()


@pytest.mark.parametrize("device", ALL_DEVICES)
async def test_nvram_reset(device, make_znp_server):
    znp_server = make_znp_server(server_cls=device)
    znp_server._nvram[ExNvIds.LEGACY][OsalNvIds.STARTUP_OPTION] = b"\xFF"

    await nvram_reset([znp_server._port_path])

    # Nothing exists but the synthetic POLL_RATE_OLD16
    assert len([v for v in znp_server._nvram.values() if v]) == 1
    assert OsalNvIds.POLL_RATE_OLD16 in znp_server._nvram[ExNvIds.LEGACY]

    znp_server.close()


@pytest.mark.parametrize("device", [FormedLaunchpadCC26X2R1])
async def test_nvram_reset_clear(device, make_znp_server, caplog):
    znp_server = make_znp_server(server_cls=device)

    with caplog.at_level(logging.WARNING):
        await nvram_reset(["-c", znp_server._port_path])

    assert "will be removed in a future release" in caplog.text

    # Nothing exists but the synthetic POLL_RATE_OLD16
    assert len([v for v in znp_server._nvram.values() if v]) == 1
    assert OsalNvIds.POLL_RATE_OLD16 in znp_server._nvram[ExNvIds.LEGACY]

    znp_server.close()