From 031a7a90d9133ed31ae653599932ce863258de91 Mon Sep 17 00:00:00 2001 From: romankr Date: Sun, 10 Dec 2023 02:58:06 +0400 Subject: [PATCH] next try --- .../CosmosDb/ContainerFactoryTests.cs | 58 ----- .../CosmosDb/CosmosDbClientTests.cs | 17 -- .../ServiceCollectionExtensionsTests.cs | 12 +- .../Converter/OddsApiObjectConverterTests.cs | 210 ++++++++++-------- .../Converter/TestAnonymous2Builder.cs | 35 +-- .../Converter/TestAnonymous3Builder.cs | 7 +- .../OddsApi/OddsApiClientTests.cs | 13 +- .../OddsCollector.Functions.Tests.csproj | 14 +- .../ServiceCollectionExtensionsTests.cs | 25 +++ .../CosmosDb/ContainerFactory.cs | 15 -- .../CosmosDb/CosmosDbClient.cs | 40 ---- .../CosmosDb/ICosmosDbClient.cs | 8 - .../Functions/EventResultsFunction.cs | 5 +- .../Functions/PredictionFunction.cs | 7 +- .../Functions/PredictionsHttpFunction.cs | 30 ++- .../Functions/UpcomingEventsFunction.cs | 9 +- OddsCollector.Functions/Models/Constants.cs | 2 +- .../Models/EventPrediction.cs | 2 +- .../Models/EventPredictionBuilder.cs | 2 +- OddsCollector.Functions/Models/EventResult.cs | 2 +- .../Models/EventResultBuilder.cs | 2 +- OddsCollector.Functions/Models/Odd.cs | 2 +- OddsCollector.Functions/Models/OddBuilder.cs | 2 +- .../Models/UpcomingEvent.cs | 2 +- .../Models/UpcomingEventBuilder.cs | 2 +- .../Configuration/OddsApiClientOptions.cs | 2 +- .../ServiceCollectionExtensions.cs | 2 +- .../Converter/IOddsApiObjectConverter.cs | 2 +- .../Converter/OddsApiObjectConverter.cs | 2 +- .../OddsApi/IOddsApiClient.cs | 9 +- .../OddsApi/OddsApiClient.cs | 21 +- .../OddsCollector.Functions.csproj | 22 +- OddsCollector.Functions/Program.cs | 6 +- .../Strategies/AdjustedConsensusStrategy.cs | 11 +- .../ServiceCollectionExtensions.cs | 13 ++ .../Strategies/IPredictionStrategy.cs | 2 +- OddsCollector.Functions/host.json | 18 +- 37 files changed, 299 insertions(+), 334 deletions(-) delete mode 100644 OddsCollector.Functions.Tests/CosmosDb/ContainerFactoryTests.cs delete mode 100644 OddsCollector.Functions.Tests/CosmosDb/CosmosDbClientTests.cs create mode 100644 OddsCollector.Functions.Tests/Strategies/Configuration/ServiceCollectionExtensionsTests.cs delete mode 100644 OddsCollector.Functions/CosmosDb/ContainerFactory.cs delete mode 100644 OddsCollector.Functions/CosmosDb/CosmosDbClient.cs delete mode 100644 OddsCollector.Functions/CosmosDb/ICosmosDbClient.cs create mode 100644 OddsCollector.Functions/Strategies/Configuration/ServiceCollectionExtensions.cs diff --git a/OddsCollector.Functions.Tests/CosmosDb/ContainerFactoryTests.cs b/OddsCollector.Functions.Tests/CosmosDb/ContainerFactoryTests.cs deleted file mode 100644 index e52b8e4..0000000 --- a/OddsCollector.Functions.Tests/CosmosDb/ContainerFactoryTests.cs +++ /dev/null @@ -1,58 +0,0 @@ -using OddsCollector.Functions.CosmosDb; - -namespace OddsCollector.Functions.Tests.CosmosDb; - -[Parallelizable(ParallelScope.All)] -internal class ContainerFactoryTests -{ - [Test] - public void CreateContainer_WithValidParameters_ReturnsNewInstance() - { - string databaseId = nameof(databaseId); - - var container = ContainerFactory.CreateContainer( - "AccountEndpoint=https://test.documents.azure.com:443/;AccountKey=test", databaseId, "containerId"); - - container.Should().NotBeNull(); - container.Database.Should().NotBeNull(); - container.Database.Id.Should().NotBeNull().And.Be(databaseId); - } - - [TestCase("")] - [TestCase(null)] - public void CreateContainer_WithNullOrEmptyConnectionString_ThrowsException(string? connectionString) - { - var action = () => - { - _ = ContainerFactory.CreateContainer(connectionString, "databaseId", "containerId"); - }; - - action.Should().Throw().WithParameterName(nameof(connectionString)); - } - - [TestCase("")] - [TestCase(null)] - public void CreateContainer_WithNullOrEmptyDatabaseId_ThrowsException(string? databaseId) - { - var action = () => - { - _ = ContainerFactory.CreateContainer( - "AccountEndpoint=https://test.documents.azure.com:443/;AccountKey=test", databaseId, "containerId"); - }; - - action.Should().Throw().WithParameterName(nameof(databaseId)); - } - - [TestCase("")] - [TestCase(null)] - public void CreateContainer_WithNullOrEmptyContainerId_ThrowsException(string? containerId) - { - var action = () => - { - _ = ContainerFactory.CreateContainer( - "AccountEndpoint=https://test.documents.azure.com:443/;AccountKey=test", "databaseId", containerId); - }; - - action.Should().Throw().WithParameterName(nameof(containerId)); - } -} diff --git a/OddsCollector.Functions.Tests/CosmosDb/CosmosDbClientTests.cs b/OddsCollector.Functions.Tests/CosmosDb/CosmosDbClientTests.cs deleted file mode 100644 index 5873b67..0000000 --- a/OddsCollector.Functions.Tests/CosmosDb/CosmosDbClientTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -using OddsCollector.Functions.CosmosDb; - -namespace OddsCollector.Functions.Tests.CosmosDb; - -[Parallelizable(ParallelScope.All)] -internal class CosmosDbClientTests -{ - [Test] - public void Constructor_WithValidDependencies_ReturnsNewInstance() - { - var result = new CosmosDbClient(); - - result.Should().NotBeNull(); - } - - // todo: test for GetEventPredictionsAsync() - hard to mock all the dependencies atm -} diff --git a/OddsCollector.Functions.Tests/OddsApi/Configuration/ServiceCollectionExtensionsTests.cs b/OddsCollector.Functions.Tests/OddsApi/Configuration/ServiceCollectionExtensionsTests.cs index e9d881c..a20c332 100644 --- a/OddsCollector.Functions.Tests/OddsApi/Configuration/ServiceCollectionExtensionsTests.cs +++ b/OddsCollector.Functions.Tests/OddsApi/Configuration/ServiceCollectionExtensionsTests.cs @@ -18,30 +18,30 @@ public void AddOddsApiClientWithDependencies_AddsProperlyConfiguredOddsApiClient var options = services.FirstOrDefault( x => x.ServiceType == typeof(IConfigureOptions) - && x.Lifetime == ServiceLifetime.Singleton); + && x.Lifetime == ServiceLifetime.Singleton); options.Should().NotBeNull(); var httpClient = services.FirstOrDefault( x => x.ServiceType == typeof(HttpClient) - && x.Lifetime == ServiceLifetime.Transient); + && x.Lifetime == ServiceLifetime.Transient); httpClient.Should().NotBeNull(); var client = services.FirstOrDefault( x => x.ImplementationType == typeof(Client) - && x.ServiceType == typeof(IClient) - && x.Lifetime == ServiceLifetime.Singleton); + && x.ServiceType == typeof(IClient) + && x.Lifetime == ServiceLifetime.Singleton); client.Should().NotBeNull(); var oddsApiClient = services.FirstOrDefault( x => x.ImplementationType == typeof(OddsApiClient) - && x.ServiceType == typeof(IOddsApiClient) - && x.Lifetime == ServiceLifetime.Singleton); + && x.ServiceType == typeof(IOddsApiClient) + && x.Lifetime == ServiceLifetime.Singleton); oddsApiClient.Should().NotBeNull(); } diff --git a/OddsCollector.Functions.Tests/OddsApi/Converter/OddsApiObjectConverterTests.cs b/OddsCollector.Functions.Tests/OddsApi/Converter/OddsApiObjectConverterTests.cs index 335e3b1..81fc845 100644 --- a/OddsCollector.Functions.Tests/OddsApi/Converter/OddsApiObjectConverterTests.cs +++ b/OddsCollector.Functions.Tests/OddsApi/Converter/OddsApiObjectConverterTests.cs @@ -115,7 +115,8 @@ public void ToUpcomingEvents_WithNullBookmakers_ThrowsException() { var converter = new OddsApiObjectConverter(); - List rawUpcomingEvents = [ + List rawUpcomingEvents = + [ new TestAnonymous2Builder().SetDefaults().SetBookmakers(null).Instance ]; @@ -133,7 +134,8 @@ public void ToUpcomingEvents_WithNullOrEmptyAwayTeam_ThrowsException(string? awa { var converter = new OddsApiObjectConverter(); - List rawUpcomingEvents = [ + List rawUpcomingEvents = + [ new TestAnonymous2Builder().SetDefaults().SetAwayTeam(awayTeam).Instance ]; @@ -173,20 +175,20 @@ public void ToUpcomingEvents_WithNullOrEmptyBookmakerKey_ThrowsException(string? List rawUpcomingEvents = [ new TestAnonymous2Builder().SetDefaults().SetBookmakers( - [ - new() + [ + new Bookmakers { Key = bookmaker, Markets = [ - new() + new Markets2 { Key = Markets2Key.H2h, Outcomes = [ - new() { Name = "Liverpool", Price = 4.08 }, - new() { Name = "Manchester City", Price = 1.7 }, - new() { Name = "Draw", Price = 3.82 } + new Outcome { Name = "Liverpool", Price = 4.08 }, + new Outcome { Name = "Manchester City", Price = 1.7 }, + new Outcome { Name = "Draw", Price = 3.82 } ] } ] @@ -211,7 +213,7 @@ public void ToUpcomingEvents_WithNullMarkets_ThrowsException() List rawUpcomingEvents = [ new TestAnonymous2Builder().SetDefaults().SetBookmakers( - [new() { Key = "onexbet", Markets = null }] + [new Bookmakers { Key = "onexbet", Markets = null }] ).Instance ]; @@ -232,19 +234,19 @@ public void ToUpcomingEvents_WithNullMarketKey_ThrowsException() [ new TestAnonymous2Builder().SetDefaults().SetBookmakers( [ - new() + new Bookmakers { Key = "onexbet", Markets = [ - new() + new Markets2 { Key = null, Outcomes = [ - new() { Name = "Liverpool", Price = 4.33 }, - new() { Name = "Manchester City", Price = 1.7 }, - new() { Name = "Draw", Price = 4.33 } + new Outcome { Name = "Liverpool", Price = 4.33 }, + new Outcome { Name = "Manchester City", Price = 1.7 }, + new Outcome { Name = "Draw", Price = 4.33 } ] } ] @@ -269,7 +271,7 @@ public void ToUpcomingEvents_WithEmptyMarkets_ThrowsException() List rawUpcomingEvents = [ new TestAnonymous2Builder().SetDefaults().SetBookmakers( - [new() { Key = "onexbet", Markets = [] }] + [new Bookmakers { Key = "onexbet", Markets = [] }] ).Instance ]; @@ -286,15 +288,15 @@ public void ToUpcomingEvents_WithNullOutcomes_ThrowsException() { var converter = new OddsApiObjectConverter(); - List rawUpcomingEvents = [ + List rawUpcomingEvents = + [ new TestAnonymous2Builder().SetDefaults().SetBookmakers( - [ - new() + [ + new Bookmakers { - Key = "onexbet", - Markets = [new() { Key = Markets2Key.H2h, Outcomes = null }] + Key = "onexbet", Markets = [new Markets2 { Key = Markets2Key.H2h, Outcomes = null }] } - ] + ] ).Instance ]; @@ -311,17 +313,19 @@ public void ToUpcomingEvents_WithEmptyOutcomes_ThrowsException() { var converter = new OddsApiObjectConverter(); - List rawUpcomingEvents = [ + List rawUpcomingEvents = + [ new TestAnonymous2Builder().SetDefaults().SetBookmakers( - [ - new() + [ + new Bookmakers { Key = "onexbet", - Markets = [ - new() { Key = Markets2Key.H2h, Outcomes = [] } + Markets = + [ + new Markets2 { Key = Markets2Key.H2h, Outcomes = [] } ] } - ] + ] ).Instance ]; @@ -338,24 +342,27 @@ public void ToUpcomingEvents_WithOneOutcome_ThrowsException() { var converter = new OddsApiObjectConverter(); - List rawUpcomingEvents = [ + List rawUpcomingEvents = + [ new TestAnonymous2Builder().SetDefaults().SetBookmakers( - [ - new() + [ + new Bookmakers { Key = "onexbet", - Markets = [ - new() + Markets = + [ + new Markets2 { Key = Markets2Key.H2h, - Outcomes = [ - new() { Name = "Manchester City", Price = 1.7 }, - new() { Name = "Draw", Price = 4.33 } + Outcomes = + [ + new Outcome { Name = "Manchester City", Price = 1.7 }, + new Outcome { Name = "Draw", Price = 4.33 } ] } ] } - ] + ] ).Instance ]; @@ -376,17 +383,19 @@ public void ToUpcomingEvents_WithNullHomePrice_ThrowsException() [ new TestAnonymous2Builder().SetDefaults().SetBookmakers( [ - new() + new Bookmakers { Key = "onexbet", - Markets = [ - new() + Markets = + [ + new Markets2 { Key = Markets2Key.H2h, - Outcomes = [ - new() { Name = "Liverpool", Price = 4.08 }, - new() { Name = "Manchester City", Price = null }, - new() { Name = "Draw", Price = 3.82 } + Outcomes = + [ + new Outcome { Name = "Liverpool", Price = 4.08 }, + new Outcome { Name = "Manchester City", Price = null }, + new Outcome { Name = "Draw", Price = 3.82 } ] } ] @@ -408,25 +417,28 @@ public void ToUpcomingEvents_WithNullAwayPrice_ThrowsException() { var converter = new OddsApiObjectConverter(); - List rawUpcomingEvents = [ + List rawUpcomingEvents = + [ new TestAnonymous2Builder().SetDefaults().SetBookmakers( - [ - new() + [ + new Bookmakers { Key = "onexbet", - Markets = [ - new() + Markets = + [ + new Markets2 { Key = Markets2Key.H2h, - Outcomes = [ - new() { Name = "Liverpool", Price = null }, - new() { Name = "Manchester City", Price = 1.7 }, - new() { Name = "Draw", Price = 3.82 } + Outcomes = + [ + new Outcome { Name = "Liverpool", Price = null }, + new Outcome { Name = "Manchester City", Price = 1.7 }, + new Outcome { Name = "Draw", Price = 3.82 } ] } ] } - ] + ] ).Instance ]; @@ -443,25 +455,28 @@ public void ToUpcomingEvents_WithNullDrawPrice_ThrowsException() { var converter = new OddsApiObjectConverter(); - List rawUpcomingEvents = [ + List rawUpcomingEvents = + [ new TestAnonymous2Builder().SetDefaults().SetBookmakers( - [ - new() + [ + new Bookmakers { Key = "onexbet", - Markets = [ - new() + Markets = + [ + new Markets2 { Key = Markets2Key.H2h, - Outcomes = [ - new() { Name = "Liverpool", Price = 4.08 }, - new() { Name = "Manchester City", Price = 1.7 }, - new() { Name = "Draw", Price = null } + Outcomes = + [ + new Outcome { Name = "Liverpool", Price = 4.08 }, + new Outcome { Name = "Manchester City", Price = 1.7 }, + new Outcome { Name = "Draw", Price = null } ] } ] } - ] + ] ).Instance ]; @@ -481,18 +496,19 @@ public void ToEventResults_WithCompletedEvents_ReturnsConvertedEvents() var timestamp = DateTime.UtcNow; var traceId = Guid.NewGuid(); - List rawEventResults = [ + List rawEventResults = + [ new TestAnonymous3Builder().SetDefaults().SetScores([ - new() { Name = "Manchester City", Score = "1" }, - new() { Name = "Liverpool", Score = "0" } + new ScoreModel { Name = "Manchester City", Score = "1" }, + new ScoreModel { Name = "Liverpool", Score = "0" } ]).Instance, new TestAnonymous3Builder().SetDefaults().SetScores([ - new() { Name = "Manchester City", Score = "0" }, - new() { Name = "Liverpool", Score = "1" } + new ScoreModel { Name = "Manchester City", Score = "0" }, + new ScoreModel { Name = "Liverpool", Score = "1" } ]).Instance, new TestAnonymous3Builder().SetDefaults().SetScores([ - new() { Name = "Manchester City", Score = "1" }, - new() { Name = "Liverpool", Score = "1" } + new ScoreModel { Name = "Manchester City", Score = "1" }, + new ScoreModel { Name = "Liverpool", Score = "1" } ]).Instance ]; @@ -558,7 +574,8 @@ public void ToEventResults_WithUncompletedEvents_ReturnsNoEvents() { var converter = new OddsApiObjectConverter(); - List rawEventResults = [ + List rawEventResults = + [ new TestAnonymous3Builder().SetDefaults().SetCompleted(null).Instance, new TestAnonymous3Builder().SetDefaults().SetCompleted(false).Instance ]; @@ -573,7 +590,8 @@ public void ToEventResults_WithEmptyScores_ThrowsException() { var converter = new OddsApiObjectConverter(); - List rawEventResults = [ + List rawEventResults = + [ new TestAnonymous3Builder().SetDefaults().SetScores(null).Instance ]; @@ -591,7 +609,8 @@ public void ToEventResults_WithNullOrEmptyHomeTeam_ThrowsException(string? homeT { var converter = new OddsApiObjectConverter(); - List rawEventResults = [ + List rawEventResults = + [ new TestAnonymous3Builder().SetDefaults().SetHomeTeam(homeTeam).Instance ]; @@ -609,7 +628,8 @@ public void ToEventResults_WithNullOrEmptyAwayTeam_ThrowsException(string? awayT { var converter = new OddsApiObjectConverter(); - List rawEventResults = [ + List rawEventResults = + [ new TestAnonymous3Builder().SetDefaults().SetAwayTeam(awayTeam).Instance ]; @@ -627,10 +647,11 @@ public void ToEventResults_WithNullOrEmptyTeamName_ThrowsException(string? name) { var converter = new OddsApiObjectConverter(); - List rawEventResults = [ + List rawEventResults = + [ new TestAnonymous3Builder().SetDefaults().SetScores([ - new() { Name = name, Score = "1" }, - new() { Name = name, Score = "1" } + new ScoreModel { Name = name, Score = "1" }, + new ScoreModel { Name = name, Score = "1" } ]).Instance ]; @@ -648,10 +669,11 @@ public void ToEventResults_WithNullOrEmptyScoreValue_ThrowsException(string? sco { var converter = new OddsApiObjectConverter(); - List rawEventResults = [ + List rawEventResults = + [ new TestAnonymous3Builder().SetDefaults().SetScores([ - new() { Name = "Manchester City", Score = score }, - new() { Name = "Liverpool", Score = score } + new ScoreModel { Name = "Manchester City", Score = score }, + new ScoreModel { Name = "Liverpool", Score = score } ]).Instance ]; @@ -668,11 +690,12 @@ public void ToEventResults_WithDuplicatedScore_ThrowsException() { var converter = new OddsApiObjectConverter(); - List rawEventResults = [ + List rawEventResults = + [ new TestAnonymous3Builder().SetDefaults().SetScores([ - new() { Name = "Manchester City", Score = "1" }, - new() { Name = "Liverpool", Score = "1" }, - new() { Name = "Liverpool", Score = "1" } + new ScoreModel { Name = "Manchester City", Score = "1" }, + new ScoreModel { Name = "Liverpool", Score = "1" }, + new ScoreModel { Name = "Liverpool", Score = "1" } ]).Instance ]; @@ -689,11 +712,12 @@ public void ToEventResults_WithExtraScore_ReturnsEventResult() { var converter = new OddsApiObjectConverter(); - List rawEventResults = [ + List rawEventResults = + [ new TestAnonymous3Builder().SetDefaults().SetScores([ - new() { Name = "Manchester City", Score = "1" }, - new() { Name = "Liverpool", Score = "0" }, - new() { Name = "Nottingham Forest", Score = "1" } + new ScoreModel { Name = "Manchester City", Score = "1" }, + new ScoreModel { Name = "Liverpool", Score = "0" }, + new ScoreModel { Name = "Nottingham Forest", Score = "1" } ]).Instance ]; @@ -709,9 +733,10 @@ public void ToEventResults_WithoutAwayTeamScore_ThrowsException() { var converter = new OddsApiObjectConverter(); - List rawEventResults = [ + List rawEventResults = + [ new TestAnonymous3Builder().SetDefaults().SetScores([ - new() { Name = "Manchester City", Score = "1" } + new ScoreModel { Name = "Manchester City", Score = "1" } ]).Instance ]; @@ -728,9 +753,10 @@ public void ToEventResults_WithoutHomeTeamScore_ThrowsException() { var converter = new OddsApiObjectConverter(); - List rawEventResults = [ + List rawEventResults = + [ new TestAnonymous3Builder().SetDefaults().SetScores([ - new() { Name = "Liverpool", Score = "1" } + new ScoreModel { Name = "Liverpool", Score = "1" } ]).Instance ]; diff --git a/OddsCollector.Functions.Tests/OddsApi/Converter/TestAnonymous2Builder.cs b/OddsCollector.Functions.Tests/OddsApi/Converter/TestAnonymous2Builder.cs index 48d5b73..229f0ab 100644 --- a/OddsCollector.Functions.Tests/OddsApi/Converter/TestAnonymous2Builder.cs +++ b/OddsCollector.Functions.Tests/OddsApi/Converter/TestAnonymous2Builder.cs @@ -10,33 +10,38 @@ internal class TestAnonymous2Builder public const string DefaultId = "4acd8f2675ca847ba33eea3664f6c0bb"; public static readonly DateTime DefaultCommenceTime = new(2023, 11, 25, 12, 30, 0); - public static readonly ICollection DefaultBookmakers = [ - new() + public static readonly ICollection DefaultBookmakers = + [ + new Bookmakers { Key = "betclic", - Markets = [ - new() + Markets = + [ + new Markets2 { Key = Markets2Key.H2h, - Outcomes = [ - new() { Name = "Liverpool", Price = 4.08 }, - new() { Name = "Manchester City", Price = 1.7 }, - new() { Name = "Draw", Price = 3.82 } + Outcomes = + [ + new Outcome { Name = "Liverpool", Price = 4.08 }, + new Outcome { Name = "Manchester City", Price = 1.7 }, + new Outcome { Name = "Draw", Price = 3.82 } ] } ] }, - new() + new Bookmakers { Key = "sport888", - Markets = [ - new() + Markets = + [ + new Markets2 { Key = Markets2Key.H2h, - Outcomes = [ - new() { Name = "Liverpool", Price = 4.33 }, - new() { Name = "Manchester City", Price = 1.7 }, - new() { Name = "Draw", Price = 4.33 } + Outcomes = + [ + new Outcome { Name = "Liverpool", Price = 4.33 }, + new Outcome { Name = "Manchester City", Price = 1.7 }, + new Outcome { Name = "Draw", Price = 4.33 } ] } ] diff --git a/OddsCollector.Functions.Tests/OddsApi/Converter/TestAnonymous3Builder.cs b/OddsCollector.Functions.Tests/OddsApi/Converter/TestAnonymous3Builder.cs index 5077f81..d6ee987 100644 --- a/OddsCollector.Functions.Tests/OddsApi/Converter/TestAnonymous3Builder.cs +++ b/OddsCollector.Functions.Tests/OddsApi/Converter/TestAnonymous3Builder.cs @@ -11,9 +11,10 @@ internal sealed class TestAnonymous3Builder public const string DefaultId = "4acd8f2675ca847ba33eea3664f6c0bb"; public static readonly DateTime DefaultCommenceTime = new(2023, 11, 25, 12, 30, 0); - public static readonly ICollection DefaultScores = [ - new() { Name = "Manchester City", Score = "1" }, - new() { Name = "Liverpool", Score = "0" } + public static readonly ICollection DefaultScores = + [ + new ScoreModel { Name = "Manchester City", Score = "1" }, + new ScoreModel { Name = "Liverpool", Score = "0" } ]; public Anonymous3 Instance { get; } = new(); diff --git a/OddsCollector.Functions.Tests/OddsApi/OddsApiClientTests.cs b/OddsCollector.Functions.Tests/OddsApi/OddsApiClientTests.cs index 8945085..9a76861 100644 --- a/OddsCollector.Functions.Tests/OddsApi/OddsApiClientTests.cs +++ b/OddsCollector.Functions.Tests/OddsApi/OddsApiClientTests.cs @@ -86,11 +86,12 @@ public void Constructor_WithNullConverter_ThrowsException() [Test] public async Task GetUpcomingEventsAsync_WithLeagues_ReturnsUpcomingEvents() { - ICollection rawUpcomingEvents = [new()]; + ICollection rawUpcomingEvents = [new Anonymous2()]; var webApiClientMock = Substitute.For(); webApiClientMock .OddsAsync(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), - Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) + Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), + Arg.Any()) .Returns(Task.FromResult(rawUpcomingEvents)); // ReSharper disable once CollectionNeverUpdated.Local @@ -116,7 +117,8 @@ public async Task GetUpcomingEventsAsync_WithLeagues_ReturnsUpcomingEvents() results.Should().NotBeNull().And.Equal(upcomingEvents); await webApiClientMock.Received() - .OddsAsync(league, secretValue, Regions.Eu, Markets.H2h, DateFormat.Iso, OddsFormat.Decimal, null, null, token) + .OddsAsync(league, secretValue, Regions.Eu, Markets.H2h, DateFormat.Iso, OddsFormat.Decimal, null, null, + token) .ConfigureAwait(false); var received = converterMock.ReceivedCalls().ToList(); @@ -138,9 +140,10 @@ await webApiClientMock.Received() [Test] public async Task GetEventResultsAsync_WithLeagues_ReturnsEventResults() { - ICollection rawEventResults = [new()]; + ICollection rawEventResults = [new Anonymous3()]; var webApiClientMock = Substitute.For(); - webApiClientMock.ScoresAsync(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) + webApiClientMock.ScoresAsync(Arg.Any(), Arg.Any(), Arg.Any(), + Arg.Any()) .Returns(Task.FromResult(rawEventResults)); // ReSharper disable once CollectionNeverUpdated.Local diff --git a/OddsCollector.Functions.Tests/OddsCollector.Functions.Tests.csproj b/OddsCollector.Functions.Tests/OddsCollector.Functions.Tests.csproj index c79a94e..f06b5a1 100644 --- a/OddsCollector.Functions.Tests/OddsCollector.Functions.Tests.csproj +++ b/OddsCollector.Functions.Tests/OddsCollector.Functions.Tests.csproj @@ -10,20 +10,20 @@ - - - - - + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + diff --git a/OddsCollector.Functions.Tests/Strategies/Configuration/ServiceCollectionExtensionsTests.cs b/OddsCollector.Functions.Tests/Strategies/Configuration/ServiceCollectionExtensionsTests.cs new file mode 100644 index 0000000..dcfd5ef --- /dev/null +++ b/OddsCollector.Functions.Tests/Strategies/Configuration/ServiceCollectionExtensionsTests.cs @@ -0,0 +1,25 @@ +using Microsoft.Extensions.DependencyInjection; +using OddsCollector.Functions.Strategies; +using OddsCollector.Functions.Strategies.Configuration; + +namespace OddsCollector.Functions.Tests.Strategies.Configuration; + +[Parallelizable(ParallelScope.All)] +internal class ServiceCollectionExtensionsTests +{ + [Test] + public void AddPredictionStrategy_AddsProperlyConfiguredPredictionStrategy() + { + var services = new ServiceCollection(); + + services.AddPredictionStrategy(); + + var strategy = + services.FirstOrDefault( + x => x.ServiceType == typeof(IPredictionStrategy) + && x.ImplementationType == typeof(AdjustedConsensusStrategy) + && x.Lifetime == ServiceLifetime.Singleton); + + strategy.Should().NotBeNull(); + } +} diff --git a/OddsCollector.Functions/CosmosDb/ContainerFactory.cs b/OddsCollector.Functions/CosmosDb/ContainerFactory.cs deleted file mode 100644 index e36bbec..0000000 --- a/OddsCollector.Functions/CosmosDb/ContainerFactory.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Microsoft.Azure.Cosmos; - -namespace OddsCollector.Functions.CosmosDb; - -internal static class ContainerFactory -{ - public static Container CreateContainer(string? connectionString, string? databaseId, string? containerId) - { - ArgumentException.ThrowIfNullOrEmpty(connectionString); - ArgumentException.ThrowIfNullOrEmpty(databaseId); - ArgumentException.ThrowIfNullOrEmpty(containerId); - - return new CosmosClient(connectionString).GetContainer(databaseId, containerId); - } -} diff --git a/OddsCollector.Functions/CosmosDb/CosmosDbClient.cs b/OddsCollector.Functions/CosmosDb/CosmosDbClient.cs deleted file mode 100644 index 4d196bf..0000000 --- a/OddsCollector.Functions/CosmosDb/CosmosDbClient.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Microsoft.Azure.Cosmos; -using Microsoft.Azure.Cosmos.Linq; -using OddsCollector.Functions.Models; - -namespace OddsCollector.Functions.CosmosDb; - -internal sealed class CosmosDbClient() : ICosmosDbClient -{ - public async Task> GetEventPredictionsAsync(CancellationToken cancellationToken) - { - var container = ContainerFactory.CreateContainer( - // workaround for https://github.com/MicrosoftDocs/azure-docs/issues/32962 - Environment.GetEnvironmentVariable("CosmosDb:Connection"), - Environment.GetEnvironmentVariable("CosmosDb:Database"), - Environment.GetEnvironmentVariable("CosmosDb:EventPredictionsContainer")); - - var queryable = container.GetItemLinqQueryable(); - - // cosmosdb doesn't support grouping - var matches = from prediction in queryable - where prediction.CommenceTime >= DateTime.UtcNow - select prediction; - - List cosmosdbresult = []; - - using FeedIterator feed = matches.ToFeedIterator(); - - while (feed.HasMoreResults) - { - var response = await feed.ReadNextAsync(cancellationToken).ConfigureAwait(false); - - cosmosdbresult.AddRange(response); - } - - // so doing it manually - var groups = cosmosdbresult.GroupBy(p => p.Id); - - return groups.Select(group => group.OrderByDescending(p => p.Timestamp).First()).ToList(); - } -} diff --git a/OddsCollector.Functions/CosmosDb/ICosmosDbClient.cs b/OddsCollector.Functions/CosmosDb/ICosmosDbClient.cs deleted file mode 100644 index 5a341ef..0000000 --- a/OddsCollector.Functions/CosmosDb/ICosmosDbClient.cs +++ /dev/null @@ -1,8 +0,0 @@ -using OddsCollector.Functions.Models; - -namespace OddsCollector.Functions.CosmosDb; - -public interface ICosmosDbClient -{ - Task> GetEventPredictionsAsync(CancellationToken cancellationToken); -} diff --git a/OddsCollector.Functions/Functions/EventResultsFunction.cs b/OddsCollector.Functions/Functions/EventResultsFunction.cs index 49cf8c5..1693eba 100644 --- a/OddsCollector.Functions/Functions/EventResultsFunction.cs +++ b/OddsCollector.Functions/Functions/EventResultsFunction.cs @@ -10,14 +10,15 @@ namespace OddsCollector.Functions.Functions; -public class EventResultsFunction(ILogger? logger, IOddsApiClient? client) +internal class EventResultsFunction(ILogger? logger, IOddsApiClient? client) { private readonly IOddsApiClient _client = client ?? throw new ArgumentNullException(nameof(client)); private readonly ILogger _logger = logger ?? throw new ArgumentNullException(nameof(logger)); [Function(nameof(EventResultsFunction))] [CosmosDBOutput("%CosmosDb:Database%", "%CosmosDb:EventResultsContainer%", Connection = "CosmosDb:Connection")] - public async Task Run([TimerTrigger("%EventResultsFunction:TimerInterval%")] CancellationToken cancellationToken) + public async Task Run( + [TimerTrigger("%EventResultsFunction:TimerInterval%")] CancellationToken cancellationToken) { try { diff --git a/OddsCollector.Functions/Functions/PredictionFunction.cs b/OddsCollector.Functions/Functions/PredictionFunction.cs index 9eafef4..604d8d7 100644 --- a/OddsCollector.Functions/Functions/PredictionFunction.cs +++ b/OddsCollector.Functions/Functions/PredictionFunction.cs @@ -6,16 +6,17 @@ namespace OddsCollector.Functions.Functions; -public class PredictionFunction(ILogger? logger, IPredictionStrategy? strategy) +internal class PredictionFunction(ILogger? logger, IPredictionStrategy? strategy) { - private readonly IPredictionStrategy _strategy = strategy ?? throw new ArgumentNullException(nameof(strategy)); private readonly ILogger _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + private readonly IPredictionStrategy _strategy = strategy ?? throw new ArgumentNullException(nameof(strategy)); [Function(nameof(PredictionFunction))] [CosmosDBOutput("%CosmosDb:Database%", "%CosmosDb:EventPredictionsContainer%", Connection = "CosmosDb:Connection")] public async Task Run( [ServiceBusTrigger("%ServiceBus:Queue%", Connection = "ServiceBus:Connection", IsBatched = true)] - ServiceBusReceivedMessage[] messages, ServiceBusMessageActions messageActions, CancellationToken cancellationToken) + ServiceBusReceivedMessage[] messages, ServiceBusMessageActions messageActions, + CancellationToken cancellationToken) { List predictions = []; diff --git a/OddsCollector.Functions/Functions/PredictionsHttpFunction.cs b/OddsCollector.Functions/Functions/PredictionsHttpFunction.cs index eecc64b..b31690f 100644 --- a/OddsCollector.Functions/Functions/PredictionsHttpFunction.cs +++ b/OddsCollector.Functions/Functions/PredictionsHttpFunction.cs @@ -1,27 +1,41 @@ using System.Net; using System.Text.Json; +using Microsoft.Azure.Cosmos; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.Extensions.Logging; -using OddsCollector.Functions.CosmosDb; +using OddsCollector.Functions.Models; namespace OddsCollector.Functions.Functions; -public class PredictionsHttpFunction(ILogger logger, ICosmosDbClient? client) +internal class PredictionsHttpFunction(ILogger logger) { - private readonly ICosmosDbClient _client = client ?? throw new ArgumentNullException(nameof(client)); - private readonly ILogger _logger = logger ?? throw new ArgumentNullException(nameof(logger)); private static readonly JsonSerializerOptions _serializerOptions = new() { WriteIndented = true }; + private readonly ILogger _logger = + logger ?? throw new ArgumentNullException(nameof(logger)); + [Function(nameof(PredictionsHttpFunction))] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData request, - CancellationToken cancellationToken) + public HttpResponseData Run( + [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] + HttpRequestData request, + [CosmosDBInput( + "CosmosDb:Database", + "CosmosDb:EventPredictionsContainer", + Connection = "CosmosDb:Connection", + Id = "id", + PartitionKey = "id", + SqlQuery = "SELECT * FROM EventPredictions p WHERE p.CommenceTime > GetCurrentDateTime()")] + EventPrediction[] predictions, CosmosClient client, Database database, Container container) { try { - var predictions = await _client.GetEventPredictionsAsync(cancellationToken).ConfigureAwait(false); + // cosmosdb sql doesn't support grouping + // so doing it manually + var grouped = predictions.GroupBy(p => p.Id) + .Select(group => group.OrderByDescending(p => p.Timestamp).First()).ToList(); - var serialized = JsonSerializer.Serialize(predictions, _serializerOptions); + var serialized = JsonSerializer.Serialize(grouped, _serializerOptions); var response = request.CreateResponse(HttpStatusCode.OK); response.Headers.Add("Content-Type", "text/plain; charset=utf-8"); diff --git a/OddsCollector.Functions/Functions/UpcomingEventsFunction.cs b/OddsCollector.Functions/Functions/UpcomingEventsFunction.cs index b00ebed..00928c5 100644 --- a/OddsCollector.Functions/Functions/UpcomingEventsFunction.cs +++ b/OddsCollector.Functions/Functions/UpcomingEventsFunction.cs @@ -5,14 +5,17 @@ namespace OddsCollector.Functions.Functions; -public class UpcomingEventsFunction(ILogger? logger, IOddsApiClient? client) +internal class UpcomingEventsFunction(ILogger? logger, IOddsApiClient? client) { private readonly IOddsApiClient _client = client ?? throw new ArgumentNullException(nameof(client)); - private readonly ILogger _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + + private readonly ILogger + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); [Function(nameof(UpcomingEventsFunction))] [ServiceBusOutput("%ServiceBus:Queue%", Connection = "ServiceBus:Connection")] - public async Task Run([TimerTrigger("%UpcomingEventsFunction:TimerInterval%")] CancellationToken cancellationToken) + public async Task Run( + [TimerTrigger("%UpcomingEventsFunction:TimerInterval%")] CancellationToken cancellationToken) { try { diff --git a/OddsCollector.Functions/Models/Constants.cs b/OddsCollector.Functions/Models/Constants.cs index 89e062e..a03fae4 100644 --- a/OddsCollector.Functions/Models/Constants.cs +++ b/OddsCollector.Functions/Models/Constants.cs @@ -1,6 +1,6 @@ namespace OddsCollector.Functions.Models; -public static class Constants +internal static class Constants { public const string Draw = "Draw"; } diff --git a/OddsCollector.Functions/Models/EventPrediction.cs b/OddsCollector.Functions/Models/EventPrediction.cs index fa1d817..4c8e514 100644 --- a/OddsCollector.Functions/Models/EventPrediction.cs +++ b/OddsCollector.Functions/Models/EventPrediction.cs @@ -2,7 +2,7 @@ namespace OddsCollector.Functions.Models; -public class EventPrediction +internal class EventPrediction { // duplicating information to avoid complex cosmosdb queries public string AwayTeam { get; set; } = string.Empty; diff --git a/OddsCollector.Functions/Models/EventPredictionBuilder.cs b/OddsCollector.Functions/Models/EventPredictionBuilder.cs index 72c44c4..445ec7b 100644 --- a/OddsCollector.Functions/Models/EventPredictionBuilder.cs +++ b/OddsCollector.Functions/Models/EventPredictionBuilder.cs @@ -1,6 +1,6 @@ namespace OddsCollector.Functions.Models; -public class EventPredictionBuilder +internal class EventPredictionBuilder { public EventPrediction Instance { get; } = new(); diff --git a/OddsCollector.Functions/Models/EventResult.cs b/OddsCollector.Functions/Models/EventResult.cs index 6cd74dc..cf4ca8e 100644 --- a/OddsCollector.Functions/Models/EventResult.cs +++ b/OddsCollector.Functions/Models/EventResult.cs @@ -2,7 +2,7 @@ namespace OddsCollector.Functions.Models; -public class EventResult +internal class EventResult { public DateTime CommenceTime { get; set; } = DateTime.MinValue; diff --git a/OddsCollector.Functions/Models/EventResultBuilder.cs b/OddsCollector.Functions/Models/EventResultBuilder.cs index 70fed45..baafa40 100644 --- a/OddsCollector.Functions/Models/EventResultBuilder.cs +++ b/OddsCollector.Functions/Models/EventResultBuilder.cs @@ -1,6 +1,6 @@ namespace OddsCollector.Functions.Models; -public class EventResultBuilder +internal class EventResultBuilder { public EventResult Instance { get; } = new(); diff --git a/OddsCollector.Functions/Models/Odd.cs b/OddsCollector.Functions/Models/Odd.cs index 44dd6ce..fbd39e1 100644 --- a/OddsCollector.Functions/Models/Odd.cs +++ b/OddsCollector.Functions/Models/Odd.cs @@ -1,6 +1,6 @@ namespace OddsCollector.Functions.Models; -public class Odd +internal class Odd { public double Away { get; set; } public string Bookmaker { get; set; } = string.Empty; diff --git a/OddsCollector.Functions/Models/OddBuilder.cs b/OddsCollector.Functions/Models/OddBuilder.cs index cab4128..3907a55 100644 --- a/OddsCollector.Functions/Models/OddBuilder.cs +++ b/OddsCollector.Functions/Models/OddBuilder.cs @@ -1,6 +1,6 @@ namespace OddsCollector.Functions.Models; -public class OddBuilder +internal class OddBuilder { public Odd Instance { get; } = new(); diff --git a/OddsCollector.Functions/Models/UpcomingEvent.cs b/OddsCollector.Functions/Models/UpcomingEvent.cs index d5b2ae8..8c35dbc 100644 --- a/OddsCollector.Functions/Models/UpcomingEvent.cs +++ b/OddsCollector.Functions/Models/UpcomingEvent.cs @@ -1,6 +1,6 @@ namespace OddsCollector.Functions.Models; -public class UpcomingEvent +internal class UpcomingEvent { public string AwayTeam { get; set; } = string.Empty; public DateTime CommenceTime { get; set; } = DateTime.MinValue; diff --git a/OddsCollector.Functions/Models/UpcomingEventBuilder.cs b/OddsCollector.Functions/Models/UpcomingEventBuilder.cs index 632d41e..835c960 100644 --- a/OddsCollector.Functions/Models/UpcomingEventBuilder.cs +++ b/OddsCollector.Functions/Models/UpcomingEventBuilder.cs @@ -1,6 +1,6 @@ namespace OddsCollector.Functions.Models; -public class UpcomingEventBuilder +internal class UpcomingEventBuilder { public UpcomingEvent Instance { get; } = new(); diff --git a/OddsCollector.Functions/OddsApi/Configuration/OddsApiClientOptions.cs b/OddsCollector.Functions/OddsApi/Configuration/OddsApiClientOptions.cs index 2a7c2a1..e9c07f8 100644 --- a/OddsCollector.Functions/OddsApi/Configuration/OddsApiClientOptions.cs +++ b/OddsCollector.Functions/OddsApi/Configuration/OddsApiClientOptions.cs @@ -1,6 +1,6 @@ namespace OddsCollector.Functions.OddsApi.Configuration; -public class OddsApiClientOptions +internal class OddsApiClientOptions { public HashSet Leagues { get; init; } = []; diff --git a/OddsCollector.Functions/OddsApi/Configuration/ServiceCollectionExtensions.cs b/OddsCollector.Functions/OddsApi/Configuration/ServiceCollectionExtensions.cs index af44a6e..63af257 100644 --- a/OddsCollector.Functions/OddsApi/Configuration/ServiceCollectionExtensions.cs +++ b/OddsCollector.Functions/OddsApi/Configuration/ServiceCollectionExtensions.cs @@ -4,7 +4,7 @@ namespace OddsCollector.Functions.OddsApi.Configuration; -public static class ServiceCollectionExtensions +internal static class ServiceCollectionExtensions { public static IServiceCollection AddOddsApiClientWithDependencies(this IServiceCollection services) { diff --git a/OddsCollector.Functions/OddsApi/Converter/IOddsApiObjectConverter.cs b/OddsCollector.Functions/OddsApi/Converter/IOddsApiObjectConverter.cs index 2182106..3f53dfa 100644 --- a/OddsCollector.Functions/OddsApi/Converter/IOddsApiObjectConverter.cs +++ b/OddsCollector.Functions/OddsApi/Converter/IOddsApiObjectConverter.cs @@ -3,7 +3,7 @@ namespace OddsCollector.Functions.OddsApi.Converter; -public interface IOddsApiObjectConverter +internal interface IOddsApiObjectConverter { IEnumerable ToUpcomingEvents(ICollection? events, Guid traceId, DateTime timestamp); IEnumerable ToEventResults(ICollection? events, Guid traceId, DateTime timestamp); diff --git a/OddsCollector.Functions/OddsApi/Converter/OddsApiObjectConverter.cs b/OddsCollector.Functions/OddsApi/Converter/OddsApiObjectConverter.cs index 7535207..1afed7b 100644 --- a/OddsCollector.Functions/OddsApi/Converter/OddsApiObjectConverter.cs +++ b/OddsCollector.Functions/OddsApi/Converter/OddsApiObjectConverter.cs @@ -4,7 +4,7 @@ namespace OddsCollector.Functions.OddsApi.Converter; -public class OddsApiObjectConverter : IOddsApiObjectConverter +internal class OddsApiObjectConverter : IOddsApiObjectConverter { private const Markets2Key HeadToHeadMarketKey = Markets2Key.H2h; diff --git a/OddsCollector.Functions/OddsApi/IOddsApiClient.cs b/OddsCollector.Functions/OddsApi/IOddsApiClient.cs index 4ef4657..939888f 100644 --- a/OddsCollector.Functions/OddsApi/IOddsApiClient.cs +++ b/OddsCollector.Functions/OddsApi/IOddsApiClient.cs @@ -2,8 +2,11 @@ namespace OddsCollector.Functions.OddsApi; -public interface IOddsApiClient +internal interface IOddsApiClient { - Task> GetUpcomingEventsAsync(Guid traceId, DateTime timestamp, CancellationToken cancellationToken); - Task> GetEventResultsAsync(Guid traceId, DateTime timestamp, CancellationToken cancellationToken); + Task> GetUpcomingEventsAsync(Guid traceId, DateTime timestamp, + CancellationToken cancellationToken); + + Task> GetEventResultsAsync(Guid traceId, DateTime timestamp, + CancellationToken cancellationToken); } diff --git a/OddsCollector.Functions/OddsApi/OddsApiClient.cs b/OddsCollector.Functions/OddsApi/OddsApiClient.cs index 939ecaf..b727df9 100644 --- a/OddsCollector.Functions/OddsApi/OddsApiClient.cs +++ b/OddsCollector.Functions/OddsApi/OddsApiClient.cs @@ -6,7 +6,9 @@ namespace OddsCollector.Functions.OddsApi; -public class OddsApiClient(IOptions? options, IClient? webApiClient, +internal class OddsApiClient( + IOptions? options, + IClient? webApiClient, IOddsApiObjectConverter? objectConverter) : IOddsApiClient { private const DateFormat IsoDateFormat = DateFormat.Iso; @@ -14,18 +16,23 @@ public class OddsApiClient(IOptions? options, IClient? web private const OddsFormat DecimalOddsFormat = OddsFormat.Decimal; private const Regions EuropeanRegion = Regions.Eu; private const int DaysFromToday = 3; - private readonly IOddsApiObjectConverter _objectConverter = objectConverter ?? throw new ArgumentNullException(nameof(objectConverter)); + + private readonly IOddsApiObjectConverter _objectConverter = + objectConverter ?? throw new ArgumentNullException(nameof(objectConverter)); + private readonly OddsApiClientOptions _options = options?.Value ?? throw new ArgumentNullException(nameof(options)); private readonly IClient _webApiClient = webApiClient ?? throw new ArgumentNullException(nameof(webApiClient)); - public async Task> GetUpcomingEventsAsync(Guid traceId, DateTime timestamp, CancellationToken cancellationToken) + public async Task> GetUpcomingEventsAsync(Guid traceId, DateTime timestamp, + CancellationToken cancellationToken) { List result = []; foreach (var league in _options.Leagues) { var events = await _webApiClient.OddsAsync(league, _options.ApiKey, - EuropeanRegion, HeadToHeadMarket, IsoDateFormat, DecimalOddsFormat, null, null, cancellationToken).ConfigureAwait(false); + EuropeanRegion, HeadToHeadMarket, IsoDateFormat, DecimalOddsFormat, null, null, cancellationToken) + .ConfigureAwait(false); result.AddRange(_objectConverter.ToUpcomingEvents(events, traceId, timestamp)); } @@ -33,14 +40,16 @@ public async Task> GetUpcomingEventsAsync(Guid traceI return result; } - public async Task> GetEventResultsAsync(Guid traceId, DateTime timestamp, CancellationToken cancellationToken) + public async Task> GetEventResultsAsync(Guid traceId, DateTime timestamp, + CancellationToken cancellationToken) { List result = []; foreach (var league in _options.Leagues) { var results = - await _webApiClient.ScoresAsync(league, _options.ApiKey, DaysFromToday, cancellationToken).ConfigureAwait(false); + await _webApiClient.ScoresAsync(league, _options.ApiKey, DaysFromToday, cancellationToken) + .ConfigureAwait(false); result.AddRange(_objectConverter.ToEventResults(results, traceId, timestamp)); } diff --git a/OddsCollector.Functions/OddsCollector.Functions.csproj b/OddsCollector.Functions/OddsCollector.Functions.csproj index a4ec9c9..3580c61 100644 --- a/OddsCollector.Functions/OddsCollector.Functions.csproj +++ b/OddsCollector.Functions/OddsCollector.Functions.csproj @@ -7,16 +7,16 @@ enable - - - - - - - - - - + + + + + + + + + + @@ -32,6 +32,6 @@ - + \ No newline at end of file diff --git a/OddsCollector.Functions/Program.cs b/OddsCollector.Functions/Program.cs index e3a7bda..5dc8996 100644 --- a/OddsCollector.Functions/Program.cs +++ b/OddsCollector.Functions/Program.cs @@ -1,16 +1,14 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using OddsCollector.Functions.CosmosDb; using OddsCollector.Functions.OddsApi.Configuration; -using OddsCollector.Functions.Strategies; +using OddsCollector.Functions.Strategies.Configuration; var host = new HostBuilder() .ConfigureFunctionsWorkerDefaults() .ConfigureServices(services => { - services.AddSingleton(); - services.AddSingleton(); + services.AddPredictionStrategy(); services.AddOddsApiClientWithDependencies(); services.AddApplicationInsightsTelemetryWorkerService(); services.ConfigureFunctionsApplicationInsights(); diff --git a/OddsCollector.Functions/Strategies/AdjustedConsensusStrategy.cs b/OddsCollector.Functions/Strategies/AdjustedConsensusStrategy.cs index 41a1f83..4bd433d 100644 --- a/OddsCollector.Functions/Strategies/AdjustedConsensusStrategy.cs +++ b/OddsCollector.Functions/Strategies/AdjustedConsensusStrategy.cs @@ -40,10 +40,11 @@ private static StrategyScore GetWinner(IEnumerable odds, string awayTeam, s ArgumentException.ThrowIfNullOrEmpty(awayTeam); ArgumentException.ThrowIfNullOrEmpty(homeTeam); - List scores = [ - new() { Name = Constants.Draw, Odd = CalculateAdjustedScore(enumerated, Draw, 0.057) }, - new() { Name = awayTeam, Odd = CalculateAdjustedScore(enumerated, AwayTeamWins, 0.034) }, - new() { Name = homeTeam, Odd = CalculateAdjustedScore(enumerated, HomeTeamWins, 0.037) } + List scores = + [ + new StrategyScore { Name = Constants.Draw, Odd = CalculateAdjustedScore(enumerated, Draw, 0.057) }, + new StrategyScore { Name = awayTeam, Odd = CalculateAdjustedScore(enumerated, AwayTeamWins, 0.034) }, + new StrategyScore { Name = homeTeam, Odd = CalculateAdjustedScore(enumerated, HomeTeamWins, 0.037) } ]; var winner = scores.MaxBy(p => p.Odd); @@ -56,7 +57,7 @@ private static StrategyScore GetWinner(IEnumerable odds, string awayTeam, s private static double CalculateAdjustedScore(IEnumerable odds, Func filter, double adjustment) { var average = odds.Select(filter).Average(); - return average == 0 ? 0 : 1 / average - adjustment; + return average == 0 ? 0 : (1 / average) - adjustment; } private static Odd GetBestOdd(IEnumerable odds, string winner, string awayTeam, string homeTeam) diff --git a/OddsCollector.Functions/Strategies/Configuration/ServiceCollectionExtensions.cs b/OddsCollector.Functions/Strategies/Configuration/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..78a3ccb --- /dev/null +++ b/OddsCollector.Functions/Strategies/Configuration/ServiceCollectionExtensions.cs @@ -0,0 +1,13 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace OddsCollector.Functions.Strategies.Configuration; + +internal static class ServiceCollectionExtensions +{ + public static IServiceCollection AddPredictionStrategy(this IServiceCollection services) + { + services.AddSingleton(); + + return services; + } +} diff --git a/OddsCollector.Functions/Strategies/IPredictionStrategy.cs b/OddsCollector.Functions/Strategies/IPredictionStrategy.cs index b36e0bd..8339d7f 100644 --- a/OddsCollector.Functions/Strategies/IPredictionStrategy.cs +++ b/OddsCollector.Functions/Strategies/IPredictionStrategy.cs @@ -2,7 +2,7 @@ namespace OddsCollector.Functions.Strategies; -public interface IPredictionStrategy +internal interface IPredictionStrategy { EventPrediction GetPrediction(UpcomingEvent? upcomingEvent, DateTime? timestamp); } diff --git a/OddsCollector.Functions/host.json b/OddsCollector.Functions/host.json index ee5cf5f..5df170b 100644 --- a/OddsCollector.Functions/host.json +++ b/OddsCollector.Functions/host.json @@ -1,12 +1,12 @@ { - "version": "2.0", - "logging": { - "applicationInsights": { - "samplingSettings": { - "isEnabled": true, - "excludedTypes": "Request" - }, - "enableLiveMetricsFilters": true - } + "version": "2.0", + "logging": { + "applicationInsights": { + "samplingSettings": { + "isEnabled": true, + "excludedTypes": "Request" + }, + "enableLiveMetricsFilters": true } + } } \ No newline at end of file