Skip to content

Commit e2b4e36

Browse files
Merge pull request #246 from AdrianJSClark/241-support-iracing-oauth
Implement the Password Limited Grant
2 parents 42a126f + 4e266c2 commit e2b4e36

Some content is hidden

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

47 files changed

+2885
-2789
lines changed

src/Aydsko.iRacingData.IntegrationTests/Aydsko.iRacingData.IntegrationTests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<PackageReference Include="Microsoft.Extensions.Caching.Memory" />
1313
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" />
1414
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" />
15+
<PackageReference Include="Microsoft.Extensions.TimeProvider.Testing" />
1516
<PackageReference Include="Microsoft.NET.Test.Sdk" />
1617
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers">
1718
<PrivateAssets>all</PrivateAssets>

src/Aydsko.iRacingData.IntegrationTests/BaseIntegrationFixture.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// © 2023 Adrian Clark
1+
// © Adrian Clark - Aydsko.iRacingData
22
// This file is licensed to you under the MIT license.
33

44
using System.Net;
Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
1-
// © 2023 Adrian Clark
1+
// © Adrian Clark - Aydsko.iRacingData
22
// This file is licensed to you under the MIT license.
33

44
using Microsoft.Extensions.Caching.Memory;
5+
using Microsoft.Extensions.Time.Testing;
56

67
namespace Aydsko.iRacingData.IntegrationTests;
78

8-
internal abstract class CachingIntegrationFixture : BaseIntegrationFixture<CachingDataClient>
9+
internal abstract class CachingIntegrationFixture
10+
: BaseIntegrationFixture<DataClient>
911
{
1012
protected IMemoryCache MemoryCache { get; private set; } = default!;
13+
protected FakeTimeProvider FakeTimeProvider { get; private set; } = new FakeTimeProvider(DateTimeOffset.UtcNow);
14+
15+
private LegacyUsernamePasswordApiClient? _legacyApiClient;
16+
private ApiClient? _apiClientBase;
17+
private CachingApiClient? _cachingApiClientBase;
1118

1219
[SetUp]
1320
public void SetUp()
@@ -16,12 +23,21 @@ public void SetUp()
1623

1724
MemoryCache = new MemoryCache(new MemoryCacheOptions() { TrackStatistics = true });
1825

19-
Client = new CachingDataClient(HttpClient, new TestLogger<CachingDataClient>(), options, CookieContainer, MemoryCache);
26+
_legacyApiClient = new(HttpClient, options, CookieContainer, new TestLogger<LegacyUsernamePasswordApiClient>());
27+
_apiClientBase = new(_legacyApiClient, options, new TestLogger<ApiClient>());
28+
_cachingApiClientBase = new(_apiClientBase, MemoryCache, new TestLogger<CachingApiClient>(), FakeTimeProvider);
29+
30+
Client = new DataClient(_cachingApiClientBase, options, new TestLogger<DataClient>(), FakeTimeProvider);
2031
}
2132

22-
[TearDown]
23-
public void TearDown()
33+
protected override void Dispose(bool disposing)
2434
{
25-
MemoryCache.Dispose();
35+
if (disposing)
36+
{
37+
_legacyApiClient?.Dispose();
38+
_apiClientBase?.Dispose();
39+
}
40+
41+
base.Dispose(disposing);
2642
}
2743
}
Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,35 @@
1-
// © 2023 Adrian Clark
1+
// © Adrian Clark - Aydsko.iRacingData
22
// This file is licensed to you under the MIT license.
33

4+
using Microsoft.Extensions.Time.Testing;
5+
46
namespace Aydsko.iRacingData.IntegrationTests;
57

6-
internal abstract class DataClientIntegrationFixture : BaseIntegrationFixture<DataClient>
8+
internal abstract class DataClientIntegrationFixture
9+
: BaseIntegrationFixture<DataClient>
710
{
11+
protected FakeTimeProvider FakeTimeProvider { get; private set; } = new FakeTimeProvider(DateTimeOffset.UtcNow);
12+
13+
private LegacyUsernamePasswordApiClient? _legacyApiClient;
14+
private ApiClient? _apiClientBase;
15+
816
[OneTimeSetUp]
917
public void OneTimeSetUp()
1018
{
1119
var options = BaseSetUp();
12-
Client = new DataClient(HttpClient, new TestLogger<DataClient>(), options, CookieContainer);
20+
21+
_legacyApiClient = new(HttpClient, options, CookieContainer, new TestLogger<LegacyUsernamePasswordApiClient>());
22+
_apiClientBase = new(_legacyApiClient, options, new TestLogger<ApiClient>());
23+
Client = new DataClient(_apiClientBase, options, new TestLogger<DataClient>(), FakeTimeProvider);
24+
}
25+
26+
protected override void Dispose(bool disposing)
27+
{
28+
if (disposing)
29+
{
30+
_legacyApiClient?.Dispose();
31+
_apiClientBase?.Dispose();
32+
}
33+
base.Dispose(disposing);
1334
}
1435
}

src/Aydsko.iRacingData.IntegrationTests/Lookups/CachingLookupTests.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// © 2023 Adrian Clark
1+
// © Adrian Clark - Aydsko.iRacingData
22
// This file is licensed to you under the MIT license.
33

44
namespace Aydsko.iRacingData.IntegrationTests.Lookups;
@@ -23,10 +23,11 @@ public async Task TestLicenseLookupsAreCachedAsync()
2323
Assert.That(license2.Data, Has.Length.EqualTo(7));
2424

2525
var stats = MemoryCache.GetCurrentStatistics();
26-
Assert.Multiple(() =>
26+
27+
using (Assert.EnterMultipleScope())
2728
{
2829
Assert.That(stats?.TotalHits, Is.Not.Null.And.EqualTo(1), "TotalHits didn't match.");
2930
Assert.That(stats?.TotalMisses, Is.Not.Null.And.EqualTo(1), "TotalMisses didn't match.");
30-
});
31+
}
3132
}
3233
}
Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,28 @@
1-
// © 2023-2024 Adrian Clark
1+
// © Adrian Clark - Aydsko.iRacingData
22
// This file is licensed to you under the MIT license.
33

44
namespace Aydsko.iRacingData.IntegrationTests.Member;
55

6-
internal sealed class CachingMemberInfoTest : CachingIntegrationFixture
6+
internal sealed class CachingMemberInfoTest
7+
: CachingIntegrationFixture
78
{
89
[Test]
910
public async Task TestMemberInfoAsync()
1011
{
11-
if (Configuration["iRacingData:CustomerId"] is not string customerIdValue || !int.TryParse(customerIdValue, out var iRacingCustomerId))
12+
if (Configuration["iRacingData:CustomerId"] is not string customerIdValue
13+
|| !int.TryParse(customerIdValue, out var iRacingCustomerId))
1214
{
1315
throw new InvalidOperationException("iRacing Customer Id value not found in configuration.");
1416
}
1517

16-
var memberInfo = await Client.GetMyInfoAsync().ConfigureAwait(false);
17-
var memberInfo2 = await Client.GetMyInfoAsync().ConfigureAwait(false);
18+
var memberInfo = await Client.GetMyInfoAsync()
19+
.ConfigureAwait(false);
20+
var memberInfo2 = await Client.GetMyInfoAsync()
21+
.ConfigureAwait(false);
1822

1923
var stats = MemoryCache.GetCurrentStatistics();
2024

21-
Assert.Multiple(() =>
25+
using (Assert.EnterMultipleScope())
2226
{
2327
Assert.That(memberInfo, Is.Not.Null);
2428
Assert.That(memberInfo.Data, Is.Not.Null);
@@ -32,6 +36,6 @@ public async Task TestMemberInfoAsync()
3236

3337
Assert.That(stats?.TotalHits, Is.Not.Null.And.EqualTo(1), "TotalHits didn't match.");
3438
Assert.That(stats?.TotalMisses, Is.Not.Null.And.EqualTo(1), "TotalMisses didn't match.");
35-
});
39+
}
3640
}
3741
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// © Adrian Clark - Aydsko.iRacingData
2+
// This file is licensed to you under the MIT license.
3+
4+
using Microsoft.Extensions.Logging;
5+
6+
namespace Aydsko.iRacingData.IntegrationTests;
7+
8+
internal sealed class NUnitLoggerProvider
9+
: ILoggerProvider
10+
{
11+
private bool disposedValue;
12+
13+
public ILogger CreateLogger(string categoryName)
14+
{
15+
return new TestLogger(categoryName);
16+
}
17+
18+
private void Dispose(bool disposing)
19+
{
20+
if (!disposedValue)
21+
{
22+
if (disposing)
23+
{
24+
// TODO: dispose managed state (managed objects)
25+
}
26+
27+
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
28+
// TODO: set large fields to null
29+
disposedValue = true;
30+
}
31+
}
32+
33+
// // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
34+
// ~NUnitLoggerProvider()
35+
// {
36+
// // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
37+
// Dispose(disposing: false);
38+
// }
39+
40+
public void Dispose()
41+
{
42+
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
43+
Dispose(disposing: true);
44+
GC.SuppressFinalize(this);
45+
}
46+
}
Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// © 2023 Adrian Clark
1+
// © Adrian Clark - Aydsko.iRacingData
22
// This file is licensed to you under the MIT license.
33

44
namespace Aydsko.iRacingData.IntegrationTests.Results;
@@ -9,26 +9,24 @@ internal sealed class CachingResultsGetTest : CachingIntegrationFixture
99
public async Task GivenAValidSubsessionIdThenAResultIsReturnedAsync()
1010
{
1111
var results = await Client.GetSubSessionResultAsync(50033865, true).ConfigureAwait(false);
12-
13-
Assert.Multiple(() =>
12+
using (Assert.EnterMultipleScope())
1413
{
1514
Assert.That(results, Is.Not.Null);
1615
Assert.That(results.Data, Is.Not.Null);
17-
});
16+
}
1817

1918
var results2 = await Client.GetSubSessionResultAsync(50033865, true).ConfigureAwait(false);
20-
21-
Assert.Multiple(() =>
19+
using (Assert.EnterMultipleScope())
2220
{
2321
Assert.That(results2, Is.Not.Null);
2422
Assert.That(results2.Data, Is.Not.Null);
25-
});
23+
}
2624

2725
var stats = MemoryCache.GetCurrentStatistics();
28-
Assert.Multiple(() =>
26+
using (Assert.EnterMultipleScope())
2927
{
3028
Assert.That(stats?.TotalHits, Is.Not.Null.And.EqualTo(1), "TotalHits didn't match.");
3129
Assert.That(stats?.TotalMisses, Is.Not.Null.And.EqualTo(1), "TotalMisses didn't match.");
32-
});
30+
}
3331
}
3432
}
Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
// © 2023 Adrian Clark
1+
// © Adrian Clark - Aydsko.iRacingData
22
// This file is licensed to you under the MIT license.
33

44
namespace Aydsko.iRacingData.IntegrationTests.Results;
55

6-
internal sealed class CachingResultsSearchSeriesTest : CachingIntegrationFixture
6+
internal sealed class CachingResultsSearchSeriesTest
7+
: CachingIntegrationFixture
78
{
89
[Test(TestOf = typeof(DataClient))]
910
public async Task GivenValidSearchParametersTheCorrectResultIsReturnedAsync()
@@ -18,31 +19,29 @@ public async Task GivenValidSearchParametersTheCorrectResultIsReturnedAsync()
1819
};
1920

2021
var searchResults = await Client.SearchOfficialResultsAsync(searchParameters).ConfigureAwait(false);
21-
22-
Assert.Multiple(() =>
22+
using (Assert.EnterMultipleScope())
2323
{
2424
Assert.That(searchResults, Is.Not.Null);
2525
Assert.That(searchResults.Data.Header, Is.Not.Null);
2626
Assert.That(searchResults.Data.Items, Is.Not.Null.Or.Empty);
2727
Assert.That(searchResults.Data.Items, Has.Length.EqualTo(10));
28-
});
28+
}
2929

3030
var searchResults2 = await Client.SearchOfficialResultsAsync(searchParameters).ConfigureAwait(false);
31-
32-
Assert.Multiple(() =>
31+
using (Assert.EnterMultipleScope())
3332
{
3433
Assert.That(searchResults2, Is.Not.Null);
3534
Assert.That(searchResults2.Data.Header, Is.Not.Null);
3635
Assert.That(searchResults2.Data.Items, Is.Not.Null.Or.Empty);
3736
Assert.That(searchResults2.Data.Items, Has.Length.EqualTo(10));
38-
});
37+
}
3938

4039
var stats = MemoryCache.GetCurrentStatistics();
41-
Assert.Multiple(() =>
40+
using (Assert.EnterMultipleScope())
4241
{
4342
Assert.That(stats?.TotalHits, Is.Not.Null.And.EqualTo(1));
4443
Assert.That(stats?.TotalMisses, Is.Not.Null.And.EqualTo(1));
45-
});
44+
}
4645
}
4746

4847
[Test(TestOf = typeof(DataClient))]
@@ -59,34 +58,32 @@ public async Task GivenSearchParametersThatResultInZeroResultsTheCorrectResultIs
5958
};
6059

6160
var searchResults = await Client.SearchOfficialResultsAsync(searchParameters).ConfigureAwait(false);
62-
63-
Assert.Multiple(() =>
61+
using (Assert.EnterMultipleScope())
6462
{
6563
Assert.That(searchResults, Is.Not.Null);
6664
Assert.That(searchResults.Data.Header, Is.Not.Null);
6765
Assert.That(searchResults.Data.Header.Data.Success, Is.True);
6866

6967
Assert.That(searchResults.Data.Items, Is.Not.Null);
7068
Assert.That(searchResults.Data.Items, Has.Length.EqualTo(0));
71-
});
69+
}
7270

7371
var searchResults2 = await Client.SearchOfficialResultsAsync(searchParameters).ConfigureAwait(false);
74-
75-
Assert.Multiple(() =>
72+
using (Assert.EnterMultipleScope())
7673
{
7774
Assert.That(searchResults2, Is.Not.Null);
7875
Assert.That(searchResults2.Data.Header, Is.Not.Null);
7976
Assert.That(searchResults2.Data.Header.Data.Success, Is.True);
8077

8178
Assert.That(searchResults2.Data.Items, Is.Not.Null);
8279
Assert.That(searchResults2.Data.Items, Has.Length.EqualTo(0));
83-
});
80+
}
8481

8582
var stats = MemoryCache.GetCurrentStatistics();
86-
Assert.Multiple(() =>
83+
using (Assert.EnterMultipleScope())
8784
{
8885
Assert.That(stats?.TotalHits, Is.Not.Null.And.EqualTo(1));
8986
Assert.That(stats?.TotalMisses, Is.Not.Null.And.EqualTo(1));
90-
});
87+
}
9188
}
9289
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// © Adrian Clark - Aydsko.iRacingData
2+
// This file is licensed to you under the MIT license.
3+
4+
using Microsoft.Extensions.DependencyInjection;
5+
6+
namespace Aydsko.iRacingData.IntegrationTests.Seasons;
7+
8+
internal sealed class GetSeasonsUsingPasswordLimited
9+
: ServiceProviderIntegrationFixture
10+
{
11+
public const int GrandPrixSeriesId = 260;
12+
13+
[Test]
14+
public async Task GetSeasonsUsingPasswordLimitedAsync()
15+
{
16+
var client = ServiceProvider.GetRequiredService<IDataClient>();
17+
18+
var seasons = await client.GetSeasonsAsync(true)
19+
.ConfigureAwait(false);
20+
21+
Assert.That(seasons, Is.Not.Null);
22+
Assert.That(seasons.Data, Has.Length.GreaterThan(0));
23+
}
24+
25+
[Test]
26+
public async Task GetGrandPrixSeriesWeek12WeatherAsync()
27+
{
28+
var client = ServiceProvider.GetRequiredService<IDataClient>();
29+
30+
var seasons = await client.GetSeasonsAsync(true)
31+
.ConfigureAwait(false);
32+
33+
Assert.That(seasons?.Data, Is.Not.Null);
34+
35+
var gpSeries = seasons.Data.Single(s => s.SeriesId == GrandPrixSeriesId);
36+
var gpSeriesWeek12Weather = gpSeries.Schedules.Single(sch => sch.RaceWeekNumber == 12).Weather;
37+
38+
Assert.That(gpSeriesWeek12Weather, Is.Not.Null);
39+
Assert.That(gpSeriesWeek12Weather.WeatherUrl, Is.Not.Null);
40+
41+
var forecast = await client.GetWeatherForecastFromUrlAsync(new Uri(gpSeriesWeek12Weather.WeatherUrl))
42+
.ConfigureAwait(false);
43+
44+
Assert.That(forecast, Is.Not.Null);
45+
}
46+
}

0 commit comments

Comments
 (0)