Skip to content

Commit

Permalink
next batch of unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
romankr committed Nov 26, 2023
1 parent 80d2915 commit f7ed0e4
Show file tree
Hide file tree
Showing 16 changed files with 194 additions and 105 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using FluentAssertions;
using OddsCollector.Common.OddsApi.Configuration;

namespace OddsCollector.Common.Tests.OddsApi.Configuration;

internal sealed class OddsApiOptionsTests
{
[Test]
public void SetLeagues_WithValidLeague_ReturnsValidInstance()
{
string league = nameof(league);

var options = new OddsApiOptions();
options.SetLeagues(league);

options.Leagues.Should().NotBeNull().And.HaveCount(1);
options.Leagues.ElementAt(0).Should().NotBeNull().And.Be(league);
}

[Test]
public void SetLeagues_WithValidLeagues_ReturnsValidInstance()
{
var leagues = "league1;league2";

var options = new OddsApiOptions();
options.SetLeagues(leagues);

options.Leagues.Should().NotBeNull().And.HaveCount(2);
options.Leagues.ElementAt(0).Should().NotBeNull().And.Be("league1");
options.Leagues.ElementAt(1).Should().NotBeNull().And.Be("league2");
}

[Test]
public void SetLeagues_WithDuplicatedLeagues_ReturnsNewInstance()
{
var leagues = "league1;league1";

var options = new OddsApiOptions();
options.SetLeagues(leagues);

options.Leagues.Should().NotBeNull().And.HaveCount(1);
options.Leagues.ElementAt(0).Should().NotBeNull().And.Be("league1");
}

[TestCase("")]
[TestCase(null)]
public void SetLeagues_WithNullOrEmptyLeagues_ThrowsException(string? leagues)
{
var action = () =>
{
var options = new OddsApiOptions();
options.SetLeagues(leagues);
};

action.Should().Throw<ArgumentException>().WithParameterName(nameof(leagues));
}
}
14 changes: 0 additions & 14 deletions OddsCollector.Common/OddsApi/Configuration/LeaguesFactory.cs

This file was deleted.

10 changes: 10 additions & 0 deletions OddsCollector.Common/OddsApi/Configuration/OddsApiOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,14 @@ public class OddsApiOptions
[Required]
[SuppressMessage("Usage", "CA2227:Collection properties should be read only")]
public HashSet<string> Leagues { get; set; } = new();

public void SetLeagues(string? leagues)
{
if (string.IsNullOrEmpty(leagues))
{
throw new ArgumentException($"{nameof(leagues)} cannot be null or empty", nameof(leagues));
}

Leagues = leagues.Split(";").ToHashSet();
}
}
2 changes: 1 addition & 1 deletion OddsCollector.Functions.EventResults/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
services.Configure<OddsApiOptions>(o =>
{
// workaround for https://github.com/MicrosoftDocs/azure-docs/issues/32962
o.Leagues = LeaguesFactory.CreateLeagues(Environment.GetEnvironmentVariable("OddsApi:Leagues"));
o.SetLeagues(Environment.GetEnvironmentVariable("OddsApi:Leagues"));
});
services.AddHttpClient<Client>();
services.AddSingleton<IClient, Client>();
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="NSubstitute" Version="5.1.0" />
<PackageReference Include="NUnit" Version="3.14.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageReference Include="NUnit.Analyzers" Version="3.9.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,51 @@ namespace OddsCollector.Functions.Notification.CommunicationServices.Configurati

internal sealed class EmailSenderOptions
{
[Required(AllowEmptyStrings = false)] public string Connection { get; set; } = string.Empty;
[Required(AllowEmptyStrings = false)] public string ConnectionString { get; set; } = string.Empty;

[Required(AllowEmptyStrings = false)] public string RecipientAddress { get; set; } = string.Empty;

[Required(AllowEmptyStrings = false)] public string SenderAddress { get; set; } = string.Empty;

[Required(AllowEmptyStrings = false)] public string Subject { get; set; } = string.Empty;

public void SetConnectionString(string? connectionString)
{
if (string.IsNullOrEmpty(connectionString))
{
throw new ArgumentException($"{nameof(connectionString)} cannot be null or empty", nameof(connectionString));
}

ConnectionString = connectionString;
}

public void SetRecipientAddress(string? recipientAddress)
{
if (string.IsNullOrEmpty(recipientAddress))
{
throw new ArgumentException($"{nameof(recipientAddress)} cannot be null or empty", nameof(recipientAddress));
}

RecipientAddress = recipientAddress;
}

public void SetSenderAddress(string? senderAddress)
{
if (string.IsNullOrEmpty(senderAddress))
{
throw new ArgumentException($"{nameof(senderAddress)} cannot be null or empty", nameof(senderAddress));
}

SenderAddress = senderAddress;
}

public void SetSubject(string? subject)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException($"{nameof(subject)} cannot be null or empty", nameof(subject));
}

Subject = subject;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public async Task SendEmailAsync(IEnumerable<EventPrediction?> predictions)

var content = JsonSerializer.Serialize(predictions, new JsonSerializerOptions { WriteIndented = true });

var client = new EmailClient(_options.Connection);
var client = new EmailClient(_options.ConnectionString);

await client.SendAsync(WaitUntil.Completed, _options.SenderAddress, _options.RecipientAddress, _options.Subject,
content).ConfigureAwait(false);
Expand Down

This file was deleted.

26 changes: 26 additions & 0 deletions OddsCollector.Functions.Notification/CosmosDb/ContainerFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Microsoft.Azure.Cosmos;

namespace OddsCollector.Functions.Notification.CosmosDb;

internal static class ContainerFactory
{
public static Container CreateContainer(string? connectionString, string? databaseId, string? containerId)
{
if (string.IsNullOrEmpty(connectionString))
{
throw new ArgumentException($"{nameof(connectionString)} cannot be null or empty", nameof(connectionString));
}

if (string.IsNullOrEmpty(databaseId))
{
throw new ArgumentException($"{nameof(databaseId)} cannot be null or empty", nameof(databaseId));
}

if (string.IsNullOrEmpty(containerId))
{
throw new ArgumentException($"{nameof(containerId)} cannot be null or empty", nameof(containerId));
}

return new CosmosClient(connectionString).GetContainer(databaseId, containerId);
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
using Microsoft.Azure.Cosmos;
using Microsoft.Azure.Cosmos.Linq;
using Microsoft.Extensions.Options;
using OddsCollector.Common.Models;
using OddsCollector.Functions.Notification.CosmosDb.Configuration;

namespace OddsCollector.Functions.Notification.CosmosDb;

internal sealed class CosmosDbClient : ICosmosDbClient
{
private readonly Container _container;

public CosmosDbClient(IOptions<CosmosDbOptions> options)
public CosmosDbClient(Container container)
{
var client = new CosmosClient(options.Value.Connection);
_container = client.GetContainer(options.Value.Database, options.Value.Container);
_container = container ?? throw new ArgumentNullException(nameof(container));
}

public async Task<IEnumerable<EventPrediction?>> GetEventPredictionsAsync()
Expand Down
7 changes: 6 additions & 1 deletion OddsCollector.Functions.Notification/NotificationFunction.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
using Microsoft.Azure.Functions.Worker;
using System.Runtime.CompilerServices;
using Microsoft.Azure.Functions.Worker;
using OddsCollector.Functions.Notification.CommunicationServices;
using OddsCollector.Functions.Notification.CosmosDb;

[assembly: InternalsVisibleTo("OddsCollector.Functions.Notification.Tests")]
// DynamicProxyGenAssembly2 is a temporary assembly built by mocking systems that use CastleProxy
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

namespace OddsCollector.Functions.Notification;

internal sealed class NotificationFunction
Expand Down
25 changes: 12 additions & 13 deletions OddsCollector.Functions.Notification/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,26 @@
using OddsCollector.Functions.Notification.CommunicationServices;
using OddsCollector.Functions.Notification.CommunicationServices.Configuration;
using OddsCollector.Functions.Notification.CosmosDb;
using OddsCollector.Functions.Notification.CosmosDb.Configuration;

var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(services =>
{
// workaround for https://github.com/MicrosoftDocs/azure-docs/issues/32962
services.Configure<CosmosDbOptions>(o =>
{
o.Container = Environment.GetEnvironmentVariable("CosmosDb:Container");
o.Database = Environment.GetEnvironmentVariable("CosmosDb:Database");
o.Connection = Environment.GetEnvironmentVariable("CosmosDb:Connection");
});
// workaround for https://github.com/MicrosoftDocs/azure-docs/issues/32962
services.Configure<EmailSenderOptions>(o =>
{
o.Subject = Environment.GetEnvironmentVariable("EmailSender:Subject");
o.Connection = Environment.GetEnvironmentVariable("EmailSender:Connection");
o.RecipientAddress = Environment.GetEnvironmentVariable("EmailSender:RecipientAddress");
o.SenderAddress = Environment.GetEnvironmentVariable("EmailSender:SenderAddress");
// workaround for https://github.com/MicrosoftDocs/azure-docs/issues/32962
o.SetSubject(Environment.GetEnvironmentVariable("EmailSender:Subject"));
o.SetConnectionString(Environment.GetEnvironmentVariable("EmailSender:Connection"));
o.SetRecipientAddress(Environment.GetEnvironmentVariable("EmailSender:RecipientAddress"));
o.SetSenderAddress(Environment.GetEnvironmentVariable("EmailSender:SenderAddress"));
});
services.AddSingleton(
ContainerFactory.CreateContainer(
// workaround for https://github.com/MicrosoftDocs/azure-docs/issues/32962
Environment.GetEnvironmentVariable("CosmosDb:Connection"),
Environment.GetEnvironmentVariable("CosmosDb:Database"),
Environment.GetEnvironmentVariable("CosmosDb:Container")
));
services.AddSingleton<ICosmosDbClient, CosmosDbClient>();
services.AddSingleton<IEmailSender, EmailSender>();
services.AddApplicationInsightsTelemetryWorkerService();
Expand Down
2 changes: 1 addition & 1 deletion OddsCollector.Functions.UpcomingEvents/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
services.Configure<OddsApiOptions>(o =>
{
// workaround for https://github.com/MicrosoftDocs/azure-docs/issues/32962
o.Leagues = LeaguesFactory.CreateLeagues(Environment.GetEnvironmentVariable("OddsApi:Leagues"));
o.SetLeagues(Environment.GetEnvironmentVariable("OddsApi:Leagues"));
});
services.AddHttpClient<Client>();
services.AddSingleton<IClient, Client>();
Expand Down
12 changes: 9 additions & 3 deletions OddsCollector.sln
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OddsCollector.Functions.Eve
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OddsCollector.Common.Tests", "OddsCollector.Common.Tests\OddsCollector.Common.Tests.csproj", "{0A5F1BC2-027B-4474-9C7E-6B00C8CCF7CD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OddsCollector.Functions.EventResults.Tests", "OddsCollector.Functions.EventResults.Tests\OddsCollector.Functions.EventResults.Tests.csproj", "{406DE1F4-069B-4189-8AA2-994CC1140BC6}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OddsCollector.Functions.EventResults.Tests", "OddsCollector.Functions.EventResults.Tests\OddsCollector.Functions.EventResults.Tests.csproj", "{406DE1F4-069B-4189-8AA2-994CC1140BC6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OddsCollector.Functions.UpcomingEvents.Tests", "OddsCollector.Functions.UpcomingEvents.Tests\OddsCollector.Functions.UpcomingEvents.Tests.csproj", "{D2E01FC2-A174-40FC-BC56-6EE3FD640AE1}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OddsCollector.Functions.UpcomingEvents.Tests", "OddsCollector.Functions.UpcomingEvents.Tests\OddsCollector.Functions.UpcomingEvents.Tests.csproj", "{D2E01FC2-A174-40FC-BC56-6EE3FD640AE1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OddsCollector.Functions.Predictions.Tests", "OddsCollector.Functions.Predictions.Tests\OddsCollector.Functions.Predictions.Tests.csproj", "{296C1955-19D3-49E5-A4E5-E68424525E8E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OddsCollector.Functions.Predictions.Tests", "OddsCollector.Functions.Predictions.Tests\OddsCollector.Functions.Predictions.Tests.csproj", "{296C1955-19D3-49E5-A4E5-E68424525E8E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OddsCollector.Functions.Notification.Tests", "OddsCollector.Functions.Notification.Tests\OddsCollector.Functions.Notification.Tests.csproj", "{687A2464-8366-4077-8AE6-00F6E3D40905}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -63,6 +65,10 @@ Global
{296C1955-19D3-49E5-A4E5-E68424525E8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{296C1955-19D3-49E5-A4E5-E68424525E8E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{296C1955-19D3-49E5-A4E5-E68424525E8E}.Release|Any CPU.Build.0 = Release|Any CPU
{687A2464-8366-4077-8AE6-00F6E3D40905}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{687A2464-8366-4077-8AE6-00F6E3D40905}.Debug|Any CPU.Build.0 = Debug|Any CPU
{687A2464-8366-4077-8AE6-00F6E3D40905}.Release|Any CPU.ActiveCfg = Release|Any CPU
{687A2464-8366-4077-8AE6-00F6E3D40905}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down

0 comments on commit f7ed0e4

Please sign in to comment.