File: test_settings.py

package info (click to toggle)
anta 1.7.0-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 8,048 kB
  • sloc: python: 48,164; sh: 28; javascript: 9; makefile: 4
file content (127 lines) | stat: -rw-r--r-- 5,728 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
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""Unit tests for the anta.settings module."""

from __future__ import annotations

import logging
import os
import sys
from unittest.mock import patch

import pytest
from pydantic import ValidationError

from anta.settings import DEFAULT_MAX_CONCURRENCY, DEFAULT_NOFILE, AntaRunnerSettings

if os.name == "posix":
    # The function is not defined on non-POSIX system
    import resource


# Some type ignores for https://github.com/pydantic/pydantic-settings/issues/201


class TestAntaRunnerSettings:
    """Tests for the AntaRunnerSettings class."""

    def test_defaults(self, setenvvar: pytest.MonkeyPatch) -> None:
        """Test defaults for ANTA runner settings."""
        settings = AntaRunnerSettings()
        assert settings.nofile == DEFAULT_NOFILE
        assert settings.max_concurrency == DEFAULT_MAX_CONCURRENCY

    def test_env_var(self, setenvvar: pytest.MonkeyPatch) -> None:
        """Test setting different ANTA runner settings."""
        setenvvar.setenv("ANTA_NOFILE", "20480")
        settings = AntaRunnerSettings()
        assert settings.nofile == 20480
        assert settings.max_concurrency == DEFAULT_MAX_CONCURRENCY

    def test_validation(self, setenvvar: pytest.MonkeyPatch) -> None:
        """Test validation of ANTA runner settings."""
        setenvvar.setenv("ANTA_NOFILE", "-1")
        with pytest.raises(ValidationError):
            AntaRunnerSettings()

        setenvvar.setenv("ANTA_MAX_CONCURRENCY", "0")
        with pytest.raises(ValidationError):
            AntaRunnerSettings()

    @pytest.mark.skipif(os.name == "posix", reason="Run this test on Windows only")
    def test_file_descriptor_limit_windows(self, caplog: pytest.LogCaptureFixture) -> None:
        """Test file_descriptor_limit on Windows."""
        caplog.set_level(logging.INFO)
        settings = AntaRunnerSettings()
        assert settings.file_descriptor_limit == sys.maxsize
        assert "Running on a non-POSIX system, cannot adjust the maximum number of file descriptors." in caplog.text

    @pytest.mark.skipif(os.name != "posix", reason="Fake non-posix for coverage")
    async def test_file_descriptor_limit_fake_windows(self, caplog: pytest.LogCaptureFixture) -> None:
        """Test file_descriptor_limit on fake Windows."""
        caplog.set_level(logging.INFO)
        with patch("os.name", new="win32"):
            settings = AntaRunnerSettings()
            assert settings.file_descriptor_limit == sys.maxsize
            assert "Running on a non-POSIX system, cannot adjust the maximum number of file descriptors." in caplog.records[0].message

    @pytest.mark.skipif(os.name != "posix", reason="Cannot run this test on Windows")
    def test_file_descriptor_limit_posix(self, caplog: pytest.LogCaptureFixture) -> None:
        """Test file_descriptor_limit on POSIX systems."""
        with (
            caplog.at_level(logging.DEBUG),
            patch.dict("os.environ", {"ANTA_NOFILE": "20480"}),
            patch("resource.getrlimit") as getrlimit_mock,
            patch("resource.setrlimit") as setrlimit_mock,
        ):
            # Simulate the default system limits
            system_limits = (8192, 1048576)

            # Setup getrlimit mock return value
            getrlimit_mock.return_value = system_limits

            # Simulate setrlimit behavior
            def side_effect_setrlimit(_resource_id: int, limits: tuple[int, int]) -> None:
                getrlimit_mock.return_value = (limits[0], limits[1])

            setrlimit_mock.side_effect = side_effect_setrlimit

            settings = AntaRunnerSettings()

            # Assert the limits were updated as expected
            assert settings.file_descriptor_limit == 20480
            assert "Initial file descriptor limits for the current ANTA process: Soft Limit: 8192 | Hard Limit: 1048576" in caplog.text
            assert "Setting file descriptor soft limit to 20480" in caplog.text

            setrlimit_mock.assert_called_once_with(resource.RLIMIT_NOFILE, (20480, 1048576))  # pylint: disable=possibly-used-before-assignment # pyright: ignore[reportPossiblyUnboundVariable]

    @pytest.mark.skipif(os.name != "posix", reason="Cannot run this test on Windows")
    def test_file_descriptor_limit_value_error(self, caplog: pytest.LogCaptureFixture) -> None:
        """Test file_descriptor_limit with invalid environment variables."""
        with (
            caplog.at_level(logging.DEBUG),
            patch.dict("os.environ", {"ANTA_NOFILE": "666"}),
            patch("resource.getrlimit") as getrlimit_mock,
            patch("resource.setrlimit") as setrlimit_mock,
        ):
            # Simulate the default system limits
            system_limits = (32768, 131072)

            # Setup getrlimit mock return value
            getrlimit_mock.return_value = system_limits

            # Simulate setrlimit behavior raising ValueError
            def side_effect_setrlimit(_resource_id: int, _limits: tuple[int, int]) -> None:
                msg = "not allowed to raise maximum limit"
                raise ValueError(msg)

            setrlimit_mock.side_effect = side_effect_setrlimit

            _ = AntaRunnerSettings()

            # Assert the limits were *NOT* updated as expected
            assert caplog.records[-1].levelname == "WARNING"
            assert "Failed to set file descriptor soft limit for the current ANTA process" in caplog.records[-1].getMessage()

            setrlimit_mock.assert_called_once_with(resource.RLIMIT_NOFILE, (666, 131072))  # pyright: ignore[reportPossiblyUnboundVariable]