refactor: improve imports, fix datetime usage, and reorganize cross-chain services
Some checks failed
Cross-Node Transaction Testing / transaction-test (push) Has been cancelled
Deploy to Testnet / deploy-testnet (push) Has been cancelled
Documentation Validation / validate-docs (push) Has been cancelled
Documentation Validation / validate-policies-strict (push) Has been cancelled
Integration Tests / test-service-integration (push) Has been cancelled
Multi-Node Stress Testing / stress-test (push) Has been cancelled
Python Tests / test-python (push) Has been cancelled
Security Scanning / security-scan (push) Has been cancelled

- Added logger initialization to EventRouter in events.py
- Fixed datetime.timedelta references to use timedelta directly in security_hardening.py
- Fixed StateTransition timestamp default_factory to use lambda in state.py
- Fixed StateValidator.validate_transitions to only check source states exist
- Moved cross_chain_bridge_enhanced.py to cross_chain/bridge_enhanced.py
- Updated import paths in global_marketplace
This commit is contained in:
aitbc
2026-05-12 20:49:01 +02:00
parent c87806b68b
commit f4688aefbd
27 changed files with 5030 additions and 16 deletions

403
tests/test_feature_flags.py Normal file
View File

@@ -0,0 +1,403 @@
"""
Tests for feature flags utilities
"""
import pytest
import json
from pathlib import Path
from datetime import datetime
from unittest.mock import patch, Mock
from aitbc.feature_flags import (
FeatureFlag,
FeatureFlagManager,
get_feature_flag_manager,
is_feature_enabled,
)
class TestFeatureFlag:
"""Tests for FeatureFlag dataclass"""
def test_feature_flag_creation(self):
"""Test FeatureFlag dataclass creation"""
flag = FeatureFlag(
name="test_feature",
enabled=True,
description="Test feature",
rollout_percentage=50.0
)
assert flag.name == "test_feature"
assert flag.enabled is True
assert flag.description == "Test feature"
assert flag.rollout_percentage == 50.0
def test_feature_flag_with_whitelist(self):
"""Test FeatureFlag with whitelisted users"""
flag = FeatureFlag(
name="test_feature",
enabled=True,
description="Test feature",
whitelisted_users={"user1", "user2"}
)
assert flag.whitelisted_users == {"user1", "user2"}
def test_feature_flag_with_blacklist(self):
"""Test FeatureFlag with blacklisted users"""
flag = FeatureFlag(
name="test_feature",
enabled=True,
description="Test feature",
blacklisted_users={"user3"}
)
assert flag.blacklisted_users == {"user3"}
def test_feature_flag_with_enabled_since(self):
"""Test FeatureFlag with enabled_since timestamp"""
now = datetime.now()
flag = FeatureFlag(
name="test_feature",
enabled=True,
description="Test feature",
enabled_since=now
)
assert flag.enabled_since == now
class TestFeatureFlagManager:
"""Tests for FeatureFlagManager"""
def test_initialization_without_config_file(self, tmp_path):
"""Test initialization without config file"""
manager = FeatureFlagManager(config_file=tmp_path / "nonexistent.json")
assert manager._flags == {}
assert manager.config_file == tmp_path / "nonexistent.json"
@patch('aitbc.feature_flags.logger')
def test_load_flags_from_file(self, mock_logger, tmp_path):
"""Test loading flags from configuration file"""
config_file = tmp_path / "feature_flags.json"
config_data = {
"test_feature": {
"enabled": True,
"description": "Test feature",
"rollout_percentage": 50.0,
"whitelisted_users": ["user1"],
"blacklisted_users": ["user2"],
"enabled_since": "2024-01-01T00:00:00"
}
}
config_file.write_text(json.dumps(config_data))
manager = FeatureFlagManager(config_file=config_file)
assert "test_feature" in manager._flags
assert manager._flags["test_feature"].enabled is True
assert manager._flags["test_feature"].description == "Test feature"
assert manager._flags["test_feature"].rollout_percentage == 50.0
mock_logger.info.assert_called_once()
@patch('aitbc.feature_flags.logger')
def test_load_flags_file_not_found(self, mock_logger, tmp_path):
"""Test loading flags when file doesn't exist"""
manager = FeatureFlagManager(config_file=tmp_path / "nonexistent.json")
mock_logger.info.assert_called_once()
assert "No feature flags file found" in mock_logger.info.call_args[0][0]
@patch('aitbc.feature_flags.logger')
def test_load_flags_invalid_json(self, mock_logger, tmp_path):
"""Test loading flags with invalid JSON"""
config_file = tmp_path / "feature_flags.json"
config_file.write_text("invalid json")
manager = FeatureFlagManager(config_file=config_file)
mock_logger.error.assert_called_once()
assert "Failed to load feature flags" in mock_logger.error.call_args[0][0]
@patch('aitbc.feature_flags.logger')
def test_save_flags(self, mock_logger, tmp_path):
"""Test saving flags to configuration file"""
config_file = tmp_path / "feature_flags.json"
manager = FeatureFlagManager(config_file=config_file)
manager._flags["test_feature"] = FeatureFlag(
name="test_feature",
enabled=True,
description="Test feature"
)
manager.save_flags()
assert config_file.exists()
with open(config_file, 'r') as f:
data = json.load(f)
assert "test_feature" in data
assert data["test_feature"]["enabled"] is True
# Check that save was logged (may have other log calls from initialization)
assert any("Saved" in str(call) for call in mock_logger.info.call_args_list)
@patch('aitbc.feature_flags.logger')
def test_is_enabled_flag_not_found(self, mock_logger):
"""Test is_enabled when flag not found"""
manager = FeatureFlagManager()
result = manager.is_enabled("nonexistent_feature")
assert result is False
mock_logger.warning.assert_called_once()
def test_is_enabled_globally_disabled(self):
"""Test is_enabled when flag is globally disabled"""
manager = FeatureFlagManager()
manager._flags["test_feature"] = FeatureFlag(
name="test_feature",
enabled=False,
description="Test feature"
)
result = manager.is_enabled("test_feature")
assert result is False
def test_is_enabled_globally_enabled(self):
"""Test is_enabled when flag is globally enabled"""
manager = FeatureFlagManager()
manager._flags["test_feature"] = FeatureFlag(
name="test_feature",
enabled=True,
description="Test feature"
)
result = manager.is_enabled("test_feature")
assert result is True
def test_is_enabled_user_blacklisted(self):
"""Test is_enabled when user is blacklisted"""
manager = FeatureFlagManager()
manager._flags["test_feature"] = FeatureFlag(
name="test_feature",
enabled=True,
description="Test feature",
blacklisted_users={"user1"}
)
result = manager.is_enabled("test_feature", user_id="user1")
assert result is False
def test_is_enabled_user_whitelisted(self):
"""Test is_enabled when user is whitelisted"""
manager = FeatureFlagManager()
manager._flags["test_feature"] = FeatureFlag(
name="test_feature",
enabled=True,
description="Test feature",
whitelisted_users={"user1"}
)
result = manager.is_enabled("test_feature", user_id="user1")
assert result is True
def test_is_enabled_percentage_rollout_included(self):
"""Test is_enabled with percentage-based rollout - user included"""
manager = FeatureFlagManager()
manager._flags["test_feature"] = FeatureFlag(
name="test_feature",
enabled=True,
description="Test feature",
rollout_percentage=50.0
)
result = manager.is_enabled("test_feature", user_hash=25)
assert result is True # 25 % 100 = 25 < 50
def test_is_enabled_percentage_rollout_excluded(self):
"""Test is_enabled with percentage-based rollout - user excluded"""
manager = FeatureFlagManager()
manager._flags["test_feature"] = FeatureFlag(
name="test_feature",
enabled=True,
description="Test feature",
rollout_percentage=50.0
)
result = manager.is_enabled("test_feature", user_hash=75)
assert result is False # 75 % 100 = 75 >= 50
@patch('aitbc.feature_flags.logger')
def test_enable_feature_new_flag(self, mock_logger, tmp_path):
"""Test enable_feature for new flag"""
config_file = tmp_path / "feature_flags.json"
manager = FeatureFlagManager(config_file=config_file)
manager.enable_feature("new_feature", rollout_percentage=75.0)
assert "new_feature" in manager._flags
assert manager._flags["new_feature"].enabled is True
assert manager._flags["new_feature"].rollout_percentage == 75.0
assert manager._flags["new_feature"].enabled_since is not None
# Check that enable was logged
assert any("Enabled" in str(call) for call in mock_logger.info.call_args_list)
@patch('aitbc.feature_flags.logger')
def test_enable_feature_existing_flag(self, mock_logger, tmp_path):
"""Test enable_feature for existing flag"""
config_file = tmp_path / "feature_flags.json"
manager = FeatureFlagManager(config_file=config_file)
manager._flags["existing_feature"] = FeatureFlag(
name="existing_feature",
enabled=False,
description="Existing feature"
)
manager.enable_feature("existing_feature", rollout_percentage=50.0)
assert manager._flags["existing_feature"].enabled is True
assert manager._flags["existing_feature"].rollout_percentage == 50.0
# Check that enable was logged
assert any("Enabled" in str(call) for call in mock_logger.info.call_args_list)
@patch('aitbc.feature_flags.logger')
def test_disable_feature(self, mock_logger, tmp_path):
"""Test disable_feature"""
config_file = tmp_path / "feature_flags.json"
manager = FeatureFlagManager(config_file=config_file)
manager._flags["test_feature"] = FeatureFlag(
name="test_feature",
enabled=True,
description="Test feature"
)
manager.disable_feature("test_feature")
assert manager._flags["test_feature"].enabled is False
# Check that disable was logged
assert any("Disabled" in str(call) for call in mock_logger.info.call_args_list)
@patch('aitbc.feature_flags.logger')
def test_add_whitelisted_user_new_flag(self, mock_logger, tmp_path):
"""Test add_whitelisted_user for new flag"""
config_file = tmp_path / "feature_flags.json"
manager = FeatureFlagManager(config_file=config_file)
manager.add_whitelisted_user("new_feature", "user1")
assert "new_feature" in manager._flags
assert "user1" in manager._flags["new_feature"].whitelisted_users
# Check that add was logged
assert any("whitelist" in str(call) for call in mock_logger.info.call_args_list)
@patch('aitbc.feature_flags.logger')
def test_add_whitelisted_user_existing_flag(self, mock_logger, tmp_path):
"""Test add_whitelisted_user for existing flag"""
config_file = tmp_path / "feature_flags.json"
manager = FeatureFlagManager(config_file=config_file)
manager._flags["test_feature"] = FeatureFlag(
name="test_feature",
enabled=True,
description="Test feature",
whitelisted_users=set()
)
manager.add_whitelisted_user("test_feature", "user1")
assert "user1" in manager._flags["test_feature"].whitelisted_users
# Check that add was logged
assert any("whitelist" in str(call) for call in mock_logger.info.call_args_list)
@patch('aitbc.feature_flags.logger')
def test_add_blacklisted_user_new_flag(self, mock_logger, tmp_path):
"""Test add_blacklisted_user for new flag"""
config_file = tmp_path / "feature_flags.json"
manager = FeatureFlagManager(config_file=config_file)
manager.add_blacklisted_user("new_feature", "user1")
assert "new_feature" in manager._flags
assert "user1" in manager._flags["new_feature"].blacklisted_users
# Check that add was logged
assert any("blacklist" in str(call) for call in mock_logger.info.call_args_list)
@patch('aitbc.feature_flags.logger')
def test_add_blacklisted_user_existing_flag(self, mock_logger, tmp_path):
"""Test add_blacklisted_user for existing flag"""
config_file = tmp_path / "feature_flags.json"
manager = FeatureFlagManager(config_file=config_file)
manager._flags["test_feature"] = FeatureFlag(
name="test_feature",
enabled=True,
description="Test feature",
blacklisted_users=set()
)
manager.add_blacklisted_user("test_feature", "user1")
assert "user1" in manager._flags["test_feature"].blacklisted_users
# Check that add was logged
assert any("blacklist" in str(call) for call in mock_logger.info.call_args_list)
def test_get_all_flags(self):
"""Test get_all_flags"""
manager = FeatureFlagManager()
manager._flags["feature1"] = FeatureFlag(
name="feature1",
enabled=True,
description="Feature 1"
)
manager._flags["feature2"] = FeatureFlag(
name="feature2",
enabled=False,
description="Feature 2"
)
flags = manager.get_all_flags()
assert len(flags) == 2
assert "feature1" in flags
assert "feature2" in flags
def test_get_flag_status_found(self):
"""Test get_flag_status when flag exists"""
manager = FeatureFlagManager()
flag = FeatureFlag(
name="test_feature",
enabled=True,
description="Test feature"
)
manager._flags["test_feature"] = flag
result = manager.get_flag_status("test_feature")
assert result == flag
def test_get_flag_status_not_found(self):
"""Test get_flag_status when flag doesn't exist"""
manager = FeatureFlagManager()
result = manager.get_flag_status("nonexistent_feature")
assert result is None
class TestGlobalFunctions:
"""Tests for global feature flag functions"""
def test_get_feature_flag_manager_singleton(self):
"""Test get_feature_flag_manager returns singleton"""
manager1 = get_feature_flag_manager()
manager2 = get_feature_flag_manager()
assert manager1 is manager2
def test_get_feature_flag_manager_with_config(self, tmp_path):
"""Test get_feature_flag_manager with custom config"""
# Reset global manager first
import aitbc.feature_flags as ff_module
ff_module._global_feature_flag_manager = None
manager = get_feature_flag_manager(config_file=tmp_path / "custom.json")
assert manager.config_file == tmp_path / "custom.json"
def test_is_feature_enabled_global(self):
"""Test is_feature_enabled global function"""
manager = get_feature_flag_manager()
manager._flags["test_feature"] = FeatureFlag(
name="test_feature",
enabled=True,
description="Test feature"
)
result = is_feature_enabled("test_feature")
assert result is True