File: test_integration_hw.py

package info (click to toggle)
s-tui 1.4.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,336 kB
  • sloc: python: 6,159; makefile: 23
file content (188 lines) | stat: -rw-r--r-- 6,167 bytes parent folder | download
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
180
181
182
183
184
185
186
187
188
"""Hardware integration tests -- run only on real machines with sensors.

All tests are marked ``@pytest.mark.hardware`` and will be automatically
skipped when CI=true or GITHUB_ACTIONS=true (see conftest.py).

Run locally with::

    pytest -m hardware -v
"""

import psutil
import pytest

from s_tui.sources.fan_source import FanSource
from s_tui.sources.freq_source import FreqSource
from s_tui.sources.rapl_power_source import RaplPowerSource
from s_tui.sources.rapl_read import get_power_reader
from s_tui.sources.temp_source import TempSource
from s_tui.sources.util_source import UtilSource

pytestmark = pytest.mark.hardware


# =====================================================================
# UtilSource
# =====================================================================


class TestUtilSourceHW:
    def test_init_and_available(self):
        """UtilSource should always be available on a Linux machine."""
        src = UtilSource()
        assert src.get_is_available() is True

    def test_sensor_list_matches_cpu_count(self):
        """Sensor list should cover all present cores (including offline) + Avg."""
        from s_tui.sources.source import Source

        src = UtilSource()
        expected = Source._get_total_core_count() + 1  # all cores + Avg
        assert len(src.get_sensor_list()) == expected

    def test_update_produces_readings(self):
        """After update(), readings should be populated."""
        src = UtilSource()
        src.update()
        readings = src.get_reading_list()
        assert len(readings) > 0
        # All values should be between 0 and 100
        for v in readings:
            assert 0.0 <= v <= 100.0

    def test_summary(self):
        """get_summary() should return a non-empty dict."""
        src = UtilSource()
        src.update()
        summary = src.get_summary()
        assert len(summary) > 0


# =====================================================================
# FreqSource
# =====================================================================


class TestFreqSourceHW:
    def test_init_and_available(self):
        """FreqSource should be available when cpu_freq works."""
        src = FreqSource()
        if psutil.cpu_freq() is not None:
            assert src.get_is_available() is True

    def test_update(self):
        """After update(), readings should contain positive values."""
        src = FreqSource()
        if not src.get_is_available():
            pytest.skip("FreqSource not available on this hardware")
        src.update()
        readings = src.get_reading_list()
        assert len(readings) > 0


# =====================================================================
# TempSource
# =====================================================================


class TestTempSourceHW:
    def test_init(self):
        """TempSource should init without crashing."""
        TempSource()

    def test_update_if_available(self):
        """If available, update produces temperature readings."""
        src = TempSource()
        if not src.get_is_available():
            pytest.skip("TempSource not available on this hardware")
        src.update()
        readings = src.get_reading_list()
        assert len(readings) > 0
        # Temperatures should be reasonable (> -40 and < 200)
        for v in readings:
            assert -40.0 < v < 200.0


# =====================================================================
# FanSource
# =====================================================================


class TestFanSourceHW:
    def test_init(self):
        """FanSource should init without crashing."""
        FanSource()

    def test_update_if_available(self):
        """If available, update produces fan readings."""
        src = FanSource()
        if not src.get_is_available():
            pytest.skip("FanSource not available on this hardware")
        src.update()
        readings = src.get_reading_list()
        assert len(readings) > 0


# =====================================================================
# RaplPowerSource
# =====================================================================


class TestRaplPowerSourceHW:
    def test_init(self):
        """RaplPowerSource should init without crashing."""
        RaplPowerSource()

    def test_update_if_available(self):
        """If available, update produces power readings.

        Note: RAPL sysfs files may require root permissions, so this test
        skips when readings are empty due to PermissionError.
        """
        src = RaplPowerSource()
        if not src.get_is_available():
            pytest.skip("RaplPowerSource not available on this hardware")
        src.update()
        readings = src.get_reading_list()
        if len(readings) == 0:
            pytest.skip("RAPL readings empty (likely permission denied)")
        assert len(readings) > 0


# =====================================================================
# get_power_reader
# =====================================================================


class TestGetPowerReaderHW:
    def test_reader_type(self):
        """get_power_reader returns a reader or None."""
        reader = get_power_reader()
        if reader is not None:
            # Should have read_power method
            assert hasattr(reader, "read_power")
            result = reader.read_power()
            assert isinstance(result, list)


# =====================================================================
# Multi-update stability
# =====================================================================


class TestMultiUpdateStability:
    def test_util_multiple_updates(self):
        """UtilSource survives multiple update() calls."""
        src = UtilSource()
        for _ in range(10):
            src.update()
        assert len(src.get_reading_list()) > 0

    def test_freq_multiple_updates(self):
        """FreqSource survives multiple update() calls."""
        src = FreqSource()
        if not src.get_is_available():
            pytest.skip("FreqSource not available")
        for _ in range(10):
            src.update()
        assert len(src.get_reading_list()) > 0