Skip to content

Commit

Permalink
maint: Adds test coverage for non generated features (#48)
Browse files Browse the repository at this point in the history
* adds auth tests

* adds coverage for handlers

* code formatting clean up

* adds coverage

* updates build tast to output coverage

* cleans up dev notes

* updates workflow to filter out generated files

* reworks file filters for exclusions

* adds coverage badging and PR comment

* reworks to use xplat format

* new results file

* disabled fail below min

* clean up left over dev comments

* run coverage and display in CI only
  • Loading branch information
nickfloyd committed Mar 7, 2024
1 parent 0c25b6f commit 27e7da4
Show file tree
Hide file tree
Showing 13 changed files with 139 additions and 42 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Expand Up @@ -28,4 +28,4 @@ jobs:
run: dotnet build --no-incremental /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=../key.snk

- name: Test SDK
run: dotnet test
run: dotnet test -p:CollectCoverage=true -p:CoverletOutput=TestResults/ -p:CoverletOutputFormat=opencover -p:ExcludeByFile="**/GitHub/**/*.cs"
11 changes: 5 additions & 6 deletions .gitignore
Expand Up @@ -104,9 +104,8 @@ node_modules/
# Local History for Visual Studio Code
.history/

# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# Tests / Coverage
testresults/
[Tt]est[Rr]esult*/
**/coverage.json
coverage/*
2 changes: 1 addition & 1 deletion GitHub.Octokit.sln
Expand Up @@ -13,7 +13,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
README.md = README.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{7EF0200D-9F10-4A77-8F73-3E26D3EBD326}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "test\Tests.csproj", "{7EF0200D-9F10-4A77-8F73-3E26D3EBD326}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
6 changes: 6 additions & 0 deletions README.md
Expand Up @@ -59,6 +59,12 @@ Currently this project is fairly simple (we hope it can stay that way). All of
- **Middleware** - this represents object and handlers that can mutate the request and are "injected" into the request/response flow.
- **Octokit** - types which represent request/response objects

## Testing

- Run tests: `dotnet test`
- Run coverage: `dotnet test /p:CollectCoverage=true`


## More details on this SDK and repo

- [Code of conduct](Docs/CODE_OF_CONDUCT.md)
Expand Down
22 changes: 0 additions & 22 deletions Tests/Client/ClientFactoryTest.cs

This file was deleted.

8 changes: 4 additions & 4 deletions src/Authentication/TokenAuthenticationProvider.cs
Expand Up @@ -36,8 +36,8 @@ public class TokenAuthenticationProvider : IAuthenticationProvider
/// <exception cref="ArgumentNullException"></exception>
public TokenAuthenticationProvider(string clientId, string token)
{
ArgumentNullException.ThrowIfNullOrEmpty(clientId);
ArgumentNullException.ThrowIfNullOrEmpty(token);
ArgumentException.ThrowIfNullOrEmpty(clientId);
ArgumentException.ThrowIfNullOrEmpty(token);

ClientId = clientId;
Token = token;
Expand All @@ -52,10 +52,10 @@ public TokenAuthenticationProvider(string clientId, string token)
/// <param name="cancellationToken"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public Task AuthenticateRequestAsync(RequestInformation request, Dictionary<string, object>? additionalAuthenticationContext = null, CancellationToken cancellationToken = default)
public Task AuthenticateRequestAsync(RequestInformation? request, Dictionary<string, object>? additionalAuthenticationContext = null, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(request);
ArgumentNullException.ThrowIfNullOrEmpty(Token);
ArgumentException.ThrowIfNullOrEmpty(Token);

if (!request.Headers.ContainsKey(AuthorizationHeaderKey))
{
Expand Down
2 changes: 1 addition & 1 deletion src/Middleware/APIVersionHandler.cs
Expand Up @@ -8,7 +8,7 @@ namespace GitHub.Octokit.Client.Middleware;
/// <summary>
/// Represents a handler that adds the API version header to outgoing HTTP requests.
/// </summary>
class APIVersionHandler(APIVersionOptions? apiVersionOptions = null) : DelegatingHandler
public class APIVersionHandler(APIVersionOptions? apiVersionOptions = null) : DelegatingHandler
{
private const string ApiVersionHeaderKey = "X-GitHub-Api-Version";

Expand Down
2 changes: 1 addition & 1 deletion src/Middleware/Options/UserAgentOptions.cs
Expand Up @@ -13,7 +13,7 @@ public class UserAgentOptions : IRequestOption
/// Gets or sets the product name used in the user agent request header.
/// Defaults to <c>"dotnet-sdk"</c>.
/// </summary>
public string ProductName { get; set; } = "dotnet-sdk";
public string ProductName { get; set; } = "GitHub.Octokit.dotnet-sdk";

/// <summary>
/// Gets or sets the product version used in the user agent request header.
Expand Down
44 changes: 44 additions & 0 deletions test/Authentication/TokenAuthenticationProviderTest.cs
@@ -0,0 +1,44 @@
using GitHub.Octokit.Authentication;
using Microsoft.Kiota.Abstractions;
using Xunit;

public class TokenAuthenticationProviderTests
{
private const string ValidClientId = "validClientId";
private const string ValidToken = "validToken";
private TokenAuthenticationProvider _provider;

public TokenAuthenticationProviderTests()
{
_provider = new TokenAuthenticationProvider(ValidClientId, ValidToken);
}

[Fact]
public void Constructor_ThrowsException_WhenClientIdIsEmpty()
{
Assert.Throws<ArgumentException>(() => new TokenAuthenticationProvider("", ValidToken));
}

[Fact]
public void Constructor_ThrowsException_WhenTokenIsEmpty()
{
Assert.Throws<ArgumentException>(() => new TokenAuthenticationProvider(ValidClientId, ""));
}

[Fact]
public async Task AuthenticateRequestAsync_ThrowsException_WhenRequestIsNull()
{
await Assert.ThrowsAsync<ArgumentNullException>(() => _provider.AuthenticateRequestAsync(null, null));
}

[Fact]
public async Task AuthenticateRequestAsync_AddsAuthorizationHeader_WhenRequestIsValid()
{
var request = new RequestInformation();
await _provider.AuthenticateRequestAsync(request);
var headerToken = request.Headers["Authorization"].FirstOrDefault<string>();

Assert.True(request.Headers.ContainsKey("Authorization"));
Assert.Equal($"Bearer {ValidToken}", headerToken);
}
}
65 changes: 65 additions & 0 deletions test/Client/ClientFactoryTest.cs
@@ -0,0 +1,65 @@
using GitHub.Octokit.Client;
using GitHub.Octokit.Client.Middleware;
using Xunit;


public class TestHandler1 : DelegatingHandler { }
public class TestHandler2 : DelegatingHandler { }

public class ClientFactoryTests
{

[Fact]
public void Creates_Client_With_Default_Timeout()
{
var clientFactory = ClientFactory.Create();
Assert.Equal(TimeSpan.FromSeconds(100), clientFactory.Timeout);
}

[Fact]
public void Creates_Client_Persists_Set_Timeout()
{
var clientFactory = ClientFactory.Create();
clientFactory.Timeout = TimeSpan.FromSeconds(5);
Assert.Equal(TimeSpan.FromSeconds(5), clientFactory.Timeout);
}

[Fact]
public void Create_Returns_NonNullHttpClient()
{
HttpMessageHandler handler = new HttpClientHandler();
var client = ClientFactory.Create(handler);
Assert.NotNull(client);
}

[Fact]
public void CreateDefaultHandlers_Returns_Expected_Handlers()
{
var handlers = ClientFactory.CreateDefaultHandlers();
Assert.Contains(handlers, h => h is APIVersionHandler);
Assert.Contains(handlers, h => h is UserAgentHandler);
}

[Fact]
public void ChainHandlersCollectionAndGetFirstLink_ChainsHandlersCorrectly()
{
var handlers = new DelegatingHandler[]
{
new TestHandler1(),
new TestHandler2()
};
var firstHandler = ClientFactory.ChainHandlersCollectionAndGetFirstLink(null, handlers);
Assert.IsType<TestHandler1>(firstHandler);
Assert.IsType<TestHandler2>(firstHandler.InnerHandler);
}

[Fact]
public void GetDefaultHttpMessageHandler_Returns_NonNullHttpMessageHandler()
{
var handler = ClientFactory.GetDefaultHttpMessageHandler();
Assert.NotNull(handler);
}

}


@@ -1,6 +1,5 @@
using GitHub.Octokit.Authentication;
using GitHub.Octokit.Client;
using NSubstitute;
using Xunit;

public class RequestAdapterTests
Expand All @@ -16,7 +15,7 @@ public void Creates_RequestAdaptor_With_Defaults()
[Fact]
public void Creates_RequestAdaptor_With_GenericHttpClient()
{
var httpClient = Substitute.For<HttpClient>();
var httpClient = new HttpClient();
var requestAdapter = RequestAdapter.Create(new TokenAuthenticationProvider("Octokit.Gen", "JRRTOLKIEN"), httpClient);
Assert.NotNull(requestAdapter);
}
Expand Down
14 changes: 10 additions & 4 deletions Tests/Tests.csproj → test/Tests.csproj
Expand Up @@ -28,22 +28,28 @@
</Content>
</ItemGroup>



<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.1">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.msbuild" Version="6.0.1">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit" Version="2.6.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.4" PrivateAssets="all" />
<PackageReference Include="NSubstitute" Version="5.1.0" />
<PackageReference Include="Moq" Version="4.20.70" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />

</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\src\GitHub.Octokit.SDK.csproj" />
</ItemGroup>
</Project>

File renamed without changes.

0 comments on commit 27e7da4

Please sign in to comment.