mirror of
https://github.com/trailofbits/algo.git
synced 2026-08-17 21:25:50 +02:00
Phase 1: Quick wins for code quality and test infrastructure (#14907)
- Replace ignore_errors: true with failed_when: false in 5 files (main.yml, users.yml, ubuntu.yml, umount.yml, test-wireguard-real-async.yml) - Add pytest.ini configuration for test discovery - Add tests/conftest.py with shared fixtures and mock helpers The failed_when: false pattern is preferred by ansible-lint as it explicitly indicates expected failure handling rather than silently ignoring all errors. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -18,7 +18,7 @@
|
|||||||
- name: Ensure the requirements installed
|
- name: Ensure the requirements installed
|
||||||
debug:
|
debug:
|
||||||
msg: "{{ '192.168.1.1' | ansible.utils.ipaddr }}"
|
msg: "{{ '192.168.1.1' | ansible.utils.ipaddr }}"
|
||||||
ignore_errors: true
|
failed_when: false
|
||||||
no_log: true
|
no_log: true
|
||||||
register: ipaddr
|
register: ipaddr
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
- block:
|
- block:
|
||||||
- name: MacOS | check fs the ramdisk exists
|
- name: MacOS | check fs the ramdisk exists
|
||||||
command: /usr/sbin/diskutil info "{{ facts.tmpfs_volume_name }}"
|
command: /usr/sbin/diskutil info "{{ facts.tmpfs_volume_name }}"
|
||||||
ignore_errors: true
|
failed_when: false
|
||||||
changed_when: false
|
changed_when: false
|
||||||
register: diskutil_info
|
register: diskutil_info
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[pytest]
|
||||||
|
testpaths = tests/unit
|
||||||
|
python_files = test_*.py
|
||||||
|
python_classes = Test*
|
||||||
|
python_functions = test_*
|
||||||
|
addopts = -v --tb=short
|
||||||
|
filterwarnings =
|
||||||
|
ignore::DeprecationWarning
|
||||||
|
ignore::PendingDeprecationWarning
|
||||||
@@ -105,7 +105,7 @@
|
|||||||
|
|
||||||
- name: Check apparmor support
|
- name: Check apparmor support
|
||||||
command: apparmor_status
|
command: apparmor_status
|
||||||
ignore_errors: true
|
failed_when: false
|
||||||
changed_when: false
|
changed_when: false
|
||||||
register: apparmor_status
|
register: apparmor_status
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,151 @@
|
|||||||
|
"""Shared pytest fixtures for Algo VPN tests."""
|
||||||
|
|
||||||
|
import base64
|
||||||
|
import secrets
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
# Add library directory to path for custom module imports
|
||||||
|
sys.path.insert(0, str(Path(__file__).parent.parent / "library"))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def test_variables():
|
||||||
|
"""Load test variables from YAML fixture."""
|
||||||
|
fixture_path = Path(__file__).parent / "fixtures" / "test_variables.yml"
|
||||||
|
with open(fixture_path) as f:
|
||||||
|
return yaml.safe_load(f)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def test_config(test_variables):
|
||||||
|
"""Get test configuration with common defaults."""
|
||||||
|
return test_variables.copy()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def temp_directory():
|
||||||
|
"""Create a temporary directory for test files."""
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
yield Path(tmpdir)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def wireguard_private_key():
|
||||||
|
"""Generate a random WireGuard-compatible private key."""
|
||||||
|
raw_key = secrets.token_bytes(32)
|
||||||
|
return base64.b64encode(raw_key).decode()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def wireguard_key_pair(temp_directory):
|
||||||
|
"""Generate a WireGuard key pair and return paths and values."""
|
||||||
|
raw_key = secrets.token_bytes(32)
|
||||||
|
b64_key = base64.b64encode(raw_key).decode()
|
||||||
|
|
||||||
|
private_key_path = temp_directory / "private.key"
|
||||||
|
private_key_path.write_bytes(raw_key)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"private_key_raw": raw_key,
|
||||||
|
"private_key_b64": b64_key,
|
||||||
|
"private_key_path": str(private_key_path),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class MockAnsibleModule:
|
||||||
|
"""Mock AnsibleModule for testing custom Ansible modules."""
|
||||||
|
|
||||||
|
def __init__(self, params):
|
||||||
|
"""Initialize with module parameters."""
|
||||||
|
self.params = params
|
||||||
|
self.result = {}
|
||||||
|
self.failed = False
|
||||||
|
self.fail_msg = None
|
||||||
|
|
||||||
|
def fail_json(self, **kwargs):
|
||||||
|
"""Record failure and raise exception."""
|
||||||
|
self.failed = True
|
||||||
|
self.fail_msg = kwargs.get("msg", "Unknown error")
|
||||||
|
raise Exception(f"Module failed: {self.fail_msg}")
|
||||||
|
|
||||||
|
def exit_json(self, **kwargs):
|
||||||
|
"""Record successful result."""
|
||||||
|
self.result = kwargs
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_ansible_module():
|
||||||
|
"""Fixture providing MockAnsibleModule class."""
|
||||||
|
return MockAnsibleModule
|
||||||
|
|
||||||
|
|
||||||
|
# Jinja2 mock filters for template testing
|
||||||
|
def mock_to_uuid(value):
|
||||||
|
"""Mock the to_uuid filter."""
|
||||||
|
return "12345678-1234-5678-1234-567812345678"
|
||||||
|
|
||||||
|
|
||||||
|
def mock_bool(value):
|
||||||
|
"""Mock the bool filter."""
|
||||||
|
return str(value).lower() in ("true", "1", "yes", "on")
|
||||||
|
|
||||||
|
|
||||||
|
def mock_lookup(lookup_type, path):
|
||||||
|
"""Mock the lookup function."""
|
||||||
|
if lookup_type == "file":
|
||||||
|
if "private" in path:
|
||||||
|
return "MOCK_PRIVATE_KEY_BASE64=="
|
||||||
|
elif "public" in path:
|
||||||
|
return "MOCK_PUBLIC_KEY_BASE64=="
|
||||||
|
elif "preshared" in path:
|
||||||
|
return "MOCK_PRESHARED_KEY_BASE64=="
|
||||||
|
return "MOCK_LOOKUP_DATA"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def jinja2_env():
|
||||||
|
"""Create a Jinja2 environment with mock Ansible filters."""
|
||||||
|
from jinja2 import Environment, FileSystemLoader, StrictUndefined
|
||||||
|
|
||||||
|
def create_env(template_dir):
|
||||||
|
env = Environment(loader=FileSystemLoader(template_dir), undefined=StrictUndefined)
|
||||||
|
env.globals["lookup"] = mock_lookup
|
||||||
|
env.filters["to_uuid"] = mock_to_uuid
|
||||||
|
env.filters["bool"] = mock_bool
|
||||||
|
return env
|
||||||
|
|
||||||
|
return create_env
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def project_root():
|
||||||
|
"""Return the project root directory."""
|
||||||
|
return Path(__file__).parent.parent
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def roles_dir(project_root):
|
||||||
|
"""Return the roles directory."""
|
||||||
|
return project_root / "roles"
|
||||||
|
|
||||||
|
|
||||||
|
# Skip markers for conditional tests
|
||||||
|
def pytest_configure(config):
|
||||||
|
"""Register custom markers."""
|
||||||
|
config.addinivalue_line("markers", "requires_wireguard: mark test as requiring WireGuard tools")
|
||||||
|
config.addinivalue_line("markers", "slow: mark test as slow running")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def skip_wireguard_tests(request):
|
||||||
|
"""Skip tests marked with requires_wireguard if WireGuard tools aren't available."""
|
||||||
|
if request.node.get_closest_marker("requires_wireguard"):
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
if not shutil.which("wg"):
|
||||||
|
pytest.skip("WireGuard tools not available")
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
mode: "0600"
|
mode: "0600"
|
||||||
when: item.changed
|
when: item.changed
|
||||||
loop: "{{ wg_genkey_results.results }}"
|
loop: "{{ wg_genkey_results.results }}"
|
||||||
ignore_errors: true
|
failed_when: false
|
||||||
|
|
||||||
- name: Cleanup
|
- name: Cleanup
|
||||||
file:
|
file:
|
||||||
|
|||||||
@@ -92,7 +92,7 @@
|
|||||||
port: "{{ ansible_ssh_port | default(ssh_port) | int }}"
|
port: "{{ ansible_ssh_port | default(ssh_port) | int }}"
|
||||||
timeout: 10
|
timeout: 10
|
||||||
register: ssh_check
|
register: ssh_check
|
||||||
ignore_errors: true
|
failed_when: false
|
||||||
when: algo_server != 'localhost'
|
when: algo_server != 'localhost'
|
||||||
|
|
||||||
- name: Fail with helpful message if server unreachable
|
- name: Fail with helpful message if server unreachable
|
||||||
|
|||||||
Reference in New Issue
Block a user