Files
TimeTracker/tests/test_installation_config.py
Dries Peeters 90dde470da style: standardize code formatting and normalize line endings
- Normalize line endings from CRLF to LF across all files to match .editorconfig
- Standardize quote style from single quotes to double quotes
- Normalize whitespace and formatting throughout codebase
- Apply consistent code style across 372 files including:
  * Application code (models, routes, services, utils)
  * Test files
  * Configuration files
  * CI/CD workflows

This ensures consistency with the project's .editorconfig settings and
improves code maintainability.
2025-11-28 20:05:37 +01:00

207 lines
7.7 KiB
Python

"""
Tests for installation configuration and setup
"""
import os
import json
import pytest
from unittest.mock import patch
from app.utils.installation import InstallationConfig, get_installation_config
@pytest.fixture
def temp_config_dir(tmp_path):
"""Create a temporary config directory"""
config_dir = tmp_path / "data"
config_dir.mkdir()
return str(config_dir)
@pytest.fixture
def installation_config(temp_config_dir, monkeypatch):
"""Create an InstallationConfig instance with temporary directory"""
monkeypatch.setattr("app.utils.installation.InstallationConfig.CONFIG_DIR", temp_config_dir)
config = InstallationConfig()
return config
class TestInstallationConfig:
"""Test installation configuration management"""
def test_installation_salt_generation(self, installation_config):
"""Test that installation salt is generated and persisted"""
# First call should generate salt
salt1 = installation_config.get_installation_salt()
assert salt1 is not None
assert len(salt1) == 64 # 32 bytes = 64 hex chars
# Second call should return same salt
salt2 = installation_config.get_installation_salt()
assert salt1 == salt2
def test_installation_id_generation(self, installation_config):
"""Test that installation ID is generated and persisted"""
# First call should generate ID
id1 = installation_config.get_installation_id()
assert id1 is not None
assert len(id1) == 16
# Second call should return same ID
id2 = installation_config.get_installation_id()
assert id1 == id2
def test_installation_id_uniqueness(self, temp_config_dir, monkeypatch):
"""Test that each installation gets a unique ID"""
monkeypatch.setattr("app.utils.installation.InstallationConfig.CONFIG_DIR", temp_config_dir)
config1 = InstallationConfig()
id1 = config1.get_installation_id()
# Create a new instance (simulating restart)
config2 = InstallationConfig()
id2 = config2.get_installation_id()
# Should be the same ID (persisted)
assert id1 == id2
def test_setup_completion(self, installation_config):
"""Test setup completion tracking"""
# Initially not complete
assert not installation_config.is_setup_complete()
# Mark as complete
installation_config.mark_setup_complete(telemetry_enabled=True)
assert installation_config.is_setup_complete()
assert installation_config.get_telemetry_preference() is True
# Verify persistence
config2 = InstallationConfig()
assert config2.is_setup_complete()
assert config2.get_telemetry_preference() is True
def test_telemetry_preference(self, installation_config):
"""Test telemetry preference management"""
# Default is False
assert installation_config.get_telemetry_preference() is False
# Enable telemetry
installation_config.set_telemetry_preference(True)
assert installation_config.get_telemetry_preference() is True
# Disable telemetry
installation_config.set_telemetry_preference(False)
assert installation_config.get_telemetry_preference() is False
def test_config_persistence(self, installation_config, temp_config_dir):
"""Test that configuration is persisted to disk"""
# Set some values
salt = installation_config.get_installation_salt()
installation_id = installation_config.get_installation_id()
installation_config.mark_setup_complete(telemetry_enabled=True)
# Read the file directly
config_path = os.path.join(temp_config_dir, "installation.json")
assert os.path.exists(config_path)
with open(config_path, "r") as f:
data = json.load(f)
assert data["telemetry_salt"] == salt
assert data["installation_id"] == installation_id
assert data["setup_complete"] is True
assert data["telemetry_enabled"] is True
def test_get_all_config(self, installation_config):
"""Test retrieving all configuration"""
# Generate salt and ID first (lazy initialization)
salt = installation_config.get_installation_salt()
installation_id = installation_config.get_installation_id()
installation_config.mark_setup_complete(telemetry_enabled=True)
config = installation_config.get_all_config()
assert "telemetry_salt" in config
assert "installation_id" in config
assert "setup_complete" in config
assert config["setup_complete"] is True
def test_initial_data_seeding_tracking(self, installation_config):
"""Test that initial data seeding is tracked"""
# Initially not seeded
assert not installation_config.is_initial_data_seeded()
# Mark as seeded
installation_config.mark_initial_data_seeded()
assert installation_config.is_initial_data_seeded()
# Verify persistence
config2 = InstallationConfig()
assert config2.is_initial_data_seeded()
def test_initial_data_seeding_persistence(self, installation_config, temp_config_dir):
"""Test that initial data seeding flag is persisted to disk"""
# Mark as seeded
installation_config.mark_initial_data_seeded()
# Read the file directly
config_path = os.path.join(temp_config_dir, "installation.json")
assert os.path.exists(config_path)
with open(config_path, "r") as f:
data = json.load(f)
assert data["initial_data_seeded"] is True
assert "initial_data_seeded_at" in data
def test_initial_data_seeding_default_value(self, installation_config):
"""Test that initial data seeding defaults to False"""
# Should default to False for new installations
assert installation_config.is_initial_data_seeded() is False
class TestSetupRoutes:
"""Test setup routes"""
def test_setup_page_redirects_if_complete(self, client, installation_config):
"""Test that setup page redirects if setup is already complete"""
# Mark setup as complete
installation_config.mark_setup_complete(telemetry_enabled=False)
# Try to access setup page
response = client.get("/setup")
assert response.status_code in [302, 200] # May redirect or show page
def test_setup_completion_flow(self, client, installation_config):
"""Test completing the setup"""
# Patch the global get_installation_config to return our fixture
with patch("app.routes.setup.get_installation_config") as mock_get_config:
mock_get_config.return_value = installation_config
# Ensure setup is not complete
assert not installation_config.is_setup_complete()
# Access setup page
response = client.get("/setup")
assert response.status_code == 200
# Complete setup with telemetry enabled
response = client.post("/setup", data={"telemetry_enabled": "on"}, follow_redirects=False)
# Should redirect after completion
assert response.status_code == 302
# Verify setup is complete
assert installation_config.is_setup_complete()
assert installation_config.get_telemetry_preference() is True
def test_setup_without_telemetry(self, client, installation_config):
"""Test completing setup with telemetry disabled"""
# Complete setup without telemetry
response = client.post("/setup", data={}, follow_redirects=False)
# Should redirect after completion
assert response.status_code == 302
# Verify telemetry is disabled
assert installation_config.get_telemetry_preference() is False