mirror of
https://github.com/HorlogeSkynet/archey4
synced 2024-12-27 16:00:13 +01:00
245 lines
11 KiB
Python
245 lines
11 KiB
Python
"""Test module for Archey's uptime detection module"""
|
|
|
|
import unittest
|
|
from datetime import timedelta
|
|
from itertools import product
|
|
from unittest.mock import MagicMock, mock_open, patch
|
|
|
|
from archey.entries.uptime import Uptime
|
|
from archey.exceptions import ArcheyException
|
|
from archey.test.entries import HelperMethods
|
|
|
|
|
|
class TestUptimeEntry(unittest.TestCase):
|
|
"""Test cases for `Uptime` entry module"""
|
|
|
|
@patch(
|
|
"archey.entries.uptime.open",
|
|
mock_open(read_data="90120.75 XXXX.XX\n"),
|
|
)
|
|
def test_proc_file_uptime(self):
|
|
"""Test `_proc_file_uptime` static method"""
|
|
self.assertEqual(
|
|
Uptime._proc_file_uptime(), # pylint: disable=protected-access
|
|
timedelta(seconds=90120.75),
|
|
)
|
|
|
|
@patch(
|
|
"archey.entries.uptime.time.CLOCK_BOOTTIME", # Ensure first `getattr` call succeeds anyhow.
|
|
create=True, # Required for Python < 3.7.
|
|
)
|
|
@patch(
|
|
"archey.entries.uptime.time.clock_gettime", # Ensure `clock_gettime` call succeeds anyhow.
|
|
return_value=1000,
|
|
create=True,
|
|
)
|
|
def test_clock_uptime(self, _, __):
|
|
"""
|
|
Test `_clock_uptime` static method`.
|
|
We only test one clock as all clocks rely on the same built-in `time.clock_gettime` method.
|
|
"""
|
|
self.assertEqual(
|
|
Uptime._clock_uptime(), # pylint: disable=protected-access
|
|
timedelta(seconds=1000),
|
|
)
|
|
|
|
@patch("archey.entries.uptime.run")
|
|
def test_parse_uptime_cmd(self, run_mock):
|
|
"""Test `_parse_uptime_cmd` static method"""
|
|
# Create an uptime instance to perform testing.
|
|
# It doesn't matter that its `__init__` will be called.
|
|
uptime_instance_mock = HelperMethods.entry_mock(Uptime)
|
|
|
|
# Keys: `uptime` outputs; values: expected `timedelta` instances.
|
|
# We will test these with various time formats (and various numbers of users).
|
|
# pylint: disable=line-too-long
|
|
test_uptime_cases = {
|
|
# Recently booted:
|
|
"{time} up 0 sec, {user_loadavg}": timedelta(seconds=0), # BSD, just booted
|
|
"{time} up 1 sec, {user_loadavg}": timedelta(seconds=1), # BSD, < 1 min uptime
|
|
"{time} up 12 secs, {user_loadavg}": timedelta(seconds=12), # BSD, < 1 min uptime
|
|
"{time} up 0 min, {user_loadavg}": timedelta(minutes=0), # Linux, < 1 min uptime
|
|
"{time} up 1 min, {user_loadavg}": timedelta(minutes=1),
|
|
# 1 min to 1 day
|
|
"{time} up 12 mins, {user_loadavg}": timedelta(minutes=12),
|
|
## Variation without plural minutes
|
|
"{time} up 12 min, {user_loadavg}": timedelta(minutes=12),
|
|
"{time} up 1:00, {user_loadavg}": timedelta(hours=1),
|
|
"{time} up 1:01, {user_loadavg}": timedelta(hours=1, minutes=1),
|
|
"{time} up 1:23, {user_loadavg}": timedelta(hours=1, minutes=23),
|
|
"{time} up 12:34, {user_loadavg}": timedelta(hours=12, minutes=34),
|
|
# 1 day to 2 days
|
|
"{time} up 1 day, 0 sec, {user_loadavg}": timedelta(days=1), # BSD
|
|
"{time} up 1 day, 1 sec, {user_loadavg}": timedelta(days=1, seconds=1), # BSD
|
|
"{time} up 1 day, 12 secs, {user_loadavg}": timedelta(days=1, seconds=12), # BSD
|
|
"{time} up 1 day, 0 min, {user_loadavg}": timedelta(days=1), # Linux
|
|
"{time} up 1 day, 1 min, {user_loadavg}": timedelta(days=1, minutes=1),
|
|
"{time} up 1 day, 12 mins, {user_loadavg}": timedelta(days=1, minutes=12),
|
|
## Variation without plural minutes
|
|
"{time} up 1 day, 12 min, {user_loadavg}": timedelta(days=1, minutes=12),
|
|
"{time} up 1 day, 1:00, {user_loadavg}": timedelta(days=1, hours=1),
|
|
"{time} up 1 day, 1:01, {user_loadavg}": timedelta(days=1, hours=1, minutes=1),
|
|
"{time} up 1 day, 1:23, {user_loadavg}": timedelta(days=1, hours=1, minutes=23),
|
|
"{time} up 1 day, 12:34, {user_loadavg}": timedelta(days=1, hours=12, minutes=34),
|
|
# 2 days onwards
|
|
"{time} up 12 days, 0 sec, {user_loadavg}": timedelta(days=12), # BSD
|
|
"{time} up 12 days, 1 sec, {user_loadavg}": timedelta(days=12, seconds=1), # BSD
|
|
"{time} up 12 days, 12 secs, {user_loadavg}": timedelta(days=12, seconds=12), # BSD
|
|
"{time} up 12 days, 0 min, {user_loadavg}": timedelta(days=12), # Linux
|
|
"{time} up 12 days, 1 min, {user_loadavg}": timedelta(days=12, minutes=1),
|
|
"{time} up 12 days, 12 mins, {user_loadavg}": timedelta(days=12, minutes=12),
|
|
## Variation without plural minutes
|
|
"{time} up 12 day, 12 min, {user_loadavg}": timedelta(days=12, minutes=12),
|
|
"{time} up 12 days, 1:00, {user_loadavg}": timedelta(days=12, hours=1),
|
|
"{time} up 12 days, 1:01, {user_loadavg}": timedelta(days=12, hours=1, minutes=1),
|
|
"{time} up 12 days, 1:23, {user_loadavg}": timedelta(days=12, hours=1, minutes=23),
|
|
"{time} up 12 days, 12:34, {user_loadavg}": timedelta(days=12, hours=12, minutes=34),
|
|
# Very long uptimes - sanity check :)
|
|
"{time} up 500 days, 0 sec, {user_loadavg}": timedelta(days=500), # BSD
|
|
"{time} up 500 days, 1 sec, {user_loadavg}": timedelta(days=500, seconds=1), # BSD
|
|
"{time} up 500 days, 12 secs, {user_loadavg}": timedelta(days=500, seconds=12), # BSD
|
|
"{time} up 500 days, 0 min, {user_loadavg}": timedelta(days=500), # Linux
|
|
"{time} up 500 days, 1 min, {user_loadavg}": timedelta(days=500, minutes=1),
|
|
"{time} up 500 days, 12 mins, {user_loadavg}": timedelta(days=500, minutes=12),
|
|
## Variation without plural minutes
|
|
"{time} up 500 day, 12 min, {user_loadavg}": timedelta(days=500, minutes=12),
|
|
"{time} up 500 days, 1:00, {user_loadavg}": timedelta(days=500, hours=1),
|
|
"{time} up 500 days, 1:01, {user_loadavg}": timedelta(days=500, hours=1, minutes=1),
|
|
"{time} up 500 days, 1:23, {user_loadavg}": timedelta(days=500, hours=1, minutes=23),
|
|
"{time} up 500 days, 12:34, {user_loadavg}": timedelta(days=500, hours=12, minutes=34),
|
|
}
|
|
# pylint: enable=line-too-long
|
|
|
|
# Variations of the time in the `{time}` section.
|
|
# These _should_ be avoided when we set the locale in `run`,
|
|
# however let's check we can handle them anyway, just in case.
|
|
time_variations = (
|
|
"0:00",
|
|
"9:43 ",
|
|
"11:37 ",
|
|
"19:21",
|
|
"23:59",
|
|
"12:00am",
|
|
"1:10am",
|
|
"1:10pm ",
|
|
"6:43pm ",
|
|
"8:26am ",
|
|
"03:14:15",
|
|
"09:26:12 ",
|
|
"23:19:20 ",
|
|
"nonsense_time ",
|
|
"hopefully_works_anyway ",
|
|
" even with strange spacing!",
|
|
)
|
|
|
|
# Variations of the user count and load average section.
|
|
# For this, we'll just combine user variations with a few load average variations.
|
|
user_variations = (
|
|
"1 user ",
|
|
"1 user ",
|
|
" 1 user, ",
|
|
" 1 user, ",
|
|
"2 users ",
|
|
"2 users ",
|
|
" 2 users, ",
|
|
" 2 users, ",
|
|
"15 users ",
|
|
"15 users ",
|
|
" 15 users, ",
|
|
" 15 users, ",
|
|
"150 users ",
|
|
"150 users ",
|
|
"150 users, ",
|
|
"150 users, ",
|
|
)
|
|
loadavg_variations = (
|
|
"load averages: 1.95 1.28 2.10",
|
|
"load average: 0.13, 0.17, 0.13",
|
|
"we never match this part so the content here",
|
|
" should not affect our parsing",
|
|
)
|
|
user_loadavg_variations = [
|
|
user + loadavg for user in user_variations for loadavg in loadavg_variations
|
|
]
|
|
|
|
for uptime_output, expected_delta in test_uptime_cases.items():
|
|
# We use `itertools.product` to get the permutations of our variations
|
|
# since there are a lot of them! (a list comprehension would be slower)
|
|
for variations in product(time_variations, user_loadavg_variations):
|
|
run_mock.return_value.stdout = uptime_output.format(
|
|
time=variations[0], user_loadavg=variations[1]
|
|
).encode()
|
|
self.assertEqual(
|
|
Uptime._parse_uptime_cmd( # pylint: disable=protected-access
|
|
uptime_instance_mock
|
|
),
|
|
expected_delta,
|
|
msg=(
|
|
"`uptime` output: "
|
|
+ uptime_output.format(time=variations[0], user_loadavg=variations[1])
|
|
),
|
|
)
|
|
|
|
# Check that our internal exception is correctly raised when `uptime` is not available.
|
|
run_mock.side_effect = FileNotFoundError()
|
|
self.assertRaises(
|
|
ArcheyException,
|
|
Uptime._parse_uptime_cmd, # pylint: disable=protected-access
|
|
uptime_instance_mock,
|
|
)
|
|
|
|
def test_various_output_cases(self):
|
|
"""Test when the device has just been started..."""
|
|
uptime_instance_mock = HelperMethods.entry_mock(Uptime)
|
|
output_mock = MagicMock()
|
|
|
|
with self.subTest("Output in case of hours and minutes."):
|
|
uptime_instance_mock.value = {
|
|
"days": 0,
|
|
"hours": 2,
|
|
"minutes": 1,
|
|
"seconds": 0,
|
|
}
|
|
Uptime.output(uptime_instance_mock, output_mock)
|
|
self.assertEqual(output_mock.append.call_args[0][1], "2 hours and 1 minute")
|
|
|
|
output_mock.reset_mock()
|
|
|
|
with self.subTest("Output in case of days, hours and minutes."):
|
|
uptime_instance_mock.value = {
|
|
"days": 1,
|
|
"hours": 1,
|
|
"minutes": 2,
|
|
"seconds": 0,
|
|
}
|
|
Uptime.output(uptime_instance_mock, output_mock)
|
|
self.assertEqual(output_mock.append.call_args[0][1], "1 day, 1 hour and 2 minutes")
|
|
|
|
output_mock.reset_mock()
|
|
|
|
with self.subTest("Output in case of days and minutes."):
|
|
uptime_instance_mock.value = {
|
|
"days": 3,
|
|
"hours": 0,
|
|
"minutes": 3,
|
|
"seconds": 0,
|
|
}
|
|
Uptime.output(uptime_instance_mock, output_mock)
|
|
self.assertEqual(output_mock.append.call_args[0][1], "3 days and 3 minutes")
|
|
|
|
output_mock.reset_mock()
|
|
|
|
with self.subTest("Output in case of very early execution."):
|
|
uptime_instance_mock.value = {
|
|
"days": 0,
|
|
"hours": 0,
|
|
"minutes": 0,
|
|
"seconds": 0,
|
|
}
|
|
Uptime.output(uptime_instance_mock, output_mock)
|
|
self.assertEqual(output_mock.append.call_args[0][1], "< 1 minute")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|