File: test_kraken2.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 (179 lines) | stat: -rw-r--r-- 5,460 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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
import pytest
from _testutils import MockHidapiDevice

from liquidctl.driver.hwmon import HwmonDevice
from liquidctl.driver.kraken2 import Kraken2
from liquidctl.error import NotSupportedByDevice


@pytest.fixture
def mockKrakenXDevice():
    device = _MockKrakenDevice(fw_version=(6, 0, 2))
    dev = Kraken2(device, 'Mock X62', device_type=Kraken2.DEVICE_KRAKENX)

    dev.connect()
    return dev


@pytest.fixture
def mockOldKrakenXDevice():
    device = _MockKrakenDevice(fw_version=(2, 1, 8))
    dev = Kraken2(device, 'Mock X62', device_type=Kraken2.DEVICE_KRAKENX)

    dev.connect()
    return dev


@pytest.fixture
def mockKrakenMDevice():
    device = _MockKrakenDevice(fw_version=(6, 0, 2))
    dev = Kraken2(device, 'Mock M22', device_type=Kraken2.DEVICE_KRAKENM)

    dev.connect()
    return dev


class _MockKrakenDevice(MockHidapiDevice):
    def __init__(self, fw_version):
        super().__init__(vendor_id=0xffff, product_id=0x1e71)
        self.fw_version = fw_version
        self.temperature = 30.9
        self.fan_speed = 1499
        self.pump_speed = 2702

    def read(self, length):
        pre = super().read(length)
        if pre:
            return pre
        buf = bytearray(64)
        buf[1:3] = divmod(int(self.temperature * 10), 10)
        buf[3:5] = self.fan_speed.to_bytes(length=2, byteorder='big')
        buf[5:7] = self.pump_speed.to_bytes(length=2, byteorder='big')
        major, minor, patch = self.fw_version
        buf[0xb] = major
        buf[0xc:0xe] = minor.to_bytes(length=2, byteorder='big')
        buf[0xe] = patch
        return buf[:length]


def test_kraken_connect(mockKrakenXDevice):
    def mock_open():
        nonlocal opened
        opened = True

    mockKrakenXDevice.device.open = mock_open
    opened = False

    with mockKrakenXDevice.connect() as cm:
        assert cm == mockKrakenXDevice
        assert opened


def test_kraken_initialize(mockKrakenXDevice):
    (fw_ver,) = mockKrakenXDevice.initialize()

    assert fw_ver[1] == '6.2'


def test_old_kraken_initialize(mockOldKrakenXDevice):
    (fw_ver,) = mockOldKrakenXDevice.initialize()

    assert fw_ver[1] == '2.1.8'


@pytest.mark.parametrize('has_hwmon,direct_access', [(False, False), (True, True)])
def test_kraken_get_status_directly(mockKrakenXDevice, has_hwmon, direct_access):
    if has_hwmon:
        mockKrakenXDevice._hwmon = HwmonDevice(None, None)

    got = mockKrakenXDevice.get_status(direct_access=direct_access)

    expected = [
        ('Liquid temperature', pytest.approx(30.9), '°C'),
        ('Fan speed', 1499, 'rpm'),
        ('Pump speed', 2702, 'rpm'),
    ]

    assert sorted(got) == sorted(expected)


def test_kraken_get_status_from_hwmon(mockKrakenXDevice, tmp_path):
    mockKrakenXDevice._hwmon = HwmonDevice('mock_module', tmp_path)
    (tmp_path / 'temp1_input').write_text('20900\n')
    (tmp_path / 'fan1_input').write_text('2499\n')
    (tmp_path / 'fan2_input').write_text('1702\n')

    got = mockKrakenXDevice.get_status()

    expected = [
        ('Liquid temperature', pytest.approx(20.9), '°C'),
        ('Fan speed', 2499, 'rpm'),
        ('Pump speed', 1702, 'rpm'),
    ]

    assert sorted(got) == sorted(expected)


def test_kraken_not_totally_broken(mockKrakenXDevice):
    """Reasonable example calls to untested APIs do not raise exceptions."""
    dev = mockKrakenXDevice

    dev.initialize()
    dev.set_color(channel='ring', mode='loading', colors=iter([[90, 80, 0]]),
                  speed='slowest')
    dev.set_speed_profile(channel='fan',
                          profile=iter([(20, 20), (30, 40), (40, 100)]))
    dev.set_fixed_speed(channel='pump', duty=50)
    dev.set_instantaneous_speed(channel='pump', duty=50)


def test_kraken_set_fixed_speeds(mockOldKrakenXDevice):
    mockOldKrakenXDevice.set_fixed_speed(channel='fan', duty=42)
    mockOldKrakenXDevice.set_fixed_speed(channel='pump', duty=84)

    fan_report, pump_report = mockOldKrakenXDevice.device.sent

    assert fan_report.number == 2
    assert fan_report.data[0:4] == [0x4d, 0, 0, 42]
    assert pump_report.number == 2
    assert pump_report.data[0:4] == [0x4d, 0x40, 0, 84]


def test_kraken_speed_profiles_not_supported(mockOldKrakenXDevice):

    with pytest.raises(NotSupportedByDevice):
        mockOldKrakenXDevice.set_speed_profile('fan', [(20, 42)])

    with pytest.raises(NotSupportedByDevice):
        mockOldKrakenXDevice.set_speed_profile('pump', [(20, 84)])


def test_krakenM_initialize(mockKrakenMDevice):
    (fw_ver,) = mockKrakenMDevice.initialize()
    assert fw_ver[1] == '6.2'


def test_krakenM_get_status(mockKrakenMDevice):
    assert mockKrakenMDevice.get_status() == []


def test_krakenM_speed_control_not_supported(mockKrakenMDevice):
    with pytest.raises(NotSupportedByDevice):
        mockKrakenMDevice.set_fixed_speed('fan', 42)

    with pytest.raises(NotSupportedByDevice):
        mockKrakenMDevice.set_fixed_speed('pump', 84)

    with pytest.raises(NotSupportedByDevice):
        mockKrakenMDevice.set_speed_profile('fan', [(20, 42)])

    with pytest.raises(NotSupportedByDevice):
        mockKrakenMDevice.set_speed_profile('pump', [(20, 84)])


def test_krakenM_not_totally_broken(mockKrakenMDevice):
    """Reasonable example calls to untested APIs do not raise exceptions."""
    dev = mockKrakenMDevice
    dev.initialize()
    dev.set_color(channel='ring', mode='loading', colors=iter([[90, 80, 0]]),
                  speed='slowest')