diff --git a/OddsCollector.Common.Tests/OddsApi/Client/OddsClientTests.cs b/OddsCollector.Common.Tests/OddsApi/Client/OddsApiClientTests.cs similarity index 61% rename from OddsCollector.Common.Tests/OddsApi/Client/OddsClientTests.cs rename to OddsCollector.Common.Tests/OddsApi/Client/OddsApiClientTests.cs index 468ba9d..6a0ee0a 100644 --- a/OddsCollector.Common.Tests/OddsApi/Client/OddsClientTests.cs +++ b/OddsCollector.Common.Tests/OddsApi/Client/OddsApiClientTests.cs @@ -1,36 +1,75 @@ using FluentAssertions; +using Microsoft.Extensions.Options; using NSubstitute; using OddsCollector.Common.KeyVault.Client; using OddsCollector.Common.Models; using OddsCollector.Common.OddsApi.Client; +using OddsCollector.Common.OddsApi.Configuration; using OddsCollector.Common.OddsApi.Converter; using OddsCollector.Common.OddsApi.WebApi; namespace OddsCollector.Common.Tests.OddsApi.Client; -internal sealed class OddsClientTests +internal sealed class OddsApiClientTests { [Test] public void Constructor_WithValidDependencies_ReturnsNewInstance() { + var optionsStub = Substitute.For>(); + optionsStub.Value.Returns(new OddsApiClientOptions { Leagues = new HashSet { } }); var webApiClientStub = Substitute.For(); var keyVaultClientStub = Substitute.For(); var converterStub = Substitute.For(); - var result = new OddsClient(webApiClientStub, keyVaultClientStub, converterStub); + var result = new OddsApiClient(optionsStub, webApiClientStub, keyVaultClientStub, converterStub); result.Should().NotBeNull(); } + [Test] + public void Constructor_WithNullOptions_ThrowsException() + { + var optionsStub = Substitute.For>(); + var webApiClientStub = Substitute.For(); + var keyVaultClientStub = Substitute.For(); + var converterStub = Substitute.For(); + + var action = () => + { + _ = new OddsApiClient(null, webApiClientStub, keyVaultClientStub, converterStub); + }; + + action.Should().Throw().WithParameterName("options"); + } + + [Test] + public void Constructor_WithNullLeaguesInOptions_ThrowsException() + { + var optionsStub = Substitute.For>(); + optionsStub.Value.Returns(null as OddsApiClientOptions); + var webApiClientStub = Substitute.For(); + var keyVaultClientStub = Substitute.For(); + var converterStub = Substitute.For(); + + var action = () => + { + _ = new OddsApiClient(optionsStub, webApiClientStub, keyVaultClientStub, converterStub); + }; + + action.Should().Throw().WithParameterName("options"); + } + [Test] public void Constructor_WithNullWebApiClient_ThrowsException() { + var optionsStub = Substitute.For>(); + optionsStub.Value.Returns(new OddsApiClientOptions { Leagues = new HashSet { } }); var keyVaultClientStub = Substitute.For(); var converterStub = Substitute.For(); var action = () => { - _ = new OddsClient(null, keyVaultClientStub, converterStub); + _ = new OddsApiClient(optionsStub, null, keyVaultClientStub, converterStub); }; action.Should().Throw().WithParameterName("webApiClient"); @@ -39,12 +78,14 @@ public void Constructor_WithNullWebApiClient_ThrowsException() [Test] public void Constructor_WithNullKeyVaultClient_ThrowsException() { + var optionsStub = Substitute.For>(); + optionsStub.Value.Returns(new OddsApiClientOptions { Leagues = new HashSet { } }); var webApiClientStub = Substitute.For(); var converterStub = Substitute.For(); var action = () => { - _ = new OddsClient(webApiClientStub, null, converterStub); + _ = new OddsApiClient(optionsStub, webApiClientStub, null, converterStub); }; action.Should().Throw().WithParameterName("keyVaultClient"); @@ -53,12 +94,14 @@ public void Constructor_WithNullKeyVaultClient_ThrowsException() [Test] public void Constructor_WithNullConverter_ThrowsException() { + var optionsStub = Substitute.For>(); + optionsStub.Value.Returns(new OddsApiClientOptions { Leagues = new HashSet { } }); var webApiClientStub = Substitute.For(); var keyVaultClientStub = Substitute.For(); var action = () => { - _ = new OddsClient(webApiClientStub, keyVaultClientStub, null); + _ = new OddsApiClient(optionsStub, webApiClientStub, keyVaultClientStub, null); }; action.Should().Throw().WithParameterName("objectConverter"); @@ -83,11 +126,16 @@ public async Task GetUpcomingEventsAsync_WithLeagues_ReturnsUpcomingEvents() var keyVaultClientStub = Substitute.For(); keyVaultClientStub.GetOddsApiKey().Returns(Task.FromResult(secretValue)); - var oddsClient = new OddsClient(webApiClientMock, keyVaultClientStub, converterMock); - const string league = nameof(league); + var optionsStub = Substitute.For>(); + optionsStub.Value.Returns(new OddsApiClientOptions { Leagues = new HashSet { league } }); + + var oddsClient = new OddsApiClient(optionsStub, webApiClientMock, keyVaultClientStub, converterMock); - var results = await oddsClient.GetUpcomingEventsAsync(league); + var traceId = Guid.NewGuid(); + var timestamp = DateTime.UtcNow; + + var results = await oddsClient.GetUpcomingEventsAsync(traceId, timestamp); results.Should().NotBeNull().And.Equal(upcomingEvents); @@ -108,8 +156,8 @@ await webApiClientMock.Received() firstReceivedArguments.Should().NotBeNull(); firstReceivedArguments[0].Should().Be(rawUpcomingEvents); - firstReceivedArguments[1].Should().NotBe(default(Guid)); - firstReceivedArguments[2].Should().NotBe(default(DateTime)); + firstReceivedArguments[1].Should().Be(traceId); + firstReceivedArguments[2].Should().Be(timestamp); } [Test] @@ -125,15 +173,20 @@ public async Task GetEventResultsAsync_WithLeagues_ReturnsEventResults() converterMock.ToEventResults(Arg.Any?>(), Arg.Any(), Arg.Any()) .Returns(eventResults); + const string league = nameof(league); + var optionsStub = Substitute.For>(); + optionsStub.Value.Returns(new OddsApiClientOptions { Leagues = new HashSet { league } }); + const string secretValue = nameof(secretValue); var keyVaultClientStub = Substitute.For(); keyVaultClientStub.GetOddsApiKey().Returns(Task.FromResult(secretValue)); - var oddsClient = new OddsClient(webApiClientMock, keyVaultClientStub, converterMock); + var oddsClient = new OddsApiClient(optionsStub, webApiClientMock, keyVaultClientStub, converterMock); - const string league = nameof(league); + var traceId = Guid.NewGuid(); + var timestamp = DateTime.UtcNow; - var results = await oddsClient.GetEventResultsAsync(league); + var results = await oddsClient.GetEventResultsAsync(traceId, timestamp); results.Should().NotBeNull().And.Equal(eventResults); @@ -151,87 +204,7 @@ public async Task GetEventResultsAsync_WithLeagues_ReturnsEventResults() firstReceivedArguments.Should().NotBeNull(); firstReceivedArguments[0].Should().Be(rawEventResults); - firstReceivedArguments[1].Should().NotBe(default(Guid)); - firstReceivedArguments[2].Should().NotBe(default(DateTime)); - } - - [Test] - public async Task GetUpcomingEventsAsync_WithMultipleLeagues_ReturnsUpcomingEvents() - { - ICollection rawUpcomingEvents = new HashSet { new() }; - var webApiClientStub = Substitute.For(); - webApiClientStub - .OddsAsync(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), - Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) - .Returns(Task.FromResult(rawUpcomingEvents)); - - var keyVaultClientStub = Substitute.For(); - - var upcomingEvents = new List { new() }; - var converterStub = Substitute.For(); - converterStub.ToUpcomingEvents(Arg.Any?>(), Arg.Any(), Arg.Any()) - .Returns(upcomingEvents); - - var oddsClient = new OddsClient(webApiClientStub, keyVaultClientStub, converterStub); - - var result = await oddsClient.GetUpcomingEventsAsync(new HashSet { "league1", "league2" }); - - result.Should().NotBeNull().And.HaveCount(2); - } - - [Test] - public async Task GetEventResultsAsync_WithMultipleLeagues_ReturnsEventResults() - { - ICollection rawEventResults = new HashSet { new() }; - var webApiClientStub = Substitute.For(); - webApiClientStub.ScoresAsync(Arg.Any(), Arg.Any(), Arg.Any()) - .Returns(Task.FromResult(rawEventResults)); - - var keyVaultClientStub = Substitute.For(); - - var eventResults = new List { new() }; - var converterStub = Substitute.For(); - converterStub.ToEventResults(Arg.Any?>(), Arg.Any(), Arg.Any()) - .Returns(eventResults); - - var oddsClient = new OddsClient(webApiClientStub, keyVaultClientStub, converterStub); - - var result = await oddsClient.GetEventResultsAsync(new HashSet { "league1", "league2" }); - - result.Should().NotBeNull().And.HaveCount(2); - } - - [Test] - public void GetUpcomingEventsAsync_WithNullLeagues_ThrowsException() - { - var webApiClient = Substitute.For(); - var keyVaultClient = Substitute.For(); - var converter = Substitute.For(); - - var oddsClient = new OddsClient(webApiClient, keyVaultClient, converter); - - var action = () => - { - _ = oddsClient.GetUpcomingEventsAsync(leagues: null).GetAwaiter().GetResult(); - }; - - action.Should().Throw().WithParameterName("leagues"); - } - - [Test] - public void GetEventResultsAsync_WithNullLeagues_ThrowsException() - { - var webApiClient = Substitute.For(); - var keyVaultClient = Substitute.For(); - var converter = Substitute.For(); - - var oddsClient = new OddsClient(webApiClient, keyVaultClient, converter); - - var action = () => - { - _ = oddsClient.GetEventResultsAsync(leagues: null).GetAwaiter().GetResult(); - }; - - action.Should().Throw().WithParameterName("leagues"); + firstReceivedArguments[1].Should().Be(traceId); + firstReceivedArguments[2].Should().Be(timestamp); } } diff --git a/OddsCollector.Common.Tests/OddsApi/Configuration/OddsApiOptionsTests.cs b/OddsCollector.Common.Tests/OddsApi/Configuration/OddsApiOptionsTests.cs index f0a7af1..8565ed2 100644 --- a/OddsCollector.Common.Tests/OddsApi/Configuration/OddsApiOptionsTests.cs +++ b/OddsCollector.Common.Tests/OddsApi/Configuration/OddsApiOptionsTests.cs @@ -10,7 +10,7 @@ public void SetLeagues_WithValidLeague_ReturnsValidInstance() { string league = nameof(league); - var options = new OddsApiOptions(); + var options = new OddsApiClientOptions(); options.SetLeagues(league); options.Leagues.Should().NotBeNull().And.HaveCount(1); @@ -22,7 +22,7 @@ public void SetLeagues_WithValidLeagues_ReturnsValidInstance() { var leagues = "league1;league2"; - var options = new OddsApiOptions(); + var options = new OddsApiClientOptions(); options.SetLeagues(leagues); options.Leagues.Should().NotBeNull().And.HaveCount(2); @@ -35,7 +35,7 @@ public void SetLeagues_WithDuplicatedLeagues_ReturnsNewInstance() { var leagues = "league1;league1"; - var options = new OddsApiOptions(); + var options = new OddsApiClientOptions(); options.SetLeagues(leagues); options.Leagues.Should().NotBeNull().And.HaveCount(1); @@ -48,7 +48,7 @@ public void SetLeagues_WithNullOrEmptyLeagues_ThrowsException(string? leagues) { var action = () => { - var options = new OddsApiOptions(); + var options = new OddsApiClientOptions(); options.SetLeagues(leagues); }; diff --git a/OddsCollector.Common.Tests/OddsApi/Converter/OddsApiObjectConverterTests.cs b/OddsCollector.Common.Tests/OddsApi/Converter/OddsApiObjectConverterTests.cs index 653fc9f..00aadea 100644 --- a/OddsCollector.Common.Tests/OddsApi/Converter/OddsApiObjectConverterTests.cs +++ b/OddsCollector.Common.Tests/OddsApi/Converter/OddsApiObjectConverterTests.cs @@ -29,42 +29,42 @@ public void ToUpcomingEvents_WithOddList_ReturnsConvertedEvents() firstEvent.Should().NotBeNull(); firstEvent.AwayTeam.Should().NotBeNull().And.Be(TestAnonymous2Builder.DefaultAwayTeam); - firstEvent.CommenceTime.Should().NotBeNull().And.Be(TestAnonymous2Builder.DefaultCommenceTime); + firstEvent.CommenceTime.Should().Be(TestAnonymous2Builder.DefaultCommenceTime); firstEvent.HomeTeam.Should().NotBeNull().And.Be(TestAnonymous2Builder.DefaultHomeTeam); firstEvent.Id.Should().NotBeNull().And.Be(TestAnonymous2Builder.DefaultId); - firstEvent.Timestamp.Should().NotBeNull().And.Be(timestamp); - firstEvent.TraceId.Should().NotBeNull().And.Be(traceId); + firstEvent.Timestamp.Should().Be(timestamp); + firstEvent.TraceId.Should().Be(traceId); firstEvent.Odds.Should().NotBeNull().And.HaveCount(2); firstEvent.Odds!.ElementAt(0).Should().NotBeNull(); firstEvent.Odds!.ElementAt(0)!.Bookmaker.Should().NotBeNull().And.Be("betclic"); - firstEvent.Odds!.ElementAt(0)!.Away.Should().NotBeNull().And.Be(4.08); - firstEvent.Odds!.ElementAt(0)!.Draw.Should().NotBeNull().And.Be(3.82); - firstEvent.Odds!.ElementAt(0)!.Home.Should().NotBeNull().And.Be(1.7); + firstEvent.Odds!.ElementAt(0)!.Away.Should().Be(4.08); + firstEvent.Odds!.ElementAt(0)!.Draw.Should().Be(3.82); + firstEvent.Odds!.ElementAt(0)!.Home.Should().Be(1.7); firstEvent.Odds!.ElementAt(1).Should().NotBeNull(); firstEvent.Odds!.ElementAt(1)!.Bookmaker.Should().NotBeNull().And.Be("sport888"); - firstEvent.Odds!.ElementAt(1)!.Away.Should().NotBeNull().And.Be(4.33); - firstEvent.Odds!.ElementAt(1)!.Draw.Should().NotBeNull().And.Be(4.33); - firstEvent.Odds!.ElementAt(1)!.Home.Should().NotBeNull().And.Be(1.7); + firstEvent.Odds!.ElementAt(1)!.Away.Should().Be(4.33); + firstEvent.Odds!.ElementAt(1)!.Draw.Should().Be(4.33); + firstEvent.Odds!.ElementAt(1)!.Home.Should().Be(1.7); var secondEvent = upcomingEvents.ElementAt(1); secondEvent.Should().NotBeNull(); secondEvent.AwayTeam.Should().NotBeNull().And.Be(TestAnonymous2Builder.DefaultAwayTeam); - secondEvent.CommenceTime.Should().NotBeNull().And.Be(TestAnonymous2Builder.DefaultCommenceTime); + secondEvent.CommenceTime.Should().Be(TestAnonymous2Builder.DefaultCommenceTime); secondEvent.HomeTeam.Should().NotBeNull().And.Be(TestAnonymous2Builder.DefaultHomeTeam); secondEvent.Id.Should().NotBeNull().And.Be("1766194919f1cbfbd846576434f0499b"); - secondEvent.Timestamp.Should().NotBeNull().And.Be(timestamp); - secondEvent.TraceId.Should().NotBeNull().And.Be(traceId); + secondEvent.Timestamp.Should().Be(timestamp); + secondEvent.TraceId.Should().Be(traceId); secondEvent.Odds.Should().NotBeNull().And.HaveCount(2); secondEvent.Odds!.ElementAt(0).Should().NotBeNull(); secondEvent.Odds!.ElementAt(0)!.Bookmaker.Should().NotBeNull().And.Be("betclic"); - secondEvent.Odds!.ElementAt(0)!.Away.Should().NotBeNull().And.Be(4.08); - secondEvent.Odds!.ElementAt(0)!.Draw.Should().NotBeNull().And.Be(3.82); - secondEvent.Odds!.ElementAt(0)!.Home.Should().NotBeNull().And.Be(1.7); + secondEvent.Odds!.ElementAt(0)!.Away.Should().Be(4.08); + secondEvent.Odds!.ElementAt(0)!.Draw.Should().Be(3.82); + secondEvent.Odds!.ElementAt(0)!.Home.Should().Be(1.7); secondEvent.Odds!.ElementAt(1)!.Bookmaker.Should().NotBeNull().And.Be("sport888"); - secondEvent.Odds!.ElementAt(1)!.Away.Should().NotBeNull().And.Be(4.33); - secondEvent.Odds!.ElementAt(1)!.Draw.Should().NotBeNull().And.Be(4.33); - secondEvent.Odds!.ElementAt(1)!.Home.Should().NotBeNull().And.Be(1.7); + secondEvent.Odds!.ElementAt(1)!.Away.Should().Be(4.33); + secondEvent.Odds!.ElementAt(1)!.Draw.Should().Be(4.33); + secondEvent.Odds!.ElementAt(1)!.Home.Should().Be(1.7); } [Test] @@ -528,28 +528,28 @@ public void ToEventResults_WithCompletedEvents_ReturnsConvertedEvents() var firstResult = results.ElementAt(0); firstResult.Should().NotBeNull(); - firstResult.CommenceTime.Should().NotBeNull().And.Be(TestAnonymous3Builder.DefaultCommenceTime); + firstResult.CommenceTime.Should().Be(TestAnonymous3Builder.DefaultCommenceTime); firstResult.Id.Should().NotBeNull().And.Be(TestAnonymous3Builder.DefaultId); - firstResult.Timestamp.Should().NotBeNull().And.Be(timestamp); - firstResult.TraceId.Should().NotBeNull().And.Be(traceId); + firstResult.Timestamp.Should().Be(timestamp); + firstResult.TraceId.Should().Be(traceId); firstResult.Winner.Should().NotBeNull().And.Be("Manchester City"); var secondResult = results.ElementAt(1); secondResult.Should().NotBeNull(); - secondResult.CommenceTime.Should().NotBeNull().And.Be(TestAnonymous3Builder.DefaultCommenceTime); + secondResult.CommenceTime.Should().Be(TestAnonymous3Builder.DefaultCommenceTime); secondResult.Id.Should().NotBeNull().And.Be(TestAnonymous3Builder.DefaultId); - secondResult.Timestamp.Should().NotBeNull().And.Be(timestamp); - secondResult.TraceId.Should().NotBeNull().And.Be(traceId); + secondResult.Timestamp.Should().Be(timestamp); + secondResult.TraceId.Should().Be(traceId); secondResult.Winner.Should().NotBeNull().And.Be("Liverpool"); var thirdResult = results.ElementAt(2); thirdResult.Should().NotBeNull(); - thirdResult.CommenceTime.Should().NotBeNull().And.Be(TestAnonymous3Builder.DefaultCommenceTime); + thirdResult.CommenceTime.Should().Be(TestAnonymous3Builder.DefaultCommenceTime); thirdResult.Id.Should().NotBeNull().And.Be(TestAnonymous3Builder.DefaultId); - thirdResult.Timestamp.Should().NotBeNull().And.Be(timestamp); - thirdResult.TraceId.Should().NotBeNull().And.Be(traceId); + thirdResult.Timestamp.Should().Be(timestamp); + thirdResult.TraceId.Should().Be(traceId); thirdResult.Winner.Should().NotBeNull().And.Be(Constants.Draw); } diff --git a/OddsCollector.Common.Tests/OddsApi/Models/EventPredictionBuilderTests.cs b/OddsCollector.Common.Tests/OddsApi/Models/EventPredictionBuilderTests.cs index ac8a685..116c2b4 100644 --- a/OddsCollector.Common.Tests/OddsApi/Models/EventPredictionBuilderTests.cs +++ b/OddsCollector.Common.Tests/OddsApi/Models/EventPredictionBuilderTests.cs @@ -45,9 +45,9 @@ public void Constructor_WithFullParameterList_ReturnsValidInstance() result.HomeTeam.Should().NotBeNull().And.Be(homeTeam); result.Id.Should().NotBeNull().And.Be(id); result.Strategy.Should().NotBeNull().And.Be(strategy); - result.CommenceTime.Should().NotBeNull().And.Be(commenceTime); - result.Timestamp.Should().NotBeNull().And.Be(timestamp); - result.TraceId.Should().NotBeNull().And.Be(traceId); + result.CommenceTime.Should().Be(commenceTime); + result.Timestamp.Should().Be(timestamp); + result.TraceId.Should().Be(traceId); } [Test] @@ -124,7 +124,7 @@ public void SetCommenceTime_WithValidCommenceTime_ReturnsValidInstance() var result = new EventPredictionBuilder().SetCommenceTime(commenceTime).Instance; result.Should().NotBeNull(); - result.CommenceTime.Should().NotBeNull().And.Be(commenceTime); + result.CommenceTime.Should().Be(commenceTime); } [Test] @@ -135,7 +135,7 @@ public void SetTimestamp_WithValidTimestamp_ReturnsValidInstance() var result = new EventPredictionBuilder().SetTimestamp(timestamp).Instance; result.Should().NotBeNull(); - result.Timestamp.Should().NotBeNull().And.Be(timestamp); + result.Timestamp.Should().Be(timestamp); } [Test] @@ -146,7 +146,7 @@ public void SetTraceId_WithValidTraceId_ReturnsValidInstance() var result = new EventPredictionBuilder().SetTraceId(traceId).Instance; result.Should().NotBeNull(); - result.TraceId.Should().NotBeNull().And.Be(traceId); + result.TraceId.Should().Be(traceId); } [TestCase("")] diff --git a/OddsCollector.Common.Tests/OddsApi/Models/EventResultBuilderTests.cs b/OddsCollector.Common.Tests/OddsApi/Models/EventResultBuilderTests.cs index 5cacb40..2a75861 100644 --- a/OddsCollector.Common.Tests/OddsApi/Models/EventResultBuilderTests.cs +++ b/OddsCollector.Common.Tests/OddsApi/Models/EventResultBuilderTests.cs @@ -33,9 +33,9 @@ public void Constructor_WithFullParameterList_ReturnsValidInstance() result.Should().NotBeNull(); result.Winner.Should().NotBeNull().And.Be(winner); result.Id.Should().NotBeNull().And.Be(id); - result.CommenceTime.Should().NotBeNull().And.Be(commenceTime); - result.Timestamp.Should().NotBeNull().And.Be(timestamp); - result.TraceId.Should().NotBeNull().And.Be(traceId); + result.CommenceTime.Should().Be(commenceTime); + result.Timestamp.Should().Be(timestamp); + result.TraceId.Should().Be(traceId); } [Test] @@ -68,7 +68,7 @@ public void SetCommenceTime_WithValidCommenceTime_ReturnsValidInstance() var result = new EventResultBuilder().SetCommenceTime(commenceTime).Instance; result.Should().NotBeNull(); - result.CommenceTime.Should().NotBeNull().And.Be(commenceTime); + result.CommenceTime.Should().Be(commenceTime); } [Test] @@ -79,7 +79,7 @@ public void SetTimestamp_WithValidTimestamp_ReturnsValidInstance() var result = new EventResultBuilder().SetTimestamp(timestamp).Instance; result.Should().NotBeNull(); - result.Timestamp.Should().NotBeNull().And.Be(timestamp); + result.Timestamp.Should().Be(timestamp); } [Test] @@ -90,7 +90,7 @@ public void SetTraceId_WithValidTraceId_ReturnsValidInstance() var result = new EventResultBuilder().SetTraceId(traceId).Instance; result.Should().NotBeNull(); - result.TraceId.Should().NotBeNull().And.Be(traceId); + result.TraceId.Should().Be(traceId); } [TestCase("")] diff --git a/OddsCollector.Common.Tests/OddsApi/Models/OddBuilderTests.cs b/OddsCollector.Common.Tests/OddsApi/Models/OddBuilderTests.cs index 0c98ad1..092c973 100644 --- a/OddsCollector.Common.Tests/OddsApi/Models/OddBuilderTests.cs +++ b/OddsCollector.Common.Tests/OddsApi/Models/OddBuilderTests.cs @@ -32,7 +32,7 @@ public void SetAway_WithValidAway_ReturnsValidInstance() var result = new OddBuilder().SetAway(away).Instance; result.Should().NotBeNull(); - result.Away.Should().NotBeNull().And.Be(away); + result.Away.Should().Be(away); } [Test] @@ -43,7 +43,7 @@ public void SetDraw_WithValidDraw_ReturnsValidInstance() var result = new OddBuilder().SetDraw(draw).Instance; result.Should().NotBeNull(); - result.Draw.Should().NotBeNull().And.Be(draw); + result.Draw.Should().Be(draw); } [Test] @@ -54,7 +54,7 @@ public void SetHome_WithValidHome_ReturnsValidInstance() var result = new OddBuilder().SetHome(home).Instance; result.Should().NotBeNull(); - result.Home.Should().NotBeNull().And.Be(home); + result.Home.Should().Be(home); } [TestCase("")] diff --git a/OddsCollector.Common.Tests/OddsApi/Models/UpcomingEventBuilderTests.cs b/OddsCollector.Common.Tests/OddsApi/Models/UpcomingEventBuilderTests.cs index c9a8f98..91f7442 100644 --- a/OddsCollector.Common.Tests/OddsApi/Models/UpcomingEventBuilderTests.cs +++ b/OddsCollector.Common.Tests/OddsApi/Models/UpcomingEventBuilderTests.cs @@ -36,9 +36,9 @@ public void Constructor_WithFullParameterList_ReturnsValidInstance() result.AwayTeam.Should().NotBeNull().And.Be(awayTeam); result.HomeTeam.Should().NotBeNull().And.Be(homeTeam); result.Id.Should().NotBeNull().And.Be(id); - result.CommenceTime.Should().NotBeNull().And.Be(commenceTime); - result.Timestamp.Should().NotBeNull().And.Be(timestamp); - result.TraceId.Should().NotBeNull().And.Be(traceId); + result.CommenceTime.Should().Be(commenceTime); + result.Timestamp.Should().Be(timestamp); + result.TraceId.Should().Be(traceId); } [Test] @@ -49,7 +49,7 @@ public void SetAwayTeam_WithValidAwayTeam_ReturnsValidInstance() var result = new UpcomingEventBuilder().SetAwayTeam(awayTeam).Instance; result.Should().NotBeNull(); - result.AwayTeam.Should().NotBeNull().And.Be(awayTeam); + result.AwayTeam.Should().Be(awayTeam); } [Test] @@ -82,7 +82,7 @@ public void SetCommenceTime_WithValidCommenceTime_ReturnsValidInstance() var result = new UpcomingEventBuilder().SetCommenceTime(commenceTime).Instance; result.Should().NotBeNull(); - result.CommenceTime.Should().NotBeNull().And.Be(commenceTime); + result.CommenceTime.Should().Be(commenceTime); } [Test] @@ -93,7 +93,7 @@ public void SetTimestamp_WithValidTimestamp_ReturnsValidInstance() var result = new UpcomingEventBuilder().SetTimestamp(timestamp).Instance; result.Should().NotBeNull(); - result.Timestamp.Should().NotBeNull().And.Be(timestamp); + result.Timestamp.Should().Be(timestamp); } [Test] @@ -104,7 +104,7 @@ public void SetTraceId_WithValidTraceId_ReturnsValidInstance() var result = new UpcomingEventBuilder().SetTraceId(traceId).Instance; result.Should().NotBeNull(); - result.TraceId.Should().NotBeNull().And.Be(traceId); + result.TraceId.Should().Be(traceId); } [TestCase("")] diff --git a/OddsCollector.Common/Models/EventPrediction.cs b/OddsCollector.Common/Models/EventPrediction.cs index 16b26a5..faa90fd 100644 --- a/OddsCollector.Common/Models/EventPrediction.cs +++ b/OddsCollector.Common/Models/EventPrediction.cs @@ -5,20 +5,20 @@ namespace OddsCollector.Common.Models; public class EventPrediction { // duplicating information to avoid complex queries to cosmosdb - public string? AwayTeam { get; set; } + public string AwayTeam { get; set; } = string.Empty; - public string? Bookmaker { get; set; } + public string Bookmaker { get; set; } = string.Empty; // duplicating information to avoid complex queries to cosmosdb - public DateTime? CommenceTime { get; set; } + public DateTime CommenceTime { get; set; } = DateTime.MinValue; // duplicating information to avoid complex queries to cosmosdb - public string? HomeTeam { get; set; } + public string HomeTeam { get; set; } = string.Empty; // fix for cosmosdb - [JsonPropertyName("id")] public string? Id { get; set; } - public string? Strategy { get; set; } - public DateTime? Timestamp { get; set; } - public Guid? TraceId { get; set; } - public string? Winner { get; set; } + [JsonPropertyName("id")] public string Id { get; set; } = string.Empty; + public string Strategy { get; set; } = string.Empty; + public DateTime Timestamp { get; set; } = DateTime.MinValue; + public Guid TraceId { get; set; } = Guid.Empty; + public string Winner { get; set; } = string.Empty; } diff --git a/OddsCollector.Common/Models/EventPredictionBuilder.cs b/OddsCollector.Common/Models/EventPredictionBuilder.cs index ff766bb..e111b0b 100644 --- a/OddsCollector.Common/Models/EventPredictionBuilder.cs +++ b/OddsCollector.Common/Models/EventPredictionBuilder.cs @@ -35,7 +35,7 @@ public EventPredictionBuilder SetCommenceTime(DateTime? commenceTime) throw new ArgumentNullException(nameof(commenceTime)); } - _state.CommenceTime = commenceTime; + _state.CommenceTime = commenceTime.Value; return this; } @@ -83,7 +83,7 @@ public EventPredictionBuilder SetTimestamp(DateTime? timestamp) throw new ArgumentNullException(nameof(timestamp)); } - _state.Timestamp = timestamp; + _state.Timestamp = timestamp.Value; return this; } @@ -95,7 +95,7 @@ public EventPredictionBuilder SetTraceId(Guid? traceId) throw new ArgumentNullException(nameof(traceId)); } - _state.TraceId = traceId; + _state.TraceId = traceId.Value; return this; } diff --git a/OddsCollector.Common/Models/EventResult.cs b/OddsCollector.Common/Models/EventResult.cs index 10d6ee3..a96f720 100644 --- a/OddsCollector.Common/Models/EventResult.cs +++ b/OddsCollector.Common/Models/EventResult.cs @@ -4,11 +4,11 @@ namespace OddsCollector.Common.Models; public class EventResult { - public DateTime? CommenceTime { get; set; } + public DateTime CommenceTime { get; set; } = DateTime.MinValue; // fix for cosmosdb - [JsonPropertyName("id")] public string? Id { get; set; } - public DateTime? Timestamp { get; set; } - public Guid? TraceId { get; set; } - public string? Winner { get; set; } + [JsonPropertyName("id")] public string Id { get; set; } = string.Empty; + public DateTime Timestamp { get; set; } = DateTime.MinValue; + public Guid TraceId { get; set; } = Guid.Empty; + public string Winner { get; set; } = string.Empty; } diff --git a/OddsCollector.Common/Models/EventResultBuilder.cs b/OddsCollector.Common/Models/EventResultBuilder.cs index 7d50ccc..cf1d1e8 100644 --- a/OddsCollector.Common/Models/EventResultBuilder.cs +++ b/OddsCollector.Common/Models/EventResultBuilder.cs @@ -35,7 +35,7 @@ public EventResultBuilder SetCommenceTime(DateTime? commenceTime) throw new ArgumentNullException(nameof(commenceTime)); } - _state.CommenceTime = commenceTime; + _state.CommenceTime = commenceTime.Value; return this; } @@ -47,7 +47,7 @@ public EventResultBuilder SetTimestamp(DateTime? timestamp) throw new ArgumentNullException(nameof(timestamp)); } - _state.Timestamp = timestamp; + _state.Timestamp = timestamp.Value; return this; } @@ -59,7 +59,7 @@ public EventResultBuilder SetTraceId(Guid? traceId) throw new ArgumentNullException(nameof(traceId)); } - _state.TraceId = traceId; + _state.TraceId = traceId.Value; return this; } diff --git a/OddsCollector.Common/Models/Odd.cs b/OddsCollector.Common/Models/Odd.cs index 60322c1..a087e0f 100644 --- a/OddsCollector.Common/Models/Odd.cs +++ b/OddsCollector.Common/Models/Odd.cs @@ -2,8 +2,8 @@ public class Odd { - public double? Away { get; set; } - public string? Bookmaker { get; set; } - public double? Draw { get; set; } - public double? Home { get; set; } + public double Away { get; set; } + public string Bookmaker { get; set; } = string.Empty; + public double Draw { get; set; } + public double Home { get; set; } } diff --git a/OddsCollector.Common/Models/OddBuilder.cs b/OddsCollector.Common/Models/OddBuilder.cs index 87f87ba..ae10e33 100644 --- a/OddsCollector.Common/Models/OddBuilder.cs +++ b/OddsCollector.Common/Models/OddBuilder.cs @@ -23,7 +23,7 @@ public OddBuilder SetAway(double? away) throw new ArgumentNullException(nameof(away)); } - _state.Away = away; + _state.Away = away.Value; return this; } @@ -35,7 +35,7 @@ public OddBuilder SetDraw(double? draw) throw new ArgumentNullException(nameof(draw)); } - _state.Draw = draw; + _state.Draw = draw.Value; return this; } @@ -47,7 +47,7 @@ public OddBuilder SetHome(double? home) throw new ArgumentNullException(nameof(home)); } - _state.Home = home; + _state.Home = home.Value; return this; } diff --git a/OddsCollector.Common/Models/UpcomingEvent.cs b/OddsCollector.Common/Models/UpcomingEvent.cs index 9ca2888..a7bd47c 100644 --- a/OddsCollector.Common/Models/UpcomingEvent.cs +++ b/OddsCollector.Common/Models/UpcomingEvent.cs @@ -2,11 +2,11 @@ public class UpcomingEvent { - public string? AwayTeam { get; set; } - public DateTime? CommenceTime { get; set; } - public string? HomeTeam { get; set; } - public string? Id { get; set; } - public IEnumerable? Odds { get; set; } - public DateTime? Timestamp { get; set; } - public Guid? TraceId { get; set; } + public string AwayTeam { get; set; } = string.Empty; + public DateTime CommenceTime { get; set; } = DateTime.MinValue; + public string HomeTeam { get; set; } = string.Empty; + public string Id { get; set; } = string.Empty; + public IEnumerable Odds { get; set; } = new List(); + public DateTime Timestamp { get; set; } = DateTime.MinValue; + public Guid TraceId { get; set; } = Guid.Empty; } diff --git a/OddsCollector.Common/Models/UpcomingEventBuilder.cs b/OddsCollector.Common/Models/UpcomingEventBuilder.cs index ea0f6eb..e34dddd 100644 --- a/OddsCollector.Common/Models/UpcomingEventBuilder.cs +++ b/OddsCollector.Common/Models/UpcomingEventBuilder.cs @@ -23,7 +23,7 @@ public UpcomingEventBuilder SetCommenceTime(DateTime? commenceTime) throw new ArgumentNullException(nameof(commenceTime)); } - _state.CommenceTime = commenceTime; + _state.CommenceTime = commenceTime.Value; return this; } @@ -59,7 +59,7 @@ public UpcomingEventBuilder SetTimestamp(DateTime? timestamp) throw new ArgumentNullException(nameof(timestamp)); } - _state.Timestamp = timestamp; + _state.Timestamp = timestamp.Value; return this; } @@ -71,7 +71,7 @@ public UpcomingEventBuilder SetTraceId(Guid? traceId) throw new ArgumentNullException(nameof(traceId)); } - _state.TraceId = traceId; + _state.TraceId = traceId.Value; return this; } diff --git a/OddsCollector.Common/OddsApi/Client/IOddsApiClient.cs b/OddsCollector.Common/OddsApi/Client/IOddsApiClient.cs new file mode 100644 index 0000000..e0ae2a7 --- /dev/null +++ b/OddsCollector.Common/OddsApi/Client/IOddsApiClient.cs @@ -0,0 +1,9 @@ +using OddsCollector.Common.Models; + +namespace OddsCollector.Common.OddsApi.Client; + +public interface IOddsApiClient +{ + Task> GetUpcomingEventsAsync(Guid traceId, DateTime timestamp); + Task> GetEventResultsAsync(Guid traceId, DateTime timestamp); +} diff --git a/OddsCollector.Common/OddsApi/Client/IOddsClient.cs b/OddsCollector.Common/OddsApi/Client/IOddsClient.cs deleted file mode 100644 index af752a2..0000000 --- a/OddsCollector.Common/OddsApi/Client/IOddsClient.cs +++ /dev/null @@ -1,11 +0,0 @@ -using OddsCollector.Common.Models; - -namespace OddsCollector.Common.OddsApi.Client; - -public interface IOddsClient -{ - Task> GetUpcomingEventsAsync(string league); - Task> GetUpcomingEventsAsync(IEnumerable leagues); - Task> GetEventResultsAsync(string league); - Task> GetEventResultsAsync(IEnumerable leagues); -} diff --git a/OddsCollector.Common/OddsApi/Client/OddsApiClient.cs b/OddsCollector.Common/OddsApi/Client/OddsApiClient.cs new file mode 100644 index 0000000..e97f8b3 --- /dev/null +++ b/OddsCollector.Common/OddsApi/Client/OddsApiClient.cs @@ -0,0 +1,58 @@ +using Microsoft.Extensions.Options; +using OddsCollector.Common.KeyVault.Client; +using OddsCollector.Common.Models; +using OddsCollector.Common.OddsApi.Configuration; +using OddsCollector.Common.OddsApi.Converter; +using OddsCollector.Common.OddsApi.WebApi; + +namespace OddsCollector.Common.OddsApi.Client; + +public class OddsApiClient : IOddsApiClient +{ + private const DateFormat IsoDateFormat = DateFormat.Iso; + private const Markets HeadToHeadMarket = Markets.H2h; + private const OddsFormat DecimalOddsFormat = OddsFormat.Decimal; + private const Regions EuropeanRegion = Regions.Eu; + private const int DaysFromToday = 3; + private readonly IKeyVaultClient _keyVaultClient; + private readonly IOddsApiObjectConverter _objectConverter; + private readonly IClient _webApiClient; + private readonly OddsApiClientOptions _options; + + public OddsApiClient(IOptions? options, IClient? webApiClient, IKeyVaultClient? keyVaultClient, IOddsApiObjectConverter? objectConverter) + { + _options = options?.Value ?? throw new ArgumentNullException(nameof(options)); + _webApiClient = webApiClient ?? throw new ArgumentNullException(nameof(webApiClient)); + _keyVaultClient = keyVaultClient ?? throw new ArgumentNullException(nameof(keyVaultClient)); + _objectConverter = objectConverter ?? throw new ArgumentNullException(nameof(objectConverter)); + } + + public async Task> GetUpcomingEventsAsync(Guid traceId, DateTime timestamp) + { + var result = new List(); + + foreach (var league in _options.Leagues) + { + var events = await _webApiClient.OddsAsync(league, await _keyVaultClient.GetOddsApiKey().ConfigureAwait(false), + EuropeanRegion, HeadToHeadMarket, IsoDateFormat, DecimalOddsFormat, null, null).ConfigureAwait(false); + + result.AddRange(_objectConverter.ToUpcomingEvents(events, traceId, timestamp)); + } + + return result; + } + + public async Task> GetEventResultsAsync(Guid traceId, DateTime timestamp) + { + var result = new List(); + + foreach (var league in _options.Leagues) + { + var results = await _webApiClient.ScoresAsync(league, await _keyVaultClient.GetOddsApiKey().ConfigureAwait(false), DaysFromToday).ConfigureAwait(false); + + result.AddRange(_objectConverter.ToEventResults(results, traceId, timestamp)); + } + + return result; + } +} diff --git a/OddsCollector.Common/OddsApi/Client/OddsClient.cs b/OddsCollector.Common/OddsApi/Client/OddsClient.cs deleted file mode 100644 index 768eaa1..0000000 --- a/OddsCollector.Common/OddsApi/Client/OddsClient.cs +++ /dev/null @@ -1,82 +0,0 @@ -using OddsCollector.Common.KeyVault.Client; -using OddsCollector.Common.Models; -using OddsCollector.Common.OddsApi.Converter; -using OddsCollector.Common.OddsApi.WebApi; - -namespace OddsCollector.Common.OddsApi.Client; - -public class OddsClient : IOddsClient -{ - private const DateFormat IsoDateFormat = DateFormat.Iso; - private const Markets HeadToHeadMarket = Markets.H2h; - private const OddsFormat DecimalOddsFormat = OddsFormat.Decimal; - private const Regions EuropeanRegion = Regions.Eu; - private const int DaysFromToday = 3; - private readonly IKeyVaultClient _keyVaultClient; - private readonly IOddsApiObjectConverter _objectConverter; - private readonly IClient _webApiClient; - - public OddsClient(IClient? webApiClient, IKeyVaultClient? keyVaultClient, IOddsApiObjectConverter? objectConverter) - { - _webApiClient = webApiClient ?? throw new ArgumentNullException(nameof(webApiClient)); - _keyVaultClient = keyVaultClient ?? throw new ArgumentNullException(nameof(keyVaultClient)); - _objectConverter = objectConverter ?? throw new ArgumentNullException(nameof(objectConverter)); - } - - public async Task> GetUpcomingEventsAsync(IEnumerable? leagues) - { - if (leagues is null) - { - throw new ArgumentNullException(nameof(leagues)); - } - - var result = new List(); - - foreach (var league in leagues) - { - result.AddRange(await GetUpcomingEventsAsync(league).ConfigureAwait(false)); - } - - return result; - } - - public async Task> GetEventResultsAsync(IEnumerable? leagues) - { - if (leagues is null) - { - throw new ArgumentNullException(nameof(leagues)); - } - - var result = new List(); - - foreach (var league in leagues) - { - result.AddRange(await GetEventResultsAsync(league).ConfigureAwait(false)); - } - - return result; - } - - public async Task> GetUpcomingEventsAsync(string league) - { - var events = await _webApiClient.OddsAsync(league, await _keyVaultClient.GetOddsApiKey().ConfigureAwait(false), - EuropeanRegion, HeadToHeadMarket, IsoDateFormat, DecimalOddsFormat, null, null).ConfigureAwait(false); - - var traceId = Guid.NewGuid(); - var timestamp = DateTime.UtcNow; - - return _objectConverter.ToUpcomingEvents(events, traceId, timestamp); - } - - public async Task> GetEventResultsAsync(string league) - { - var results = await _webApiClient - .ScoresAsync(league, await _keyVaultClient.GetOddsApiKey().ConfigureAwait(false), DaysFromToday) - .ConfigureAwait(false); - - var traceId = Guid.NewGuid(); - var timestamp = DateTime.UtcNow; - - return _objectConverter.ToEventResults(results, traceId, timestamp); - } -} diff --git a/OddsCollector.Common/OddsApi/Configuration/OddsApiOptions.cs b/OddsCollector.Common/OddsApi/Configuration/OddsApiClientOptions.cs similarity index 94% rename from OddsCollector.Common/OddsApi/Configuration/OddsApiOptions.cs rename to OddsCollector.Common/OddsApi/Configuration/OddsApiClientOptions.cs index 73ad041..46f5700 100644 --- a/OddsCollector.Common/OddsApi/Configuration/OddsApiOptions.cs +++ b/OddsCollector.Common/OddsApi/Configuration/OddsApiClientOptions.cs @@ -3,7 +3,7 @@ namespace OddsCollector.Common.OddsApi.Configuration; -public class OddsApiOptions +public class OddsApiClientOptions { [Required] [SuppressMessage("Usage", "CA2227:Collection properties should be read only")] diff --git a/OddsCollector.Common/OddsApi/WebApi/ApiClient.cs b/OddsCollector.Common/OddsApi/WebApi/WebApiClient.cs similarity index 100% rename from OddsCollector.Common/OddsApi/WebApi/ApiClient.cs rename to OddsCollector.Common/OddsApi/WebApi/WebApiClient.cs diff --git a/OddsCollector.Functions.EventResults.Tests/EventResultsFunctionTests.cs b/OddsCollector.Functions.EventResults.Tests/EventResultsFunctionTests.cs index 2d4da03..5f55bea 100644 --- a/OddsCollector.Functions.EventResults.Tests/EventResultsFunctionTests.cs +++ b/OddsCollector.Functions.EventResults.Tests/EventResultsFunctionTests.cs @@ -1,10 +1,8 @@ using FluentAssertions; using Microsoft.Azure.Functions.Worker; -using Microsoft.Extensions.Options; using NSubstitute; using OddsCollector.Common.Models; using OddsCollector.Common.OddsApi.Client; -using OddsCollector.Common.OddsApi.Configuration; namespace OddsCollector.Functions.EventResults.Tests; @@ -13,23 +11,9 @@ internal sealed class EventResultsFunctionTests [Test] public void Constructor_WithValidDependencies_ReturnsNewInstance() { - var clientStub = Substitute.For(); - var optionsStub = Substitute.For>(); - optionsStub.Value.Returns(new OddsApiOptions { Leagues = new HashSet { "league1" } }); + var clientStub = Substitute.For(); - var function = new EventResultsFunction(optionsStub, clientStub); - - function.Should().NotBeNull(); - } - - [Test] - public void Constructor_WithEmptyLeagues_ReturnsNewInstance() - { - var clientStub = Substitute.For(); - var optionsStub = Substitute.For>(); - optionsStub.Value.Returns(new OddsApiOptions { Leagues = new HashSet() }); - - var function = new EventResultsFunction(optionsStub, clientStub); + var function = new EventResultsFunction(clientStub); function.Should().NotBeNull(); } @@ -37,57 +21,23 @@ public void Constructor_WithEmptyLeagues_ReturnsNewInstance() [Test] public void Constructor_WithNullOddsClient_ThrowsException() { - var optionsStub = Substitute.For>(); - optionsStub.Value.Returns(new OddsApiOptions { Leagues = new HashSet { "league1" } }); - var action = () => { - _ = new EventResultsFunction(optionsStub, null); + _ = new EventResultsFunction(null); }; action.Should().Throw().WithParameterName("client"); } - [Test] - public void Constructor_WithNullOptions_ThrowsException() - { - var clientStub = Substitute.For(); - - var action = () => - { - _ = new EventResultsFunction(null, clientStub); - }; - - action.Should().Throw().WithParameterName("options"); - } - - [Test] - public void Constructor_WithNullLeagues_ThrowsException() - { - var clientStub = Substitute.For(); - var optionsStub = Substitute.For>(); - optionsStub.Value.Returns(new OddsApiOptions { Leagues = null! }); - - var action = () => - { - _ = new EventResultsFunction(null, clientStub); - }; - - action.Should().Throw().WithParameterName("options"); - } - [Test] public async Task Run_WithValidTimer_ReturnsEventResults() { IEnumerable expectedEventResults = new List(); - var clientStub = Substitute.For(); - clientStub.GetEventResultsAsync(Arg.Any>()).Returns(Task.FromResult(expectedEventResults)); - - var optionsStub = Substitute.For>(); - optionsStub.Value.Returns(new OddsApiOptions { Leagues = new HashSet() }); + var clientStub = Substitute.For(); + clientStub.GetEventResultsAsync(Arg.Any(), Arg.Any()).Returns(Task.FromResult(expectedEventResults)); - var function = new EventResultsFunction(optionsStub, clientStub); + var function = new EventResultsFunction(clientStub); var timerStub = Substitute.For(); diff --git a/OddsCollector.Functions.EventResults/EventResultsFunction.cs b/OddsCollector.Functions.EventResults/EventResultsFunction.cs index 562ae74..1f1ede0 100644 --- a/OddsCollector.Functions.EventResults/EventResultsFunction.cs +++ b/OddsCollector.Functions.EventResults/EventResultsFunction.cs @@ -1,9 +1,7 @@ using System.Runtime.CompilerServices; using Microsoft.Azure.Functions.Worker; -using Microsoft.Extensions.Options; using OddsCollector.Common.Models; using OddsCollector.Common.OddsApi.Client; -using OddsCollector.Common.OddsApi.Configuration; [assembly: InternalsVisibleTo("OddsCollector.Functions.EventResults.Tests")] // DynamicProxyGenAssembly2 is a temporary assembly built by mocking systems that use CastleProxy @@ -13,12 +11,10 @@ namespace OddsCollector.Functions.EventResults; internal sealed class EventResultsFunction { - private readonly IOddsClient _client; - private readonly HashSet _leagues; + private readonly IOddsApiClient _client; - public EventResultsFunction(IOptions? options, IOddsClient? client) + public EventResultsFunction(IOddsApiClient? client) { - _leagues = options?.Value?.Leagues ?? throw new ArgumentNullException(nameof(options)); _client = client ?? throw new ArgumentNullException(nameof(client)); } @@ -26,6 +22,6 @@ public EventResultsFunction(IOptions? options, IOddsClient? clie [CosmosDBOutput("%CosmosDb:Database%", "%CosmosDb:Container%", Connection = "CosmosDb:Connection")] public async Task Run([TimerTrigger("%TimerInterval%")] TimerInfo myTimer) { - return (await _client.GetEventResultsAsync(_leagues).ConfigureAwait(false)).ToArray(); + return (await _client.GetEventResultsAsync(Guid.NewGuid(), DateTime.UtcNow).ConfigureAwait(false)).ToArray(); } } diff --git a/OddsCollector.Functions.EventResults/Program.cs b/OddsCollector.Functions.EventResults/Program.cs index 31fd818..ea8132b 100644 --- a/OddsCollector.Functions.EventResults/Program.cs +++ b/OddsCollector.Functions.EventResults/Program.cs @@ -12,10 +12,10 @@ .ConfigureFunctionsWorkerDefaults() .ConfigureServices(services => { - services.Configure(o => + services.Configure(o => { // workaround for https://github.com/MicrosoftDocs/azure-docs/issues/32962 - o.SetLeagues(Environment.GetEnvironmentVariable("OddsApi:Leagues")); + o.SetLeagues(Environment.GetEnvironmentVariable("OddsApiClient:Leagues")); }); services.AddHttpClient(); services.AddSingleton(); @@ -25,7 +25,7 @@ SecretClientFactory.CreateSecretClient(Environment.GetEnvironmentVariable("KeyVault:Name")) ); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddApplicationInsightsTelemetryWorkerService(); services.ConfigureFunctionsApplicationInsights(); }) diff --git a/OddsCollector.Functions.Predictions.Tests/Strategies/AdjustedConsensusStrategyTests.cs b/OddsCollector.Functions.Predictions.Tests/Strategies/AdjustedConsensusStrategyTests.cs index a691a7a..e9ecb82 100644 --- a/OddsCollector.Functions.Predictions.Tests/Strategies/AdjustedConsensusStrategyTests.cs +++ b/OddsCollector.Functions.Predictions.Tests/Strategies/AdjustedConsensusStrategyTests.cs @@ -9,7 +9,7 @@ internal class AdjustedConsensusStrategyTests [Test] public void GetPrediction_WithUpcomingEventWithWinningHomeTeam_ReturnsPrediction() { - var upcomingEvent = new TestUpcomingEventBuilder().SetDefaults().GetUpcomingEvent(); + var upcomingEvent = new UpcomingEventBuilder().SetDefaults().Instance; var timestamp = DateTime.Now; @@ -18,21 +18,21 @@ public void GetPrediction_WithUpcomingEventWithWinningHomeTeam_ReturnsPrediction var prediction = strategy.GetPrediction(upcomingEvent, timestamp); prediction.Should().NotBeNull(); - prediction.AwayTeam.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultAwayTeam); + prediction.AwayTeam.Should().NotBeNull().And.Be(UpcomingEventBuilderExtensions.DefaultAwayTeam); prediction.Bookmaker.Should().NotBeNull().And.Be("betclic"); - prediction.CommenceTime.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultCommenceTime); - prediction.HomeTeam.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultHomeTeam); - prediction.Id.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultId); + prediction.CommenceTime.Should().Be(UpcomingEventBuilderExtensions.DefaultCommenceTime); + prediction.HomeTeam.Should().NotBeNull().And.Be(UpcomingEventBuilderExtensions.DefaultHomeTeam); + prediction.Id.Should().NotBeNull().And.Be(UpcomingEventBuilderExtensions.DefaultId); prediction.Strategy.Should().NotBeNull().And.Be(nameof(AdjustedConsensusStrategy)); - prediction.Timestamp.Should().NotBeNull().And.Be(timestamp); - prediction.TraceId.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultTraceId); + prediction.Timestamp.Should().Be(timestamp); + prediction.TraceId.Should().Be(UpcomingEventBuilderExtensions.DefaultTraceId); prediction.Winner.Should().NotBeNull().And.Be("Manchester City"); } [Test] public void GetPrediction_WithUpcomingEventWithWinningAwayTeam_ReturnsPrediction() { - var upcomingEvent = new TestUpcomingEventBuilder().SetDefaults().SetOdds(new List + var upcomingEvent = new UpcomingEventBuilder().SetDefaults().SetOdds(new List { new() { @@ -55,7 +55,7 @@ public void GetPrediction_WithUpcomingEventWithWinningAwayTeam_ReturnsPrediction Draw = 4.5, Home = 4.5 } - }).GetUpcomingEvent(); + }).Instance; var timestamp = DateTime.Now; @@ -64,21 +64,21 @@ public void GetPrediction_WithUpcomingEventWithWinningAwayTeam_ReturnsPrediction var prediction = strategy.GetPrediction(upcomingEvent, timestamp); prediction.Should().NotBeNull(); - prediction.AwayTeam.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultAwayTeam); + prediction.AwayTeam.Should().NotBeNull().And.Be(UpcomingEventBuilderExtensions.DefaultAwayTeam); prediction.Bookmaker.Should().NotBeNull().And.Be("betclic"); - prediction.CommenceTime.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultCommenceTime); - prediction.HomeTeam.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultHomeTeam); - prediction.Id.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultId); + prediction.CommenceTime.Should().Be(UpcomingEventBuilderExtensions.DefaultCommenceTime); + prediction.HomeTeam.Should().NotBeNull().And.Be(UpcomingEventBuilderExtensions.DefaultHomeTeam); + prediction.Id.Should().NotBeNull().And.Be(UpcomingEventBuilderExtensions.DefaultId); prediction.Strategy.Should().NotBeNull().And.Be(nameof(AdjustedConsensusStrategy)); - prediction.Timestamp.Should().NotBeNull().And.Be(timestamp); - prediction.TraceId.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultTraceId); + prediction.Timestamp.Should().Be(timestamp); + prediction.TraceId.Should().Be(UpcomingEventBuilderExtensions.DefaultTraceId); prediction.Winner.Should().NotBeNull().And.Be("Liverpool"); } [Test] public void GetPrediction_WithUpcomingEventWithDraw_ReturnsPrediction() { - var upcomingEvent = new TestUpcomingEventBuilder().SetDefaults().SetOdds(new List + var upcomingEvent = new UpcomingEventBuilder().SetDefaults().SetOdds(new List { new() { @@ -101,7 +101,7 @@ public void GetPrediction_WithUpcomingEventWithDraw_ReturnsPrediction() Draw = 1.67, Home = 4.5 } - }).GetUpcomingEvent(); + }).Instance; var timestamp = DateTime.Now; @@ -110,21 +110,21 @@ public void GetPrediction_WithUpcomingEventWithDraw_ReturnsPrediction() var prediction = strategy.GetPrediction(upcomingEvent, timestamp); prediction.Should().NotBeNull(); - prediction.AwayTeam.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultAwayTeam); + prediction.AwayTeam.Should().NotBeNull().And.Be(UpcomingEventBuilderExtensions.DefaultAwayTeam); prediction.Bookmaker.Should().NotBeNull().And.Be("betclic"); - prediction.CommenceTime.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultCommenceTime); - prediction.HomeTeam.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultHomeTeam); - prediction.Id.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultId); + prediction.CommenceTime.Should().Be(UpcomingEventBuilderExtensions.DefaultCommenceTime); + prediction.HomeTeam.Should().NotBeNull().And.Be(UpcomingEventBuilderExtensions.DefaultHomeTeam); + prediction.Id.Should().NotBeNull().And.Be(UpcomingEventBuilderExtensions.DefaultId); prediction.Strategy.Should().NotBeNull().And.Be(nameof(AdjustedConsensusStrategy)); - prediction.Timestamp.Should().NotBeNull().And.Be(timestamp); - prediction.TraceId.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultTraceId); + prediction.Timestamp.Should().Be(timestamp); + prediction.TraceId.Should().Be(UpcomingEventBuilderExtensions.DefaultTraceId); prediction.Winner.Should().NotBeNull().And.Be("Draw"); } [Test] public void GetPrediction_WithValidUpcomingEvent_ReturnsPrediction() { - var upcomingEvent = new TestUpcomingEventBuilder().SetDefaults().GetUpcomingEvent(); + var upcomingEvent = new UpcomingEventBuilder().SetDefaults().Instance; var timestamp = DateTime.Now; @@ -133,14 +133,14 @@ public void GetPrediction_WithValidUpcomingEvent_ReturnsPrediction() var prediction = strategy.GetPrediction(upcomingEvent, timestamp); prediction.Should().NotBeNull(); - prediction.AwayTeam.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultAwayTeam); + prediction.AwayTeam.Should().NotBeNull().And.Be(UpcomingEventBuilderExtensions.DefaultAwayTeam); prediction.Bookmaker.Should().NotBeNull().And.Be("betclic"); - prediction.CommenceTime.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultCommenceTime); - prediction.HomeTeam.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultHomeTeam); - prediction.Id.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultId); + prediction.CommenceTime.Should().Be(UpcomingEventBuilderExtensions.DefaultCommenceTime); + prediction.HomeTeam.Should().NotBeNull().And.Be(UpcomingEventBuilderExtensions.DefaultHomeTeam); + prediction.Id.Should().NotBeNull().And.Be(UpcomingEventBuilderExtensions.DefaultId); prediction.Strategy.Should().NotBeNull().And.Be(nameof(AdjustedConsensusStrategy)); - prediction.Timestamp.Should().NotBeNull().And.Be(timestamp); - prediction.TraceId.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultTraceId); + prediction.Timestamp.Should().Be(timestamp); + prediction.TraceId.Should().Be(UpcomingEventBuilderExtensions.DefaultTraceId); prediction.Winner.Should().NotBeNull().And.Be("Manchester City"); } @@ -164,7 +164,7 @@ public void GetPrediction_WithNullTimestamp_ThrowsException() var action = () => { - _ = strategy.GetPrediction(new TestUpcomingEventBuilder().SetDefaults().GetUpcomingEvent(), null); + _ = strategy.GetPrediction(new UpcomingEventBuilder().SetDefaults().Instance, null); }; action.Should().Throw().WithParameterName("timestamp"); @@ -178,33 +178,23 @@ public void GetPrediction_WithNullOrEmptyId_ThrowsException(string? id) var action = () => { - _ = strategy.GetPrediction(new TestUpcomingEventBuilder().SetDefaults().SetId(id).GetUpcomingEvent(), DateTime.Now); + _ = strategy.GetPrediction(new UpcomingEventBuilder().SetDefaults().SetId(id).Instance, DateTime.Now); }; action.Should().Throw().WithParameterName(nameof(id)); } [Test] - public void GetPrediction_WithNullEventTimestamp_ReturnsNewInstance() + public void GetPrediction_WithNullEventTimestamp_ThrowsException() { - var upcomingEvent = new TestUpcomingEventBuilder().SetDefaults().SetTimestamp(null).GetUpcomingEvent(); - - var timestamp = DateTime.Now; - var strategy = new AdjustedConsensusStrategy(); - var prediction = strategy.GetPrediction(upcomingEvent, timestamp); + var action = () => + { + _ = strategy.GetPrediction(new UpcomingEventBuilder().SetDefaults().SetTimestamp(null).Instance, DateTime.Now); + }; - prediction.Should().NotBeNull(); - prediction.AwayTeam.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultAwayTeam); - prediction.Bookmaker.Should().NotBeNull().And.Be("betclic"); - prediction.CommenceTime.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultCommenceTime); - prediction.HomeTeam.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultHomeTeam); - prediction.Id.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultId); - prediction.Strategy.Should().NotBeNull().And.Be(nameof(AdjustedConsensusStrategy)); - prediction.Timestamp.Should().NotBeNull().And.Be(timestamp); - prediction.TraceId.Should().NotBeNull().And.Be(TestUpcomingEventBuilder.DefaultTraceId); - prediction.Winner.Should().NotBeNull().And.Be("Manchester City"); + action.Should().Throw().WithParameterName("timestamp"); } [Test] @@ -214,7 +204,7 @@ public void GetPrediction_WithNullEventTraceId_ThrowsException() var action = () => { - _ = strategy.GetPrediction(new TestUpcomingEventBuilder().SetDefaults().SetTraceId(null).GetUpcomingEvent(), DateTime.Now); + _ = strategy.GetPrediction(new UpcomingEventBuilder().SetDefaults().SetTraceId(null).Instance, DateTime.Now); }; action.Should().Throw().WithParameterName("traceId"); @@ -227,7 +217,7 @@ public void GetPrediction_WithNullEventCommenceTime_ThrowsException() var action = () => { - _ = strategy.GetPrediction(new TestUpcomingEventBuilder().SetDefaults().SetCommenceTime(null).GetUpcomingEvent(), DateTime.Now); + _ = strategy.GetPrediction(new UpcomingEventBuilder().SetDefaults().SetCommenceTime(null).Instance, DateTime.Now); }; action.Should().Throw().WithParameterName("commenceTime"); @@ -241,7 +231,7 @@ public void GetPrediction_WithNullEventAwayTeam_ThrowsException(string? awayTeam var action = () => { - _ = strategy.GetPrediction(new TestUpcomingEventBuilder().SetDefaults().SetAwayTeam(null).GetUpcomingEvent(), DateTime.Now); + _ = strategy.GetPrediction(new UpcomingEventBuilder().SetDefaults().SetAwayTeam(null).Instance, DateTime.Now); }; action.Should().Throw().WithParameterName(nameof(awayTeam)); @@ -255,7 +245,7 @@ public void GetPrediction_WithNullEventHomeTeam_ThrowsException(string? homeTeam var action = () => { - _ = strategy.GetPrediction(new TestUpcomingEventBuilder().SetDefaults().SetHomeTeam(null).GetUpcomingEvent(), DateTime.Now); + _ = strategy.GetPrediction(new UpcomingEventBuilder().SetDefaults().SetHomeTeam(null).Instance, DateTime.Now); }; action.Should().Throw().WithParameterName(nameof(homeTeam)); @@ -268,7 +258,7 @@ public void GetPrediction_WithNullOdds_ThrowsException() var action = () => { - _ = strategy.GetPrediction(new TestUpcomingEventBuilder().SetDefaults().SetOdds(null).GetUpcomingEvent(), DateTime.Now); + _ = strategy.GetPrediction(new UpcomingEventBuilder().SetDefaults().SetOdds(null).Instance, DateTime.Now); }; action.Should().Throw().WithParameterName("odds"); @@ -281,7 +271,7 @@ public void GetPrediction_WithEmptyOdds_ThrowsException() var action = () => { - _ = strategy.GetPrediction(new TestUpcomingEventBuilder().SetDefaults().SetOdds(new List() { }).GetUpcomingEvent(), DateTime.Now); + _ = strategy.GetPrediction(new UpcomingEventBuilder().SetDefaults().SetOdds(new List() { }).Instance, DateTime.Now); }; action.Should().Throw().WithParameterName("odds"); @@ -294,12 +284,12 @@ public void GetPrediction_WithNullAwayScoreInOdds_ThrowsException() var action = () => { - _ = strategy.GetPrediction(new TestUpcomingEventBuilder().SetDefaults().SetOdds(new List() { - new TestOddsBuilder().SetDefaults().SetAway(null).Instance - }).GetUpcomingEvent(), DateTime.Now); + _ = strategy.GetPrediction(new UpcomingEventBuilder().SetDefaults().SetOdds(new List() { + new OddBuilder().SetDefaults().SetAway(null).Instance + }).Instance, DateTime.Now); }; - action.Should().Throw().WithParameterName("odd"); + action.Should().Throw().WithParameterName("away"); } [TestCase("")] @@ -310,9 +300,9 @@ public void GetPrediction_WithNullOrEmptyBookmakerInOdds_ThrowsException(string? var action = () => { - _ = strategy.GetPrediction(new TestUpcomingEventBuilder().SetDefaults().SetOdds(new List() { - new TestOddsBuilder().SetDefaults().SetBookmaker(bookmaker).Instance - }).GetUpcomingEvent(), DateTime.Now); + _ = strategy.GetPrediction(new UpcomingEventBuilder().SetDefaults().SetOdds(new List() { + new OddBuilder().SetDefaults().SetBookmaker(bookmaker).Instance + }).Instance, DateTime.Now); }; action.Should().Throw().WithParameterName(nameof(bookmaker)); @@ -325,12 +315,12 @@ public void GetPrediction_WithNullDrawScoreInOdds_ThrowsException() var action = () => { - _ = strategy.GetPrediction(new TestUpcomingEventBuilder().SetDefaults().SetOdds(new List() { - new TestOddsBuilder().SetDefaults().SetDraw(null).Instance - }).GetUpcomingEvent(), DateTime.Now); + _ = strategy.GetPrediction(new UpcomingEventBuilder().SetDefaults().SetOdds(new List() { + new OddBuilder().SetDefaults().SetDraw(null).Instance + }).Instance, DateTime.Now); }; - action.Should().Throw().WithParameterName("odd"); + action.Should().Throw().WithParameterName("draw"); } [Test] @@ -340,11 +330,11 @@ public void GetPrediction_WithNullHomeScoreInOdds_ThrowsException() var action = () => { - _ = strategy.GetPrediction(new TestUpcomingEventBuilder().SetDefaults().SetOdds(new List() { - new TestOddsBuilder().SetDefaults().SetHome(null).Instance - }).GetUpcomingEvent(), DateTime.Now); + _ = strategy.GetPrediction(new UpcomingEventBuilder().SetDefaults().SetOdds(new List() { + new OddBuilder().SetDefaults().SetHome(null).Instance + }).Instance, DateTime.Now); }; - action.Should().Throw().WithParameterName("odd"); + action.Should().Throw().WithParameterName("home"); } } diff --git a/OddsCollector.Functions.Predictions.Tests/Strategies/OddsBuilderExtensions.cs b/OddsCollector.Functions.Predictions.Tests/Strategies/OddsBuilderExtensions.cs new file mode 100644 index 0000000..c29ea09 --- /dev/null +++ b/OddsCollector.Functions.Predictions.Tests/Strategies/OddsBuilderExtensions.cs @@ -0,0 +1,20 @@ +using OddsCollector.Common.Models; + +namespace OddsCollector.Functions.Predictions.Tests.Strategies; + +internal static class OddsBuilderExtensions +{ + public const double DefaultAway = 4.08; + public const string DefaultBookmaker = "betclic"; + public const double DefaultDraw = 3.82; + public const double DefaultHome = 1.8; + + public static OddBuilder SetDefaults(this OddBuilder builder) + { + return builder + .SetAway(DefaultAway) + .SetBookmaker(DefaultBookmaker) + .SetHome(DefaultHome) + .SetDraw(DefaultDraw); + } +} diff --git a/OddsCollector.Functions.Predictions.Tests/Strategies/StrategyScoreBuilderTest.cs b/OddsCollector.Functions.Predictions.Tests/Strategies/StrategyScoreBuilderTest.cs deleted file mode 100644 index 1fcd3f2..0000000 --- a/OddsCollector.Functions.Predictions.Tests/Strategies/StrategyScoreBuilderTest.cs +++ /dev/null @@ -1,102 +0,0 @@ -using FluentAssertions; -using OddsCollector.Functions.Predictions.Strategies; - -namespace OddsCollector.Functions.Predictions.Tests.Strategies; - -internal class StrategyScoreBuilderTest -{ - [Test] - public void Constructor_WithoutParameters_ReturnsValidInstance() - { - var result = new StrategyScoreBuilder().Instance; - - result.Should().NotBeNull(); - } - - [Test] - public void Constructor_WithFullParameterList_ReturnsValidInstance() - { - const string bookmaker = nameof(bookmaker); - const string name = nameof(name); - const double odd = 1.1; - - var result = new StrategyScoreBuilder() - .SetBookmaker(bookmaker) - .SetName(name) - .SetOdd(odd) - .Instance; - - result.Should().NotBeNull(); - result.Bookmaker.Should().NotBeNull().And.Be(bookmaker); - result.Name.Should().NotBeNull().And.Be(name); - result.Odd.Should().NotBeNull().And.Be(odd); - } - - [Test] - public void SetBookmaker_WithValidBookmaker_ReturnsValidInstance() - { - const string bookmaker = nameof(bookmaker); - - var result = new StrategyScoreBuilder().SetBookmaker(bookmaker).Instance; - - result.Should().NotBeNull(); - result.Bookmaker.Should().NotBeNull().And.Be(bookmaker); - } - - [Test] - public void SetName_WithValidName_ReturnsValidInstance() - { - const string name = nameof(name); - - var result = new StrategyScoreBuilder().SetName(name).Instance; - - result.Should().NotBeNull(); - result.Name.Should().NotBeNull().And.Be(name); - } - - [Test] - public void SetOdd_WithValidOdd_ReturnsValidInstance() - { - const double odd = 1.1; - - var result = new StrategyScoreBuilder().SetOdd(odd).Instance; - - result.Should().NotBeNull(); - result.Odd.Should().NotBeNull().And.Be(odd); - } - - [TestCase("")] - [TestCase(null)] - public void SetBookmaker_WithNullOrEmptyBookmaker_ThrowsException(string? bookmaker) - { - var action = () => - { - var result = new StrategyScoreBuilder().SetBookmaker(bookmaker).Instance; - }; - - action.Should().Throw().WithParameterName(nameof(bookmaker)); - } - - [TestCase("")] - [TestCase(null)] - public void SetName_WithNullOrEmptyName_ThrowsException(string? name) - { - var action = () => - { - var result = new StrategyScoreBuilder().SetName(name).Instance; - }; - - action.Should().Throw().WithParameterName(nameof(name)); - } - - [Test] - public void SetOdd_WithNullOdd_ThrowsException() - { - var action = () => - { - var result = new StrategyScoreBuilder().SetOdd(null).Instance; - }; - - action.Should().Throw().WithParameterName("odd"); - } -} diff --git a/OddsCollector.Functions.Predictions.Tests/Strategies/TestOddsBuilder.cs b/OddsCollector.Functions.Predictions.Tests/Strategies/TestOddsBuilder.cs deleted file mode 100644 index 9471bdd..0000000 --- a/OddsCollector.Functions.Predictions.Tests/Strategies/TestOddsBuilder.cs +++ /dev/null @@ -1,51 +0,0 @@ -using OddsCollector.Common.Models; - -namespace OddsCollector.Functions.Predictions.Tests.Strategies; - -internal class TestOddsBuilder -{ - public const double DefaultAway = 4.08; - public const string DefaultBookmaker = "betclic"; - public const double DefaultDraw = 3.82; - public const double DefaultHome = 1.8; - - private readonly Odd _state = new(); - - public TestOddsBuilder SetDefaults() - { - return SetAway(DefaultAway) - .SetBookmaker(DefaultBookmaker) - .SetHome(DefaultHome) - .SetDraw(DefaultDraw); - } - - public TestOddsBuilder SetBookmaker(string? bookmaker) - { - _state.Bookmaker = bookmaker; - - return this; - } - - public TestOddsBuilder SetAway(double? away) - { - _state.Away = away; - - return this; - } - - public TestOddsBuilder SetDraw(double? draw) - { - _state.Draw = draw; - - return this; - } - - public TestOddsBuilder SetHome(double? home) - { - _state.Home = home; - - return this; - } - - public Odd Instance => _state; -} diff --git a/OddsCollector.Functions.Predictions.Tests/Strategies/TestUpcomingEventBuilder.cs b/OddsCollector.Functions.Predictions.Tests/Strategies/TestUpcomingEventBuilder.cs deleted file mode 100644 index 7e6e6c5..0000000 --- a/OddsCollector.Functions.Predictions.Tests/Strategies/TestUpcomingEventBuilder.cs +++ /dev/null @@ -1,86 +0,0 @@ -using OddsCollector.Common.Models; - -namespace OddsCollector.Functions.Predictions.Tests.Strategies; - -internal class TestUpcomingEventBuilder -{ - public const string DefaultAwayTeam = "Liverpool"; - public const string DefaultHomeTeam = "Manchester City"; - public const string DefaultId = "4acd8f2675ca847ba33eea3664f6c0bb"; - public static readonly DateTime DefaultCommenceTime = new(2023, 11, 25, 12, 30, 0); - public static readonly DateTime DefaultTimestamp = new(2023, 11, 25, 15, 30, 0); - public static readonly Guid DefaultTraceId = new("447b57dd-84bc-4e79-95d0-695f7493bf41"); - public static readonly IEnumerable DefaultOdds = new List - { - new TestOddsBuilder().SetDefaults().Instance, - new TestOddsBuilder().SetAway(4.33).SetBookmaker("sport888").SetDraw(4.33).SetHome(1.7).Instance, - new TestOddsBuilder().SetAway(4.5).SetBookmaker("mybookieag").SetDraw(4.5).SetHome(1.67).Instance, - }; - - private readonly UpcomingEvent _state = new(); - - public TestUpcomingEventBuilder SetDefaults() - { - return SetAwayTeam(DefaultAwayTeam) - .SetCommenceTime(DefaultCommenceTime) - .SetHomeTeam(DefaultHomeTeam) - .SetId(DefaultId) - .SetTimestamp(DefaultTimestamp) - .SetTraceId(DefaultTraceId) - .SetOdds(DefaultOdds); - } - - public TestUpcomingEventBuilder SetAwayTeam(string? awayTeam) - { - _state.AwayTeam = awayTeam; - - return this; - } - - public TestUpcomingEventBuilder SetCommenceTime(DateTime? commenceTime) - { - _state.CommenceTime = commenceTime; - - return this; - } - - public TestUpcomingEventBuilder SetHomeTeam(string? homeTeam) - { - _state.HomeTeam = homeTeam; - - return this; - } - - public TestUpcomingEventBuilder SetId(string? id) - { - _state.Id = id; - - return this; - } - - public TestUpcomingEventBuilder SetTimestamp(DateTime? timestamp) - { - _state.Timestamp = timestamp; - - return this; - } - - public TestUpcomingEventBuilder SetTraceId(Guid? traceId) - { - _state.TraceId = traceId; - - return this; - } - - public TestUpcomingEventBuilder SetOdds(IEnumerable? odds) - { - _state.Odds = odds; - - return this; - } - - public UpcomingEvent GetUpcomingEvent() - { - return _state; - } -} diff --git a/OddsCollector.Functions.Predictions.Tests/Strategies/UpcomingEventBuilderExtensions.cs b/OddsCollector.Functions.Predictions.Tests/Strategies/UpcomingEventBuilderExtensions.cs new file mode 100644 index 0000000..b8aaee3 --- /dev/null +++ b/OddsCollector.Functions.Predictions.Tests/Strategies/UpcomingEventBuilderExtensions.cs @@ -0,0 +1,31 @@ +using OddsCollector.Common.Models; + +namespace OddsCollector.Functions.Predictions.Tests.Strategies; + +internal static class UpcomingEventBuilderExtensions +{ + public const string DefaultAwayTeam = "Liverpool"; + public const string DefaultHomeTeam = "Manchester City"; + public const string DefaultId = "4acd8f2675ca847ba33eea3664f6c0bb"; + public static readonly DateTime DefaultCommenceTime = new(2023, 11, 25, 12, 30, 0); + public static readonly DateTime DefaultTimestamp = new(2023, 11, 25, 15, 30, 0); + public static readonly Guid DefaultTraceId = new("447b57dd-84bc-4e79-95d0-695f7493bf41"); + public static readonly IEnumerable DefaultOdds = new List + { + new OddBuilder().SetDefaults().Instance, + new OddBuilder().SetAway(4.33).SetBookmaker("sport888").SetDraw(4.33).SetHome(1.7).Instance, + new OddBuilder().SetAway(4.5).SetBookmaker("mybookieag").SetDraw(4.5).SetHome(1.67).Instance, + }; + + public static UpcomingEventBuilder SetDefaults(this UpcomingEventBuilder builder) + { + return builder + .SetAwayTeam(DefaultAwayTeam) + .SetCommenceTime(DefaultCommenceTime) + .SetHomeTeam(DefaultHomeTeam) + .SetId(DefaultId) + .SetTimestamp(DefaultTimestamp) + .SetTraceId(DefaultTraceId) + .SetOdds(DefaultOdds); + } +} diff --git a/OddsCollector.Functions.Predictions/Strategies/AdjustedConsensusStrategy.cs b/OddsCollector.Functions.Predictions/Strategies/AdjustedConsensusStrategy.cs index 2ed5090..8c3ce50 100644 --- a/OddsCollector.Functions.Predictions/Strategies/AdjustedConsensusStrategy.cs +++ b/OddsCollector.Functions.Predictions/Strategies/AdjustedConsensusStrategy.cs @@ -35,13 +35,8 @@ public EventPrediction GetPrediction(UpcomingEvent? upcomingEvent, DateTime? tim .Instance; } - private static StrategyScore GetWinner(IEnumerable? odds, string? awayTeam, string? homeTeam) + private static StrategyScore GetWinner(IEnumerable odds, string awayTeam, string homeTeam) { - if (odds is null) - { - throw new ArgumentNullException(nameof(odds)); - } - if (!odds.Any()) { throw new ArgumentException($"{nameof(odds)} cannot be empty", nameof(odds)); @@ -57,54 +52,73 @@ private static StrategyScore GetWinner(IEnumerable? odds, string? awayTeam throw new ArgumentException($"{nameof(homeTeam)} is null or empty", nameof(homeTeam)); } - IEnumerable filteredOdds = odds.Where(o => o is not null).ToList()!; + IEnumerable filteredOdds = odds.Where(o => o is not null).ToList(); var scores = new List() { - new StrategyScoreBuilder().SetName(Constants.Draw).SetOdd(CalculateAdjustedScore(filteredOdds, Draw, 0.057)).Instance, - new StrategyScoreBuilder().SetName(awayTeam).SetOdd(CalculateAdjustedScore(filteredOdds, AwayTeamWins, 0.034)).Instance, - new StrategyScoreBuilder().SetName(homeTeam).SetOdd(CalculateAdjustedScore(filteredOdds, HomeTeamWins, 0.037)).Instance + new() + { + Name = Constants.Draw, + Odd = CalculateAdjustedScore(filteredOdds, Draw, 0.057) + }, + new() + { + Name = awayTeam, + Odd = CalculateAdjustedScore(filteredOdds, AwayTeamWins, 0.034) + }, + new() + { + Name = homeTeam, + Odd = CalculateAdjustedScore(filteredOdds, HomeTeamWins, 0.037) + } }; - var winner = scores.MaxBy(p => p.Odd)!; + var winner = scores.MaxBy(p => p.Odd); - winner.Bookmaker = GetBestOdd(odds!, winner.Name!, awayTeam, homeTeam)?.Bookmaker; + winner!.Bookmaker = GetBestOdd(filteredOdds, winner.Name, awayTeam, homeTeam).Bookmaker; return winner; } - private static double? CalculateAdjustedScore(IEnumerable odds, Func filter, double adjustment) + private static double CalculateAdjustedScore(IEnumerable odds, Func filter, double adjustment) { var average = odds.Select(filter).Average(); return average == 0 ? 0 : (1 / average) - adjustment; } - private static Odd? GetBestOdd(IEnumerable odds, string winner, string awayTeam, string homeTeam) + private static Odd GetBestOdd(IEnumerable odds, string winner, string awayTeam, string homeTeam) { + IEnumerable? filtered = null; + if (winner == Constants.Draw) { - return GetBestOdd(odds, Draw); + filtered = odds.OrderByDescending(Draw); } - return winner == awayTeam ? GetBestOdd(odds, AwayTeamWins) : GetBestOdd(odds, HomeTeamWins); - } + if (winner == awayTeam) + { + filtered = odds.OrderByDescending(AwayTeamWins); + } - private static Odd? GetBestOdd(IEnumerable odds, Func filter) - { - return odds.Where(o => o is not null).OrderByDescending(filter).FirstOrDefault(); + if (winner == homeTeam) + { + filtered = odds.OrderByDescending(HomeTeamWins); + } + + return filtered!.FirstOrDefault()!; } - private static double? Draw(Odd odd) + private static double Draw(Odd odd) { return odd.Draw; } - private static double? AwayTeamWins(Odd odd) + private static double AwayTeamWins(Odd odd) { return odd.Away; } - private static double? HomeTeamWins(Odd odd) + private static double HomeTeamWins(Odd odd) { return odd.Home; } diff --git a/OddsCollector.Functions.Predictions/Strategies/StrategyScore.cs b/OddsCollector.Functions.Predictions/Strategies/StrategyScore.cs index 21412ae..02f61a9 100644 --- a/OddsCollector.Functions.Predictions/Strategies/StrategyScore.cs +++ b/OddsCollector.Functions.Predictions/Strategies/StrategyScore.cs @@ -2,7 +2,7 @@ internal class StrategyScore { - public string? Name { get; set; } - public double? Odd { get; set; } - public string? Bookmaker { get; set; } + public string Name { get; set; } = string.Empty; + public double Odd { get; set; } + public string Bookmaker { get; set; } = string.Empty; } diff --git a/OddsCollector.Functions.Predictions/Strategies/StrategyScoreBuilder.cs b/OddsCollector.Functions.Predictions/Strategies/StrategyScoreBuilder.cs deleted file mode 100644 index 24ffb3d..0000000 --- a/OddsCollector.Functions.Predictions/Strategies/StrategyScoreBuilder.cs +++ /dev/null @@ -1,44 +0,0 @@ -namespace OddsCollector.Functions.Predictions.Strategies; - -internal class StrategyScoreBuilder -{ - private readonly StrategyScore _state = new(); - - public StrategyScoreBuilder SetBookmaker(string? bookmaker) - { - if (string.IsNullOrEmpty(bookmaker)) - { - throw new ArgumentException($"{nameof(bookmaker)} cannot be null or empty", nameof(bookmaker)); - } - - _state.Bookmaker = bookmaker; - - return this; - } - - public StrategyScoreBuilder SetName(string? name) - { - if (string.IsNullOrEmpty(name)) - { - throw new ArgumentException($"{nameof(name)} cannot be null or empty", nameof(name)); - } - - _state.Name = name; - - return this; - } - - public StrategyScoreBuilder SetOdd(double? odd) - { - if (odd is null) - { - throw new ArgumentNullException(nameof(odd), $"odd for {_state.Name} cannot be null"); - } - - _state.Odd = odd; - - return this; - } - - public StrategyScore Instance => _state; -} diff --git a/OddsCollector.Functions.UpcomingEvents.Tests/UpcomingEventsFunctionTest.cs b/OddsCollector.Functions.UpcomingEvents.Tests/UpcomingEventsFunctionTest.cs index 76afa04..e81e24c 100644 --- a/OddsCollector.Functions.UpcomingEvents.Tests/UpcomingEventsFunctionTest.cs +++ b/OddsCollector.Functions.UpcomingEvents.Tests/UpcomingEventsFunctionTest.cs @@ -1,10 +1,8 @@ using FluentAssertions; using Microsoft.Azure.Functions.Worker; -using Microsoft.Extensions.Options; using NSubstitute; using OddsCollector.Common.Models; using OddsCollector.Common.OddsApi.Client; -using OddsCollector.Common.OddsApi.Configuration; namespace OddsCollector.Functions.UpcomingEvents.Tests; @@ -13,23 +11,9 @@ internal class UpcomingEventsFunctionTest [Test] public void Constructor_WithValidDependencies_ReturnsNewInstance() { - var clientStub = Substitute.For(); - var optionsStub = Substitute.For>(); - optionsStub.Value.Returns(new OddsApiOptions { Leagues = new HashSet { "league1" } }); + var clientStub = Substitute.For(); - var function = new UpcomingEventsFunction(optionsStub, clientStub); - - function.Should().NotBeNull(); - } - - [Test] - public void Constructor_WithEmptyLeagues_ReturnsNewInstance() - { - var clientStub = Substitute.For(); - var optionsStub = Substitute.For>(); - optionsStub.Value.Returns(new OddsApiOptions { Leagues = new HashSet() }); - - var function = new UpcomingEventsFunction(optionsStub, clientStub); + var function = new UpcomingEventsFunction(clientStub); function.Should().NotBeNull(); } @@ -37,57 +21,23 @@ public void Constructor_WithEmptyLeagues_ReturnsNewInstance() [Test] public void Constructor_WithNullOddsClient_ThrowsException() { - var optionsStub = Substitute.For>(); - optionsStub.Value.Returns(new OddsApiOptions { Leagues = new HashSet { "league1" } }); - var action = () => { - _ = new UpcomingEventsFunction(optionsStub, null); + _ = new UpcomingEventsFunction(null); }; action.Should().Throw().WithParameterName("client"); } - [Test] - public void Constructor_WithNullOptions_ThrowsException() - { - var clientStub = Substitute.For(); - - var action = () => - { - _ = new UpcomingEventsFunction(null!, clientStub); - }; - - action.Should().Throw().WithParameterName("options"); - } - - [Test] - public void Constructor_WithNullLeagues_ThrowsException() - { - var clientStub = Substitute.For(); - var optionsStub = Substitute.For>(); - optionsStub.Value.Returns(new OddsApiOptions { Leagues = null! }); - - var action = () => - { - _ = new UpcomingEventsFunction(null!, clientStub); - }; - - action.Should().Throw().WithParameterName("options"); - } - [Test] public async Task Run_WithValidTimer_ReturnsEventResults() { IEnumerable expectedEventResults = new List(); - var clientStub = Substitute.For(); - clientStub.GetUpcomingEventsAsync(Arg.Any>()).Returns(Task.FromResult(expectedEventResults)); - - var optionsStub = Substitute.For>(); - optionsStub.Value.Returns(new OddsApiOptions { Leagues = new HashSet() }); + var clientStub = Substitute.For(); + clientStub.GetUpcomingEventsAsync(Arg.Any(), Arg.Any()).Returns(Task.FromResult(expectedEventResults)); - var function = new UpcomingEventsFunction(optionsStub, clientStub); + var function = new UpcomingEventsFunction(clientStub); var timerStub = Substitute.For(); diff --git a/OddsCollector.Functions.UpcomingEvents/Program.cs b/OddsCollector.Functions.UpcomingEvents/Program.cs index 31fd818..ea8132b 100644 --- a/OddsCollector.Functions.UpcomingEvents/Program.cs +++ b/OddsCollector.Functions.UpcomingEvents/Program.cs @@ -12,10 +12,10 @@ .ConfigureFunctionsWorkerDefaults() .ConfigureServices(services => { - services.Configure(o => + services.Configure(o => { // workaround for https://github.com/MicrosoftDocs/azure-docs/issues/32962 - o.SetLeagues(Environment.GetEnvironmentVariable("OddsApi:Leagues")); + o.SetLeagues(Environment.GetEnvironmentVariable("OddsApiClient:Leagues")); }); services.AddHttpClient(); services.AddSingleton(); @@ -25,7 +25,7 @@ SecretClientFactory.CreateSecretClient(Environment.GetEnvironmentVariable("KeyVault:Name")) ); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddApplicationInsightsTelemetryWorkerService(); services.ConfigureFunctionsApplicationInsights(); }) diff --git a/OddsCollector.Functions.UpcomingEvents/UpcomingEventsFunction.cs b/OddsCollector.Functions.UpcomingEvents/UpcomingEventsFunction.cs index 5f9975e..83ff839 100644 --- a/OddsCollector.Functions.UpcomingEvents/UpcomingEventsFunction.cs +++ b/OddsCollector.Functions.UpcomingEvents/UpcomingEventsFunction.cs @@ -1,9 +1,7 @@ using System.Runtime.CompilerServices; using Microsoft.Azure.Functions.Worker; -using Microsoft.Extensions.Options; using OddsCollector.Common.Models; using OddsCollector.Common.OddsApi.Client; -using OddsCollector.Common.OddsApi.Configuration; [assembly: InternalsVisibleTo("OddsCollector.Functions.UpcomingEvents.Tests")] // DynamicProxyGenAssembly2 is a temporary assembly built by mocking systems that use CastleProxy @@ -13,12 +11,10 @@ namespace OddsCollector.Functions.UpcomingEvents; internal sealed class UpcomingEventsFunction { - private readonly IOddsClient _client; - private readonly HashSet _leagues; + private readonly IOddsApiClient _client; - public UpcomingEventsFunction(IOptions? options, IOddsClient? client) + public UpcomingEventsFunction(IOddsApiClient? client) { - _leagues = options?.Value?.Leagues ?? throw new ArgumentNullException(nameof(options)); _client = client ?? throw new ArgumentNullException(nameof(client)); } @@ -26,6 +22,6 @@ public UpcomingEventsFunction(IOptions? options, IOddsClient? cl [ServiceBusOutput("%ServiceBus:Queue%", Connection = "ServiceBus:Connection")] public async Task Run([TimerTrigger("%TimerInterval%")] TimerInfo myTimer) { - return (await _client.GetUpcomingEventsAsync(_leagues).ConfigureAwait(false)).ToArray(); + return (await _client.GetUpcomingEventsAsync(Guid.NewGuid(), DateTime.UtcNow).ConfigureAwait(false)).ToArray(); } }