Skip to content

Commit 7065dce

Browse files
committed
Implement Dynamic DataSource registration
Signed-off-by: Bill DeRusha <[email protected]>
1 parent b3b3189 commit 7065dce

File tree

48 files changed

+670
-611
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+670
-611
lines changed

.vscode/launch.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@
3737
"uriFormat": "%s/swagger"
3838
},
3939
"env": {
40-
"ASPNETCORE_ENVIRONMENT": "Development"
40+
"ASPNETCORE_ENVIRONMENT": "Development",
41+
"DOTNET_HOSTBUILDER__RELOADCONFIGONCHANGE": "false"
4142
},
4243
"sourceFileMap": {
4344
"/Views": "${workspaceFolder}/Views"

src/CarbonAware.CLI/test/integrationTests/CarbonAware.CLI.IntegrationTests.csproj

-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
<ItemGroup>
1616
<ProjectReference
1717
Include="..\..\..\CarbonAware.DataSources\CarbonAware.DataSources.Json\mock\CarbonAware.DataSources.Json.Mocks.csproj" />
18-
<ProjectReference
19-
Include="..\..\..\CarbonAware.DataSources\CarbonAware.DataSources.Registration\CarbonAware.DataSources.Registration.csproj" />
2018
<ProjectReference
2119
Include="..\..\..\CarbonAware.DataSources\CarbonAware.DataSources.WattTime\mock\CarbonAware.DataSources.WattTime.Mocks.csproj" />
2220
<ProjectReference

src/CarbonAware.CLI/test/integrationTests/Commands/Emissions/EmissionsCommandTests.cs

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using CarbonAware.DataSources.Configuration;
21
using NUnit.Framework;
32
using System.Text.Json.Nodes;
43
using System.Text.RegularExpressions;

src/CarbonAware.CLI/test/integrationTests/Commands/EmissionsForecasts/EmissionsForecastsCommandTests.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using CarbonAware.DataSources.Configuration;
2-
using NUnit.Framework;
1+
using NUnit.Framework;
32
using System.Text.Json.Nodes;
43

54
namespace CarbonAware.CLI.IntegrationTests.Commands.EmissionsForecasts;

src/CarbonAware.CLI/test/integrationTests/Commands/Location/LocationCommandTests.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using CarbonAware.DataSources.Configuration;
2-
using NUnit.Framework;
1+
using NUnit.Framework;
32
using System.Text.Json;
43

54
namespace CarbonAware.CLI.IntegrationTests.Commands.Location;

src/CarbonAware.CLI/test/integrationTests/IntegrationTestingBase.cs

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using CarbonAware.DataSources.Configuration;
2-
using CarbonAware.Interfaces;
1+
using CarbonAware.Interfaces;
32
using CarbonAware.DataSources.ElectricityMaps.Mocks;
43
using CarbonAware.DataSources.ElectricityMapsFree.Mocks;
54
using CarbonAware.DataSources.Json.Mocks;
@@ -11,6 +10,15 @@
1110

1211
namespace CarbonAware.CLI.IntegrationTests;
1312

13+
public enum DataSourceType
14+
{
15+
None,
16+
WattTime,
17+
JSON,
18+
ElectricityMaps,
19+
ElectricityMapsFree,
20+
}
21+
1422
/// <summary>
1523
/// A base class that does all the common setup for the Integration Testing
1624
/// Overrides WebAPI factory by switching out different configurations via _datasource

src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/src/CarbonAware.DataSources.ElectricityMaps.csproj

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
<ItemGroup>
1111
<InternalsVisibleTo Include="CarbonAware.DataSources.ElectricityMaps.Mocks" />
1212
<InternalsVisibleTo Include="CarbonAware.DataSources.ElectricityMaps.Tests" />
13-
<InternalsVisibleTo Include="CarbonAware.DataSources.Registration" />
1413
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
1514
</ItemGroup>
1615

src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/src/Configuration/ServiceCollectionExtensions.cs

-56
This file was deleted.

src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/src/ElectricityMapsDataSource.cs

+50-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1+
using CarbonAware.Configuration;
12
using CarbonAware.DataSources.ElectricityMaps.Client;
3+
using CarbonAware.DataSources.ElectricityMaps.Configuration;
24
using CarbonAware.DataSources.ElectricityMaps.Model;
35
using CarbonAware.Exceptions;
46
using CarbonAware.Interfaces;
57
using CarbonAware.Model;
8+
using Microsoft.Extensions.Configuration;
9+
using Microsoft.Extensions.DependencyInjection;
10+
using Microsoft.Extensions.DependencyInjection.Extensions;
611
using Microsoft.Extensions.Logging;
7-
using System.Diagnostics;
12+
using System.Net;
813

914
namespace CarbonAware.DataSources.ElectricityMaps;
1015

@@ -40,6 +45,21 @@ public ElectricityMapsDataSource(ILogger<ElectricityMapsDataSource> logger, IEle
4045
this._locationSource = locationSource;
4146
}
4247

48+
public static IServiceCollection ConfigureDI<T>(IServiceCollection services, DataSourcesConfiguration dataSourcesConfig)
49+
where T : IDataSource
50+
{
51+
var configSection = dataSourcesConfig.ConfigurationSection<T>();
52+
AddElectricityMapsClient(services, configSection);
53+
try
54+
{
55+
services.TryAddSingleton(typeof(T), typeof(ElectricityMapsDataSource));
56+
} catch (Exception ex)
57+
{
58+
throw new ArgumentException($"ElectricityMapsDataSource is not a supported {typeof(T).Name} data source.", ex);
59+
}
60+
return services;
61+
}
62+
4363
/// <inheritdoc />
4464
public async Task<EmissionsForecast> GetCurrentCarbonIntensityForecastAsync(Location location)
4565
{
@@ -176,4 +196,33 @@ private TimeSpan GetDurationFromHistoryDataPoints(IEnumerable<CarbonIntensity> d
176196
// the absolute value of the TimeSpan between the two points.
177197
return first.DateTime.Subtract(second.DateTime).Duration();
178198
}
199+
200+
private static void AddElectricityMapsClient(IServiceCollection services, IConfigurationSection configSection)
201+
{
202+
services.Configure<ElectricityMapsClientConfiguration>(c =>
203+
{
204+
configSection.Bind(c);
205+
});
206+
207+
var httpClientBuilder = services.AddHttpClient<ElectricityMapsClient>(IElectricityMapsClient.NamedClient);
208+
209+
var Proxy = configSection.GetSection("Proxy").Get<WebProxyConfiguration>();
210+
if (Proxy?.UseProxy == true)
211+
{
212+
if (String.IsNullOrEmpty(Proxy.Url))
213+
{
214+
throw new ConfigurationException("Proxy Url is not configured.");
215+
}
216+
httpClientBuilder.ConfigurePrimaryHttpMessageHandler(() =>
217+
new HttpClientHandler() {
218+
Proxy = new WebProxy {
219+
Address = new Uri(Proxy.Url),
220+
Credentials = new NetworkCredential(Proxy.Username, Proxy.Password),
221+
BypassProxyOnLocal = true
222+
}
223+
}
224+
);
225+
}
226+
services.TryAddSingleton<IElectricityMapsClient, ElectricityMapsClient>();
227+
}
179228
}

src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/test/Configuration/ServiceCollectionExtensionTests.cs

-81
This file was deleted.

src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMaps/test/ElectricityMapsDataSourceTests.cs

+86
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
using CarbonAware.Configuration;
12
using CarbonAware.DataSources.ElectricityMaps.Client;
23
using CarbonAware.DataSources.ElectricityMaps.Model;
34
using CarbonAware.Exceptions;
45
using CarbonAware.Interfaces;
56
using CarbonAware.Model;
7+
using Microsoft.Extensions.Configuration;
8+
using Microsoft.Extensions.DependencyInjection;
69
using Microsoft.Extensions.Logging;
710
using Moq;
811

@@ -23,6 +26,14 @@ class ElectricityMapsDataSourceTests
2326
private static string _defaultLongitude => _defaultLocation.Longitude.ToString() ?? "";
2427
private static DateTimeOffset _defaultDataStartTime = new DateTimeOffset(2022, 4, 18, 12, 32, 42, TimeSpan.FromHours(-6));
2528

29+
private readonly string TypeKey = $"Configurations:ElectricityMaps:Type";
30+
private readonly string UsernameKey = $"Configurations:ElectricityMaps:Username";
31+
private readonly string PasswordKey = $"Configurations:ElectricityMaps:Password";
32+
private readonly string UseProxyKey = $"Configurations:ElectricityMaps:Proxy:UseProxy";
33+
private readonly string ProxyUrlKey = $"Configurations:ElectricityMaps:Proxy:Url";
34+
private readonly string ProxyUsernameKey = $"Configurations:ElectricityMaps:Proxy:Username";
35+
private readonly string ProxyPasswordKey = $"Configurations:ElectricityMaps:Proxy:Password";
36+
2637
[SetUp]
2738
public void Setup()
2839
{
@@ -324,4 +335,79 @@ public async Task GetDurationBetweenHistoryDataPoints_WhenMultipleDataPoints_Ret
324335
Assert.IsNotNull(second);
325336
Assert.That(second.Duration, Is.EqualTo(expectedDuration));
326337
}
338+
339+
[Test]
340+
public void ConfigureDI_ClientProxyTest_With_Missing_ProxyURL_ThrowsException()
341+
{
342+
// Arrange
343+
var inMemorySettings = new Dictionary<string, string> {
344+
{ TypeKey, "ElectricityMaps" },
345+
{ UsernameKey, "testUsername" },
346+
{ PasswordKey, "testPassword123!" },
347+
{ UseProxyKey, "true" },
348+
};
349+
350+
var configuration = new ConfigurationBuilder()
351+
.AddInMemoryCollection(inMemorySettings)
352+
.Build();
353+
354+
var dataSourceConfig = new DataSourcesConfiguration()
355+
{
356+
EmissionsDataSource = "ElectricityMaps",
357+
ForecastDataSource = "ElectricityMaps",
358+
Section = configuration.GetSection("Configurations")
359+
};
360+
361+
var serviceCollection = new ServiceCollection();
362+
363+
// Act & Assert
364+
Assert.Throws<ConfigurationException>(() => ElectricityMapsDataSource.ConfigureDI<IEmissionsDataSource>(serviceCollection, dataSourceConfig));
365+
Assert.Throws<ConfigurationException>(() => ElectricityMapsDataSource.ConfigureDI<IForecastDataSource>(serviceCollection, dataSourceConfig));
366+
}
367+
368+
[TestCase(true, TestName = "ClientProxyTest, successful: denotes adding ElectricityMaps data sources using proxy.")]
369+
[TestCase(false, TestName = "ClientProxyTest, successful: denotes adding ElectricityMaps data sources without using proxy.")]
370+
public void ConfigureDI_ClientProxyTest_AddsDataSource(bool withProxyUrl)
371+
{
372+
// Arrange
373+
var inMemorySettings = new Dictionary<string, string> {
374+
{ TypeKey, "ElectricityMaps" },
375+
{ UsernameKey, "testUsername" },
376+
{ PasswordKey, "testPassword123!" },
377+
{ UseProxyKey, withProxyUrl.ToString() },
378+
};
379+
380+
if (withProxyUrl)
381+
{
382+
inMemorySettings.Add(ProxyUrlKey, "http://10.10.10.1");
383+
inMemorySettings.Add(ProxyUsernameKey, "proxyUsername");
384+
inMemorySettings.Add(ProxyPasswordKey, "proxyPassword");
385+
}
386+
387+
var configuration = new ConfigurationBuilder()
388+
.AddInMemoryCollection(inMemorySettings)
389+
.Build();
390+
391+
var dataSourceConfig = new DataSourcesConfiguration()
392+
{
393+
EmissionsDataSource = "ElectricityMaps",
394+
ForecastDataSource = "ElectricityMaps",
395+
Section = configuration.GetSection("Configurations")
396+
};
397+
398+
var serviceCollection = new ServiceCollection();
399+
var emissionsDescriptor = new ServiceDescriptor(typeof(IEmissionsDataSource), typeof(ElectricityMapsDataSource), ServiceLifetime.Singleton);
400+
var forecastDescriptor = new ServiceDescriptor(typeof(IForecastDataSource), typeof(ElectricityMapsDataSource), ServiceLifetime.Singleton);
401+
402+
Assert.That(!serviceCollection.Any(i => i.ToString() == emissionsDescriptor.ToString()));
403+
Assert.That(!serviceCollection.Any(i => i.ToString() == forecastDescriptor.ToString()));
404+
405+
// Act
406+
ElectricityMapsDataSource.ConfigureDI<IEmissionsDataSource>(serviceCollection, dataSourceConfig);
407+
ElectricityMapsDataSource.ConfigureDI<IForecastDataSource>(serviceCollection, dataSourceConfig);
408+
409+
// Assert
410+
Assert.That(serviceCollection.Any(i => i.ToString() == emissionsDescriptor.ToString()));
411+
Assert.That(serviceCollection.Any(i => i.ToString() == forecastDescriptor.ToString()));
412+
}
327413
}

src/CarbonAware.DataSources/CarbonAware.DataSources.ElectricityMapsFree/mock/CarbonAware.DataSources.ElectricityMapsFree.Mocks.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
<ItemGroup>
1818
<InternalsVisibleTo Include="CarbonAware.CLI.IntegrationTests" />
19+
<InternalsVisibleTo Include="CarbonAware.WebApi.IntegrationTests" />
1920
</ItemGroup>
2021

2122
</Project>

0 commit comments

Comments
 (0)