File: test_smbus.py

package info (click to toggle)
liquidctl 1.16.0-1
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 3,452 kB
  • sloc: python: 15,304; sh: 712; xml: 84; makefile: 4
file content (158 lines) | stat: -rw-r--r-- 4,401 bytes parent folder | download | duplicates (3)
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 pytest

from pathlib import Path

from liquidctl.driver.smbus import LinuxI2c, LinuxI2cBus, SmbusDriver


class Canary(SmbusDriver):
    """Canary driver to reveal if SMBus probing is taking place."""

    @classmethod
    def probe(cls, smbus, **kwargs):
        yield Canary(smbus, 'Canary', vendor_id=-1, product_id=-1, address=-1)

    def connect(self, **kwargs):
        # there is no justification for calling connect on this test driver
        raise RuntimeError('forbidden')

    def __repr__(self):
        return repr(self._smbus)


def replace_smbus(replacement, monkeypatch):
    import liquidctl.driver.smbus

    # fragile hack: since messing with sys.meta_path (PEP 302) is tricky in a
    # pytest context, get into liquidctl.driver.smbus module and replace the
    # imported SMBus class after the fact
    monkeypatch.setattr(liquidctl.driver.smbus, 'SMBus', replacement)

    return replacement


@pytest.fixture
def emulated_smbus(monkeypatch):
    """Replace the SMBus implementation in liquidctl.driver.smbus."""

    class SMBus:
        def __init__(self, number):
            pass

    return replace_smbus(SMBus, monkeypatch)


def test__helper_fixture_replaces_real_smbus_implementation(emulated_smbus, tmpdir):
    i2c_dev = Path(tmpdir.mkdir('i2c-9999'))  # unlikely to be valid
    bus = LinuxI2cBus(i2c_dev=i2c_dev)

    bus.open()

    assert type(bus._smbus) == emulated_smbus


def test_filter_by_usb_port_yields_no_devices(emulated_smbus):
    discovered = Canary.find_supported_devices(usb_port='usb1')
    assert discovered == []


def test_aborts_if_sysfs_is_missing_devices(emulated_smbus, tmpdir):
    empty = tmpdir.mkdir('sys').mkdir('bus').mkdir('i2c')
    virtual_bus = LinuxI2c(i2c_root=empty)

    discovered = Canary.find_supported_devices(root_bus=virtual_bus)
    assert discovered == []


def test_finds_a_device(emulated_smbus, tmpdir):
    i2c_root = tmpdir.mkdir('sys').mkdir('bus').mkdir('i2c')
    i2c_root.mkdir('devices').mkdir('i2c-42')

    virtual_bus = LinuxI2c(i2c_root=i2c_root)

    discovered = Canary.find_supported_devices(root_bus=virtual_bus)
    assert len(discovered) == 1
    assert discovered[0]._smbus.name == 'i2c-42'


def test_ignores_non_bus_sysfs_entries(emulated_smbus, tmpdir):
    i2c_root = tmpdir.mkdir('sys').mkdir('bus').mkdir('i2c')
    devices = i2c_root.mkdir('devices')
    devices.mkdir('i2c-0')
    devices.mkdir('0-0050')  # SPD info chip on i2c-0
    devices.mkdir('i2c-DELL0829:00')  # i2c HID chip from Dell laptop

    virtual_bus = LinuxI2c(i2c_root=i2c_root)

    discovered = Canary.find_supported_devices(root_bus=virtual_bus)
    assert len(discovered) == 1
    assert discovered[0]._smbus.name == 'i2c-0'


def test_honors_a_bus_filter(emulated_smbus, tmpdir):
    i2c_root = tmpdir.mkdir('sys').mkdir('bus').mkdir('i2c')
    devices = i2c_root.mkdir('devices')
    devices.mkdir('i2c-0')
    devices.mkdir('i2c-1')

    virtual_bus = LinuxI2c(i2c_root=i2c_root)

    discovered = Canary.find_supported_devices(bus='i2c-1',
                                               root_bus=virtual_bus)
    assert len(discovered) == 1
    assert discovered[0]._smbus.name == 'i2c-1'


@pytest.fixture
def emulated_device(tmpdir, emulated_smbus):
    i2c_dev = Path(tmpdir.mkdir('i2c-0'))
    bus = LinuxI2cBus(i2c_dev=i2c_dev)
    dev = SmbusDriver(smbus=bus, description='Test', vendor_id=-1,
                      product_id=-1, address=-1)

    return (bus, dev)


def test_connect_is_unsafe(emulated_device):
    bus, dev = emulated_device

    def mock_open():
        nonlocal opened
        opened = True

    bus.open = mock_open
    opened = False

    dev.connect()
    assert not opened


def test_connects(emulated_device):
    bus, dev = emulated_device

    def mock_open():
        nonlocal opened
        opened = True

    bus.open = mock_open
    opened = False

    with dev.connect(unsafe='smbus') as cm:
        assert cm == dev
        assert opened


def test_loading_unnavailable_eeprom_returns_none(emulated_device):
    bus, dev = emulated_device
    assert bus.load_eeprom(0x51) is None


def test_loads_eeprom(emulated_device):
    bus, dev = emulated_device

    spd = bus._i2c_dev.joinpath('0-0051')
    spd.mkdir()
    spd.joinpath('eeprom').write_bytes(b'012345')
    spd.joinpath('name').write_text('name\n')

    assert bus.load_eeprom(0x51) == ('name', b'012345')