From fbbd9af0778a474d9ccf9ac78ff24737146c683b Mon Sep 17 00:00:00 2001
From: Bill DeRusha <444835+bderusha@users.noreply.github.com>
Date: Fri, 23 Jun 2023 13:51:27 -0400
Subject: [PATCH] Implement Dynamic DataSource registration
Signed-off-by: Bill DeRusha <444835+bderusha@users.noreply.github.com>
---
.vscode/launch.json | 3 +-
.../src/CarbonAware.CLI.csproj | 4 +
.../CarbonAware.CLI.IntegrationTests.csproj | 2 -
.../Emissions/EmissionsCommandTests.cs | 1 -
.../EmissionsForecastsCommandTests.cs | 3 +-
.../Commands/Location/LocationCommandTests.cs | 3 +-
.../IntegrationTestingBase.cs | 12 +-
...onAware.DataSources.ElectricityMaps.csproj | 1 -
.../ServiceCollectionExtensions.cs | 56 -----
.../src/ElectricityMapsDataSource.cs | 51 ++++-
.../ServiceCollectionExtensionTests.cs | 81 -------
.../test/ElectricityMapsDataSourceTests.cs | 86 ++++++++
...taSources.ElectricityMapsFree.Mocks.csproj | 1 +
.../ElectricityMapsFreeDataSourceMocker.cs | 16 +-
...are.DataSources.ElectricityMapsFree.csproj | 1 -
.../ServiceCollectionExtensions.cs | 50 -----
.../src/ElectricityMapsFreeDataSource.cs | 50 +++++
.../src/CarbonAware.DataSources.Json.csproj | 1 -
.../ServiceCollectionExtensions.cs | 20 --
.../src/JsonDataSource.cs | 27 ++-
...arbonAware.DataSources.Registration.csproj | 26 ---
.../Configuration/DataSourceType.cs | 10 -
.../ServiceCollectionExtensions.cs | 99 ---------
.../CarbonAware.DataSources.WattTime.csproj | 1 -
.../ServiceCollectionExtensions.cs | 62 ------
.../src/WattTimeDataSource.cs | 54 ++++-
.../ServiceCollectionExtensionTests.cs | 198 +++++++++---------
.../WattTimeClientConfigurationTests.cs | 3 +-
.../test/WattTimeDataSourceTests.cs | 89 +++++++-
.../Properties/launchSettings.json | 8 +
.../src/CarbonAware.WebApi.csproj | 4 +
src/CarbonAware.WebApi/src/Program.cs | 2 +-
...CarbonAware.WebApi.IntegrationTests.csproj | 4 +-
.../CarbonAwareControllerTests.cs | 15 +-
.../IntegrationTestingBase.cs | 23 +-
.../LocationsControllerTests.cs | 1 -
.../UnconfiguredWebApiTests.cs | 34 ---
src/CarbonAware/src/CarbonAware.csproj | 1 -
.../Configuration/DataSourcesConfiguration.cs | 51 ++++-
.../DataSourcesConfigurationExtensions.cs | 2 +-
.../Extensions/ServiceCollectionExtensions.cs | 80 +++++++
src/CarbonAware/src/Interfaces/IDataSource.cs | 12 ++
.../src/Interfaces/IEmissionsDataSource.cs | 2 +-
.../src/Interfaces/IForecastDataSource.cs | 2 +-
.../DataSourcesConfigurationTests.cs | 6 +-
src/CarbonAwareSDK.sln | 6 -
.../ServiceCollectionExtensions.cs | 6 +-
.../src/GSF.CarbonAware.csproj | 3 -
.../test/GSF.CarbonAware.Tests.csproj | 2 +
.../test/Handlers/EmissionsHandlerTests.cs | 6 +-
50 files changed, 671 insertions(+), 610 deletions(-)
delete mode 100644 src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/src/Configuration/ServiceCollectionExtensions.cs
delete mode 100644 src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/test/Configuration/ServiceCollectionExtensionTests.cs
delete mode 100644 src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/src/Configuration/ServiceCollectionExtensions.cs
delete mode 100644 src/CarbonAware.DataSources/CarbonAware.DataSources.Json/src/Configuration/ServiceCollectionExtensions.cs
delete mode 100644 src/CarbonAware.DataSources/CarbonAware.DataSources.Registration/CarbonAware.DataSources.Registration.csproj
delete mode 100644 src/CarbonAware.DataSources/CarbonAware.DataSources.Registration/Configuration/DataSourceType.cs
delete mode 100644 src/CarbonAware.DataSources/CarbonAware.DataSources.Registration/Configuration/ServiceCollectionExtensions.cs
delete mode 100644 src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Configuration/ServiceCollectionExtensions.cs
create mode 100644 src/CarbonAware.Tools/CarbonAware.Tools.AzureRegionTestDataGenerator/Properties/launchSettings.json
delete mode 100644 src/CarbonAware.WebApi/test/integrationTests/UnconfiguredWebApiTests.cs
create mode 100644 src/CarbonAware/src/Extensions/ServiceCollectionExtensions.cs
create mode 100644 src/CarbonAware/src/Interfaces/IDataSource.cs
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 7df71697f..e5b060d98 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -37,7 +37,8 @@
"uriFormat": "%s/swagger"
},
"env": {
- "ASPNETCORE_ENVIRONMENT": "Development"
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "DOTNET_HOSTBUILDER__RELOADCONFIGONCHANGE": "false"
},
"sourceFileMap": {
"/Views": "${workspaceFolder}/Views"
diff --git a/src/CarbonAware.CLI/src/CarbonAware.CLI.csproj b/src/CarbonAware.CLI/src/CarbonAware.CLI.csproj
index fcc1f9bfb..0f9dc57a4 100644
--- a/src/CarbonAware.CLI/src/CarbonAware.CLI.csproj
+++ b/src/CarbonAware.CLI/src/CarbonAware.CLI.csproj
@@ -27,6 +27,10 @@
+
+
+
+
diff --git a/src/CarbonAware.CLI/test/integrationTests/CarbonAware.CLI.IntegrationTests.csproj b/src/CarbonAware.CLI/test/integrationTests/CarbonAware.CLI.IntegrationTests.csproj
index 9b0dd0efe..a0859cea7 100644
--- a/src/CarbonAware.CLI/test/integrationTests/CarbonAware.CLI.IntegrationTests.csproj
+++ b/src/CarbonAware.CLI/test/integrationTests/CarbonAware.CLI.IntegrationTests.csproj
@@ -15,8 +15,6 @@
-
/// A base class that does all the common setup for the Integration Testing
/// Overrides WebAPI factory by switching out different configurations via _datasource
diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/src/CarbonAware.DataSources.ElectricityMaps.csproj b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/src/CarbonAware.DataSources.ElectricityMaps.csproj
index d9dab5e3e..a8758481a 100644
--- a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/src/CarbonAware.DataSources.ElectricityMaps.csproj
+++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/src/CarbonAware.DataSources.ElectricityMaps.csproj
@@ -10,7 +10,6 @@
-
diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/src/Configuration/ServiceCollectionExtensions.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/src/Configuration/ServiceCollectionExtensions.cs
deleted file mode 100644
index c1a036977..000000000
--- a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/src/Configuration/ServiceCollectionExtensions.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using CarbonAware.Configuration;
-using CarbonAware.Interfaces;
-using CarbonAware.DataSources.ElectricityMaps.Client;
-using CarbonAware.Exceptions;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.DependencyInjection.Extensions;
-using System.Net;
-
-namespace CarbonAware.DataSources.ElectricityMaps.Configuration;
-
-internal static class ServiceCollectionExtensions
-{
- public static IServiceCollection AddElectricityMapsForecastDataSource(this IServiceCollection services, DataSourcesConfiguration dataSourcesConfig)
- {
- AddElectricityMapsClient(services, dataSourcesConfig.ForecastConfigurationSection());
- services.TryAddSingleton();
- return services;
- }
-
- public static IServiceCollection AddElectricityMapsEmissionsDataSource(this IServiceCollection services, DataSourcesConfiguration dataSourcesConfig)
- {
- AddElectricityMapsClient(services, dataSourcesConfig.EmissionsConfigurationSection());
- services.TryAddSingleton();
- return services;
- }
-
- private static void AddElectricityMapsClient(IServiceCollection services, IConfigurationSection configSection)
- {
- services.Configure(c =>
- {
- configSection.Bind(c);
- });
-
- var httpClientBuilder = services.AddHttpClient(IElectricityMapsClient.NamedClient);
-
- var Proxy = configSection.GetSection("Proxy").Get();
- if (Proxy?.UseProxy == true)
- {
- if (String.IsNullOrEmpty(Proxy.Url))
- {
- throw new ConfigurationException("Proxy Url is not configured.");
- }
- httpClientBuilder.ConfigurePrimaryHttpMessageHandler(() =>
- new HttpClientHandler() {
- Proxy = new WebProxy {
- Address = new Uri(Proxy.Url),
- Credentials = new NetworkCredential(Proxy.Username, Proxy.Password),
- BypassProxyOnLocal = true
- }
- }
- );
- }
- services.TryAddSingleton();
- }
-}
diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/src/ElectricityMapsDataSource.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/src/ElectricityMapsDataSource.cs
index ea4a99b0e..610e53e75 100644
--- a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/src/ElectricityMapsDataSource.cs
+++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/src/ElectricityMapsDataSource.cs
@@ -1,10 +1,15 @@
+using CarbonAware.Configuration;
using CarbonAware.DataSources.ElectricityMaps.Client;
+using CarbonAware.DataSources.ElectricityMaps.Configuration;
using CarbonAware.DataSources.ElectricityMaps.Model;
using CarbonAware.Exceptions;
using CarbonAware.Interfaces;
using CarbonAware.Model;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
-using System.Diagnostics;
+using System.Net;
namespace CarbonAware.DataSources.ElectricityMaps;
@@ -40,6 +45,21 @@ public ElectricityMapsDataSource(ILogger logger, IEle
this._locationSource = locationSource;
}
+ public static IServiceCollection ConfigureDI(IServiceCollection services, DataSourcesConfiguration dataSourcesConfig)
+ where T : IDataSource
+ {
+ var configSection = dataSourcesConfig.ConfigurationSection();
+ AddElectricityMapsClient(services, configSection);
+ try
+ {
+ services.TryAddSingleton(typeof(T), typeof(ElectricityMapsDataSource));
+ } catch (Exception ex)
+ {
+ throw new ArgumentException($"ElectricityMapsDataSource is not a supported {typeof(T).Name} data source.", ex);
+ }
+ return services;
+ }
+
///
public async Task GetCurrentCarbonIntensityForecastAsync(Location location)
{
@@ -176,4 +196,33 @@ private TimeSpan GetDurationFromHistoryDataPoints(IEnumerable d
// the absolute value of the TimeSpan between the two points.
return first.DateTime.Subtract(second.DateTime).Duration();
}
+
+ private static void AddElectricityMapsClient(IServiceCollection services, IConfigurationSection configSection)
+ {
+ services.Configure(c =>
+ {
+ configSection.Bind(c);
+ });
+
+ var httpClientBuilder = services.AddHttpClient(IElectricityMapsClient.NamedClient);
+
+ var Proxy = configSection.GetSection("Proxy").Get();
+ if (Proxy?.UseProxy == true)
+ {
+ if (String.IsNullOrEmpty(Proxy.Url))
+ {
+ throw new ConfigurationException("Proxy Url is not configured.");
+ }
+ httpClientBuilder.ConfigurePrimaryHttpMessageHandler(() =>
+ new HttpClientHandler() {
+ Proxy = new WebProxy {
+ Address = new Uri(Proxy.Url),
+ Credentials = new NetworkCredential(Proxy.Username, Proxy.Password),
+ BypassProxyOnLocal = true
+ }
+ }
+ );
+ }
+ services.TryAddSingleton();
+ }
}
diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/test/Configuration/ServiceCollectionExtensionTests.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/test/Configuration/ServiceCollectionExtensionTests.cs
deleted file mode 100644
index 8fa70908e..000000000
--- a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/test/Configuration/ServiceCollectionExtensionTests.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-using CarbonAware.Configuration;
-using CarbonAware.DataSources.ElectricityMaps.Configuration;
-using CarbonAware.Exceptions;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-
-namespace CarbonAware.DataSources.ElectricityMaps.Tests;
-
-[TestFixture]
-class ServiceCollectionExtensionTests
-{
- const string ForecastDataSourceKey = $"DataSources:ForecastDataSource";
- const string EmissionsDataSourceKey = $"DataSources:EmissionsDataSource";
- const string ForecastDataSourceValue = $"ElectricityMapsTest";
- const string EmissionsDataSourceValue = $"ElectricityMapsTest";
- const string HeaderKey = $"DataSources:Configurations:ElectricityMapsTest:APITokenHeader";
- const string AuthHeader = "auth-token";
- const string TokenKey = $"DataSources:Configurations:ElectricityMapsTest:APIToken";
- const string DefaultTokenValue = "myDefaultToken123";
- const string UseProxyKey = $"DataSources:Configurations:ElectricityMapsTest:Proxy:UseProxy";
- const string ProxyUrl = $"DataSources:Configurations:ElectricityMapsTest:Proxy:Url";
- const string ProxyUsername = $"DataSources:Configurations:ElectricityMapsTest:Proxy:Username";
- const string ProxyPassword = $"DataSources:Configurations:ElectricityMapsTest:Proxy:Password";
-
- [Test]
- public void ClientProxyTest_With_Missing_ProxyURL_ThrowsException()
- {
- // Arrange
- var settings = new Dictionary {
- { ForecastDataSourceKey, ForecastDataSourceValue },
- { EmissionsDataSourceKey, EmissionsDataSourceValue },
- { HeaderKey, AuthHeader },
- { TokenKey, DefaultTokenValue },
- { UseProxyKey, "true" },
- };
- var configuration = new ConfigurationBuilder()
- .AddInMemoryCollection(settings)
- .AddEnvironmentVariables()
- .Build();
- var serviceCollection = new ServiceCollection();
-
- // Act & Assert
- Assert.Throws(() => serviceCollection.AddElectricityMapsForecastDataSource(configuration.DataSources()));
- Assert.Throws(() => serviceCollection.AddElectricityMapsEmissionsDataSource(configuration.DataSources()));
- }
-
- [TestCase(true, TestName = "ClientProxyTest, successful: denotes adding ElectricityMaps data sources using proxy.")]
- [TestCase(false, TestName = "ClientProxyTest, successful: denotes adding ElectricityMaps data sources without using proxy.")]
- public void ClientProxy_ConfigurationTest(bool withProxyUrl)
- {
- // Arrange
- var settings = new Dictionary {
- { ForecastDataSourceKey, ForecastDataSourceValue },
- { EmissionsDataSourceKey, EmissionsDataSourceValue },
- { HeaderKey, AuthHeader },
- { TokenKey, DefaultTokenValue },
- { UseProxyKey, withProxyUrl.ToString() }
- };
-
- if (withProxyUrl)
- {
- settings.Add(ProxyUrl, "http://fakeProxy");
- settings.Add(ProxyUsername, "proxyUsername");
- settings.Add(ProxyPassword, "proxyPassword");
- }
-
- var configuration = new ConfigurationBuilder()
- .AddInMemoryCollection(settings)
- .AddEnvironmentVariables()
- .Build();
- var serviceCollection = new ServiceCollection();
-
- // Act
- var forecastDataSource = serviceCollection.AddElectricityMapsForecastDataSource(configuration.DataSources());
- var emissionsDataSource = serviceCollection.AddElectricityMapsEmissionsDataSource(configuration.DataSources());
-
- // Assert
- Assert.That(forecastDataSource, Is.Not.Null);
- Assert.That(emissionsDataSource, Is.Not.Null);
- }
-}
\ No newline at end of file
diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/test/ElectricityMapsDataSourceTests.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/test/ElectricityMapsDataSourceTests.cs
index ff1dcc56a..77025d52f 100644
--- a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/test/ElectricityMapsDataSourceTests.cs
+++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/test/ElectricityMapsDataSourceTests.cs
@@ -1,8 +1,11 @@
+using CarbonAware.Configuration;
using CarbonAware.DataSources.ElectricityMaps.Client;
using CarbonAware.DataSources.ElectricityMaps.Model;
using CarbonAware.Exceptions;
using CarbonAware.Interfaces;
using CarbonAware.Model;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Moq;
@@ -23,6 +26,14 @@ class ElectricityMapsDataSourceTests
private static string _defaultLongitude => _defaultLocation.Longitude.ToString() ?? "";
private static DateTimeOffset _defaultDataStartTime = new DateTimeOffset(2022, 4, 18, 12, 32, 42, TimeSpan.FromHours(-6));
+ private readonly string TypeKey = $"Configurations:ElectricityMaps:Type";
+ private readonly string UsernameKey = $"Configurations:ElectricityMaps:Username";
+ private readonly string PasswordKey = $"Configurations:ElectricityMaps:Password";
+ private readonly string UseProxyKey = $"Configurations:ElectricityMaps:Proxy:UseProxy";
+ private readonly string ProxyUrlKey = $"Configurations:ElectricityMaps:Proxy:Url";
+ private readonly string ProxyUsernameKey = $"Configurations:ElectricityMaps:Proxy:Username";
+ private readonly string ProxyPasswordKey = $"Configurations:ElectricityMaps:Proxy:Password";
+
[SetUp]
public void Setup()
{
@@ -324,4 +335,79 @@ public async Task GetDurationBetweenHistoryDataPoints_WhenMultipleDataPoints_Ret
Assert.IsNotNull(second);
Assert.That(second.Duration, Is.EqualTo(expectedDuration));
}
+
+ [Test]
+ public void ConfigureDI_ClientProxyTest_With_Missing_ProxyURL_ThrowsException()
+ {
+ // Arrange
+ var inMemorySettings = new Dictionary {
+ { TypeKey, "ElectricityMaps" },
+ { UsernameKey, "testUsername" },
+ { PasswordKey, "testPassword123!" },
+ { UseProxyKey, "true" },
+ };
+
+ var configuration = new ConfigurationBuilder()
+ .AddInMemoryCollection(inMemorySettings)
+ .Build();
+
+ var dataSourceConfig = new DataSourcesConfiguration()
+ {
+ EmissionsDataSource = "ElectricityMaps",
+ ForecastDataSource = "ElectricityMaps",
+ Section = configuration.GetSection("Configurations")
+ };
+
+ var serviceCollection = new ServiceCollection();
+
+ // Act & Assert
+ Assert.Throws(() => ElectricityMapsDataSource.ConfigureDI(serviceCollection, dataSourceConfig));
+ Assert.Throws(() => ElectricityMapsDataSource.ConfigureDI(serviceCollection, dataSourceConfig));
+ }
+
+ [TestCase(true, TestName = "ClientProxyTest, successful: denotes adding ElectricityMaps data sources using proxy.")]
+ [TestCase(false, TestName = "ClientProxyTest, successful: denotes adding ElectricityMaps data sources without using proxy.")]
+ public void ConfigureDI_ClientProxyTest_AddsDataSource(bool withProxyUrl)
+ {
+ // Arrange
+ var inMemorySettings = new Dictionary {
+ { TypeKey, "ElectricityMaps" },
+ { UsernameKey, "testUsername" },
+ { PasswordKey, "testPassword123!" },
+ { UseProxyKey, withProxyUrl.ToString() },
+ };
+
+ if (withProxyUrl)
+ {
+ inMemorySettings.Add(ProxyUrlKey, "http://10.10.10.1");
+ inMemorySettings.Add(ProxyUsernameKey, "proxyUsername");
+ inMemorySettings.Add(ProxyPasswordKey, "proxyPassword");
+ }
+
+ var configuration = new ConfigurationBuilder()
+ .AddInMemoryCollection(inMemorySettings)
+ .Build();
+
+ var dataSourceConfig = new DataSourcesConfiguration()
+ {
+ EmissionsDataSource = "ElectricityMaps",
+ ForecastDataSource = "ElectricityMaps",
+ Section = configuration.GetSection("Configurations")
+ };
+
+ var serviceCollection = new ServiceCollection();
+ var emissionsDescriptor = new ServiceDescriptor(typeof(IEmissionsDataSource), typeof(ElectricityMapsDataSource), ServiceLifetime.Singleton);
+ var forecastDescriptor = new ServiceDescriptor(typeof(IForecastDataSource), typeof(ElectricityMapsDataSource), ServiceLifetime.Singleton);
+
+ Assert.That(!serviceCollection.Any(i => i.ToString() == emissionsDescriptor.ToString()));
+ Assert.That(!serviceCollection.Any(i => i.ToString() == forecastDescriptor.ToString()));
+
+ // Act
+ ElectricityMapsDataSource.ConfigureDI(serviceCollection, dataSourceConfig);
+ ElectricityMapsDataSource.ConfigureDI(serviceCollection, dataSourceConfig);
+
+ // Assert
+ Assert.That(serviceCollection.Any(i => i.ToString() == emissionsDescriptor.ToString()));
+ Assert.That(serviceCollection.Any(i => i.ToString() == forecastDescriptor.ToString()));
+ }
}
\ No newline at end of file
diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/mock/CarbonAware.DataSources.ElectricityMapsFree.Mocks.csproj b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/mock/CarbonAware.DataSources.ElectricityMapsFree.Mocks.csproj
index 60a945672..ae28cd4a8 100644
--- a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/mock/CarbonAware.DataSources.ElectricityMapsFree.Mocks.csproj
+++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/mock/CarbonAware.DataSources.ElectricityMapsFree.Mocks.csproj
@@ -16,6 +16,7 @@
+
diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/mock/ElectricityMapsFreeDataSourceMocker.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/mock/ElectricityMapsFreeDataSourceMocker.cs
index f8a645aca..92d6253ce 100644
--- a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/mock/ElectricityMapsFreeDataSourceMocker.cs
+++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/mock/ElectricityMapsFreeDataSourceMocker.cs
@@ -44,21 +44,11 @@ public void SetupDataMock(DateTimeOffset start, DateTimeOffset end, string locat
SetupResponseGivenGetRequest(Paths.Latest, data);
}
- public void SetupForecastMock()
- {
- throw new NotImplementedException();
- }
+ public void SetupForecastMock() { }
- public void SetupBatchForecastMock()
- {
- throw new NotImplementedException();
- }
+ public void SetupBatchForecastMock() { }
- public void Initialize()
- {
- // No initialization needed
- return;
- }
+ public void Initialize() { }
public void Reset() => _server.Reset();
diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/src/CarbonAware.DataSources.ElectricityMapsFree.csproj b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/src/CarbonAware.DataSources.ElectricityMapsFree.csproj
index 8db8bc27b..b3a907bc4 100644
--- a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/src/CarbonAware.DataSources.ElectricityMapsFree.csproj
+++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/src/CarbonAware.DataSources.ElectricityMapsFree.csproj
@@ -8,7 +8,6 @@
-
diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/src/Configuration/ServiceCollectionExtensions.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/src/Configuration/ServiceCollectionExtensions.cs
deleted file mode 100644
index 8156b2b87..000000000
--- a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/src/Configuration/ServiceCollectionExtensions.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-using CarbonAware.Configuration;
-using CarbonAware.DataSources.ElectricityMapsFree.Client;
-using CarbonAware.Exceptions;
-using CarbonAware.Interfaces;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.DependencyInjection.Extensions;
-using System.Net;
-
-namespace CarbonAware.DataSources.ElectricityMapsFree.Configuration;
-
-internal static class ServiceCollectionExtensions
-{
- public static IServiceCollection AddElectricityMapsFreeEmissionsDataSource(this IServiceCollection services, DataSourcesConfiguration dataSourcesConfig)
- {
- AddElectricityMapsFreeClient(services, dataSourcesConfig.EmissionsConfigurationSection());
- services.TryAddSingleton();
- return services;
- }
-
-
- private static void AddElectricityMapsFreeClient(IServiceCollection services, IConfigurationSection configSection)
- {
- services.Configure(c =>
- {
- configSection.Bind(c);
- });
-
- var httpClientBuilder = services.AddHttpClient(IElectricityMapsFreeClient.NamedClient);
-
- var Proxy = configSection.GetSection("Proxy").Get();
- if (Proxy?.UseProxy == true)
- {
- if (String.IsNullOrEmpty(Proxy.Url))
- {
- throw new ConfigurationException("Proxy Url is not configured.");
- }
- httpClientBuilder.ConfigurePrimaryHttpMessageHandler(() =>
- new HttpClientHandler() {
- Proxy = new WebProxy {
- Address = new Uri(Proxy.Url),
- Credentials = new NetworkCredential(Proxy.Username, Proxy.Password),
- BypassProxyOnLocal = true
- }
- }
- );
- }
- services.TryAddSingleton();
- }
-}
\ No newline at end of file
diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/src/ElectricityMapsFreeDataSource.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/src/ElectricityMapsFreeDataSource.cs
index 60ad2a61c..1aff0174f 100644
--- a/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/src/ElectricityMapsFreeDataSource.cs
+++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/src/ElectricityMapsFreeDataSource.cs
@@ -1,9 +1,16 @@
using CarbonAware.DataSources.ElectricityMapsFree.Client;
+using CarbonAware.DataSources.ElectricityMapsFree.Configuration;
using CarbonAware.DataSources.ElectricityMapsFree.Model;
+using CarbonAware.Exceptions;
using CarbonAware.Interfaces;
using CarbonAware.Model;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
+using System.Net;
using System.Diagnostics;
+using CarbonAware.Configuration;
namespace CarbonAware.DataSources.ElectricityMapsFree;
///
@@ -40,6 +47,20 @@ public ElectricityMapsFreeDataSource(ILogger logg
this._locationSource = locationSource;
}
+ public static IServiceCollection ConfigureDI(IServiceCollection services, DataSourcesConfiguration dataSourcesConfig)
+ where T : IDataSource
+ {
+ var configSection = dataSourcesConfig.ConfigurationSection();
+ AddElectricityMapsFreeClient(services, configSection);
+ try
+ {
+ services.TryAddSingleton(typeof(T), typeof(ElectricityMapsFreeDataSource));
+ } catch (Exception ex)
+ {
+ throw new ArgumentException($"ElectricityMapsFreeDataSource is not a supported {typeof(T).Name} data source.", ex);
+ }
+ return services;
+ }
///
public async Task> GetCarbonIntensityAsync(IEnumerable locations, DateTimeOffset periodStartTime, DateTimeOffset periodEndTime)
@@ -98,4 +119,33 @@ public async Task> GetCarbonIntensityAsync(Location l
return EmissionsDataList;
}
+
+ private static void AddElectricityMapsFreeClient(IServiceCollection services, IConfigurationSection configSection)
+ {
+ services.Configure(c =>
+ {
+ configSection.Bind(c);
+ });
+
+ var httpClientBuilder = services.AddHttpClient(IElectricityMapsFreeClient.NamedClient);
+
+ var Proxy = configSection.GetSection("Proxy").Get();
+ if (Proxy?.UseProxy == true)
+ {
+ if (String.IsNullOrEmpty(Proxy.Url))
+ {
+ throw new ConfigurationException("Proxy Url is not configured.");
+ }
+ httpClientBuilder.ConfigurePrimaryHttpMessageHandler(() =>
+ new HttpClientHandler() {
+ Proxy = new WebProxy {
+ Address = new Uri(Proxy.Url),
+ Credentials = new NetworkCredential(Proxy.Username, Proxy.Password),
+ BypassProxyOnLocal = true
+ }
+ }
+ );
+ }
+ services.TryAddSingleton();
+ }
}
diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.Json/src/CarbonAware.DataSources.Json.csproj b/src/CarbonAware.DataSources/CarbonAware.DataSources.Json/src/CarbonAware.DataSources.Json.csproj
index 7c9905d41..1d0002f72 100644
--- a/src/CarbonAware.DataSources/CarbonAware.DataSources.Json/src/CarbonAware.DataSources.Json.csproj
+++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.Json/src/CarbonAware.DataSources.Json.csproj
@@ -17,7 +17,6 @@
-
diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.Json/src/Configuration/ServiceCollectionExtensions.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.Json/src/Configuration/ServiceCollectionExtensions.cs
deleted file mode 100644
index edde1f037..000000000
--- a/src/CarbonAware.DataSources/CarbonAware.DataSources.Json/src/Configuration/ServiceCollectionExtensions.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using CarbonAware.Configuration;
-using CarbonAware.Interfaces;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.DependencyInjection.Extensions;
-
-namespace CarbonAware.DataSources.Json.Configuration;
-
-internal static class ServiceCollectionExtensions
-{
- public static void AddJsonEmissionsDataSource(this IServiceCollection services, DataSourcesConfiguration dataSourcesConfig)
- {
- // configuring dependency injection to have config.
- services.Configure(config =>
- {
- dataSourcesConfig.EmissionsConfigurationSection().Bind(config);
- });
- services.TryAddSingleton();
- }
-}
\ No newline at end of file
diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.Json/src/JsonDataSource.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.Json/src/JsonDataSource.cs
index c62735dcb..63fc7f2f7 100644
--- a/src/CarbonAware.DataSources/CarbonAware.DataSources.Json/src/JsonDataSource.cs
+++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.Json/src/JsonDataSource.cs
@@ -1,8 +1,14 @@
-using CarbonAware.Interfaces;
+using CarbonAware.Configuration;
using CarbonAware.DataSources.Json.Configuration;
+using CarbonAware.Exceptions;
+using CarbonAware.Interfaces;
using CarbonAware.Model;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
+using System.Net;
using System.Text.Json;
namespace CarbonAware.DataSources.Json;
@@ -42,6 +48,25 @@ public JsonDataSource(ILogger logger, IOptionsMonitor(IServiceCollection services, DataSourcesConfiguration dataSourcesConfig)
+ where T : IDataSource
+ {
+ var configSection = dataSourcesConfig.ConfigurationSection();
+ services.Configure(config =>
+ {
+ configSection.Bind(config);
+ });
+
+ try
+ {
+ services.TryAddSingleton(typeof(T), typeof(JsonDataSource));
+ } catch (Exception ex)
+ {
+ throw new ArgumentException($"JsonDataSource is not a supported {typeof(T).Name} data source.", ex);
+ }
+ return services;
+ }
+
///
public Task> GetCarbonIntensityAsync(Location location, DateTimeOffset periodStartTime, DateTimeOffset periodEndTime)
{
diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.Registration/CarbonAware.DataSources.Registration.csproj b/src/CarbonAware.DataSources/CarbonAware.DataSources.Registration/CarbonAware.DataSources.Registration.csproj
deleted file mode 100644
index d66d5e8c7..000000000
--- a/src/CarbonAware.DataSources/CarbonAware.DataSources.Registration/CarbonAware.DataSources.Registration.csproj
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
- net6.0
- enable
- enable
- true
- false
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.Registration/Configuration/DataSourceType.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.Registration/Configuration/DataSourceType.cs
deleted file mode 100644
index a1d93e1d7..000000000
--- a/src/CarbonAware.DataSources/CarbonAware.DataSources.Registration/Configuration/DataSourceType.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace CarbonAware.DataSources.Configuration;
-
-public enum DataSourceType
-{
- None,
- WattTime,
- JSON,
- ElectricityMaps,
- ElectricityMapsFree,
-}
\ No newline at end of file
diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.Registration/Configuration/ServiceCollectionExtensions.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.Registration/Configuration/ServiceCollectionExtensions.cs
deleted file mode 100644
index 872ec4bae..000000000
--- a/src/CarbonAware.DataSources/CarbonAware.DataSources.Registration/Configuration/ServiceCollectionExtensions.cs
+++ /dev/null
@@ -1,99 +0,0 @@
-using CarbonAware.Configuration;
-using CarbonAware.Interfaces;
-using CarbonAware.DataSources.ElectricityMaps.Configuration;
-using CarbonAware.DataSources.ElectricityMapsFree.Configuration;
-using CarbonAware.DataSources.Json.Configuration;
-using CarbonAware.DataSources.WattTime.Configuration;
-using CarbonAware.Exceptions;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.DependencyInjection.Extensions;
-
-namespace CarbonAware.DataSources.Configuration;
-internal static class ServiceCollectionExtensions
-{
- public static IServiceCollection AddDataSourceService(this IServiceCollection services, IConfiguration configuration)
- {
- var dataSources = configuration.DataSources();
-
- var emissionsDataSource = GetDataSourceTypeFromValue(dataSources.EmissionsConfigurationType());
- var forecastDataSource = GetDataSourceTypeFromValue(dataSources.ForecastConfigurationType());
-
- switch (emissionsDataSource)
- {
- case DataSourceType.JSON:
- {
- services.AddJsonEmissionsDataSource(dataSources);
- break;
- }
- case DataSourceType.WattTime:
- {
- services.AddWattTimeEmissionsDataSource(dataSources);
- break;
- }
- case DataSourceType.ElectricityMaps:
- {
- services.AddElectricityMapsEmissionsDataSource(dataSources);
- break;
- }
- case DataSourceType.ElectricityMapsFree:
- {
- services.AddElectricityMapsFreeEmissionsDataSource(dataSources);
- break;
- }
- case DataSourceType.None:
- {
- services.TryAddSingleton();
- break;
- }
- }
-
- switch (forecastDataSource)
- {
- case DataSourceType.JSON:
- {
- throw new ArgumentException("JSON data source is not supported for forecast data");
- }
- case DataSourceType.WattTime:
- {
- services.AddWattTimeForecastDataSource(dataSources);
- break;
- }
- case DataSourceType.ElectricityMaps:
- {
- services.AddElectricityMapsForecastDataSource(dataSources);
- break;
- }
- case DataSourceType.ElectricityMapsFree:
- {
- throw new ArgumentException("ElectricityMapsFree data source is not supported for forecast data");
- }
- case DataSourceType.None:
- {
- services.TryAddSingleton();
- break;
- }
- }
-
- if (forecastDataSource == DataSourceType.None && emissionsDataSource == DataSourceType.None)
- {
- throw new ConfigurationException("No data sources are configured");
- }
-
- return services;
- }
-
- private static DataSourceType GetDataSourceTypeFromValue(string? srcVal)
- {
- DataSourceType result;
- if (String.IsNullOrWhiteSpace(srcVal))
- {
- result = DataSourceType.None;
- }
- else if (!Enum.TryParse(srcVal, true, out result))
- {
- throw new ArgumentException($"Unknown data source type: {srcVal}");
- }
- return result;
- }
-}
diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/CarbonAware.DataSources.WattTime.csproj b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/CarbonAware.DataSources.WattTime.csproj
index 20f6d7230..f9f3e6bcc 100644
--- a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/CarbonAware.DataSources.WattTime.csproj
+++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/CarbonAware.DataSources.WattTime.csproj
@@ -9,7 +9,6 @@
-
diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Configuration/ServiceCollectionExtensions.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Configuration/ServiceCollectionExtensions.cs
deleted file mode 100644
index b3ba9d358..000000000
--- a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Configuration/ServiceCollectionExtensions.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-using CarbonAware.Configuration;
-using CarbonAware.DataSources.WattTime.Client;
-using CarbonAware.Exceptions;
-using CarbonAware.Interfaces;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.DependencyInjection.Extensions;
-using System.Net;
-
-namespace CarbonAware.DataSources.WattTime.Configuration;
-
-internal static class ServiceCollectionExtensions
-{
- public static IServiceCollection AddWattTimeForecastDataSource(this IServiceCollection services, DataSourcesConfiguration dataSourcesConfig)
- {
- AddDependencies(services, dataSourcesConfig.ForecastConfigurationSection());
- services.TryAddSingleton();
- return services;
- }
-
- public static IServiceCollection AddWattTimeEmissionsDataSource(this IServiceCollection services, DataSourcesConfiguration dataSourcesConfig)
- {
- AddDependencies(services, dataSourcesConfig.EmissionsConfigurationSection());
- services.TryAddSingleton();
- return services;
- }
-
- private static void AddDependencies(IServiceCollection services, IConfigurationSection configSection)
- {
- AddWattTimeClient(services, configSection);
- services.AddMemoryCache();
- }
-
- private static void AddWattTimeClient(IServiceCollection services, IConfigurationSection configSection)
- {
- services.Configure(c =>
- {
- configSection.Bind(c);
- });
-
- var httpClientBuilder = services.AddHttpClient(IWattTimeClient.NamedClient);
-
- var Proxy = configSection.GetSection("Proxy").Get();
- if (Proxy != null && Proxy.UseProxy == true)
- {
- if (String.IsNullOrEmpty(Proxy.Url))
- {
- throw new Exceptions.ConfigurationException("Proxy Url is not configured.");
- }
- httpClientBuilder.ConfigurePrimaryHttpMessageHandler(() =>
- new HttpClientHandler() {
- Proxy = new WebProxy {
- Address = new Uri(Proxy.Url),
- Credentials = new NetworkCredential(Proxy.Username, Proxy.Password),
- BypassProxyOnLocal = true
- }
- }
- );
- }
- services.TryAddSingleton();
- }
-}
diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/WattTimeDataSource.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/WattTimeDataSource.cs
index b639bd2e7..4c7e9a758 100644
--- a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/WattTimeDataSource.cs
+++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/WattTimeDataSource.cs
@@ -1,10 +1,15 @@
-using CarbonAware.DataSources.WattTime.Client;
+using CarbonAware.Configuration;
+using CarbonAware.DataSources.WattTime.Client;
+using CarbonAware.DataSources.WattTime.Configuration;
using CarbonAware.DataSources.WattTime.Model;
using CarbonAware.Exceptions;
using CarbonAware.Interfaces;
using CarbonAware.Model;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
-using System.Diagnostics;
+using System.Net;
namespace CarbonAware.DataSources.WattTime;
@@ -44,6 +49,22 @@ public WattTimeDataSource(ILogger logger, IWattTimeClient cl
this.LocationSource = locationSource;
}
+ public static IServiceCollection ConfigureDI(IServiceCollection services, DataSourcesConfiguration dataSourcesConfig)
+ where T : IDataSource
+ {
+ var configSection = dataSourcesConfig.ConfigurationSection();
+ AddWattTimeClient(services, configSection);
+ services.AddMemoryCache();
+ try
+ {
+ services.TryAddSingleton(typeof(T), typeof(WattTimeDataSource));
+ } catch (Exception ex)
+ {
+ throw new ArgumentException($"WattTimeDataSource is not a supported {typeof(T).Name} data source.", ex);
+ }
+ return services;
+ }
+
///
public async Task> GetCarbonIntensityAsync(IEnumerable locations, DateTimeOffset periodStartTime, DateTimeOffset periodEndTime)
{
@@ -196,4 +217,33 @@ private DateTimeOffset TimeToLowestIncrement(DateTimeOffset date, int minutes =
var d = TimeSpan.FromMinutes(minutes);
return new DateTimeOffset((date.Ticks / d.Ticks) * d.Ticks, date.Offset);
}
+
+ private static void AddWattTimeClient(IServiceCollection services, IConfigurationSection configSection)
+ {
+ services.Configure(c =>
+ {
+ configSection.Bind(c);
+ });
+
+ var httpClientBuilder = services.AddHttpClient(IWattTimeClient.NamedClient);
+
+ var Proxy = configSection.GetSection("Proxy").Get();
+ if (Proxy != null && Proxy.UseProxy == true)
+ {
+ if (String.IsNullOrEmpty(Proxy.Url))
+ {
+ throw new Exceptions.ConfigurationException("Proxy Url is not configured.");
+ }
+ httpClientBuilder.ConfigurePrimaryHttpMessageHandler(() =>
+ new HttpClientHandler() {
+ Proxy = new WebProxy {
+ Address = new Uri(Proxy.Url),
+ Credentials = new NetworkCredential(Proxy.Username, Proxy.Password),
+ BypassProxyOnLocal = true
+ }
+ }
+ );
+ }
+ services.TryAddSingleton();
+ }
}
diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/Configuration/ServiceCollectionExtensionTests.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/Configuration/ServiceCollectionExtensionTests.cs
index b3f845e3a..e6ddac947 100644
--- a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/Configuration/ServiceCollectionExtensionTests.cs
+++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/Configuration/ServiceCollectionExtensionTests.cs
@@ -1,112 +1,112 @@
-using CarbonAware.Configuration;
-using CarbonAware.DataSources.WattTime.Client;
-using CarbonAware.DataSources.WattTime.Configuration;
-using CarbonAware.Exceptions;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using NUnit.Framework;
-using System.Collections.Generic;
-using System.Net.Http;
+// using CarbonAware.Configuration;
+// using CarbonAware.DataSources.WattTime.Client;
+// using CarbonAware.DataSources.WattTime.Configuration;
+// using CarbonAware.Exceptions;
+// using Microsoft.Extensions.Configuration;
+// using Microsoft.Extensions.DependencyInjection;
+// using NUnit.Framework;
+// using System.Collections.Generic;
+// using System.Net.Http;
-namespace CarbonAware.DataSources.WattTime.Tests;
+// namespace CarbonAware.DataSources.WattTime.Tests;
-[TestFixture]
-class ServiceCollectionExtensionTests
-{
- private readonly string ForecastDataSourceKey = $"DataSources:ForecastDataSource";
- private readonly string EmissionsDataSourceKey = $"DataSources:EmissionsDataSource";
- private readonly string ForecastDataSourceValue = $"WattTimeTest";
- private readonly string EmissionsDataSourceValue = $"WattTimeTest";
- private readonly string UsernameKey = $"DataSources:Configurations:WattTimeTest:Username";
- private readonly string Username = "devuser";
- private readonly string PasswordKey = $"DataSources:Configurations:WattTimeTest:Password";
- private readonly string Password = "12345";
- private readonly string ProxyUrl = $"DataSources:Configurations:WattTimeTest:Proxy:Url";
- private readonly string ProxyUsername = $"DataSources:Configurations:WattTimeTest:Proxy:Username";
- private readonly string ProxyPassword = $"DataSources:Configurations:WattTimeTest:Proxy:Password";
- private readonly string UseProxyKey = $"DataSources:Configurations:WattTimeTest:Proxy:UseProxy";
+// [TestFixture]
+// class ServiceCollectionExtensionTests
+// {
+// private readonly string ForecastDataSourceKey = $"DataSources:ForecastDataSource";
+// private readonly string EmissionsDataSourceKey = $"DataSources:EmissionsDataSource";
+// private readonly string ForecastDataSourceValue = $"WattTimeTest";
+// private readonly string EmissionsDataSourceValue = $"WattTimeTest";
+// private readonly string UsernameKey = $"DataSources:Configurations:WattTimeTest:Username";
+// private readonly string Username = "devuser";
+// private readonly string PasswordKey = $"DataSources:Configurations:WattTimeTest:Password";
+// private readonly string Password = "12345";
+// private readonly string ProxyUrl = $"DataSources:Configurations:WattTimeTest:Proxy:Url";
+// private readonly string ProxyUsername = $"DataSources:Configurations:WattTimeTest:Proxy:Username";
+// private readonly string ProxyPassword = $"DataSources:Configurations:WattTimeTest:Proxy:Password";
+// private readonly string UseProxyKey = $"DataSources:Configurations:WattTimeTest:Proxy:UseProxy";
- [Test]
- public void ClientProxyTest_With_Invalid_ProxyURL_ThrowsException()
- {
- // Arrange
- var settings = new Dictionary {
- { ForecastDataSourceKey, ForecastDataSourceValue },
- { EmissionsDataSourceKey, EmissionsDataSourceValue },
- { UsernameKey, Username },
- { PasswordKey, Password },
- { ProxyUrl, "http://fakeproxy:8080" },
- { UseProxyKey, "true" },
- };
+// [Test]
+// public void ClientProxyTest_With_Invalid_ProxyURL_ThrowsException()
+// {
+// // Arrange
+// var settings = new Dictionary {
+// { ForecastDataSourceKey, ForecastDataSourceValue },
+// { EmissionsDataSourceKey, EmissionsDataSourceValue },
+// { UsernameKey, Username },
+// { PasswordKey, Password },
+// { ProxyUrl, "http://fakeproxy:8080" },
+// { UseProxyKey, "true" },
+// };
- var configuration = new ConfigurationBuilder()
- .AddInMemoryCollection(settings)
- .AddEnvironmentVariables()
- .Build();
- var serviceCollection = new ServiceCollection();
- serviceCollection.AddWattTimeForecastDataSource(configuration.DataSources());
- var serviceProvider = serviceCollection.BuildServiceProvider();
- var client = serviceProvider.GetRequiredService();
+// var configuration = new ConfigurationBuilder()
+// .AddInMemoryCollection(settings)
+// .AddEnvironmentVariables()
+// .Build();
+// var serviceCollection = new ServiceCollection();
+// serviceCollection.AddWattTimeForecastDataSource(configuration.DataSources());
+// var serviceProvider = serviceCollection.BuildServiceProvider();
+// var client = serviceProvider.GetRequiredService();
- // Act & Assert
- Assert.ThrowsAsync(async () => await client.GetBalancingAuthorityAsync("lat", "long"));
- }
+// // Act & Assert
+// Assert.ThrowsAsync(async () => await client.GetBalancingAuthorityAsync("lat", "long"));
+// }
- [Test]
- public void ClientProxyTest_With_Missing_ProxyURL_ThrowsException()
- {
- // Arrange
- var settings = new Dictionary {
- { ForecastDataSourceKey, ForecastDataSourceValue },
- { EmissionsDataSourceKey, EmissionsDataSourceValue },
- { UsernameKey, Username },
- { PasswordKey, Password },
- { UseProxyKey, "true" },
- };
+// [Test]
+// public void ClientProxyTest_With_Missing_ProxyURL_ThrowsException()
+// {
+// // Arrange
+// var settings = new Dictionary {
+// { ForecastDataSourceKey, ForecastDataSourceValue },
+// { EmissionsDataSourceKey, EmissionsDataSourceValue },
+// { UsernameKey, Username },
+// { PasswordKey, Password },
+// { UseProxyKey, "true" },
+// };
- var configuration = new ConfigurationBuilder()
- .AddInMemoryCollection(settings)
- .AddEnvironmentVariables()
- .Build();
- var serviceCollection = new ServiceCollection();
+// var configuration = new ConfigurationBuilder()
+// .AddInMemoryCollection(settings)
+// .AddEnvironmentVariables()
+// .Build();
+// var serviceCollection = new ServiceCollection();
- // Act & Assert
- Assert.Throws(() => serviceCollection.AddWattTimeForecastDataSource(configuration.DataSources()));
- Assert.Throws(() => serviceCollection.AddWattTimeEmissionsDataSource(configuration.DataSources()));
- }
+// // Act & Assert
+// Assert.Throws(() => serviceCollection.AddWattTimeForecastDataSource(configuration.DataSources()));
+// Assert.Throws(() => serviceCollection.AddWattTimeEmissionsDataSource(configuration.DataSources()));
+// }
- [TestCase(true, TestName = "ClientProxyTest, successful: denotes adding WattTime data sources using proxy.")]
- [TestCase(false, TestName = "ClientProxyTest, successful: denotes adding WattTime data sources without using proxy.")]
- public void ClientProxyTest_AddsDataSource(bool withProxyUrl)
- {
- // Arrange
- var settings = new Dictionary {
- { ForecastDataSourceKey, ForecastDataSourceValue },
- { EmissionsDataSourceKey, EmissionsDataSourceValue },
- { UsernameKey, Username },
- { PasswordKey, Password },
- { UseProxyKey, withProxyUrl.ToString() }
- };
+// [TestCase(true, TestName = "ClientProxyTest, successful: denotes adding WattTime data sources using proxy.")]
+// [TestCase(false, TestName = "ClientProxyTest, successful: denotes adding WattTime data sources without using proxy.")]
+// public void ClientProxyTest_AddsDataSource(bool withProxyUrl)
+// {
+// // Arrange
+// var settings = new Dictionary {
+// { ForecastDataSourceKey, ForecastDataSourceValue },
+// { EmissionsDataSourceKey, EmissionsDataSourceValue },
+// { UsernameKey, Username },
+// { PasswordKey, Password },
+// { UseProxyKey, withProxyUrl.ToString() }
+// };
- if (withProxyUrl)
- {
- settings.Add(ProxyUrl, "http://10.10.10.1");
- settings.Add(ProxyUsername, "proxyUsername");
- settings.Add(ProxyPassword, "proxyPassword");
- }
+// if (withProxyUrl)
+// {
+// settings.Add(ProxyUrl, "http://10.10.10.1");
+// settings.Add(ProxyUsername, "proxyUsername");
+// settings.Add(ProxyPassword, "proxyPassword");
+// }
- var configuration = new ConfigurationBuilder()
- .AddInMemoryCollection(settings)
- .AddEnvironmentVariables()
- .Build();
- var serviceCollection = new ServiceCollection();
+// var configuration = new ConfigurationBuilder()
+// .AddInMemoryCollection(settings)
+// .AddEnvironmentVariables()
+// .Build();
+// var serviceCollection = new ServiceCollection();
- // Act
- var forecastDataSource = serviceCollection.AddWattTimeEmissionsDataSource(configuration.DataSources());
- var emissionsDataSource = serviceCollection.AddWattTimeForecastDataSource(configuration.DataSources());
+// // Act
+// var forecastDataSource = serviceCollection.AddWattTimeEmissionsDataSource(configuration.DataSources());
+// var emissionsDataSource = serviceCollection.AddWattTimeForecastDataSource(configuration.DataSources());
- // Assert
- Assert.That(forecastDataSource, Is.Not.Null);
- Assert.That(emissionsDataSource, Is.Not.Null);
- }
-}
\ No newline at end of file
+// // Assert
+// Assert.That(forecastDataSource, Is.Not.Null);
+// Assert.That(emissionsDataSource, Is.Not.Null);
+// }
+// }
\ No newline at end of file
diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/Configuration/WattTimeClientConfigurationTests.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/Configuration/WattTimeClientConfigurationTests.cs
index 69c666c40..008888d06 100644
--- a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/Configuration/WattTimeClientConfigurationTests.cs
+++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/Configuration/WattTimeClientConfigurationTests.cs
@@ -26,8 +26,7 @@ public void Validate_DoesNotThrow(string? username, string? password, string? ur
[TestCase("testuser", "12345", "not a url", TestName = "Validate throws: username; password; bad url")]
[TestCase(null, "12345", "http://example.com", TestName = "Validate throws: no username; password; url")]
- [TestCase("testuser", null, "http://example.com", TestName = "Validate throws: no username; password; url")]
- [TestCase(null, "password", "http://example.com", TestName = "Validate throws: username; no password; url")]
+ [TestCase("testuser", null, "http://example.com", TestName = "Validate throws: username; no password; url")]
public void Validate_Throws(string? username, string? password, string? url)
{
diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/WattTimeDataSourceTests.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/WattTimeDataSourceTests.cs
index 9d721cf56..3cadb1648 100644
--- a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/WattTimeDataSourceTests.cs
+++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/WattTimeDataSourceTests.cs
@@ -1,14 +1,18 @@
-using CarbonAware.DataSources.WattTime.Client;
+using CarbonAware.Configuration;
+using CarbonAware.DataSources.WattTime.Client;
using CarbonAware.DataSources.WattTime.Model;
using CarbonAware.Exceptions;
using CarbonAware.Interfaces;
using CarbonAware.Model;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Net.Http;
using System.Threading.Tasks;
namespace CarbonAware.DataSources.WattTime.Tests;
@@ -35,6 +39,14 @@ class WattTimeDataSourceTests
private const double GRAMS_TO_POUNDS = 0.00220462262185;
private const double KWH_TO_MWH = 0.001;
+ private readonly string TypeKey = $"Configurations:WattTime:Type";
+ private readonly string UsernameKey = $"Configurations:WattTime:Username";
+ private readonly string PasswordKey = $"Configurations:WattTime:Password";
+ private readonly string UseProxyKey = $"Configurations:WattTime:Proxy:UseProxy";
+ private readonly string ProxyUrlKey = $"Configurations:WattTime:Proxy:Url";
+ private readonly string ProxyUsernameKey = $"Configurations:WattTime:Proxy:Username";
+ private readonly string ProxyPasswordKey = $"Configurations:WattTime:Proxy:Password";
+
[SetUp]
public void Setup()
@@ -288,6 +300,81 @@ public async Task GetCarbonIntensity_CalculatesDurationBasedOnFrequency(double[]
CollectionAssert.AreEqual(expectedDurationList, actualDurationList);
}
+ [Test]
+ public void ConfigureDI_ClientProxyTest_With_Missing_ProxyURL_ThrowsException()
+ {
+ // Arrange
+ var inMemorySettings = new Dictionary {
+ { TypeKey, "WattTime" },
+ { UsernameKey, "testUsername" },
+ { PasswordKey, "testPassword123!" },
+ { UseProxyKey, "true" },
+ };
+
+ var configuration = new ConfigurationBuilder()
+ .AddInMemoryCollection(inMemorySettings)
+ .Build();
+
+ var dataSourceConfig = new DataSourcesConfiguration()
+ {
+ EmissionsDataSource = "WattTime",
+ ForecastDataSource = "WattTime",
+ Section = configuration.GetSection("Configurations")
+ };
+
+ var serviceCollection = new ServiceCollection();
+
+ // Act & Assert
+ Assert.Throws(() => WattTimeDataSource.ConfigureDI(serviceCollection, dataSourceConfig));
+ Assert.Throws(() => WattTimeDataSource.ConfigureDI(serviceCollection, dataSourceConfig));
+ }
+
+ [TestCase(true, TestName = "ClientProxyTest, successful: denotes adding WattTime data sources using proxy.")]
+ [TestCase(false, TestName = "ClientProxyTest, successful: denotes adding WattTime data sources without using proxy.")]
+ public void ConfigureDI_ClientProxyTest_AddsDataSource(bool withProxyUrl)
+ {
+ // Arrange
+ var inMemorySettings = new Dictionary {
+ { TypeKey, "WattTime" },
+ { UsernameKey, "testUsername" },
+ { PasswordKey, "testPassword123!" },
+ { UseProxyKey, withProxyUrl.ToString() },
+ };
+
+ if (withProxyUrl)
+ {
+ inMemorySettings.Add(ProxyUrlKey, "http://10.10.10.1");
+ inMemorySettings.Add(ProxyUsernameKey, "proxyUsername");
+ inMemorySettings.Add(ProxyPasswordKey, "proxyPassword");
+ }
+
+ var configuration = new ConfigurationBuilder()
+ .AddInMemoryCollection(inMemorySettings)
+ .Build();
+
+ var dataSourceConfig = new DataSourcesConfiguration()
+ {
+ EmissionsDataSource = "WattTime",
+ ForecastDataSource = "WattTime",
+ Section = configuration.GetSection("Configurations")
+ };
+
+ var serviceCollection = new ServiceCollection();
+ var emissionsDescriptor = new ServiceDescriptor(typeof(IEmissionsDataSource), typeof(WattTimeDataSource), ServiceLifetime.Singleton);
+ var forecastDescriptor = new ServiceDescriptor(typeof(IForecastDataSource), typeof(WattTimeDataSource), ServiceLifetime.Singleton);
+
+ Assert.That(!serviceCollection.Any( i => i.ToString() == emissionsDescriptor.ToString()));
+ Assert.That(!serviceCollection.Any( i => i.ToString() == forecastDescriptor.ToString()));
+
+ // Act
+ WattTimeDataSource.ConfigureDI(serviceCollection, dataSourceConfig);
+ WattTimeDataSource.ConfigureDI(serviceCollection, dataSourceConfig);
+
+ // Assert
+ Assert.That(serviceCollection.Any( i => i.ToString() == emissionsDescriptor.ToString()));
+ Assert.That(serviceCollection.Any( i => i.ToString() == forecastDescriptor.ToString()));
+ }
+
private void MockBalancingAuthorityLocationMapping()
{
this.LocationSource.Setup(r => r.ToGeopositionLocationAsync(this.DefaultLocation)).Returns(Task.FromResult(this.DefaultLocation));
diff --git a/src/CarbonAware.Tools/CarbonAware.Tools.AzureRegionTestDataGenerator/Properties/launchSettings.json b/src/CarbonAware.Tools/CarbonAware.Tools.AzureRegionTestDataGenerator/Properties/launchSettings.json
new file mode 100644
index 000000000..33504c948
--- /dev/null
+++ b/src/CarbonAware.Tools/CarbonAware.Tools.AzureRegionTestDataGenerator/Properties/launchSettings.json
@@ -0,0 +1,8 @@
+{
+ "profiles": {
+ "WSL": {
+ "commandName": "WSL2",
+ "distributionName": ""
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/CarbonAware.WebApi/src/CarbonAware.WebApi.csproj b/src/CarbonAware.WebApi/src/CarbonAware.WebApi.csproj
index 356e23088..c487e77d9 100644
--- a/src/CarbonAware.WebApi/src/CarbonAware.WebApi.csproj
+++ b/src/CarbonAware.WebApi/src/CarbonAware.WebApi.csproj
@@ -29,6 +29,10 @@
+
+
+
+
diff --git a/src/CarbonAware.WebApi/src/Program.cs b/src/CarbonAware.WebApi/src/Program.cs
index 9a70c15ab..995ea034b 100644
--- a/src/CarbonAware.WebApi/src/Program.cs
+++ b/src/CarbonAware.WebApi/src/Program.cs
@@ -1,9 +1,9 @@
using CarbonAware;
using CarbonAware.WebApi.Configuration;
-using Microsoft.AspNetCore.StaticFiles;
using CarbonAware.WebApi.Filters;
using GSF.CarbonAware.Configuration;
using GSF.CarbonAware.Exceptions;
+using Microsoft.AspNetCore.StaticFiles;
using Microsoft.OpenApi.Models;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
diff --git a/src/CarbonAware.WebApi/test/integrationTests/CarbonAware.WebApi.IntegrationTests.csproj b/src/CarbonAware.WebApi/test/integrationTests/CarbonAware.WebApi.IntegrationTests.csproj
index df1ed5ada..8cad60d2e 100644
--- a/src/CarbonAware.WebApi/test/integrationTests/CarbonAware.WebApi.IntegrationTests.csproj
+++ b/src/CarbonAware.WebApi/test/integrationTests/CarbonAware.WebApi.IntegrationTests.csproj
@@ -28,9 +28,9 @@
Include="..\..\..\CarbonAware.DataSources\CarbonAware.DataSources.WattTime\mock\CarbonAware.DataSources.WattTime.Mocks.csproj" />
-
+ Include="..\..\..\CarbonAware.DataSources\CarbonAware.DataSources.ElectricityMapsFree\mock\CarbonAware.DataSources.ElectricityMapsFree.Mocks.csproj" />
+
diff --git a/src/CarbonAware.WebApi/test/integrationTests/CarbonAwareControllerTests.cs b/src/CarbonAware.WebApi/test/integrationTests/CarbonAwareControllerTests.cs
index 700c3ffc8..9da43e4fc 100644
--- a/src/CarbonAware.WebApi/test/integrationTests/CarbonAwareControllerTests.cs
+++ b/src/CarbonAware.WebApi/test/integrationTests/CarbonAwareControllerTests.cs
@@ -1,4 +1,3 @@
-using CarbonAware.DataSources.Configuration;
using CarbonAware.WebApi.IntegrationTests;
using CarbonAware.WebApi.Models;
using NUnit.Framework;
@@ -69,8 +68,8 @@ public async Task BestLocations_ReturnsOK(DateTimeOffset start, DateTimeOffset e
Assert.That(result.StatusCode, Is.EqualTo(HttpStatusCode.OK));
}
- [TestCase("location", "", TestName = "empty location query string")]
- [TestCase("non-location-param", "", TestName = "location param not present")]
+ [TestCase("location", "", TestName = "BestLocations_EmptyLocationQueryString: empty location query string")]
+ [TestCase("non-location-param", "", TestName = "BestLocations_EmptyLocationQueryString: location param not present")]
public async Task BestLocations_EmptyLocationQueryString_ReturnsBadRequest(string queryString, string value)
{
//Call the private method to construct with parameters
@@ -107,7 +106,7 @@ public async Task EmissionsForecastsCurrent_SupportedDataSources_ReturnsOk()
[Test]
public async Task EmissionsForecastsCurrent_StartAndEndOutsideWindow_ReturnsBadRequest()
{
- IgnoreTestForDataSource("data source does not implement '/emissions/forecasts/current'", DataSourceType.JSON);
+ IgnoreTestForDataSource($"data source does not implement '{currentForecastURI}'", DataSourceType.JSON, DataSourceType.ElectricityMapsFree);
_dataSourceMocker?.SetupForecastMock();
@@ -130,7 +129,7 @@ public async Task EmissionsForecastsCurrent_StartAndEndOutsideWindow_ReturnsBadR
public async Task EmissionsForecastsCurrent_InvalidLocationQueryString_ReturnsBadRequest(string queryString, string value)
{
- IgnoreTestForDataSource("data source does not implement '/emissions/forecasts/current'", DataSourceType.JSON);
+ IgnoreTestForDataSource($"data source does not implement '{currentForecastURI}'", DataSourceType.JSON, DataSourceType.ElectricityMapsFree);
_dataSourceMocker?.SetupForecastMock();
@@ -150,7 +149,7 @@ public async Task EmissionsForecastsCurrent_InvalidLocationQueryString_ReturnsBa
[TestCase("eastus", "2021-9-1T08:30:00Z", TestName = "EmissionsForecastsBatch returns BadRequest for wrong date format")]
public async Task EmissionsForecastsBatch_MissingRequiredParams_ReturnsBadRequest(string location, string requestedAt)
{
- IgnoreTestForDataSource("data source does not implement '/emissions/forecasts/batch'", DataSourceType.JSON);
+ IgnoreTestForDataSource($"data source does not implement '{batchForecastURI}'", DataSourceType.JSON, DataSourceType.ElectricityMapsFree);
_dataSourceMocker?.SetupForecastMock();
var forecastData = Enumerable.Range(0, 1).Select(x => new
@@ -242,6 +241,8 @@ public async Task EmissionsMarginalCarbonIntensity_ReturnsOk(string start, strin
[TestCase("non-location-param", "", TestName = "EmissionsMarginalCarbonIntensity returns BadRequest for location not present")]
public async Task EmissionsMarginalCarbonIntensity_EmptyLocationQueryString_ReturnsBadRequest(string queryString, string value)
{
+ IgnoreTestForDataSource($"data source does not implement '{averageCarbonIntensityURI}'", DataSourceType.ElectricityMapsFree);
+
var queryStrings = new Dictionary();
queryStrings[queryString] = value;
@@ -259,6 +260,8 @@ public async Task EmissionsMarginalCarbonIntensity_EmptyLocationQueryString_Retu
[TestCase("westus", "2022-3-1T15:30:00Z", "2022-3-1T18:00:00Z", TestName = "EmissionsMarginalCarbonIntensityBatch returns BadRequest for wrong date format")]
public async Task EmissionsMarginalCarbonIntensityBatch_MissingRequiredParams_ReturnsBadRequest(string location, string startTime, string endTime)
{
+ IgnoreTestForDataSource($"data source does not implement '{batchAverageCarbonIntensityURI}'", DataSourceType.ElectricityMapsFree);
+
var intesityData = Enumerable.Range(0, 1).Select(x => new
{
location = location,
diff --git a/src/CarbonAware.WebApi/test/integrationTests/IntegrationTestingBase.cs b/src/CarbonAware.WebApi/test/integrationTests/IntegrationTestingBase.cs
index 5dcb499bd..41771fefd 100644
--- a/src/CarbonAware.WebApi/test/integrationTests/IntegrationTestingBase.cs
+++ b/src/CarbonAware.WebApi/test/integrationTests/IntegrationTestingBase.cs
@@ -1,7 +1,7 @@
-using CarbonAware.DataSources.Configuration;
-using CarbonAware.Interfaces;
+using CarbonAware.Interfaces;
using CarbonAware.DataSources.Json.Mocks;
using CarbonAware.DataSources.ElectricityMaps.Mocks;
+using CarbonAware.DataSources.ElectricityMapsFree.Mocks;
using CarbonAware.DataSources.WattTime.Mocks;
using Microsoft.AspNetCore.Mvc.Testing;
using NUnit.Framework;
@@ -12,6 +12,15 @@
namespace CarbonAware.WebApi.IntegrationTests;
+public enum DataSourceType
+{
+ None,
+ WattTime,
+ JSON,
+ ElectricityMaps,
+ ElectricityMapsFree,
+}
+
///
/// A base class that does all the common setup for the Integration Testing
/// Overrides WebAPI factory by switching out different configurations via _datasource
@@ -112,6 +121,16 @@ public void Setup()
_dataSourceMocker = new ElectricityMapsDataSourceMocker();
break;
}
+ case DataSourceType.ElectricityMapsFree:
+ {
+ Environment.SetEnvironmentVariable("DataSources__EmissionsDataSource", "ElectricityMapsFree");
+ Environment.SetEnvironmentVariable("DataSources__ForecastDataSource", "");
+ Environment.SetEnvironmentVariable("DataSources__Configurations__ElectricityMapsFree__Type", "ElectricityMapsFree");
+ Environment.SetEnvironmentVariable("DataSources__Configurations__ElectricityMapsFree__Token", "test");
+
+ _dataSourceMocker = new ElectricityMapsFreeDataSourceMocker();
+ break;
+ }
case DataSourceType.None:
{
Environment.SetEnvironmentVariable("DataSources__EmissionsDataSource", "");
diff --git a/src/CarbonAware.WebApi/test/integrationTests/LocationsControllerTests.cs b/src/CarbonAware.WebApi/test/integrationTests/LocationsControllerTests.cs
index 1a1fd79c1..1049abd88 100644
--- a/src/CarbonAware.WebApi/test/integrationTests/LocationsControllerTests.cs
+++ b/src/CarbonAware.WebApi/test/integrationTests/LocationsControllerTests.cs
@@ -1,4 +1,3 @@
-using CarbonAware.DataSources.Configuration;
using CarbonAware.WebApi.IntegrationTests;
using NUnit.Framework;
using System.Net;
diff --git a/src/CarbonAware.WebApi/test/integrationTests/UnconfiguredWebApiTests.cs b/src/CarbonAware.WebApi/test/integrationTests/UnconfiguredWebApiTests.cs
deleted file mode 100644
index 665b3884a..000000000
--- a/src/CarbonAware.WebApi/test/integrationTests/UnconfiguredWebApiTests.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using CarbonAware.DataSources.Configuration;
-using NUnit.Framework;
-using System.Net;
-
-namespace CarbonAware.WebApi.IntegrationTests;
-
-///
-/// Tests that the Web API starts without configuration.
-///
-[TestFixture(DataSourceType.None)]
-class UnconfiguredWebApiTests : IntegrationTestingBase
-{
- private readonly string healthURI = "/health";
- private readonly string fakeURI = "/fake-endpoint";
-
- public UnconfiguredWebApiTests(DataSourceType dataSource) : base(dataSource) { }
-
- [Test]
- public async Task HealthCheck_ReturnsOK()
- {
- //Use client to get endpoint
- var result = await _client.GetAsync(healthURI);
- Assert.That(result, Is.Not.Null);
- Assert.That(result.StatusCode, Is.EqualTo(HttpStatusCode.OK));
- }
-
- [Test]
- public async Task FakeEndPoint_ReturnsNotFound()
- {
- var result = await _client.GetAsync(fakeURI);
- Assert.That(result, Is.Not.Null);
- Assert.That(result.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
- }
-}
\ No newline at end of file
diff --git a/src/CarbonAware/src/CarbonAware.csproj b/src/CarbonAware/src/CarbonAware.csproj
index d691e0f80..3e8ec44e4 100644
--- a/src/CarbonAware/src/CarbonAware.csproj
+++ b/src/CarbonAware/src/CarbonAware.csproj
@@ -31,7 +31,6 @@
-
diff --git a/src/CarbonAware/src/Configuration/DataSourcesConfiguration.cs b/src/CarbonAware/src/Configuration/DataSourcesConfiguration.cs
index 7b54c9c51..8b738ce1a 100644
--- a/src/CarbonAware/src/Configuration/DataSourcesConfiguration.cs
+++ b/src/CarbonAware/src/Configuration/DataSourcesConfiguration.cs
@@ -1,4 +1,5 @@
-using Microsoft.Extensions.Configuration;
+using CarbonAware.Interfaces;
+using Microsoft.Extensions.Configuration;
namespace CarbonAware.Configuration;
internal class DataSourcesConfiguration
@@ -8,9 +9,29 @@ internal class DataSourcesConfiguration
#nullable enable
public string? EmissionsDataSource { get; set; }
public string? ForecastDataSource { get; set; }
- public IConfigurationSection? ConfigurationSection { get; set; }
+ public IConfigurationSection? Section { get; set; }
#nullable disable
+ ///
+ /// Gets the "Type" field for configuration object associated with a setting by data source interface type.
+ ///
+ /// Returns the string value of the associated "Type" field.
+ public string ConfigurationType() where T : IDataSource
+ {
+ if (typeof(T) == typeof(IEmissionsDataSource))
+ {
+ return EmissionsConfigurationType();
+ }
+ else if (typeof(T) == typeof(IForecastDataSource))
+ {
+ return ForecastConfigurationType();
+ }
+ else
+ {
+ throw new ArgumentException($"Data source interface type '{typeof(T)}' is not supported.");
+ }
+ }
+
///
/// Gets the "Type" field for configuration object associated with EmissionsDataSource setting.
///
@@ -29,6 +50,26 @@ public string ForecastConfigurationType()
return GetConfigurationType(ForecastDataSource);
}
+ ///
+ /// Gets the entire configuration object associated with a setting by data source interface type.
+ ///
+ /// Returns the of the associated data source interface.
+ public IConfigurationSection ConfigurationSection() where T : IDataSource
+ {
+ if (typeof(T) == typeof(IEmissionsDataSource))
+ {
+ return EmissionsConfigurationSection();
+ }
+ else if (typeof(T) == typeof(IForecastDataSource))
+ {
+ return ForecastConfigurationSection();
+ }
+ else
+ {
+ throw new ArgumentException($"Data source interface type '{typeof(T)}' is not supported.");
+ }
+ }
+
///
/// Gets the entire configuration object associated with EmissionsDataSource setting.
///
@@ -66,17 +107,17 @@ public void AssertValid()
private string GetConfigurationType(string dataSourceName)
{
- return ConfigurationSection.GetValue($"{dataSourceName}:Type");
+ return Section.GetValue($"{dataSourceName}:Type");
}
private IConfigurationSection GetConfigurationSection(string dataSourceName)
{
- return ConfigurationSection.GetSection(dataSourceName);
+ return Section.GetSection(dataSourceName);
}
private bool ConfigurationSectionContainsKey(string key)
{
- foreach (var subsection in ConfigurationSection.GetChildren())
+ foreach (var subsection in Section.GetChildren())
{
if (subsection.Key == key)
{
diff --git a/src/CarbonAware/src/Configuration/DataSourcesConfigurationExtensions.cs b/src/CarbonAware/src/Configuration/DataSourcesConfigurationExtensions.cs
index 6894b14c4..30aa90539 100644
--- a/src/CarbonAware/src/Configuration/DataSourcesConfigurationExtensions.cs
+++ b/src/CarbonAware/src/Configuration/DataSourcesConfigurationExtensions.cs
@@ -7,7 +7,7 @@ internal static class DataSourcesConfigurationExtensions
public static DataSourcesConfiguration DataSources(this IConfiguration configuration)
{
var dataSources = configuration.GetSection(DataSourcesConfiguration.Key).Get() ?? new DataSourcesConfiguration();
- dataSources.ConfigurationSection = configuration.GetSection($"{DataSourcesConfiguration.Key}:Configurations");
+ dataSources.Section = configuration.GetSection($"{DataSourcesConfiguration.Key}:Configurations");
dataSources.AssertValid();
return dataSources;
diff --git a/src/CarbonAware/src/Extensions/ServiceCollectionExtensions.cs b/src/CarbonAware/src/Extensions/ServiceCollectionExtensions.cs
new file mode 100644
index 000000000..8a1ecb486
--- /dev/null
+++ b/src/CarbonAware/src/Extensions/ServiceCollectionExtensions.cs
@@ -0,0 +1,80 @@
+using CarbonAware.Configuration;
+using CarbonAware.Exceptions;
+using CarbonAware.Interfaces;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using System.Reflection;
+
+namespace CarbonAware.Extensions;
+internal static class ServiceCollectionExtensions
+{
+ public static IServiceCollection AddDataSourceServices(this IServiceCollection services, IConfiguration configuration)
+ {
+ var noEmissionsDataSource = false;
+ var noForecastDataSource = false;
+
+ try
+ {
+ services.AddDataSource(configuration);
+ }
+ catch (Exception)
+ {
+ services.TryAddSingleton();
+ noEmissionsDataSource = true;
+ }
+
+ try
+ {
+ services.AddDataSource(configuration);
+ }
+ catch (Exception)
+ {
+ services.TryAddSingleton();
+ noForecastDataSource = true;
+ }
+
+ if (noEmissionsDataSource && noForecastDataSource)
+ {
+ throw new ConfigurationException("No data sources are configured");
+ }
+
+ return services;
+ }
+
+ public static IServiceCollection AddDataSource(this IServiceCollection services, IConfiguration configuration)
+ where T : IDataSource
+ {
+ // Get the config
+ var dataSources = configuration.DataSources();
+
+ // Load the assembly for the configured IDataSource interface, T.
+ Assembly assembly;
+ try
+ {
+ assembly = Assembly.Load($"CarbonAware.DataSources.{dataSources.ConfigurationType()}");
+ } catch (Exception e)
+ {
+ throw new ConfigurationException($"Could not load assembly for data source '{dataSources.ConfigurationType()}'", e);
+ }
+
+
+ // Get the classes that implement the interface, T.
+ // Pick the first, because we only expect one per interface.
+ Type dataSourceType = assembly.GetTypes()
+ .Where(type => typeof(T).IsAssignableFrom(type) && !type.IsInterface && !type.IsAbstract)
+ .First() ?? throw new ConfigurationException("No data sources are configured");
+
+ // Call static configuration method on the data source to allow it
+ // to configure itself and its dependencies.
+ MethodInfo configureMethod = dataSourceType.GetMethod(
+ "ConfigureDI",
+ BindingFlags.Static
+ | BindingFlags.Public)
+ ?.MakeGenericMethod(typeof(T)) ?? throw new ConfigurationException("No data method 'ConfigureDI' is configured");
+
+ configureMethod.Invoke(null, new Object[2] {services, dataSources});
+
+ return services;
+ }
+}
diff --git a/src/CarbonAware/src/Interfaces/IDataSource.cs b/src/CarbonAware/src/Interfaces/IDataSource.cs
new file mode 100644
index 000000000..98e1d3e3d
--- /dev/null
+++ b/src/CarbonAware/src/Interfaces/IDataSource.cs
@@ -0,0 +1,12 @@
+using CarbonAware.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace CarbonAware.Interfaces;
+
+internal interface IDataSource
+{
+ public static IServiceCollection ConfigureDI(IServiceCollection services, DataSourcesConfiguration dataSourcesConfig)
+ {
+ throw new NotImplementedException();
+ }
+}
\ No newline at end of file
diff --git a/src/CarbonAware/src/Interfaces/IEmissionsDataSource.cs b/src/CarbonAware/src/Interfaces/IEmissionsDataSource.cs
index fa9351a40..56808ce13 100644
--- a/src/CarbonAware/src/Interfaces/IEmissionsDataSource.cs
+++ b/src/CarbonAware/src/Interfaces/IEmissionsDataSource.cs
@@ -1,6 +1,6 @@
namespace CarbonAware.Interfaces;
-internal interface IEmissionsDataSource
+internal interface IEmissionsDataSource : IDataSource
{
///
/// Gets the carbon intensity for multiple locations for a given start and end time
diff --git a/src/CarbonAware/src/Interfaces/IForecastDataSource.cs b/src/CarbonAware/src/Interfaces/IForecastDataSource.cs
index cd8d06c08..cbfc0b8fa 100644
--- a/src/CarbonAware/src/Interfaces/IForecastDataSource.cs
+++ b/src/CarbonAware/src/Interfaces/IForecastDataSource.cs
@@ -1,6 +1,6 @@
namespace CarbonAware.Interfaces;
-internal interface IForecastDataSource
+internal interface IForecastDataSource : IDataSource
{
///
/// Gets the current forecasted carbon intensity for a location
diff --git a/src/CarbonAware/test/Configuration/DataSourcesConfigurationTests.cs b/src/CarbonAware/test/Configuration/DataSourcesConfigurationTests.cs
index 671435bbb..26787f6c2 100644
--- a/src/CarbonAware/test/Configuration/DataSourcesConfigurationTests.cs
+++ b/src/CarbonAware/test/Configuration/DataSourcesConfigurationTests.cs
@@ -27,7 +27,7 @@ public void AssertValid_WithAtleastOneDataSourceConfigured_DoesNotThrowException
{
EmissionsDataSource = emissionsDataSource,
ForecastDataSource = forecastDataSource,
- ConfigurationSection = configuration.GetSection("Configurations")
+ Section = configuration.GetSection("Configurations")
};
Assert.DoesNotThrow(() => dataSourceConfig.AssertValid());
@@ -51,7 +51,7 @@ public void AssertValid_DataSourceNotInConfigurationSection_ThrowsException(stri
{
EmissionsDataSource = emissionsDataSource,
ForecastDataSource = forecastDataSource,
- ConfigurationSection = configuration.GetSection("Configurations")
+ Section = configuration.GetSection("Configurations")
};
var ex = Assert.Throws(() => dataSourceConfig.AssertValid());
Assert.That(ex!.Message, Contains.Substring(errorMessage));
@@ -78,7 +78,7 @@ public void ConfigurationTypesAndSections_ReturnCorrectType(string forecastDataS
{
EmissionsDataSource = emissionsDataSource,
ForecastDataSource = forecastDataSource,
- ConfigurationSection = configuration.GetSection("Configurations")
+ Section = configuration.GetSection("Configurations")
};
// Act
diff --git a/src/CarbonAwareSDK.sln b/src/CarbonAwareSDK.sln
index 82672374a..06256aa9f 100644
--- a/src/CarbonAwareSDK.sln
+++ b/src/CarbonAwareSDK.sln
@@ -25,8 +25,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CarbonAware.DataSources.Wat
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CarbonAware.DataSources.WattTime", "CarbonAware.DataSources\CarbonAware.DataSources.WattTime\src\CarbonAware.DataSources.WattTime.csproj", "{12D19F2D-0427-4591-949D-0DCDEDACF5B2}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CarbonAware.DataSources.Registration", "CarbonAware.DataSources\CarbonAware.DataSources.Registration\CarbonAware.DataSources.Registration.csproj", "{5CFC4F4D-7E8D-4682-A659-35050C637FF4}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CarbonAware.LocationSources", "CarbonAware.LocationSources\src\CarbonAware.LocationSources.csproj", "{C120DB7C-E4D8-4A8F-B180-0C5D0D8C085C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CarbonAware.LocationSources.Test", "CarbonAware.LocationSources\test\CarbonAware.LocationSources.Test.csproj", "{F4BD1233-447F-4245-AE7B-A877427EB2D7}"
@@ -107,10 +105,6 @@ Global
{12D19F2D-0427-4591-949D-0DCDEDACF5B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{12D19F2D-0427-4591-949D-0DCDEDACF5B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{12D19F2D-0427-4591-949D-0DCDEDACF5B2}.Release|Any CPU.Build.0 = Release|Any CPU
- {5CFC4F4D-7E8D-4682-A659-35050C637FF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {5CFC4F4D-7E8D-4682-A659-35050C637FF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {5CFC4F4D-7E8D-4682-A659-35050C637FF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {5CFC4F4D-7E8D-4682-A659-35050C637FF4}.Release|Any CPU.Build.0 = Release|Any CPU
{C120DB7C-E4D8-4A8F-B180-0C5D0D8C085C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C120DB7C-E4D8-4A8F-B180-0C5D0D8C085C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C120DB7C-E4D8-4A8F-B180-0C5D0D8C085C}.Release|Any CPU.ActiveCfg = Release|Any CPU
diff --git a/src/GSF.CarbonAware/src/Configuration/ServiceCollectionExtensions.cs b/src/GSF.CarbonAware/src/Configuration/ServiceCollectionExtensions.cs
index 459351ae6..5be9ebc0a 100644
--- a/src/GSF.CarbonAware/src/Configuration/ServiceCollectionExtensions.cs
+++ b/src/GSF.CarbonAware/src/Configuration/ServiceCollectionExtensions.cs
@@ -1,5 +1,5 @@
-using CarbonAware.DataSources.Configuration;
using CarbonAware.Interfaces;
+using CarbonAware.Extensions;
using CarbonAware.LocationSources;
using CarbonAware.LocationSources.Configuration;
using GSF.CarbonAware.Handlers;
@@ -21,7 +21,7 @@ public static IServiceCollection AddEmissionsServices(this IServiceCollection se
configuration.GetSection(LocationDataSourcesConfiguration.Key).Bind(c);
});
services.TryAddSingleton();
- services.AddDataSourceService(configuration);
+ services.AddDataSourceServices(configuration);
services.TryAddSingleton();
services.TryAddSingleton();
return services;
@@ -37,7 +37,7 @@ public static IServiceCollection AddForecastServices(this IServiceCollection ser
configuration.GetSection(LocationDataSourcesConfiguration.Key).Bind(c);
});
services.TryAddSingleton();
- services.AddDataSourceService(configuration);
+ services.AddDataSourceServices(configuration);
services.TryAddSingleton();
services.TryAddSingleton();
return services;
diff --git a/src/GSF.CarbonAware/src/GSF.CarbonAware.csproj b/src/GSF.CarbonAware/src/GSF.CarbonAware.csproj
index f113e0b98..e90160bd1 100644
--- a/src/GSF.CarbonAware/src/GSF.CarbonAware.csproj
+++ b/src/GSF.CarbonAware/src/GSF.CarbonAware.csproj
@@ -18,9 +18,6 @@
-
diff --git a/src/GSF.CarbonAware/test/GSF.CarbonAware.Tests.csproj b/src/GSF.CarbonAware/test/GSF.CarbonAware.Tests.csproj
index 64e74590c..f742970ae 100644
--- a/src/GSF.CarbonAware/test/GSF.CarbonAware.Tests.csproj
+++ b/src/GSF.CarbonAware/test/GSF.CarbonAware.Tests.csproj
@@ -24,6 +24,8 @@
+
+
diff --git a/src/GSF.CarbonAware/test/Handlers/EmissionsHandlerTests.cs b/src/GSF.CarbonAware/test/Handlers/EmissionsHandlerTests.cs
index 1ee70763a..c628604c3 100644
--- a/src/GSF.CarbonAware/test/Handlers/EmissionsHandlerTests.cs
+++ b/src/GSF.CarbonAware/test/Handlers/EmissionsHandlerTests.cs
@@ -160,8 +160,8 @@ public async Task GetBestEmissionsDataAsync_ReturnsExpected()
}
[TestCase("2000-01-01T00:00:00Z", "2000-01-02T00:00:00Z", 0, TestName = "GetBestEmissionsDataAsync calls data source with expected dates: start & end")]
- [TestCase("2000-01-01T00:00:00Z", null, 1000, TestName = "GetBestEmissionsDataAsync calls data source with expected dates: only start")]
- [TestCase(null, null, 1000, TestName = "GetBestEmissionsDataAsync calls data source with expected dates: no start or end")]
+ [TestCase("2000-01-01T00:00:00Z", null, 10000, TestName = "GetBestEmissionsDataAsync calls data source with expected dates: only start")]
+ [TestCase(null, null, 10000, TestName = "GetBestEmissionsDataAsync calls data source with expected dates: no start or end")]
public async Task GetBestEmissionsDataAsync_CallsWithExpectedDates(DateTimeOffset? start, DateTimeOffset? end, long tickTolerance)
{
// Arrange
@@ -203,7 +203,7 @@ public async Task GetBestEmissionsDataAsync_CallsWithExpectedDates(DateTimeOffse
// Because this method uses DateTimeOffset.UtcNow as a default, we cannot precisely check our date expectations
// so instead, we test that the dates are within a tolerable range using DateTimeOffset Ticks.
// 1 Second == 10,000,000 Ticks
- // 1000 Ticks == 0.1 Milliseconds
+ // 10,000 Ticks == 1 Millisecond
var minAllowableStartTicks = expectedStart.Ticks - tickTolerance;
var maxAllowableStartTicks = expectedStart.Ticks + tickTolerance;
var minAllowableEndTicks = expectedEnd.Ticks - tickTolerance;