From 83146add1ae0f021db6a56312d9a880cc0761de1 Mon Sep 17 00:00:00 2001 From: Maximilian Behrendt Date: Fri, 29 Nov 2024 11:59:30 +0100 Subject: [PATCH] improve usage of CarbonAwareComputingAPI - correct use of windowsSize as duration of the task - improve response mapping with a check whether the optimal timeframe is in the future - // TODO work around the limitation that the api does not provide a value for the earliestForecastedValue --- .../CarbonAwareComputingApiClient.java | 3 +-- .../CarbonAwareComputingMapper.java | 11 +++++++++++ .../CarbonAwareComputingApiClientTest.java | 18 ++++++++---------- .../domain/model/EmissionTimeframeTest.java | 10 +++++----- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/carbon-reductor-core/src/main/java/de/envite/greenbpm/carbonreductor/core/adapter/carbonawarecomputing/CarbonAwareComputingApiClient.java b/carbon-reductor-core/src/main/java/de/envite/greenbpm/carbonreductor/core/adapter/carbonawarecomputing/CarbonAwareComputingApiClient.java index 5cf93a6..8615b58 100644 --- a/carbon-reductor-core/src/main/java/de/envite/greenbpm/carbonreductor/core/adapter/carbonawarecomputing/CarbonAwareComputingApiClient.java +++ b/carbon-reductor-core/src/main/java/de/envite/greenbpm/carbonreductor/core/adapter/carbonawarecomputing/CarbonAwareComputingApiClient.java @@ -29,7 +29,6 @@ public class CarbonAwareComputingApiClient implements CarbonEmissionQuery { @Override public EmissionTimeframe getEmissionTimeframe(Location location, ProcessDuration processDuration, ProcessDuration executiontime) throws CarbonEmissionQueryException { - final int windowSizeMinutes = 5; List emissionsForecast = null; final String mappedLocation = locationMapper.mapLocation(location); if (mappedLocation == null) { @@ -37,7 +36,7 @@ public EmissionTimeframe getEmissionTimeframe(Location location, ProcessDuration } try { - emissionsForecast = forecastApi.getBestExecutionTime(mappedLocation, null, processDuration.timeshiftFromNow(), windowSizeMinutes); + emissionsForecast = forecastApi.getBestExecutionTime(mappedLocation, null, processDuration.timeshiftFromNow(), executiontime.inMinutes()); } catch (Exception e) { log.error("Error when calling the API for the optimal forecast", e); throw new CarbonEmissionQueryException(e); diff --git a/carbon-reductor-core/src/main/java/de/envite/greenbpm/carbonreductor/core/adapter/carbonawarecomputing/CarbonAwareComputingMapper.java b/carbon-reductor-core/src/main/java/de/envite/greenbpm/carbonreductor/core/adapter/carbonawarecomputing/CarbonAwareComputingMapper.java index 99d0e2d..e409c10 100644 --- a/carbon-reductor-core/src/main/java/de/envite/greenbpm/carbonreductor/core/adapter/carbonawarecomputing/CarbonAwareComputingMapper.java +++ b/carbon-reductor-core/src/main/java/de/envite/greenbpm/carbonreductor/core/adapter/carbonawarecomputing/CarbonAwareComputingMapper.java @@ -6,9 +6,20 @@ import de.envite.greenbpm.carbonreductor.core.domain.model.emissionframe.ForecastedValue; import de.envite.greenbpm.carbonreductor.core.domain.model.emissionframe.OptimalTime; +import java.time.OffsetDateTime; + public class CarbonAwareComputingMapper { public EmissionTimeframe mapToDomain(EmissionsData emissionsData) { + // TODO keep in mind: cleanerEnergyInFuture will not work as expected with earliestForecastedValue 0.0 + if (emissionsData.getTimestamp().isAfter(OffsetDateTime.now())) { + return new EmissionTimeframe( + new OptimalTime(emissionsData.getTimestamp()), + new EarliestForecastedValue(0.0), + new ForecastedValue(emissionsData.getValue()) + ); + } + return new EmissionTimeframe( new OptimalTime(emissionsData.getTimestamp()), new EarliestForecastedValue(emissionsData.getValue()), diff --git a/carbon-reductor-core/src/test/java/de/envite/greenbpm/carbonreductor/core/adapter/carbonawarecomputing/CarbonAwareComputingApiClientTest.java b/carbon-reductor-core/src/test/java/de/envite/greenbpm/carbonreductor/core/adapter/carbonawarecomputing/CarbonAwareComputingApiClientTest.java index 9a609b8..94960a0 100644 --- a/carbon-reductor-core/src/test/java/de/envite/greenbpm/carbonreductor/core/adapter/carbonawarecomputing/CarbonAwareComputingApiClientTest.java +++ b/carbon-reductor-core/src/test/java/de/envite/greenbpm/carbonreductor/core/adapter/carbonawarecomputing/CarbonAwareComputingApiClientTest.java @@ -39,11 +39,11 @@ class CarbonAwareComputingApiClientTest { private CarbonAwareComputingMapper carbonAwareComputingMapperMock; static class Data { - final static Location location = Locations.FRANCE_CENTRAL.asLocation(); - final static ProcessDuration PROCESS_DURATION = new ProcessDuration("PT5M"); - final static ProcessDuration executiontime = new ProcessDuration("PT10M"); + static final Location location = Locations.FRANCE_CENTRAL.asLocation(); + static final ProcessDuration PROCESS_DURATION = new ProcessDuration("PT5M"); + static final ProcessDuration executiontime = new ProcessDuration("PT10M"); - final static EmissionTimeframe emissionTimeframe = new EmissionTimeframe( + static final EmissionTimeframe emissionTimeframe = new EmissionTimeframe( new OptimalTime(java.time.OffsetDateTime.now().plusHours(3)), new EarliestForecastedValue(200.6), new ForecastedValue(0.0) @@ -51,8 +51,6 @@ static class Data { } private static final String LOCATION = "de"; - private static final int WINDOW_SIZE_MINUTES = 5; - @BeforeEach void setUp() { @@ -67,7 +65,7 @@ void should_call_api_and_map() throws Exception { EmissionsData emissionsData = mock(EmissionsData.class); when(emissionsForecast.getOptimalDataPoints()).thenReturn(List.of(emissionsData)); when(forecastApiMock.getBestExecutionTime( - eq(LOCATION), isNull(), any(OffsetDateTime.class), eq(WINDOW_SIZE_MINUTES)) + eq(LOCATION), isNull(), any(OffsetDateTime.class), eq(Data.executiontime.inMinutes())) ).thenReturn(List.of(emissionsForecast)); when(carbonAwareComputingMapperMock.mapToDomain(emissionsData)).thenReturn(Data.emissionTimeframe); @@ -77,7 +75,7 @@ void should_call_api_and_map() throws Exception { } @Test - void should_throw_if_location_unknown() throws Exception { + void should_throw_if_location_unknown() { when(locationMapperMock.mapLocation(any(Location.class))).thenReturn(null); assertThatThrownBy(() -> classUnderTest.getEmissionTimeframe(Data.location, Data.PROCESS_DURATION, Data.executiontime)) @@ -91,7 +89,7 @@ void should_throw_if_location_unknown() throws Exception { void should_throw_if_no_element_in_list_response() throws Exception { when(locationMapperMock.mapLocation(any(Location.class))).thenReturn(LOCATION); when(forecastApiMock.getBestExecutionTime( - eq(LOCATION), isNull(), any(OffsetDateTime.class), eq(WINDOW_SIZE_MINUTES)) + eq(LOCATION), isNull(), any(OffsetDateTime.class), eq(Data.executiontime.inMinutes())) ).thenReturn(List.of()); assertThatThrownBy(() -> classUnderTest.getEmissionTimeframe(Data.location, Data.PROCESS_DURATION, Data.executiontime)) @@ -106,7 +104,7 @@ void should_throw_if_no_element_in_inner_list_response() throws Exception { EmissionsForecast emissionsForecast = mock(EmissionsForecast.class); when(emissionsForecast.getOptimalDataPoints()).thenReturn(List.of()); when(forecastApiMock.getBestExecutionTime( - eq(LOCATION), isNull(), any(OffsetDateTime.class), eq(WINDOW_SIZE_MINUTES)) + eq(LOCATION), isNull(), any(OffsetDateTime.class), eq(Data.executiontime.inMinutes())) ).thenReturn(List.of(emissionsForecast)); assertThatThrownBy(() -> classUnderTest.getEmissionTimeframe(Data.location, Data.PROCESS_DURATION, Data.executiontime)) diff --git a/carbon-reductor-core/src/test/java/de/envite/greenbpm/carbonreductor/core/domain/model/EmissionTimeframeTest.java b/carbon-reductor-core/src/test/java/de/envite/greenbpm/carbonreductor/core/domain/model/EmissionTimeframeTest.java index 5dc7178..ccb76f2 100644 --- a/carbon-reductor-core/src/test/java/de/envite/greenbpm/carbonreductor/core/domain/model/EmissionTimeframeTest.java +++ b/carbon-reductor-core/src/test/java/de/envite/greenbpm/carbonreductor/core/domain/model/EmissionTimeframeTest.java @@ -38,7 +38,7 @@ void should_throw_if_optimal_time_is_null() { } @Test - void should_throw_if_rating_is_null() { + void should_throw_if_earliestForecastedValue_is_null() { assertThatThrownBy(() -> new EmissionTimeframe(optimalTime, null, forecastedValue)) .isInstanceOf(InvariantException .class); } @@ -54,15 +54,15 @@ void should_throw_if_forecast_is_null() { class CleanEnergyInFutureCalculation { @Test - void should_return_false_if_rating_is_smaller_than_forecast() { - ForecastedValue forecastedValue = new ForecastedValue(500.0); - EmissionTimeframe emissionTimeframe = new EmissionTimeframe(optimalTime, earliestForecastedValue, forecastedValue); + void should_return_false_if_earliestForecastedValue_is_smaller_than_forecast() { + ForecastedValue higherForecastedValue = new ForecastedValue(500.0); + EmissionTimeframe emissionTimeframe = new EmissionTimeframe(optimalTime, earliestForecastedValue, higherForecastedValue); assertThat(emissionTimeframe.isCleanerEnergyInFuture()).isFalse(); } @Test - void should_return_true_if_rating_is_greater_than_forecast() { + void should_return_true_if_earliestForecastedValue_is_greater_than_forecast() { EmissionTimeframe emissionTimeframe = new EmissionTimeframe(optimalTime, earliestForecastedValue, forecastedValue); assertThat(emissionTimeframe.isCleanerEnergyInFuture()).isTrue();