Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds test coverage for non generated features #48

Merged
merged 14 commits into from Mar 7, 2024
22 changes: 21 additions & 1 deletion .github/workflows/build.yml
Expand Up @@ -28,4 +28,24 @@ jobs:
run: dotnet build --no-incremental /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=../key.snk

- name: Test SDK
run: dotnet test
run: dotnet test --configuration Release --verbosity normal --collect:"XPlat Code Coverage" --results-directory ./coverage -p:ExcludeByFile="**/GitHub/**/*.cs"

- name: Code Coverage Report
uses: irongut/CodeCoverageSummary@v1.3.0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mind explaining why you've gone with this tool? I haven't heard of it before and I'm curious what the alternatives and tradeoffs were.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure... it was the most streamlined, most starred, I would've liked it to be more recently maintained - some other implementations had gists, repos, and accounts tied to it so while I was evaluating different tooling and trying to decide if we even want to do something like this - it seemed to be the most reasonable option.

with:
filename: coverage/**/coverage.cobertura.xml
badge: true
fail_below_min: false
format: markdown
hide_branch_rate: false
hide_complexity: true
indicators: true
output: both
thresholds: '60 80'

- name: Add Coverage PR Comment
uses: marocchino/sticky-pull-request-comment@v2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm also curious about this choice, since many other options exist here, like https://github.com/thollander/actions-comment-pull-request.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As with the above - this was the favored implementation and streamlined option. I'm not sure I am 100% sold on having a PR comment with coverage details - this is really try on the shoe and see if it fits. I am most likely going to pull this out and leave it as reporting in the CI step and leave bubbling up the results for another PR.

if: github.event_name == 'pull_request'
with:
recreate: true
path: code-coverage-results.md
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);
}
}
68 changes: 68 additions & 0 deletions test/Client/ClientFactoryTest.cs
@@ -0,0 +1,68 @@
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);
}

// ChainHandlersCollectionAndGetFirstLink
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of this comment and the below one on line 58? Are they going to be expanded upon?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this needs to be cleaned up - I began grouping tests and this was just a remark to keep things ordered for me.

[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);
}


// GetDefaultHttpMessageHandler
[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" />
kfcampbell marked this conversation as resolved.
Show resolved Hide resolved
</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.