Skip to content

Commit

Permalink
Add GitHubApiStatusService.IsProductHeaderValueValid and IsProductHea…
Browse files Browse the repository at this point in the history
…derValueValid.IsAuthenticationHeaderValueSet
  • Loading branch information
brminnick committed Nov 26, 2020
1 parent cbeda54 commit 44c8d8d
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace GitHubApiStatus.UnitTests
class IsAuthenticatedTests : BaseTest
{
[Test]
public void IsUserAuthenticated_ValidHttpResponseHeaders_True()
public void IsResponseFromAuthenticatedRequest_ValidHttpResponseHeaders_True()
{
//Act
bool isUserAuthenticated_Actual;
Expand All @@ -21,14 +21,14 @@ public void IsUserAuthenticated_ValidHttpResponseHeaders_True()
var validHttpResponseHeaders = CreateHttpResponseHeaders(rateLimit, DateTimeOffset.UtcNow, rateLimitRemaining, isAuthenticated: isUserAuthenticated_Expected);

//Act
isUserAuthenticated_Actual = GitHubApiStatusService.IsAuthenticated(validHttpResponseHeaders);
isUserAuthenticated_Actual = GitHubApiStatusService.IsResponseFromAuthenticatedRequest(validHttpResponseHeaders);

//Assert
Assert.AreEqual(isUserAuthenticated_Expected, isUserAuthenticated_Actual);
}

[Test]
public void IsUserAuthenticated_ValidHttpResponseHeaders_False()
public void IsResponseFromAuthenticatedRequest_ValidHttpResponseHeaders_False()
{
//Act
bool isUserAuthenticated_Actual;
Expand All @@ -41,27 +41,27 @@ public void IsUserAuthenticated_ValidHttpResponseHeaders_False()
var validHttpResponseHeaders = CreateHttpResponseHeaders(rateLimit, DateTimeOffset.UtcNow, rateLimitRemaining, isAuthenticated: isUserAuthenticated_Expected);

//Act
isUserAuthenticated_Actual = GitHubApiStatusService.IsAuthenticated(validHttpResponseHeaders);
isUserAuthenticated_Actual = GitHubApiStatusService.IsResponseFromAuthenticatedRequest(validHttpResponseHeaders);

//Assert
Assert.AreEqual(isUserAuthenticated_Expected, isUserAuthenticated_Actual);
}

[Test]
public void IsUserAuthenticated_InvalidHttpResponseHeaders()
public void IsResponseFromAuthenticatedRequest_InvalidHttpResponseHeaders()
{
//Arrange
var invalidHttpResponseMessage = new HttpResponseMessage();

//Act
var isUserAuthenticated = GitHubApiStatusService.IsAuthenticated(invalidHttpResponseMessage.Headers);
var isUserAuthenticated = GitHubApiStatusService.IsResponseFromAuthenticatedRequest(invalidHttpResponseMessage.Headers);

//Assert
Assert.IsFalse(isUserAuthenticated);
}

[Test]
public void IsUserAuthenticated_NullHttpResponseHeaders()
public void IsResponseFromAuthenticatedRequest_NullHttpResponseHeaders()
{
//Arrange
HttpResponseHeaders? nullHttpResponseHeaders = null;
Expand All @@ -70,7 +70,7 @@ public void IsUserAuthenticated_NullHttpResponseHeaders()

//Assert
#pragma warning disable CS8604 // Possible null reference argument.
Assert.Throws<GitHubApiStatusException>(() => GitHubApiStatusService.IsAuthenticated(nullHttpResponseHeaders));
Assert.Throws<GitHubApiStatusException>(() => GitHubApiStatusService.IsResponseFromAuthenticatedRequest(nullHttpResponseHeaders));
#pragma warning restore CS8604 // Possible null reference argument.
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace GitHubApiStatus.UnitTests
{
class AddProductHeaderValueTests
class AddProductHeaderValueTests : BaseTest
{
[Test]
public void NullProductHeaderValueTest()
Expand All @@ -20,6 +20,7 @@ public void NullProductHeaderValueTest()
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
Assert.Throws<GitHubApiStatusException>(() => gitHubApiStatusService.AddProductHeaderValue(null));
#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type.
Assert.IsFalse(gitHubApiStatusService.IsProductHeaderValueValid);
}

[Test]
Expand All @@ -32,6 +33,7 @@ public void NullNameTest()

//Assert
Assert.Throws<ArgumentException>(() => gitHubApiStatusService.AddProductHeaderValue(new ProductHeaderValue(null)));
Assert.IsFalse(gitHubApiStatusService.IsProductHeaderValueValid);
}

[Test]
Expand All @@ -47,6 +49,8 @@ public async Task ValidProductHeaderValueTest()

//Assert
Assert.IsNotNull(gitHubApiStatusService);
Assert.IsTrue(gitHubApiStatusService.IsProductHeaderValueValid);

Assert.IsNotNull(apiRateLimits);
Assert.IsNotNull(apiRateLimits.AppManifestConfiguration);
Assert.IsNotNull(apiRateLimits.CodeScanningUpload);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public void NullAuthenticationHeaderValue()
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
Assert.Throws<GitHubApiStatusException>(() => gitHubApiStatusService.SetAuthenticationHeaderValue(null));
#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type.
Assert.IsFalse(gitHubApiStatusService.IsAuthenticationHeaderValueSet);
}

[TestCase("Basic")]
Expand Down
2 changes: 1 addition & 1 deletion Src/GitHubApiStatus/GitHubApiStatus.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ New In This Release:
- Added GitHubApiStatusService.SetAuthenticationHeaderValue()
- Breaking Changes: Removed GitHubApiStatusService.Instance
</PackageReleaseNotes>
<Version>2.0.0-pre2</Version>
<Version>2.0.0-pre3</Version>
<RepositoryUrl>https://github.com/brminnick/GitHubApiStatus</RepositoryUrl>
<Product>$(AssemblyName) ($(TargetFramework))</Product>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
Expand Down
11 changes: 9 additions & 2 deletions Src/GitHubApiStatus/GitHubApiStatusException.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
using System;
namespace GitHubApiStatus
{
public class GitHubApiStatusException : Exception
/// <summary>
/// Exception thrown by GitHubApiStatus
/// </summary>
public sealed class GitHubApiStatusException : Exception
{
public GitHubApiStatusException(string message) : base(message)
/// <summary>
/// Initialize GitHubApiStatusException
/// </summary>
/// <param name="message"></param>
internal GitHubApiStatusException(string message) : base(message)
{
}
}
Expand Down
2 changes: 1 addition & 1 deletion Src/GitHubApiStatus/Interfaces/IGitHubApiStatusService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public interface IGitHubApiStatusService
/// </summary>
/// <param name="httpResponseHeaders">HttpResponseHeaders from GitHub API Response</param>
/// <returns>Whether the Http Response Was From an Authenticated Http Request</returns>
bool IsAuthenticated(in HttpResponseHeaders httpResponseHeaders);
bool IsResponseFromAuthenticatedRequest(in HttpResponseHeaders httpResponseHeaders);

/// <summary>
/// Get the DateTimeOffset When the GitHub API Rate Limit Will Reset
Expand Down
8 changes: 8 additions & 0 deletions Src/GitHubApiStatus/Models/GitHubApiStatusClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,16 @@

namespace GitHubApiStatus
{
/// <summary>
/// HttpClient for GitHub's API
/// </summary>
public class GitHubApiClient : HttpClient
{
/// <summary>
/// Initialize GitHubApiClient
/// </summary>
/// <param name="authenticationHeaderValue">GitHub Personal Access Token, aka Bearer Token</param>
/// <param name="productHeaderValue">User Agent</param>
public GitHubApiClient(AuthenticationHeaderValue authenticationHeaderValue, ProductHeaderValue productHeaderValue)
{
GitHubApiStatusService.ValidateAuthenticationHeaderValue(authenticationHeaderValue);
Expand Down
64 changes: 53 additions & 11 deletions Src/GitHubApiStatus/Services/GitHubApiStatusService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ namespace GitHubApiStatus
/// </summary>
public class GitHubApiStatusService : IGitHubApiStatusService
{

readonly GitHubApiClient _client;
/// <summary>
/// GitHub Http Response Rate Limit Header Key
/// </summary>
Expand All @@ -42,7 +44,7 @@ public class GitHubApiStatusService : IGitHubApiStatusService
/// </summary>
public GitHubApiStatusService()
{
Client = new GitHubApiClient();
_client = new GitHubApiClient();
}

/// <summary>
Expand All @@ -52,7 +54,7 @@ public GitHubApiStatusService()
/// <param name="productHeaderValue">User-Agent Name</param>
public GitHubApiStatusService(AuthenticationHeaderValue authenticationHeaderValue, ProductHeaderValue productHeaderValue)
{
Client = new GitHubApiClient(authenticationHeaderValue, productHeaderValue);
_client = new GitHubApiClient(authenticationHeaderValue, productHeaderValue);
}

/// <summary>
Expand All @@ -67,31 +69,71 @@ public GitHubApiStatusService(GitHubApiClient client)
ValidateAuthenticationHeaderValue(client.DefaultRequestHeaders.Authorization);
ValidateProductHeaderValue(client.DefaultRequestHeaders.UserAgent);

Client = client;
_client = client;
}

/// <summary>
/// Determines if GitHubApiClient.DefaultRequestHeaders.UserAgent is Valid
/// </summary>
public bool IsProductHeaderValueValid
{
get
{
try
{
ValidateProductHeaderValue(_client.DefaultRequestHeaders.UserAgent);
return true;
}
catch
{
return false;
}
}
}

GitHubApiClient Client { get; }
/// <summary>
/// Determines if GitHubApiClient.DefaultRequestHeaders.Authorization is Valid
/// </summary>
public bool IsAuthenticationHeaderValueSet
{
get
{
try
{
ValidateAuthenticationHeaderValue(_client.DefaultRequestHeaders.Authorization);
return true;
}
catch
{
return false;
}
}
}

#if NETSTANDARD
static JsonSerializer Serializer => _serializerHolder.Value;
#endif

/// <summary>
/// Adds ProductHeaderValue to
/// Add ProductHeaderValue to HttpClient.DefaultRequestHeaders.UserAgent
/// </summary>
/// <param name="productHeaderValue"></param>
public void AddProductHeaderValue(ProductHeaderValue productHeaderValue)
{
ValidateProductHeaderValue(productHeaderValue);

Client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(productHeaderValue));
_client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(productHeaderValue));
}

/// <summary>
/// Set HttpClient.DefaultRequestHeaders.Authorization
/// </summary>
/// <param name="authenticationHeaderValue"></param>
public void SetAuthenticationHeaderValue(AuthenticationHeaderValue authenticationHeaderValue)
{
ValidateAuthenticationHeaderValue(authenticationHeaderValue);

Client.DefaultRequestHeaders.Authorization = authenticationHeaderValue;
_client.DefaultRequestHeaders.Authorization = authenticationHeaderValue;
}

/// <summary>
Expand All @@ -107,7 +149,7 @@ public void SetAuthenticationHeaderValue(AuthenticationHeaderValue authenticatio
/// <returns></returns>
public async Task<GitHubApiRateLimits> GetApiRateLimits(CancellationToken cancellationToken)
{
var response = await GetGitHubApiRateLimitResponse(Client, cancellationToken).ConfigureAwait(false);
var response = await GetGitHubApiRateLimitResponse(_client, cancellationToken).ConfigureAwait(false);
return response.Results;
}

Expand Down Expand Up @@ -157,10 +199,10 @@ public int GetRemainingRequestCount(in HttpResponseHeaders httpResponseHeaders)
/// </summary>
/// <param name="httpResponseHeaders">HttpResponseHeaders from GitHub API Response</param>
/// <returns>Whether the Http Response Was From an Authenticated Http Request</returns>
public bool IsAuthenticated(in HttpResponseHeaders httpResponseHeaders)
public bool IsResponseFromAuthenticatedRequest(in HttpResponseHeaders httpResponseHeaders)
{
ValidateHttpResponseHeaders(httpResponseHeaders);
return httpResponseHeaders?.Vary.Any(x => x is "Authorization") ?? throw new ArgumentNullException(nameof(httpResponseHeaders));
return httpResponseHeaders.Vary.Any(x => x is "Authorization");
}

/// <summary>
Expand All @@ -187,7 +229,7 @@ public long GetRateLimitResetDateTime_UnixEpochSeconds(in HttpResponseHeaders ht
{
ValidateHttpResponseHeaders(httpResponseHeaders);

var rateLimitResetHeader = httpResponseHeaders?.Single(x => x.Key.Equals(RateLimitResetHeader, StringComparison.OrdinalIgnoreCase)) ?? throw new ArgumentNullException(nameof(httpResponseHeaders));
var rateLimitResetHeader = httpResponseHeaders.Single(x => x.Key.Equals(RateLimitResetHeader, StringComparison.OrdinalIgnoreCase));
return long.Parse(rateLimitResetHeader.Value.First());
}

Expand Down
12 changes: 6 additions & 6 deletions Src/GitStatus.ConsoleApp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ static async Task Main(string[] args)
{
var restApiRateLimitDataFromHeaders = await GetRestApiRateLimitDataFromHeaders();

Console.WriteLine($"What is the GitHub REST API Rate Limit? {restApiRateLimitDataFromHeaders.RateLimit}"); // What is the GitHub REST API Rate Limit? 60
Console.WriteLine($"What is the GitHub REST API Rate Limit? {restApiRateLimitDataFromHeaders.RateLimit}"); // What is the GitHub REST API Rate Limit? 5000
Console.WriteLine($"Have I reached the Maximum REST API Limit? {restApiRateLimitDataFromHeaders.HasReachedMaximumApiLimit}"); // Have I reached the Maximum REST API Limit? False
Console.WriteLine($"How many REST API requests do I have remaining? {restApiRateLimitDataFromHeaders.RemainingRequestCount}"); // How many REST API requests do I have remaining? 56
Console.WriteLine($"How many REST API requests do I have remaining? {restApiRateLimitDataFromHeaders.RemainingRequestCount}"); // How many REST API requests do I have remaining? 4956
Console.WriteLine($"How long until the GitHub REST API Rate Limit resets? {restApiRateLimitDataFromHeaders.RateLimitTimeRemaining}"); // How long until the GitHub REST API Rate Limit resets? 00:29:12.4134330
Console.WriteLine($"Did the GitHub REST API Request include a Bearer Token? {restApiRateLimitDataFromHeaders.IsAuthenticated}"); // Did GitHub REST API Request include a Bearer Token? False
Console.WriteLine($"Did the GitHub REST API Request include a Bearer Token? {restApiRateLimitDataFromHeaders.IsResponseFromAuthenticatedRequest}"); // Did GitHub REST API Request include a Bearer Token? True

Console.WriteLine();

Expand Down Expand Up @@ -75,7 +75,7 @@ static async Task Main(string[] args)
Console.WriteLine();
}

static async Task<(TimeSpan RateLimitTimeRemaining, int RateLimit, int RemainingRequestCount, bool IsAuthenticated, bool HasReachedMaximumApiLimit)> GetRestApiRateLimitDataFromHeaders()
static async Task<(TimeSpan RateLimitTimeRemaining, int RateLimit, int RemainingRequestCount, bool IsResponseFromAuthenticatedRequest, bool HasReachedMaximumApiLimit)> GetRestApiRateLimitDataFromHeaders()
{
HttpResponseMessage restApiResponse = await _client.GetAsync($"{GitHubConstants.GitHubRestApiUrl}/repos/brminnick/GitHubApiStatus");
restApiResponse.EnsureSuccessStatusCode();
Expand All @@ -85,11 +85,11 @@ static async Task Main(string[] args)
int rateLimit = _gitHubApiStatusService.GetRateLimit(restApiResponse.Headers);
int remainingRequestCount = _gitHubApiStatusService.GetRemainingRequestCount(restApiResponse.Headers);

bool isAuthenticated = _gitHubApiStatusService.IsAuthenticated(restApiResponse.Headers);
bool isResponseFromAuthenticatedRequest = _gitHubApiStatusService.IsResponseFromAuthenticatedRequest(restApiResponse.Headers);

bool hasReachedMaximumApiLimit = _gitHubApiStatusService.HasReachedMaximimApiCallLimit(restApiResponse.Headers);

return (rateLimitTimeRemaining, rateLimit, remainingRequestCount, isAuthenticated, hasReachedMaximumApiLimit);
return (rateLimitTimeRemaining, rateLimit, remainingRequestCount, isResponseFromAuthenticatedRequest, hasReachedMaximumApiLimit);
}

static Task<GitHubApiRateLimits> GetApiRateLimits()
Expand Down

0 comments on commit 44c8d8d

Please sign in to comment.