class TestAreaClass(unittest.TestCase): def setUp(self): ConstSettings.BalancingSettings.ENABLE_BALANCING_MARKET = True DeviceRegistry.REGISTRY = { "H1 General Load": (33, 35), "H2 General Load": (33, 35), "H1 Storage1": (23, 25), "H1 Storage2": (23, 25), } self.strategy = MagicMock(spec=StorageStrategy) self.config = MagicMock(spec=SimulationConfig) self.config.slot_length = duration(minutes=15) self.config.tick_length = duration(seconds=15) self.config.ticks_per_slot = int(self.config.slot_length.seconds / self.config.tick_length.seconds) self.config.start_date = today(tz=constants.TIME_ZONE) GlobalConfig.sim_duration = duration(days=1) self.config.sim_duration = duration(days=1) self.config.grid_fee_type = 1 self.config.end_date = self.config.start_date + self.config.sim_duration self.area = Area("test_area", None, None, self.strategy, self.config, None, grid_fee_percentage=1) self.area_child = Area("test_area_c", None, None, self.strategy, self.config, None, grid_fee_percentage=1) self.area_child.parent = self.area self.area.children = [self.area_child] self.area.grid_fee_percentage = 1 self.dispatcher = AreaDispatcher(self.area) self.stats = AreaStats(self.area._markets, self.area) def tearDown(self): GlobalConfig.market_count = GlobalConfig.MARKET_COUNT constants.RETAIN_PAST_MARKET_STRATEGIES_STATE = False def test_respective_area_grid_fee_is_applied(self): self.config.grid_fee_type = 2 self.area = Area(name="Street", children=[Area(name="House")], grid_fee_percentage=5, config=self.config) self.area.parent = Area(name="GRID", config=self.config) self.area.config.market_count = 1 self.area.activate() assert self.area.next_market.fee_class.grid_fee_rate == 0.05 self.area.next_market.offer(1, 1, "test", "test") assert list(self.area.next_market.offers.values())[0].price == 1.05 def test_markets_are_cycled_according_to_market_count(self): self.area._bc = None for i in range(2, 97): self.config.market_count = i self.config.grid_fee_type = ConstSettings.IAASettings.GRID_FEE_TYPE self.area.cycle_markets(False, False) assert len(self.area.all_markets) == i def test_delete_past_markets_instead_of_last(self): constants.RETAIN_PAST_MARKET_STRATEGIES_STATE = False self.area = Area(name="Street", children=[Area(name="House")], config=self.config, grid_fee_percentage=5) self.area.config.market_count = 1 self.area.activate() self.area._bc = None self.area.cycle_markets(False, False, False) assert len(self.area.past_markets) == 0 current_time = today(tz=constants.TIME_ZONE).add(hours=1) self.area._markets.rotate_markets(current_time) assert len(self.area.past_markets) == 1 self.area._markets.create_future_markets(current_time, True, self.area) current_time = today(tz=constants.TIME_ZONE).add(hours=2) self.area._markets.rotate_markets(current_time) assert len(self.area.past_markets) == 1 assert (list(self.area.past_markets)[-1].time_slot == today( tz=constants.TIME_ZONE).add(hours=1)) def test_keep_past_markets(self): constants.RETAIN_PAST_MARKET_STRATEGIES_STATE = True self.area = Area(name="Street", children=[Area(name="House")], config=self.config, grid_fee_percentage=5) self.area.config.market_count = 1 self.area.activate() self.area._bc = None self.area.cycle_markets(False, False, False) assert len(self.area.past_markets) == 0 current_time = today(tz=constants.TIME_ZONE).add(hours=1) self.area._markets.rotate_markets(current_time) assert len(self.area.past_markets) == 1 self.area._markets.create_future_markets(current_time, True, self.area) current_time = today(tz=constants.TIME_ZONE).add(hours=2) self.area._markets.rotate_markets(current_time) assert len(self.area.past_markets) == 2 def test_market_with_most_expensive_offer(self): m1 = MagicMock(spec=Market) m1.in_sim_duration = True o1 = MagicMock(spec=Offer) o1.price = 12 o1.energy = 1 o1.energy_rate = 12 m2 = MagicMock(spec=Market) m2.in_sim_duration = True o2 = MagicMock(spec=Offer) o2.price = 12 o2.energy = 1 o2.energy_rate = 12 m3 = MagicMock(spec=Market) m3.in_sim_duration = True o3 = MagicMock(spec=Offer) o3.price = 12 o3.energy = 1 o3.energy_rate = 12 markets = OrderedDict() td = today(tz=constants.TIME_ZONE) td1 = td + self.config.slot_length m1.time_slot = td1 markets[m1.time_slot] = m1 td2 = td1 + self.config.slot_length m2.time_slot = td2 markets[m2.time_slot] = m2 td3 = td2 + self.config.slot_length m3.time_slot = td3 markets[m3.time_slot] = m3 self.area._markets = MagicMock(spec=AreaMarkets) self.area._markets.markets = markets m1.sorted_offers = [o1, o1] m2.sorted_offers = [o2, o2] m3.sorted_offers = [o3, o3] assert self.area.market_with_most_expensive_offer is m1 o1.energy_rate = 19 o2.energy_rate = 20 o3.energy_rate = 18 assert self.area.market_with_most_expensive_offer is m2 o1.energy_rate = 18 o2.energy_rate = 19 o3.energy_rate = 20 assert self.area.market_with_most_expensive_offer is m3 def test_cycle_markets(self): GlobalConfig.end_date = GlobalConfig.start_date + GlobalConfig.sim_duration self.area = Area(name="Street", children=[Area(name="House")], config=GlobalConfig, grid_fee_percentage=1) self.area.parent = Area(name="GRID") self.area.config.market_count = 5 self.area.activate() assert len(self.area.all_markets) == 5 assert len(self.area.balancing_markets) == 5 self.area.current_tick = 900 self.area.cycle_markets() assert len(self.area.past_markets) == 1 assert len(self.area.past_balancing_markets) == 1 assert len(self.area.all_markets) == 5 assert len(self.area.balancing_markets) == 5 def test_get_restore_state_get_called_on_all_areas(self): strategy = MagicMock(spec=StorageStrategy) bat = Area(name="battery", strategy=strategy) house = Area(name="House", children=[bat]) house.stats.get_state = MagicMock() house.stats.restore_state = MagicMock() area = Area(name="Street", children=[house]) area.stats.get_state = MagicMock() area.stats.restore_state = MagicMock() area.parent = Area(name="GRID") area.get_state() area.stats.get_state.assert_called_once() area.restore_state({"current_tick": 200, "area_stats": None}) area.stats.restore_state.assert_called_once() assert area.current_tick == 200 house.get_state() house.stats.get_state.assert_called_once() house.restore_state({"current_tick": 2432, "area_stats": None}) house.stats.restore_state.assert_called_once() assert house.current_tick == 2432 bat.get_state() strategy.get_state.assert_called_once()
class TestGlobalObjects(unittest.TestCase): def setUp(self): self.config = MagicMock(spec=SimulationConfig) self.config.slot_length = duration(minutes=15) self.config.tick_length = duration(seconds=15) self.config.ticks_per_slot = int(self.config.slot_length.seconds / self.config.tick_length.seconds) self.config.start_date = today(tz=TIME_ZONE) self.config.sim_duration = duration(days=1) self.config.grid_fee_type = 1 self.config.end_date = self.config.start_date + self.config.sim_duration self.config.market_count = 1 self.config.max_panel_power_W = 1000 self.config.external_redis_communicator = \ MagicMock(spec=ExternalConnectionCommunicator(True)) self.storage = Area("Storage", strategy=StorageExternalStrategy(), config=self.config, external_connection_available=True) self.load = Area("Load", strategy=LoadHoursExternalStrategy(avg_power_W=100), config=self.config, external_connection_available=True) self.pv = Area("PV", strategy=PVExternalStrategy(), config=self.config, external_connection_available=True) self.house_area = Area("House", children=[self.storage, self.load, self.pv], config=self.config) self.grid_area = Area("Grid", children=[self.house_area], config=self.config) self.grid_area.activate() def test_global_objects_area_stats_tree_dict_general_structure(self): go = ExternalConnectionGlobalStatistics() go(self.grid_area, self.config.ticks_per_slot) self.grid_area.current_tick += 15 self.house_area.current_tick += 15 self.grid_area.cycle_markets(_trigger_event=True) go.update() expected_area_stats_tree_dict = { self.grid_area.uuid: {'last_market_bill': {'accumulated_trades': {}, 'external_trades': {}}, 'last_market_stats': {'min_trade_rate': None, 'max_trade_rate': None, 'avg_trade_rate': None, 'median_trade_rate': None, 'total_traded_energy_kWh': None}, 'last_market_fee': 0.0, 'current_market_fee': None, 'area_name': 'Grid', 'children': { self.house_area.uuid: { 'last_market_bill': {'accumulated_trades': {}, 'external_trades': {}}, 'last_market_stats': {'min_trade_rate': None, 'max_trade_rate': None, 'avg_trade_rate': None, 'median_trade_rate': None, 'total_traded_energy_kWh': None}, 'last_market_fee': 0.0, 'current_market_fee': None, 'area_name': 'House', 'children': { self.storage.uuid: { 'asset_info': {'energy_to_sell': 0.0, 'energy_active_in_bids': 0, 'energy_to_buy': 1.08, 'energy_active_in_offers': 0, 'free_storage': 1.08, 'used_storage': 0.12, 'energy_traded': 0.0, 'total_cost': 0.0}, 'last_slot_asset_info': {'energy_traded': 0.0, 'total_cost': 0.0}, 'asset_bill': None, 'area_name': 'Storage'}, self.load.uuid: {'asset_info': { 'energy_requirement_kWh': 0.025, 'energy_active_in_bids': 0.0, 'energy_traded': 0.0, 'total_cost': 0.0}, 'last_slot_asset_info': { 'energy_traded': 0.0, 'total_cost': 0.0}, 'asset_bill': None, 'area_name': 'Load'}, self.pv.uuid: {'asset_info': { 'available_energy_kWh': 0.0, 'energy_active_in_offers': 0, 'energy_traded': 0, 'total_cost': 0}, 'last_slot_asset_info': { 'energy_traded': 0, 'total_cost': 0}, 'asset_bill': None, 'area_name': 'PV' }}}}}} assert expected_area_stats_tree_dict == go.area_stats_tree_dict