feat(coordinator-api): integrate dynamic pricing engine with GPU marketplace and add agent identity router
- Add DynamicPricingEngine and MarketDataCollector dependencies to GPU marketplace endpoints
- Implement dynamic pricing calculation for GPU registration with market_balance strategy
- Calculate real-time dynamic prices at booking time with confidence scores and pricing factors
- Enhance /marketplace/pricing/{model} endpoint with comprehensive dynamic pricing analysis
- Add static vs dynamic price
This commit is contained in:
611
tests/unit/test_dynamic_pricing.py
Normal file
611
tests/unit/test_dynamic_pricing.py
Normal file
@@ -0,0 +1,611 @@
|
||||
"""
|
||||
Unit Tests for Dynamic Pricing Engine
|
||||
Tests pricing calculations, strategies, and market data processing
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import asyncio
|
||||
from datetime import datetime, timedelta
|
||||
from unittest.mock import Mock, patch, AsyncMock
|
||||
import numpy as np
|
||||
|
||||
from app.services.dynamic_pricing_engine import (
|
||||
DynamicPricingEngine,
|
||||
PricingStrategy,
|
||||
ResourceType,
|
||||
PriceConstraints,
|
||||
PricingFactors,
|
||||
MarketConditions,
|
||||
PriceTrend
|
||||
)
|
||||
from app.domain.pricing_strategies import StrategyLibrary
|
||||
|
||||
|
||||
class TestDynamicPricingEngine:
|
||||
"""Test cases for DynamicPricingEngine"""
|
||||
|
||||
@pytest.fixture
|
||||
def pricing_engine(self):
|
||||
"""Create a pricing engine instance for testing"""
|
||||
config = {
|
||||
"min_price": 0.001,
|
||||
"max_price": 1000.0,
|
||||
"update_interval": 300,
|
||||
"forecast_horizon": 72,
|
||||
"max_volatility_threshold": 0.3,
|
||||
"circuit_breaker_threshold": 0.5
|
||||
}
|
||||
engine = DynamicPricingEngine(config)
|
||||
return engine
|
||||
|
||||
@pytest.fixture
|
||||
def sample_market_conditions(self):
|
||||
"""Create sample market conditions for testing"""
|
||||
return MarketConditions(
|
||||
region="us_west",
|
||||
resource_type=ResourceType.GPU,
|
||||
demand_level=0.8,
|
||||
supply_level=0.6,
|
||||
average_price=0.05,
|
||||
price_volatility=0.15,
|
||||
utilization_rate=0.75,
|
||||
competitor_prices=[0.045, 0.055, 0.048, 0.052],
|
||||
market_sentiment=0.2
|
||||
)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_engine_initialization(self, pricing_engine):
|
||||
"""Test engine initialization"""
|
||||
await pricing_engine.initialize()
|
||||
|
||||
assert pricing_engine.min_price == 0.001
|
||||
assert pricing_engine.max_price == 1000.0
|
||||
assert pricing_engine.update_interval == 300
|
||||
assert pricing_engine.forecast_horizon == 72
|
||||
assert isinstance(pricing_engine.pricing_history, dict)
|
||||
assert isinstance(pricing_engine.provider_strategies, dict)
|
||||
assert isinstance(pricing_engine.price_constraints, dict)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_calculate_dynamic_price_basic(self, pricing_engine, sample_market_conditions):
|
||||
"""Test basic dynamic price calculation"""
|
||||
|
||||
# Mock market conditions
|
||||
with patch.object(pricing_engine, '_get_market_conditions', return_value=sample_market_conditions):
|
||||
result = await pricing_engine.calculate_dynamic_price(
|
||||
resource_id="test_gpu_1",
|
||||
resource_type=ResourceType.GPU,
|
||||
base_price=0.05,
|
||||
strategy=PricingStrategy.MARKET_BALANCE,
|
||||
region="us_west"
|
||||
)
|
||||
|
||||
assert result.resource_id == "test_gpu_1"
|
||||
assert result.resource_type == ResourceType.GPU
|
||||
assert result.current_price == 0.05
|
||||
assert result.recommended_price > 0
|
||||
assert result.recommended_price <= pricing_engine.max_price
|
||||
assert result.recommended_price >= pricing_engine.min_price
|
||||
assert isinstance(result.price_trend, PriceTrend)
|
||||
assert 0 <= result.confidence_score <= 1
|
||||
assert isinstance(result.factors_exposed, dict)
|
||||
assert isinstance(result.reasoning, list)
|
||||
assert result.strategy_used == PricingStrategy.MARKET_BALANCE
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_pricing_strategies_different_results(self, pricing_engine, sample_market_conditions):
|
||||
"""Test that different strategies produce different results"""
|
||||
|
||||
with patch.object(pricing_engine, '_get_market_conditions', return_value=sample_market_conditions):
|
||||
# Test aggressive growth strategy
|
||||
result_growth = await pricing_engine.calculate_dynamic_price(
|
||||
resource_id="test_gpu_1",
|
||||
resource_type=ResourceType.GPU,
|
||||
base_price=0.05,
|
||||
strategy=PricingStrategy.AGGRESSIVE_GROWTH,
|
||||
region="us_west"
|
||||
)
|
||||
|
||||
# Test profit maximization strategy
|
||||
result_profit = await pricing_engine.calculate_dynamic_price(
|
||||
resource_id="test_gpu_1",
|
||||
resource_type=ResourceType.GPU,
|
||||
base_price=0.05,
|
||||
strategy=PricingStrategy.PROFIT_MAXIMIZATION,
|
||||
region="us_west"
|
||||
)
|
||||
|
||||
# Results should be different
|
||||
assert result_growth.recommended_price != result_profit.recommended_price
|
||||
assert result_growth.strategy_used == PricingStrategy.AGGRESSIVE_GROWTH
|
||||
assert result_profit.strategy_used == PricingStrategy.PROFIT_MAXIMIZATION
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_price_constraints_application(self, pricing_engine, sample_market_conditions):
|
||||
"""Test that price constraints are properly applied"""
|
||||
|
||||
constraints = PriceConstraints(
|
||||
min_price=0.03,
|
||||
max_price=0.08,
|
||||
max_change_percent=0.2
|
||||
)
|
||||
|
||||
with patch.object(pricing_engine, '_get_market_conditions', return_value=sample_market_conditions):
|
||||
result = await pricing_engine.calculate_dynamic_price(
|
||||
resource_id="test_gpu_1",
|
||||
resource_type=ResourceType.GPU,
|
||||
base_price=0.05,
|
||||
strategy=PricingStrategy.PROFIT_MAXIMIZATION,
|
||||
constraints=constraints,
|
||||
region="us_west"
|
||||
)
|
||||
|
||||
# Should respect constraints
|
||||
assert result.recommended_price >= constraints.min_price
|
||||
assert result.recommended_price <= constraints.max_price
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_circuit_breaker_activation(self, pricing_engine, sample_market_conditions):
|
||||
"""Test circuit breaker activation during high volatility"""
|
||||
|
||||
# Create high volatility conditions
|
||||
high_volatility_conditions = MarketConditions(
|
||||
region="us_west",
|
||||
resource_type=ResourceType.GPU,
|
||||
demand_level=0.9,
|
||||
supply_level=0.3,
|
||||
average_price=0.05,
|
||||
price_volatility=0.6, # High volatility
|
||||
utilization_rate=0.95,
|
||||
competitor_prices=[0.045, 0.055, 0.048, 0.052],
|
||||
market_sentiment=-0.3
|
||||
)
|
||||
|
||||
# Add some pricing history
|
||||
pricing_engine.pricing_history["test_gpu_1"] = [
|
||||
Mock(price=0.05, timestamp=datetime.utcnow() - timedelta(minutes=10))
|
||||
]
|
||||
|
||||
with patch.object(pricing_engine, '_get_market_conditions', return_value=high_volatility_conditions):
|
||||
result = await pricing_engine.calculate_dynamic_price(
|
||||
resource_id="test_gpu_1",
|
||||
resource_type=ResourceType.GPU,
|
||||
base_price=0.05,
|
||||
strategy=PricingStrategy.MARKET_BALANCE,
|
||||
region="us_west"
|
||||
)
|
||||
|
||||
# Circuit breaker should be activated
|
||||
assert "test_gpu_1" in pricing_engine.circuit_breakers
|
||||
assert pricing_engine.circuit_breakers["test_gpu_1"] is True
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_price_forecast_generation(self, pricing_engine):
|
||||
"""Test price forecast generation"""
|
||||
|
||||
# Add historical data
|
||||
base_time = datetime.utcnow()
|
||||
for i in range(48): # 48 data points
|
||||
pricing_engine.pricing_history["test_gpu_1"] = pricing_engine.pricing_history.get("test_gpu_1", [])
|
||||
pricing_engine.pricing_history["test_gpu_1"].append(
|
||||
Mock(
|
||||
price=0.05 + (i * 0.001),
|
||||
demand_level=0.6 + (i % 10) * 0.02,
|
||||
supply_level=0.7 - (i % 8) * 0.01,
|
||||
confidence=0.8,
|
||||
strategy_used="market_balance",
|
||||
timestamp=base_time - timedelta(hours=48-i)
|
||||
)
|
||||
)
|
||||
|
||||
forecast = await pricing_engine.get_price_forecast("test_gpu_1", 24)
|
||||
|
||||
assert len(forecast) == 24
|
||||
for point in forecast:
|
||||
assert hasattr(point, 'timestamp')
|
||||
assert hasattr(point, 'price')
|
||||
assert hasattr(point, 'demand_level')
|
||||
assert hasattr(point, 'supply_level')
|
||||
assert hasattr(point, 'confidence')
|
||||
assert 0 <= point.confidence <= 1
|
||||
assert point.price >= pricing_engine.min_price
|
||||
assert point.price <= pricing_engine.max_price
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_provider_strategy_management(self, pricing_engine):
|
||||
"""Test setting and retrieving provider strategies"""
|
||||
|
||||
constraints = PriceConstraints(
|
||||
min_price=0.02,
|
||||
max_price=0.10
|
||||
)
|
||||
|
||||
# Set strategy
|
||||
success = await pricing_engine.set_provider_strategy(
|
||||
provider_id="test_provider",
|
||||
strategy=PricingStrategy.AGGRESSIVE_GROWTH,
|
||||
constraints=constraints
|
||||
)
|
||||
|
||||
assert success is True
|
||||
assert pricing_engine.provider_strategies["test_provider"] == PricingStrategy.AGGRESSIVE_GROWTH
|
||||
assert pricing_engine.price_constraints["test_provider"] == constraints
|
||||
|
||||
def test_demand_multiplier_calculation(self, pricing_engine):
|
||||
"""Test demand multiplier calculation"""
|
||||
|
||||
# High demand
|
||||
multiplier_high = pricing_engine._calculate_demand_multiplier(0.9, PricingStrategy.MARKET_BALANCE)
|
||||
assert multiplier_high > 1.0
|
||||
|
||||
# Low demand
|
||||
multiplier_low = pricing_engine._calculate_demand_multiplier(0.2, PricingStrategy.MARKET_BALANCE)
|
||||
assert multiplier_low < 1.0
|
||||
|
||||
# Aggressive growth strategy should have lower multipliers
|
||||
multiplier_growth = pricing_engine._calculate_demand_multiplier(0.8, PricingStrategy.AGGRESSIVE_GROWTH)
|
||||
multiplier_balance = pricing_engine._calculate_demand_multiplier(0.8, PricingStrategy.MARKET_BALANCE)
|
||||
assert multiplier_growth < multiplier_balance
|
||||
|
||||
def test_supply_multiplier_calculation(self, pricing_engine):
|
||||
"""Test supply multiplier calculation"""
|
||||
|
||||
# Low supply (should increase prices)
|
||||
multiplier_low_supply = pricing_engine._calculate_supply_multiplier(0.2, PricingStrategy.MARKET_BALANCE)
|
||||
assert multiplier_low_supply > 1.0
|
||||
|
||||
# High supply (should decrease prices)
|
||||
multiplier_high_supply = pricing_engine._calculate_supply_multiplier(0.9, PricingStrategy.MARKET_BALANCE)
|
||||
assert multiplier_high_supply < 1.0
|
||||
|
||||
def test_time_multiplier_calculation(self, pricing_engine):
|
||||
"""Test time-based multiplier calculation"""
|
||||
|
||||
# Test different hours
|
||||
business_hour_multiplier = pricing_engine._calculate_time_multiplier()
|
||||
|
||||
# Mock different hours by temporarily changing the method
|
||||
with patch('datetime.datetime') as mock_datetime:
|
||||
mock_datetime.utcnow.return_value.hour = 14 # 2 PM business hour
|
||||
business_hour_multiplier = pricing_engine._calculate_time_multiplier()
|
||||
assert business_hour_multiplier > 1.0
|
||||
|
||||
mock_datetime.utcnow.return_value.hour = 3 # 3 AM late night
|
||||
late_night_multiplier = pricing_engine._calculate_time_multiplier()
|
||||
assert late_night_multiplier < 1.0
|
||||
|
||||
def test_competition_multiplier_calculation(self, pricing_engine):
|
||||
"""Test competition-based multiplier calculation"""
|
||||
|
||||
competitor_prices = [0.045, 0.055, 0.048, 0.052]
|
||||
base_price = 0.05
|
||||
|
||||
# Competitive response strategy
|
||||
multiplier_competitive = pricing_engine._calculate_competition_multiplier(
|
||||
base_price, competitor_prices, PricingStrategy.COMPETITIVE_RESPONSE
|
||||
)
|
||||
|
||||
# Profit maximization strategy
|
||||
multiplier_profit = pricing_engine._calculate_competition_multiplier(
|
||||
base_price, competitor_prices, PricingStrategy.PROFIT_MAXIMIZATION
|
||||
)
|
||||
|
||||
# Competitive strategy should be more responsive to competition
|
||||
assert isinstance(multiplier_competitive, float)
|
||||
assert isinstance(multiplier_profit, float)
|
||||
|
||||
def test_price_trend_determination(self, pricing_engine):
|
||||
"""Test price trend determination"""
|
||||
|
||||
# Create increasing trend
|
||||
pricing_engine.pricing_history["test_resource"] = [
|
||||
Mock(price=0.05, timestamp=datetime.utcnow() - timedelta(minutes=50)),
|
||||
Mock(price=0.051, timestamp=datetime.utcnow() - timedelta(minutes=40)),
|
||||
Mock(price=0.052, timestamp=datetime.utcnow() - timedelta(minutes=30)),
|
||||
Mock(price=0.053, timestamp=datetime.utcnow() - timedelta(minutes=20)),
|
||||
Mock(price=0.054, timestamp=datetime.utcnow() - timedelta(minutes=10))
|
||||
]
|
||||
|
||||
trend = pricing_engine._determine_price_trend("test_resource", 0.055)
|
||||
assert trend == PriceTrend.INCREASING
|
||||
|
||||
# Create decreasing trend
|
||||
pricing_engine.pricing_history["test_resource"] = [
|
||||
Mock(price=0.055, timestamp=datetime.utcnow() - timedelta(minutes=50)),
|
||||
Mock(price=0.054, timestamp=datetime.utcnow() - timedelta(minutes=40)),
|
||||
Mock(price=0.053, timestamp=datetime.utcnow() - timedelta(minutes=30)),
|
||||
Mock(price=0.052, timestamp=datetime.utcnow() - timedelta(minutes=20)),
|
||||
Mock(price=0.051, timestamp=datetime.utcnow() - timedelta(minutes=10))
|
||||
]
|
||||
|
||||
trend = pricing_engine._determine_price_trend("test_resource", 0.05)
|
||||
assert trend == PriceTrend.DECREASING
|
||||
|
||||
def test_confidence_score_calculation(self, pricing_engine, sample_market_conditions):
|
||||
"""Test confidence score calculation"""
|
||||
|
||||
factors = PricingFactors(
|
||||
base_price=0.05,
|
||||
demand_level=0.8,
|
||||
supply_level=0.6,
|
||||
market_volatility=0.1,
|
||||
confidence_score=0.8
|
||||
)
|
||||
|
||||
confidence = pricing_engine._calculate_confidence_score(factors, sample_market_conditions)
|
||||
|
||||
assert 0 <= confidence <= 1
|
||||
assert isinstance(confidence, float)
|
||||
|
||||
def test_pricing_factors_calculation(self, pricing_engine, sample_market_conditions):
|
||||
"""Test pricing factors calculation"""
|
||||
|
||||
factors = asyncio.run(pricing_engine._calculate_pricing_factors(
|
||||
resource_id="test_gpu_1",
|
||||
resource_type=ResourceType.GPU,
|
||||
base_price=0.05,
|
||||
strategy=PricingStrategy.MARKET_BALANCE,
|
||||
market_conditions=sample_market_conditions
|
||||
))
|
||||
|
||||
assert isinstance(factors, PricingFactors)
|
||||
assert factors.base_price == 0.05
|
||||
assert 0 <= factors.demand_multiplier <= 3.0
|
||||
assert 0.8 <= factors.supply_multiplier <= 2.5
|
||||
assert 0.7 <= factors.time_multiplier <= 1.5
|
||||
assert 0.9 <= factors.performance_multiplier <= 1.3
|
||||
assert 0.8 <= factors.competition_multiplier <= 1.4
|
||||
assert 0.9 <= factors.sentiment_multiplier <= 1.2
|
||||
assert 0.8 <= factors.regional_multiplier <= 1.3
|
||||
|
||||
def test_strategy_pricing_application(self, pricing_engine, sample_market_conditions):
|
||||
"""Test strategy-specific pricing application"""
|
||||
|
||||
factors = PricingFactors(
|
||||
base_price=0.05,
|
||||
demand_multiplier=1.2,
|
||||
supply_multiplier=1.1,
|
||||
time_multiplier=1.0,
|
||||
performance_multiplier=1.05,
|
||||
competition_multiplier=0.95,
|
||||
sentiment_multiplier=1.02,
|
||||
regional_multiplier=1.0
|
||||
)
|
||||
|
||||
# Test different strategies
|
||||
price_aggressive = asyncio.run(pricing_engine._apply_strategy_pricing(
|
||||
0.05, factors, PricingStrategy.AGGRESSIVE_GROWTH, sample_market_conditions
|
||||
))
|
||||
|
||||
price_profit = asyncio.run(pricing_engine._apply_strategy_pricing(
|
||||
0.05, factors, PricingStrategy.PROFIT_MAXIMIZATION, sample_market_conditions
|
||||
))
|
||||
|
||||
# Should produce different results
|
||||
assert price_aggressive != price_profit
|
||||
assert price_aggressive > 0
|
||||
assert price_profit > 0
|
||||
|
||||
def test_constraints_and_risk_application(self, pricing_engine):
|
||||
"""Test constraints and risk management application"""
|
||||
|
||||
constraints = PriceConstraints(
|
||||
min_price=0.03,
|
||||
max_price=0.08,
|
||||
max_change_percent=0.2
|
||||
)
|
||||
|
||||
factors = PricingFactors(
|
||||
base_price=0.05,
|
||||
market_volatility=0.1
|
||||
)
|
||||
|
||||
# Test normal price within constraints
|
||||
normal_price = asyncio.run(pricing_engine._apply_constraints_and_risk(
|
||||
"test_resource", 0.06, constraints, factors
|
||||
))
|
||||
assert 0.03 <= normal_price <= 0.08
|
||||
|
||||
# Test price above max constraint
|
||||
high_price = asyncio.run(pricing_engine._apply_constraints_and_risk(
|
||||
"test_resource", 0.10, constraints, factors
|
||||
))
|
||||
assert high_price <= constraints.max_price
|
||||
|
||||
# Test price below min constraint
|
||||
low_price = asyncio.run(pricing_engine._apply_constraints_and_risk(
|
||||
"test_resource", 0.01, constraints, factors
|
||||
))
|
||||
assert low_price >= constraints.min_price
|
||||
|
||||
def test_price_point_storage(self, pricing_engine):
|
||||
"""Test price point storage in history"""
|
||||
|
||||
factors = PricingFactors(
|
||||
base_price=0.05,
|
||||
demand_level=0.8,
|
||||
supply_level=0.6,
|
||||
confidence_score=0.85
|
||||
)
|
||||
|
||||
asyncio.run(pricing_engine._store_price_point(
|
||||
"test_resource", 0.055, factors, PricingStrategy.MARKET_BALANCE
|
||||
))
|
||||
|
||||
assert "test_resource" in pricing_engine.pricing_history
|
||||
assert len(pricing_engine.pricing_history["test_resource"]) == 1
|
||||
|
||||
point = pricing_engine.pricing_history["test_resource"][0]
|
||||
assert point.price == 0.055
|
||||
assert point.demand_level == 0.8
|
||||
assert point.supply_level == 0.6
|
||||
assert point.confidence == 0.85
|
||||
assert point.strategy_used == "market_balance"
|
||||
|
||||
def test_seasonal_factor_calculation(self, pricing_engine):
|
||||
"""Test seasonal factor calculation"""
|
||||
|
||||
# Test morning hours
|
||||
morning_factor = pricing_engine._calculate_seasonal_factor(9)
|
||||
assert morning_factor > 1.0
|
||||
|
||||
# Test business peak
|
||||
peak_factor = pricing_engine._calculate_seasonal_factor(14)
|
||||
assert peak_factor > morning_factor
|
||||
|
||||
# Test late night
|
||||
night_factor = pricing_engine._calculate_seasonal_factor(3)
|
||||
assert night_factor < 1.0
|
||||
|
||||
def test_demand_supply_forecasting(self, pricing_engine):
|
||||
"""Test demand and supply level forecasting"""
|
||||
|
||||
demand_history = [0.6, 0.7, 0.8, 0.75, 0.9, 0.85]
|
||||
supply_history = [0.7, 0.6, 0.5, 0.55, 0.4, 0.45]
|
||||
|
||||
demand_forecast = pricing_engine._forecast_demand_level(demand_history, 1)
|
||||
supply_forecast = pricing_engine._forecast_supply_level(supply_history, 1)
|
||||
|
||||
assert 0 <= demand_forecast <= 1
|
||||
assert 0 <= supply_forecast <= 1
|
||||
assert isinstance(demand_forecast, float)
|
||||
assert isinstance(supply_forecast, float)
|
||||
|
||||
|
||||
class TestPricingFactors:
|
||||
"""Test cases for PricingFactors dataclass"""
|
||||
|
||||
def test_pricing_factors_creation(self):
|
||||
"""Test PricingFactors creation with default values"""
|
||||
factors = PricingFactors(base_price=0.05)
|
||||
|
||||
assert factors.base_price == 0.05
|
||||
assert factors.demand_multiplier == 1.0
|
||||
assert factors.supply_multiplier == 1.0
|
||||
assert factors.time_multiplier == 1.0
|
||||
assert factors.performance_multiplier == 1.0
|
||||
assert factors.competition_multiplier == 1.0
|
||||
assert factors.sentiment_multiplier == 1.0
|
||||
assert factors.regional_multiplier == 1.0
|
||||
assert factors.confidence_score == 0.8
|
||||
assert factors.risk_adjustment == 0.0
|
||||
|
||||
def test_pricing_factors_with_custom_values(self):
|
||||
"""Test PricingFactors creation with custom values"""
|
||||
factors = PricingFactors(
|
||||
base_price=0.05,
|
||||
demand_multiplier=1.5,
|
||||
supply_multiplier=0.8,
|
||||
confidence_score=0.9
|
||||
)
|
||||
|
||||
assert factors.base_price == 0.05
|
||||
assert factors.demand_multiplier == 1.5
|
||||
assert factors.supply_multiplier == 0.8
|
||||
assert factors.confidence_score == 0.9
|
||||
|
||||
|
||||
class TestPriceConstraints:
|
||||
"""Test cases for PriceConstraints dataclass"""
|
||||
|
||||
def test_price_constraints_creation(self):
|
||||
"""Test PriceConstraints creation with default values"""
|
||||
constraints = PriceConstraints()
|
||||
|
||||
assert constraints.min_price is None
|
||||
assert constraints.max_price is None
|
||||
assert constraints.max_change_percent == 0.5
|
||||
assert constraints.min_change_interval == 300
|
||||
assert constraints.strategy_lock_period == 3600
|
||||
|
||||
def test_price_constraints_with_custom_values(self):
|
||||
"""Test PriceConstraints creation with custom values"""
|
||||
constraints = PriceConstraints(
|
||||
min_price=0.02,
|
||||
max_price=0.10,
|
||||
max_change_percent=0.3
|
||||
)
|
||||
|
||||
assert constraints.min_price == 0.02
|
||||
assert constraints.max_price == 0.10
|
||||
assert constraints.max_change_percent == 0.3
|
||||
|
||||
|
||||
class TestMarketConditions:
|
||||
"""Test cases for MarketConditions dataclass"""
|
||||
|
||||
def test_market_conditions_creation(self):
|
||||
"""Test MarketConditions creation"""
|
||||
conditions = MarketConditions(
|
||||
region="us_west",
|
||||
resource_type=ResourceType.GPU,
|
||||
demand_level=0.8,
|
||||
supply_level=0.6,
|
||||
average_price=0.05,
|
||||
price_volatility=0.15,
|
||||
utilization_rate=0.75
|
||||
)
|
||||
|
||||
assert conditions.region == "us_west"
|
||||
assert conditions.resource_type == ResourceType.GPU
|
||||
assert conditions.demand_level == 0.8
|
||||
assert conditions.supply_level == 0.6
|
||||
assert conditions.average_price == 0.05
|
||||
assert conditions.price_volatility == 0.15
|
||||
assert conditions.utilization_rate == 0.75
|
||||
assert conditions.competitor_prices == []
|
||||
assert conditions.market_sentiment == 0.0
|
||||
assert isinstance(conditions.timestamp, datetime)
|
||||
|
||||
|
||||
class TestStrategyLibrary:
|
||||
"""Test cases for StrategyLibrary"""
|
||||
|
||||
def test_get_all_strategies(self):
|
||||
"""Test getting all available strategies"""
|
||||
strategies = StrategyLibrary.get_all_strategies()
|
||||
|
||||
assert isinstance(strategies, dict)
|
||||
assert len(strategies) > 0
|
||||
assert PricingStrategy.AGGRESSIVE_GROWTH in strategies
|
||||
assert PricingStrategy.PROFIT_MAXIMIZATION in strategies
|
||||
assert PricingStrategy.MARKET_BALANCE in strategies
|
||||
|
||||
# Check strategy configurations
|
||||
for strategy_type, config in strategies.items():
|
||||
assert config.strategy_type == strategy_type
|
||||
assert config.name is not None
|
||||
assert config.description is not None
|
||||
assert config.parameters is not None
|
||||
assert isinstance(config.parameters.base_multiplier, float)
|
||||
|
||||
def test_aggressive_growth_strategy(self):
|
||||
"""Test aggressive growth strategy configuration"""
|
||||
strategy = StrategyLibrary.get_aggressive_growth_strategy()
|
||||
|
||||
assert strategy.strategy_type == PricingStrategy.AGGRESSIVE_GROWTH
|
||||
assert strategy.parameters.base_multiplier < 1.0 # Lower prices for growth
|
||||
assert strategy.parameters.growth_target_rate > 0.2 # High growth target
|
||||
assert strategy.risk_tolerance.value == "aggressive"
|
||||
|
||||
def test_profit_maximization_strategy(self):
|
||||
"""Test profit maximization strategy configuration"""
|
||||
strategy = StrategyLibrary.get_profit_maximization_strategy()
|
||||
|
||||
assert strategy.strategy_type == PricingStrategy.PROFIT_MAXIMIZATION
|
||||
assert strategy.parameters.base_multiplier > 1.0 # Higher prices for profit
|
||||
assert strategy.parameters.profit_target_margin > 0.3 # High profit target
|
||||
assert strategy.parameters.demand_sensitivity > 0.5 # Demand sensitive
|
||||
|
||||
def test_market_balance_strategy(self):
|
||||
"""Test market balance strategy configuration"""
|
||||
strategy = StrategyLibrary.get_market_balance_strategy()
|
||||
|
||||
assert strategy.strategy_type == PricingStrategy.MARKET_BALANCE
|
||||
assert strategy.parameters.base_multiplier == 1.0 # Balanced pricing
|
||||
assert strategy.parameters.volatility_threshold < 0.2 # Lower volatility tolerance
|
||||
assert strategy.risk_tolerance.value == "moderate"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__])
|
||||
Reference in New Issue
Block a user