wrolpi/modules/archive/test/test_domains_config.py

290 lines
9.4 KiB
Python

"""
Tests for DomainsConfig import/upgrade scenarios.
Tests cover:
1. Onboarding (new install) - no config file exists
2. Upgrade - config file exists with data
3. Edge cases - empty config, missing config with DB data
"""
import pytest
import yaml
from modules.archive.lib import get_domains_config
from wrolpi.collections import Collection
@pytest.mark.asyncio
class TestDomainsConfigOnboarding:
"""Tests for new install scenarios where no config file exists."""
async def test_new_install_no_db_data(self, test_session, test_directory, async_client):
"""
New install with empty DB and no config file.
Should succeed with empty config.
"""
config = get_domains_config()
config_path = config.get_file()
# Ensure no config file exists
if config_path.is_file():
config_path.unlink()
# Ensure DB has no domain collections
assert test_session.query(Collection).filter_by(kind='domain').count() == 0
# Import should succeed
config.import_config()
assert config.successful_import is True
async def test_new_install_with_db_data(self, test_session, test_directory, async_client):
"""
Config file missing but DB has data.
Import should succeed (nothing to import), DB data preserved.
"""
config = get_domains_config()
config_path = config.get_file()
# Create a domain collection in DB
collection = Collection(
name='example.com',
kind='domain',
directory=None,
)
test_session.add(collection)
test_session.commit()
# Remove config file to simulate missing config
if config_path.is_file():
config_path.unlink()
# Import should succeed (nothing to import)
config.import_config()
assert config.successful_import is True
# DB data should be preserved
collections = test_session.query(Collection).filter_by(kind='domain').all()
assert len(collections) == 1
assert collections[0].name == 'example.com'
@pytest.mark.asyncio
class TestDomainsConfigUpgrade:
"""Tests for upgrade scenarios where config file exists."""
async def test_upgrade_config_exists_with_data(self, test_session, test_directory, async_client):
"""
Upgrade with existing config containing collection data.
Should import and sync DB with config.
"""
config = get_domains_config()
config_path = config.get_file()
# Create a collection in DB
collection = Collection(
name='test.org',
kind='domain',
directory=None,
)
test_session.add(collection)
test_session.commit()
# Dump to create config file
config.dump_config()
assert config_path.is_file()
# Now import should succeed and preserve the collection
config.import_config()
assert config.successful_import is True
# Collection should still exist
collections = test_session.query(Collection).filter_by(kind='domain').all()
assert len(collections) == 1
assert collections[0].name == 'test.org'
async def test_upgrade_config_exists_empty_list(self, test_session, test_directory, async_client):
"""
Config exists but has empty collections list.
Should NOT delete existing DB collections (never delete on empty).
"""
config = get_domains_config()
config_path = config.get_file()
# Create a collection in DB
collection = Collection(
name='preserve.me',
kind='domain',
directory=None,
)
test_session.add(collection)
test_session.commit()
# Write empty config
config_path.parent.mkdir(parents=True, exist_ok=True)
with open(config_path, 'w') as f:
yaml.dump({'version': 0, 'collections': []}, f)
# Reinitialize config to read the empty file
config.initialize()
# Import should succeed but NOT delete the collection
config.import_config()
assert config.successful_import is True
# Collection should still exist (never delete on empty config)
collections = test_session.query(Collection).filter_by(kind='domain').all()
assert len(collections) == 1
assert collections[0].name == 'preserve.me'
async def test_upgrade_config_missing_db_has_data(self, test_session, test_directory, async_client):
"""
Config file missing but DB has domain collections.
Import should succeed (nothing to import), DB data preserved.
"""
config = get_domains_config()
config_path = config.get_file()
# Create collections in DB
for name in ['domain1.com', 'domain2.org']:
collection = Collection(
name=name,
kind='domain',
directory=None,
)
test_session.add(collection)
test_session.commit()
# Remove config file
if config_path.is_file():
config_path.unlink()
# Import should succeed (nothing to import)
config.import_config()
assert config.successful_import is True
# DB data should be preserved
collections = test_session.query(Collection).filter_by(kind='domain').all()
assert len(collections) == 2
collection_names = {c.name for c in collections}
assert 'domain1.com' in collection_names
assert 'domain2.org' in collection_names
@pytest.mark.asyncio
class TestDomainsConfigEdgeCases:
"""Tests for edge cases in config import."""
async def test_config_deletes_removed_items(self, test_session, test_directory, async_client):
"""
Config removes a collection that exists in DB.
Should delete the collection from DB.
"""
config = get_domains_config()
config_path = config.get_file()
# Create two collections
for name in ['keep.this', 'delete.this']:
collection = Collection(
name=name,
kind='domain',
directory=None,
)
test_session.add(collection)
test_session.commit()
# Dump to config
config.dump_config()
# Modify config to remove one collection
with open(config_path) as f:
config_data = yaml.safe_load(f)
config_data['collections'] = [c for c in config_data['collections'] if c['name'] == 'keep.this']
with open(config_path, 'w') as f:
yaml.dump(config_data, f)
# Reinitialize and import
config.initialize()
config.import_config()
assert config.successful_import is True
# Only one collection should remain
collections = test_session.query(Collection).filter_by(kind='domain').all()
assert len(collections) == 1
assert collections[0].name == 'keep.this'
async def test_config_adds_new_items(self, test_session, test_directory, async_client):
"""
Config has a new collection that doesn't exist in DB.
Should create the collection in DB.
"""
config = get_domains_config()
config_path = config.get_file()
# Ensure no collections in DB
assert test_session.query(Collection).filter_by(kind='domain').count() == 0
# Write config with a new collection
config_data = {
'version': 0,
'collections': [{
'name': 'new.domain',
'kind': 'domain',
}]
}
config_path.parent.mkdir(parents=True, exist_ok=True)
with open(config_path, 'w') as f:
yaml.dump(config_data, f)
# Reinitialize and import
config.initialize()
config.import_config()
assert config.successful_import is True
# Collection should be created
collections = test_session.query(Collection).filter_by(kind='domain').all()
assert len(collections) == 1
assert collections[0].name == 'new.domain'
async def test_config_updates_existing_items(self, test_session, test_directory, async_client):
"""
Config updates an existing collection's description.
Should update the collection in DB.
"""
config = get_domains_config()
config_path = config.get_file()
# Create a collection
collection = Collection(
name='update.me',
kind='domain',
directory=None,
description='Old description',
)
test_session.add(collection)
test_session.commit()
# Dump to config
config.dump_config()
# Modify config to change description
with open(config_path) as f:
config_data = yaml.safe_load(f)
for c in config_data['collections']:
if c['name'] == 'update.me':
c['description'] = 'New description'
with open(config_path, 'w') as f:
yaml.dump(config_data, f)
# Reinitialize and import
config.initialize()
config.import_config()
assert config.successful_import is True
# Collection should be updated
collection = test_session.query(Collection).filter_by(name='update.me').first()
assert collection is not None
assert collection.description == 'New description'