From f343cab37533d74a06fd2b57557354b3ee8259a3 Mon Sep 17 00:00:00 2001 From: Margaret Date: Sat, 4 Mar 2023 16:34:11 -0500 Subject: [PATCH 1/8] Additional integration tests Fix missing FromQuery params Fix integration tests not using JSON datasource mocker --- .../Emissions/EmissionsCommandTests.cs | 20 +++ .../src/Controllers/CarbonAwareController.cs | 6 +- .../src/Models/CarbonIntensityDTO.cs | 6 +- .../CarbonAwareControllerTests.cs | 115 ++++++++++++++++-- .../IntegrationTestingBase.cs | 11 +- 5 files changed, 142 insertions(+), 16 deletions(-) diff --git a/src/CarbonAware.CLI/test/integrationTests/Commands/Emissions/EmissionsCommandTests.cs b/src/CarbonAware.CLI/test/integrationTests/Commands/Emissions/EmissionsCommandTests.cs index 9ce5f2e9c..cd9c7db3f 100644 --- a/src/CarbonAware.CLI/test/integrationTests/Commands/Emissions/EmissionsCommandTests.cs +++ b/src/CarbonAware.CLI/test/integrationTests/Commands/Emissions/EmissionsCommandTests.cs @@ -154,4 +154,24 @@ public async Task Emissions_AverageOption_ReturnsExpectedData() Assert.IsNotNull(firstResult["Duration"]); } + [Test] + public async Task Average_Best_ReturnsExpectedError() + { + // Arrange + var start = DateTimeOffset.Parse("2022-09-01T00:00:00Z"); + var end = DateTimeOffset.Parse("2022-09-01T03:00:00Z"); + var location = "eastus"; + _dataSourceMocker.SetupDataMock(start, end, location); + + // Act + var exitCode = await InvokeCliAsync($"emissions -l {location} -s 2022-09-01T02:01:00Z -e 2022-09-01T02:04:00Z -a -best"); + // Assert + Assert.AreEqual(1, exitCode); + var expectedError = "Options --average and --best cannot be used together Option '-s' expects a single argument but 2 were provided. "; + // Whitespace characters regex + var regex = @"\s+"; + var output = Regex.Replace(_console.Error.ToString()!, regex, " "); + + Assert.AreEqual(expectedError, output); + } } diff --git a/src/CarbonAware.WebApi/src/Controllers/CarbonAwareController.cs b/src/CarbonAware.WebApi/src/Controllers/CarbonAwareController.cs index 5d1de6074..d568cdc04 100644 --- a/src/CarbonAware.WebApi/src/Controllers/CarbonAwareController.cs +++ b/src/CarbonAware.WebApi/src/Controllers/CarbonAwareController.cs @@ -74,9 +74,9 @@ public async Task GetEmissionsDataForLocationsByTime([FromQuery] [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ValidationProblemDetails))] [HttpGet("bylocation")] public async Task GetEmissionsDataForLocationByTime( - [FromQuery, SwaggerParameter(Required = true)] string location, - DateTimeOffset? startTime = null, - DateTimeOffset? endTime = null) + [FromQuery, SwaggerParameter(Required = true)] string location, + [FromQuery(Name = "time")] DateTimeOffset? startTime = null, + [FromQuery(Name = "toTime")] DateTimeOffset? endTime = null) { var parameters = new EmissionsDataForLocationsParametersDTO { diff --git a/src/CarbonAware.WebApi/src/Models/CarbonIntensityDTO.cs b/src/CarbonAware.WebApi/src/Models/CarbonIntensityDTO.cs index bcaf7fccf..4396c9fbe 100644 --- a/src/CarbonAware.WebApi/src/Models/CarbonIntensityDTO.cs +++ b/src/CarbonAware.WebApi/src/Models/CarbonIntensityDTO.cs @@ -5,6 +5,8 @@ namespace CarbonAware.WebApi.Models; [Serializable] public record CarbonIntensityDTO { + private DateTimeOffset? _startTime; + private DateTimeOffset? _endTime; /// the location name where workflow is run /// eastus [JsonPropertyName("location")] @@ -13,12 +15,12 @@ public record CarbonIntensityDTO /// the time at which the workflow we are measuring carbon intensity for started /// 2022-03-01T15:30:00Z [JsonPropertyName("startTime")] - public DateTimeOffset? StartTime { get; set; } + public DateTimeOffset? StartTime { get => _startTime; set => _startTime = value?.ToUniversalTime(); } /// the time at which the workflow we are measuring carbon intensity for ended /// 2022-03-01T18:30:00Z [JsonPropertyName("endTime")] - public DateTimeOffset? EndTime { get; set; } + public DateTimeOffset? EndTime { get => _endTime; set => _endTime = value?.ToUniversalTime(); } /// Value of the marginal carbon intensity in grams per kilowatt-hour. /// 345.434 diff --git a/src/CarbonAware.WebApi/test/integrationTests/CarbonAwareControllerTests.cs b/src/CarbonAware.WebApi/test/integrationTests/CarbonAwareControllerTests.cs index e881c2230..95ade1e37 100644 --- a/src/CarbonAware.WebApi/test/integrationTests/CarbonAwareControllerTests.cs +++ b/src/CarbonAware.WebApi/test/integrationTests/CarbonAwareControllerTests.cs @@ -20,12 +20,13 @@ public class CarbonAwareControllerTests : IntegrationTestingBase private readonly string healthURI = "/health"; private readonly string fakeURI = "/fake-endpoint"; private readonly string bestLocationsURI = "/emissions/bylocations/best"; + private readonly string bylocationsURI = "/emissions/bylocations"; + private readonly string bylocationURI = "/emissions/bylocation"; private readonly string currentForecastURI = "/emissions/forecasts/current"; private readonly string batchForecastURI = "/emissions/forecasts/batch"; private readonly string averageCarbonIntensityURI = "/emissions/average-carbon-intensity"; private readonly string batchAverageCarbonIntensityURI = "/emissions/average-carbon-intensity/batch"; - public CarbonAwareControllerTests(DataSourceType dataSource) : base(dataSource) { } [Test] @@ -46,9 +47,89 @@ public async Task FakeEndPoint_ReturnsNotFound() } //ISO8601: YYYY-MM-DD - [TestCase("2022-1-1T04:05:06Z", "2022-1-2T04:05:06Z", "eastus")] - [TestCase("2021-12-25", "2021-12-26", "westus")] - public async Task BestLocations_ReturnsOK(DateTimeOffset start, DateTimeOffset end, string location) + [TestCase("2022-1-1T04:05:06Z", "2022-1-2T04:05:06Z", "eastus", nameof(ByLocationURI_ReturnsOK) + "0")] + [TestCase("2021-12-25T00:00:00+06:00", "2021-12-26T00:00:00+06:00", "westus", nameof(ByLocationURI_ReturnsOK) + "1")] + public async Task ByLocationURI_ReturnsOK(DateTimeOffset start, DateTimeOffset end, string location, string expectedResultName) + { + //Sets up any data endpoints needed for mocking purposes + _dataSourceMocker?.SetupDataMock(start, end, location); + + //Call the private method to construct with parameters + var queryStrings = new Dictionary(); + queryStrings["location"] = location; + queryStrings["time"] = $"{start:O}"; + queryStrings["toTime"] = $"{end:O}"; + + var endpointURI = ConstructUriWithQueryString(bylocationURI, queryStrings); + + //Get response and response content + var result = await _client.GetAsync(endpointURI); + + Assert.That(result, Is.Not.Null); + Assert.That(result.StatusCode, Is.EqualTo(HttpStatusCode.OK)); + } + + [TestCase("location", "", TestName = "empty location query string")] + [TestCase("non-location-param", "", TestName = "location param not present")] + public async Task ByLocation_EmptyLocationQueryString_ReturnsBadRequest(string queryString, string value) + { + //Call the private method to construct with parameters + var queryStrings = new Dictionary(); + queryStrings[queryString] = value; + + var endpointURI = ConstructUriWithQueryString(bylocationURI, queryStrings); + + //Get response and response content + var result = await _client.GetAsync(endpointURI); + + Assert.That(result, Is.Not.Null); + Assert.That(result.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest)); + } + + //ISO8601: YYYY-MM-DD + [TestCase("2022-1-1T04:05:06Z", "2022-1-2T04:05:06Z", "eastus", nameof(ByLocationsURI_ReturnsOK) + "0")] + [TestCase("2021-12-25T00:00:00+06:00", "2021-12-26T00:00:00+06:00", "westus", nameof(ByLocationsURI_ReturnsOK) + "1")] + public async Task ByLocationsURI_ReturnsOK(DateTimeOffset start, DateTimeOffset end, string location, string expectedResultName) + { + //Sets up any data endpoints needed for mocking purposes + _dataSourceMocker?.SetupDataMock(start, end, location); + + //Call the private method to construct with parameters + var queryStrings = new Dictionary(); + queryStrings["location"] = location; + queryStrings["time"] = $"{start:O}"; + queryStrings["toTime"] = $"{end:O}"; + + var endpointURI = ConstructUriWithQueryString(bylocationsURI, queryStrings); + + //Get response and response content + var result = await _client.GetAsync(endpointURI); + + Assert.That(result, Is.Not.Null); + Assert.That(result.StatusCode, Is.EqualTo(HttpStatusCode.OK)); + } + + [TestCase("location", "", TestName = "empty location query string")] + [TestCase("non-location-param", "", TestName = "location param not present")] + public async Task ByLocations_EmptyLocationQueryString_ReturnsBadRequest(string queryString, string value) + { + //Call the private method to construct with parameters + var queryStrings = new Dictionary(); + queryStrings[queryString] = value; + + var endpointURI = ConstructUriWithQueryString(bylocationsURI, queryStrings); + + //Get response and response content + var result = await _client.GetAsync(endpointURI); + + Assert.That(result, Is.Not.Null); + Assert.That(result.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest)); + } + + //ISO8601: YYYY-MM-DD + [TestCase("2022-1-1T04:05:06Z", "2022-1-2T04:05:06Z", "eastus", nameof(BestLocations_ReturnsOK) + "0")] + [TestCase("2021-12-25T00:00:00+06:00", "2021-12-26T00:00:00+06:00", "westus", nameof(BestLocations_ReturnsOK) + "1")] + public async Task BestLocations_ReturnsOK(DateTimeOffset start, DateTimeOffset end, string location, string expectedResultName) { //Sets up any data endpoints needed for mocking purposes _dataSourceMocker?.SetupDataMock(start, end, location); @@ -101,6 +182,20 @@ public async Task EmissionsForecastsCurrent_SupportedDataSources_ReturnsOk() var result = await _client.GetAsync(endpointURI); Assert.That(result, Is.Not.Null); Assert.That(result.StatusCode, Is.EqualTo(HttpStatusCode.OK)); + using (var data = await result!.Content.ReadAsStreamAsync()) + { + Assert.That(data, Is.Not.Null); + var forecasts = await JsonSerializer.DeserializeAsync>(data); + Assert.That(forecasts, Is.Not.Null); + Assert.AreEqual(forecasts!.Count(), 1); + foreach (var forecast in forecasts!) + { + Assert.That(forecast.RequestedAt, Is.Not.Null); + Assert.That(forecast.GeneratedAt, Is.Not.Null); + Assert.That(forecast.OptimalDataPoints, Is.Not.Null); + Assert.That(forecast.ForecastData, Is.Not.Null); + } + } } [Test] @@ -204,9 +299,9 @@ public async Task EmissionsForecastsBatch_SupportedDataSources_ReturnsOk(string } } - [TestCase("2022-1-1T04:05:06Z", "2022-1-2T04:05:06Z", "eastus", TestName = "EmissionsMarginalCarbonIntensity expects OK for full datetime")] - [TestCase("2021-12-25", "2021-12-26", "westus", TestName = "EmissionsMarginalCarbonIntensity expects OK date only, no time")] - public async Task EmissionsMarginalCarbonIntensity_ReturnsOk(string start, string end, string location) + [TestCase("2022-1-1T04:05:06Z", "2022-1-2T04:05:06Z", "eastus", nameof(EmissionsMarginalCarbonIntensity_ReturnsOk) + "0", TestName = "EmissionsMarginalCarbonIntensity expects OK for full datetime")] + [TestCase("2021-12-25T00:00:00+06:00", "2021-12-26T00:00:00+06:00", "westus", nameof(EmissionsMarginalCarbonIntensity_ReturnsOk) + "1", TestName = "EmissionsMarginalCarbonIntensity expects OK date only, no time")] + public async Task EmissionsMarginalCarbonIntensity_ReturnsOk(string start, string end, string location, string expectedResultName) { var startDate = DateTimeOffset.Parse(start); var endDate = DateTimeOffset.Parse(end); @@ -268,9 +363,9 @@ public async Task EmissionsMarginalCarbonIntensityBatch_MissingRequiredParams_Re Assert.That(result!.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest)); } - [TestCase("2022-01-01T04:05:06Z", "2022-01-02T04:05:06Z", "eastus", 1, TestName = "EmissionsMarginalCarbonIntensityBatch expects OK for single element batch")] - [TestCase("2021-12-25", "2021-12-26", "westus", 3, TestName = "EmissionsMarginalCarbonIntensityBatch expects OK for multiple element batch")] - public async Task EmissionsMarginalCarbonIntensityBatch_SupportedDataSources_ReturnsOk(string start, string end, string location, int nelems) + [TestCase("2022-01-01T04:05:06Z", "2022-01-02T04:05:06Z", "eastus", 1, nameof(EmissionsMarginalCarbonIntensityBatch_SupportedDataSources_ReturnsOk) + "0", TestName = "EmissionsMarginalCarbonIntensityBatch expects OK for single element batch")] + [TestCase("2021-12-25T00:00:00+06:00", "2021-12-26T00:00:00+06:00", "westus", 3, nameof(EmissionsMarginalCarbonIntensityBatch_SupportedDataSources_ReturnsOk) + "1", TestName = "EmissionsMarginalCarbonIntensityBatch expects OK for multiple element batch")] + public async Task EmissionsMarginalCarbonIntensityBatch_SupportedDataSources_ReturnsOk(string start, string end, string location, int nelems, string expectedResultName) { var startDate = DateTimeOffset.Parse(start); var endDate = DateTimeOffset.Parse(end); diff --git a/src/CarbonAware.WebApi/test/integrationTests/IntegrationTestingBase.cs b/src/CarbonAware.WebApi/test/integrationTests/IntegrationTestingBase.cs index 152d65614..cb9e6b9f2 100644 --- a/src/CarbonAware.WebApi/test/integrationTests/IntegrationTestingBase.cs +++ b/src/CarbonAware.WebApi/test/integrationTests/IntegrationTestingBase.cs @@ -86,7 +86,7 @@ public void Setup() Environment.SetEnvironmentVariable("DataSources__EmissionsDataSource", "Json"); Environment.SetEnvironmentVariable("DataSources__ForecastDataSource", ""); Environment.SetEnvironmentVariable("DataSources__Configurations__Json__Type", "Json"); - Environment.SetEnvironmentVariable("DataSources__Configurations__Json__DataFileLocation", "demo.json"); + Environment.SetEnvironmentVariable("DataSources__Configurations__Json__DataFileLocation", "test-data-azure-emissions.json"); Environment.SetEnvironmentVariable("CarbonAwareVars__VerboseApi", "true"); _dataSourceMocker = new JsonDataSourceMocker(); break; @@ -127,6 +127,15 @@ public void Setup() [SetUp] public void SetupTests() { + if (_dataSource == DataSourceType.JSON) + { + // To force WebApplication to consume new JSON datasorce it needs to be restarted. + // This is a direct result of JSON caching in the CatbonAware code + _factory.Dispose(); + _factory = new WebApplicationFactory(); + _client = _factory.CreateClient(); + } + _dataSourceMocker?.Initialize(); } From 146165e915d4d1f394e7792dc0318433b63b5fac Mon Sep 17 00:00:00 2001 From: Margaret Date: Sat, 4 Mar 2023 16:43:56 -0500 Subject: [PATCH 2/8] DCO Remediation Commit for Margaret I, Margaret , hereby add my Signed-off-by to this commit: f881406a8674645a96d05af2c520dd89f36d7c4f I, Margaret , hereby add my Signed-off-by to this commit: f343cab37533d74a06fd2b57557354b3ee8259a3 Signed-off-by: Margaret --- .../test/integrationTests/CarbonAwareControllerTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CarbonAware.WebApi/test/integrationTests/CarbonAwareControllerTests.cs b/src/CarbonAware.WebApi/test/integrationTests/CarbonAwareControllerTests.cs index 95ade1e37..5323491c0 100644 --- a/src/CarbonAware.WebApi/test/integrationTests/CarbonAwareControllerTests.cs +++ b/src/CarbonAware.WebApi/test/integrationTests/CarbonAwareControllerTests.cs @@ -372,7 +372,7 @@ public async Task EmissionsMarginalCarbonIntensityBatch_SupportedDataSources_Ret _dataSourceMocker?.SetupDataMock(startDate, endDate, location); var intesityData = Enumerable.Range(0, nelems).Select(x => new { - location = location, + location, startTime = start, endTime = end }); From 371905a8835f8a735b8b19b19dc3515bc8aa56b9 Mon Sep 17 00:00:00 2001 From: Christian Binder <43334159+xcbinder@users.noreply.github.com> Date: Tue, 22 Aug 2023 01:28:59 +0200 Subject: [PATCH 3/8] Update ElectricityMapsDataSource.cs (#365) Issue : I have tested a ElectricityMaps forecast scenario CLI: "emissions-forecasts -l westeurope -v" will return server error 500. Analysis: public async Task GetCurrentCarbonIntensityForecastAsync(Location location) is causing the EM server to return 500. Reason is that the "." in geolocation.Latitude will be passed as "," Fix: The following changes are fixing this bug. Signed-off-by: Christian Binder <43334159+xcbinder@users.noreply.github.com> --- .../src/ElectricityMapsDataSource.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/src/ElectricityMapsDataSource.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/src/ElectricityMapsDataSource.cs index ea4a99b0e..01e494bbd 100644 --- a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/src/ElectricityMapsDataSource.cs +++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/src/ElectricityMapsDataSource.cs @@ -45,8 +45,8 @@ public async Task GetCurrentCarbonIntensityForecastAsync(Loca { ForecastedCarbonIntensityData forecast; var geolocation = await this._locationSource.ToGeopositionLocationAsync(location); - if (geolocation.Latitude != null && geolocation.Latitude != null) - forecast = await this._electricityMapsClient.GetForecastedCarbonIntensityAsync (geolocation.Latitude.ToString() ?? "", geolocation.Longitude.ToString() ?? ""); + if (geolocation.Latitude != null && geolocation.Longitude != null) + forecast = await this._electricityMapsClient.GetForecastedCarbonIntensityAsync (geolocation.LatitudeAsCultureInvariantString(), geolocation.LongitudeAsCultureInvariantString()); else { forecast = await this._electricityMapsClient.GetForecastedCarbonIntensityAsync (geolocation.Name ?? ""); From cb4af960c566c21ab8040a86f68f3cc783890449 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Mon, 4 Sep 2023 09:34:42 +0900 Subject: [PATCH 4/8] EMFree data source should regard specified time range Signed-off-by: Yasumasa Suenaga --- .../Emissions/EmissionsCommandTests.cs | 4 +-- .../EmissionsForecastsCommandTests.cs | 4 +-- .../src/ElectricityMapsFreeDataSource.cs | 26 ++++++++++++++----- .../ElectricityMapsFreeDataSourceTests.cs | 12 ++++++--- 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/CarbonAware.CLI/test/integrationTests/Commands/Emissions/EmissionsCommandTests.cs b/src/CarbonAware.CLI/test/integrationTests/Commands/Emissions/EmissionsCommandTests.cs index af0316ec5..8831dae25 100644 --- a/src/CarbonAware.CLI/test/integrationTests/Commands/Emissions/EmissionsCommandTests.cs +++ b/src/CarbonAware.CLI/test/integrationTests/Commands/Emissions/EmissionsCommandTests.cs @@ -72,7 +72,7 @@ public async Task Emissions_StartAndEndOptions_ReturnsExpectedData() _dataSourceMocker.SetupDataMock(start, end, location); // Act - var exitCode = await InvokeCliAsync($"emissions -l {location} -s 2022-09-01T02:01:00Z -e 2022-09-01T02:04:00Z"); + var exitCode = await InvokeCliAsync($"emissions -l {location} -s 2022-09-01T00:00:00Z -e 2022-09-01T00:04:00Z"); // Assert Assert.AreEqual(0, exitCode); @@ -117,7 +117,7 @@ public async Task Emissions_BestOption_ReturnsExpectedData() _dataSourceMocker.SetupDataMock(start, end, location); // Act - var exitCode = await InvokeCliAsync($"emissions -l {location} -s 2022-09-01T02:01:00Z -e 2022-09-01T02:04:00Z -b"); + var exitCode = await InvokeCliAsync($"emissions -l {location} -s 2022-09-01T00:00:00Z -e 2022-09-01T00:04:00Z -b"); // Assert Assert.AreEqual(0, exitCode); diff --git a/src/CarbonAware.CLI/test/integrationTests/Commands/EmissionsForecasts/EmissionsForecastsCommandTests.cs b/src/CarbonAware.CLI/test/integrationTests/Commands/EmissionsForecasts/EmissionsForecastsCommandTests.cs index e5703f974..2c232d187 100644 --- a/src/CarbonAware.CLI/test/integrationTests/Commands/EmissionsForecasts/EmissionsForecastsCommandTests.cs +++ b/src/CarbonAware.CLI/test/integrationTests/Commands/EmissionsForecasts/EmissionsForecastsCommandTests.cs @@ -71,8 +71,8 @@ public async Task EmissionsForecasts_StartAndEndOptions_ReturnsExpectedData() var location = "eastus"; var start = DateTimeOffset.UtcNow.AddMinutes(10); var end = start.AddHours(5); - var dataStartAt = start.ToString("yyyy-MM-ddTHH:mm:ss"); - var dataEndAt = end.ToString("yyyy-MM-ddTHH:mm:ss"); + var dataStartAt = start.ToString("yyyy-MM-ddTHH:mm:ssZ"); + var dataEndAt = end.ToString("yyyy-MM-ddTHH:mm:ssZ"); _dataSourceMocker.SetupForecastMock(); // Act diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/src/ElectricityMapsFreeDataSource.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/src/ElectricityMapsFreeDataSource.cs index 60ad2a61c..f0a1687f7 100644 --- a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/src/ElectricityMapsFreeDataSource.cs +++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/src/ElectricityMapsFreeDataSource.cs @@ -86,15 +86,27 @@ public async Task> GetCarbonIntensityAsync(Location l } List EmissionsDataList = new List(); + var emissionDateTime = gridEmissionData.Data.Datetime; + var shouldReturn = true; + if (emissionDateTime != null && periodStartTime < periodEndTime) + { + // periodEndTime would be set periodStartTime in EmissionHandler if it is not specified. + // So we can assume we should return the most recent data if they equal. + // If not, we should return the data after checking it is within specified time range. + shouldReturn = periodStartTime <= emissionDateTime && emissionDateTime < periodEndTime; + } - var emissionData = new EmissionsData() + if (shouldReturn) { - Location = location.Name ?? "", - Time = gridEmissionData.Data.Datetime ?? new DateTimeOffset(), - Rating = gridEmissionData.Data.CarbonIntensity ?? 0.0, - Duration = new TimeSpan(0, 0, 0) - }; - EmissionsDataList.Add(emissionData); + var emissionData = new EmissionsData() + { + Location = location.Name ?? "", + Time = emissionDateTime ?? new DateTimeOffset(), + Rating = gridEmissionData.Data.CarbonIntensity ?? 0.0, + Duration = new TimeSpan(0, 0, 0) + }; + EmissionsDataList.Add(emissionData); + } return EmissionsDataList; } diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/test/ElectricityMapsFreeDataSourceTests.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/test/ElectricityMapsFreeDataSourceTests.cs index 8a8eb39c8..21203ef35 100644 --- a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/test/ElectricityMapsFreeDataSourceTests.cs +++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/test/ElectricityMapsFreeDataSourceTests.cs @@ -36,8 +36,9 @@ public ElectricityMapsFreeDataSourceTests() _dataSource = new ElectricityMapsFreeDataSource(_logger.Object, _ElectricityMapsFreeClient.Object, _locationSource.Object); } - [Test] - public async Task GetCarbonIntensity_ReturnsResultsWhenRecordsFound() + [TestCase(false, TestName = "GetCarbonIntensity_ReturnsResultsWhenRecordsFound without emission date time")] + [TestCase(true, TestName = "GetCarbonIntensity_ReturnsResultsWhenRecordsFound with emission date time")] + public async Task GetCarbonIntensity_ReturnsResultsWhenRecordsFound(bool withEmissionDateTime) { var startDate = DateTimeOffset.UtcNow.AddHours(-10); var endDate = startDate.AddHours(1); @@ -49,6 +50,7 @@ public async Task GetCarbonIntensity_ReturnsResultsWhenRecordsFound() { Data = new Data() { + Datetime = withEmissionDateTime ? startDate.AddMinutes(30) : null, CarbonIntensity = expectedCarbonIntensity, } }; @@ -71,8 +73,9 @@ public async Task GetCarbonIntensity_ReturnsResultsWhenRecordsFound() this._locationSource.Verify(l => l.ToGeopositionLocationAsync(_defaultLocation)); } - [Test] - public async Task GetCarbonIntensity_UseRegionNameWhenCoordinatesNotAvailable() + [TestCase(false, TestName = "GetCarbonIntensity_UseRegionNameWhenCoordinatesNotAvailable without emission date time")] + [TestCase(true, TestName = "GetCarbonIntensity_UseRegionNameWhenCoordinatesNotAvailable with emission date time")] + public async Task GetCarbonIntensity_UseRegionNameWhenCoordinatesNotAvailable(bool withEmissionDateTime) { var startDate = new DateTimeOffset(2022, 4, 18, 12, 32, 42, TimeSpan.FromHours(-6)); var endDate = startDate.AddMinutes(1); @@ -84,6 +87,7 @@ public async Task GetCarbonIntensity_UseRegionNameWhenCoordinatesNotAvailable() { Data = new Data() { + Datetime = withEmissionDateTime ? startDate.AddSeconds(30) : null, CarbonIntensity = expectedCarbonIntensity, } }; From c2cb7300690214ca4243807456a539a5ec36986f Mon Sep 17 00:00:00 2001 From: nttDamien <125525959+nttDamien@users.noreply.github.com> Date: Tue, 12 Sep 2023 15:44:39 +0900 Subject: [PATCH 5/8] fixing 3 broken links in overview.md (#391) fixing 3 broken links in overview.md Signed-off-by: nttDamien <125525959+nttDamien@users.noreply.github.com> --- docs/overview.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/overview.md b/docs/overview.md index 6ceddccf9..b83998618 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -6,14 +6,14 @@ you different data than the WebAPI for the same query). We provide a number of different endpoints to provide the most flexibility to integrate to your environment: -- You can run the application using the [CLI](./src/CarbonAware.CLI) and refer +- You can run the application using the [CLI](../src/CarbonAware.CLI) and refer to more documentation [here](./carbon-aware-cli.md). -- You can build a container containing the [WebAPI](./src/CarbonAware.WebApi) +- You can build a container containing the [WebAPI](../src/CarbonAware.WebApi) and connect via REST requests and refer to more documentation [here](./carbon-aware-webapi.md). -- You can reference the [Carbon Aware C# Library](./src/GSF.CarbonAware) in your +- You can reference the [Carbon Aware C# Library](../src/GSF.CarbonAware) in your projects and make use of its functionalities and features. - (Future) You can install the Nuget package and make requests directly. From 25121e6d6ce63d1c873e7780652b7786b4678750 Mon Sep 17 00:00:00 2001 From: Roman Lutz Date: Tue, 12 Sep 2023 03:42:44 -0400 Subject: [PATCH 6/8] Fix quickstart.md (#375) Signed-off-by: Roman Lutz --- docs/quickstart.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/quickstart.md b/docs/quickstart.md index a3b68dfa7..463901e8e 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -96,7 +96,7 @@ Expected output: For example, to get emissions in the `eastus` and `uksouth` region between `2022-08-23 at 11:15am` and `2022-08-23 at 11:20am`, run: -`dotnet run -l eastus,uksouth -t 2022-08-23T11:15 --toTime 2022-08-23T11:20` +`dotnet run emissions -l eastus,uksouth -s 2022-08-23T11:15 -e 2022-08-23T11:20` Expected output: @@ -147,7 +147,7 @@ hour window on the 23rd of August in the regions: `eastus`, `westus`, `westus3`,`uksouth`, run the command: ```bash -dotnet run -l eastus,westus,westus3,uksouth -t 2022-08-23T00:00 --toTime 2022-08-23T23:59 --best +dotnet run -l eastus,westus,westus3,uksouth -s 2022-08-23T00:00 -e 2022-08-23T23:59 --best ``` Expected output: From d1cb14cb0d9c8ba0229c6a1e8beddad770a4a7cb Mon Sep 17 00:00:00 2001 From: Szymon Duchniewicz Date: Tue, 12 Sep 2023 10:47:51 +0200 Subject: [PATCH 7/8] Fix: verify-azure-function-with-packages #383 Signed-off-by: Szymon Duchniewicz --- .github/workflows/verify-azure-function-with-packages.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/verify-azure-function-with-packages.yaml b/.github/workflows/verify-azure-function-with-packages.yaml index d5faa3dba..0ef34fef0 100644 --- a/.github/workflows/verify-azure-function-with-packages.yaml +++ b/.github/workflows/verify-azure-function-with-packages.yaml @@ -26,10 +26,11 @@ jobs: continue-on-error: true run: docker rm -f ${{ env.CONTAINER_RUNTIME_NAME }} + # Build and tag final image, remove dangling images only if there are any - name: Docker Target Final run: | docker build --no-cache . -f ${{ env.DOCKERFILE_PATH }} -t ${{ env.CONTAINER_IMAGE_NAME }} - docker rmi -f $(docker images -f "dangling=true" -q) + docker images -qf dangling=true | xargs --no-run-if-empty docker rmi - name: Docker Run Container run: docker run -d --name ${{ env.CONTAINER_RUNTIME_NAME }} -p 8080:80 ${{ env.CONTAINER_IMAGE_NAME }} From 1695a63350892a40ae05de91d7c85b0789948182 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Tue, 19 Sep 2023 21:40:59 +0900 Subject: [PATCH 8/8] Return empty list when ElectricityMapsFree.GetCarbonIntensityAsync() receives request for forecast Signed-off-by: Yasumasa Suenaga --- .../src/ElectricityMapsFreeDataSource.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/src/ElectricityMapsFreeDataSource.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/src/ElectricityMapsFreeDataSource.cs index f0a1687f7..d4268e352 100644 --- a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/src/ElectricityMapsFreeDataSource.cs +++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/src/ElectricityMapsFreeDataSource.cs @@ -87,8 +87,10 @@ public async Task> GetCarbonIntensityAsync(Location l List EmissionsDataList = new List(); var emissionDateTime = gridEmissionData.Data.Datetime; - var shouldReturn = true; - if (emissionDateTime != null && periodStartTime < periodEndTime) + + // periodStartTime should be less than current date time because this method should not handle forecast data. + var shouldReturn = periodStartTime <= DateTimeOffset.UtcNow; + if (shouldReturn && emissionDateTime != null && periodStartTime < periodEndTime) { // periodEndTime would be set periodStartTime in EmissionHandler if it is not specified. // So we can assume we should return the most recent data if they equal.