Skip to content

Commit

Permalink
Update MiscellaneousClient to ApiClient approach and add pagination s…
Browse files Browse the repository at this point in the history
…upport to GetAllLicenses. (#1716)

Co-authored-by: Brendan Forster <[email protected]>
  • Loading branch information
gdziadkiewicz and shiftkey authored Feb 25, 2020
1 parent 65bb8d5 commit 04c9a9a
Show file tree
Hide file tree
Showing 9 changed files with 312 additions and 126 deletions.
9 changes: 8 additions & 1 deletion Octokit.Reactive/Clients/IObservableMiscellaneousClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,18 @@ public interface IObservableMiscellaneousClient
/// Returns a list of the licenses shown in the license picker on GitHub.com. This is not a comprehensive
/// list of all possible OSS licenses.
/// </summary>
/// <remarks>This is a PREVIEW API! Use it at your own risk.</remarks>
/// <returns>A list of licenses available on the site</returns>
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
IObservable<LicenseMetadata> GetAllLicenses();

/// <summary>
/// Returns a list of the licenses shown in the license picker on GitHub.com. This is not a comprehensive
/// list of all possible OSS licenses.
/// </summary>
/// <param name="options">Options for changing the API response</param>
/// <returns>A list of licenses available on the site</returns>
IObservable<LicenseMetadata> GetAllLicenses(ApiOptions options);

/// <summary>
/// Retrieves a license based on the license key such as "MIT"
/// </summary>
Expand Down
14 changes: 12 additions & 2 deletions Octokit.Reactive/Clients/ObservableMiscellaneousClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,21 @@ public IObservable<GitIgnoreTemplate> GetGitIgnoreTemplate(string templateName)
/// Returns a list of the licenses shown in the license picker on GitHub.com. This is not a comprehensive
/// list of all possible OSS licenses.
/// </summary>
/// <remarks>This is a PREVIEW API! Use it at your own risk.</remarks>
/// <returns>A list of licenses available on the site</returns>
public IObservable<LicenseMetadata> GetAllLicenses()
{
return _client.GetAllLicenses().ToObservable().SelectMany(l => l);
return GetAllLicenses(ApiOptions.None);
}

/// <summary>
/// Returns a list of the licenses shown in the license picker on GitHub.com. This is not a comprehensive
/// list of all possible OSS licenses.
/// </summary>
/// <param name="options">Options for changing the API response</param>
/// <returns>A list of licenses available on the site</returns>
public IObservable<LicenseMetadata> GetAllLicenses(ApiOptions options)
{
return _client.GetAllLicenses(options).ToObservable().SelectMany(l => l);
}

/// <summary>
Expand Down
52 changes: 51 additions & 1 deletion Octokit.Tests.Integration/Clients/MiscellaneousClientTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Threading.Tasks;
using Octokit;
using Octokit.Tests.Integration;
using Xunit;

Expand Down Expand Up @@ -55,6 +56,47 @@ public async Task CanRetrieveListOfLicenses()
Assert.True(result.Count > 2);
Assert.Contains(result, license => license.Key == "mit");
}

[IntegrationTest]
public async Task CanRetrieveListOfLicensesWithPagination()
{
var github = Helper.GetAuthenticatedClient();

var options = new ApiOptions
{
PageCount = 1,
PageSize = 5,
};

var result = await github.Miscellaneous.GetAllLicenses(options);

Assert.Equal(5, result.Count);
}

[IntegrationTest]
public async Task CanRetrieveDistinctListOfLicensesBasedOnPageStart()
{
var github = Helper.GetAuthenticatedClient();

var startOptions = new ApiOptions
{
PageSize = 1,
PageCount = 1
};

var firstPage = await github.Miscellaneous.GetAllLicenses(startOptions);

var skipStartOptions = new ApiOptions
{
PageSize = 1,
PageCount = 1,
StartPage = 2
};

var secondPage = await github.Miscellaneous.GetAllLicenses(skipStartOptions);

Assert.NotEqual(firstPage[0].Key, secondPage[0].Key);
}
}

public class TheGetLicenseMethod
Expand All @@ -69,6 +111,14 @@ public async Task CanRetrieveListOfLicenses()
Assert.Equal("mit", result.Key);
Assert.Equal("MIT License", result.Name);
}

[IntegrationTest]
public async Task ReportsErrorWhenInvalidLicenseProvided()
{
var github = Helper.GetAuthenticatedClient();

await Assert.ThrowsAsync<NotFoundException>(() => github.Miscellaneous.GetLicense("purple-monkey-dishwasher"));
}
}

public class TheGetResourceRateLimitsMethod
Expand Down Expand Up @@ -120,4 +170,4 @@ public async Task CanRetrieveMetadata()
Assert.True(result.Importer.Count > 0);
}
}
}
}
170 changes: 104 additions & 66 deletions Octokit.Tests/Clients/MiscellaneousClientTests.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using NSubstitute;
using Octokit.Internal;
using Xunit;
using System.Globalization;

Expand All @@ -13,41 +13,49 @@ public class MiscellaneousClientTests
public class TheRenderRawMarkdownMethod
{
[Fact]
public async Task RequestsTheEmojiEndpoint()
public async Task RequestsTheRawMarkdownEndpoint()
{
IApiResponse<string> response = new ApiResponse<string>(new Response(), "<strong>Test</strong>");
var connection = Substitute.For<IConnection>();
connection.Post<string>(Args.Uri, "**Test**", "text/html", "text/plain")
var markdown = "**Test**";
var response = "<strong>Test</strong>";
var apiConnection = Substitute.For<IApiConnection>();
apiConnection.Post<string>(
Arg.Is<Uri>(u => u.ToString() == "markdown/raw"),
markdown,
"text/html",
"text/plain")
.Returns(Task.FromResult(response));
var client = new MiscellaneousClient(connection);
var client = new MiscellaneousClient(apiConnection);

var html = await client.RenderRawMarkdown("**Test**");
var html = await client.RenderRawMarkdown(markdown);

Assert.Equal("<strong>Test</strong>", html);
connection.Received()
apiConnection.Received()
.Post<string>(Arg.Is<Uri>(u => u.ToString() == "markdown/raw"),
"**Test**",
markdown,
"text/html",
"text/plain");
}
}
public class TheRenderArbitraryMarkdownMethod
{
[Fact]
public async Task RequestsTheEmojiEndpoint()
public async Task RequestsTheMarkdownEndpoint()
{
IApiResponse<string> response = new ApiResponse<string>(new Response(), "<strong>Test</strong>");
var connection = Substitute.For<IConnection>();
var forTest = new NewArbitraryMarkdown("testMarkdown", "gfm", "testContext");
connection.Post<string>(Args.Uri, forTest, "text/html", "text/plain")
var response = "<strong>Test</strong>";

var payload = new NewArbitraryMarkdown("testMarkdown", "gfm", "testContext");

var apiConnection = Substitute.For<IApiConnection>();
apiConnection.Post<string>(Args.Uri, payload, "text/html", "text/plain")
.Returns(Task.FromResult(response));
var client = new MiscellaneousClient(connection);

var html = await client.RenderArbitraryMarkdown(forTest);
var client = new MiscellaneousClient(apiConnection);

var html = await client.RenderArbitraryMarkdown(payload);
Assert.Equal("<strong>Test</strong>", html);
connection.Received()
apiConnection.Received()
.Post<string>(Arg.Is<Uri>(u => u.ToString() == "markdown"),
forTest,
payload,
"text/html",
"text/plain");
}
Expand All @@ -57,25 +65,24 @@ public class TheGetEmojisMethod
[Fact]
public async Task RequestsTheEmojiEndpoint()
{
IApiResponse<Dictionary<string, string>> response = new ApiResponse<Dictionary<string, string>>
(
new Response(),
new Dictionary<string, string>
{
{ "foo", "http://example.com/foo.gif" },
{ "bar", "http://example.com/bar.gif" }
}
);
var connection = Substitute.For<IConnection>();
connection.Get<Dictionary<string, string>>(Args.Uri, null, null).Returns(Task.FromResult(response));
var client = new MiscellaneousClient(connection);
IReadOnlyList<Emoji> response = new List<Emoji>
{
{ new Emoji("foo", "http://example.com/foo.gif") },
{ new Emoji("bar", "http://example.com/bar.gif") }
};

var apiConnection = Substitute.For<IApiConnection>();
apiConnection.GetAll<Emoji>(Args.Uri)
.Returns(Task.FromResult(response));

var client = new MiscellaneousClient(apiConnection);

var emojis = await client.GetAllEmojis();

Assert.Equal(2, emojis.Count);
Assert.Equal("foo", emojis[0].Name);
connection.Received()
.Get<Dictionary<string, string>>(Arg.Is<Uri>(u => u.ToString() == "emojis"), null, null);
apiConnection.Received()
.GetAll<Emoji>(Arg.Is<Uri>(u => u.ToString() == "emojis"));
}
}

Expand All @@ -84,20 +91,17 @@ public class TheGetResourceRateLimitsMethod
[Fact]
public async Task RequestsTheResourceRateLimitEndpoint()
{
IApiResponse<MiscellaneousRateLimit> response = new ApiResponse<MiscellaneousRateLimit>
(
new Response(),
new MiscellaneousRateLimit(
new ResourceRateLimit(
new RateLimit(5000, 4999, 1372700873),
new RateLimit(30, 18, 1372700873)
),
new RateLimit(100, 75, 1372700873)
)
);
var connection = Substitute.For<IConnection>();
connection.Get<MiscellaneousRateLimit>(Args.Uri, null, null).Returns(Task.FromResult(response));
var client = new MiscellaneousClient(connection);
var rateLimit = new MiscellaneousRateLimit(
new ResourceRateLimit(
new RateLimit(5000, 4999, 1372700873),
new RateLimit(30, 18, 1372700873)
),
new RateLimit(100, 75, 1372700873)
);
var apiConnection = Substitute.For<IApiConnection>();
apiConnection.Get<MiscellaneousRateLimit>(Arg.Is<Uri>(u => u.ToString() == "rate_limit")).Returns(Task.FromResult(rateLimit));

var client = new MiscellaneousClient(apiConnection);

var result = await client.GetRateLimits();

Expand Down Expand Up @@ -131,8 +135,8 @@ public async Task RequestsTheResourceRateLimitEndpoint()
CultureInfo.InvariantCulture);
Assert.Equal(expectedReset, result.Rate.Reset);

connection.Received()
.Get<MiscellaneousRateLimit>(Arg.Is<Uri>(u => u.ToString() == "rate_limit"), null, null);
apiConnection.Received()
.Get<MiscellaneousRateLimit>(Arg.Is<Uri>(u => u.ToString() == "rate_limit"));
}
}

Expand All @@ -141,22 +145,18 @@ public class TheGetMetadataMethod
[Fact]
public async Task RequestsTheMetadataEndpoint()
{
IApiResponse<Meta> response = new ApiResponse<Meta>
(
new Response(),
new Meta(
false,
"12345ABCDE",
new[] { "1.1.1.1/24", "1.1.1.2/24" },
new[] { "1.1.2.1/24", "1.1.2.2/24" },
new[] { "1.1.3.1/24", "1.1.3.2/24" },
new[] { "1.1.4.1", "1.1.4.2" }
)
);
var connection = Substitute.For<IConnection>();
connection.Get<Meta>(Args.Uri, null, null)
.Returns(Task.FromResult(response));
var client = new MiscellaneousClient(connection);
var meta = new Meta(
false,
"12345ABCDE",
new[] { "1.1.1.1/24", "1.1.1.2/24" },
new[] { "1.1.2.1/24", "1.1.2.2/24" },
new[] { "1.1.3.1/24", "1.1.3.2/24" },
new[] { "1.1.4.1", "1.1.4.2" }
);

var apiConnection = Substitute.For<IApiConnection>();
apiConnection.Get<Meta>(Arg.Is<Uri>(u => u.ToString() == "meta")).Returns(Task.FromResult(meta));
var client = new MiscellaneousClient(apiConnection);

var result = await client.GetMetadata();

Expand All @@ -167,8 +167,8 @@ public async Task RequestsTheMetadataEndpoint()
Assert.Equal(result.Pages, new[] { "1.1.3.1/24", "1.1.3.2/24" });
Assert.Equal(result.Importer, new[] { "1.1.4.1", "1.1.4.2" });

connection.Received()
.Get<Meta>(Arg.Is<Uri>(u => u.ToString() == "meta"), null, null);
apiConnection.Received()
.Get<Meta>(Arg.Is<Uri>(u => u.ToString() == "meta"));
}
}

Expand All @@ -180,5 +180,43 @@ public void EnsuresNonNullArguments()
Assert.Throws<ArgumentNullException>(() => new MiscellaneousClient(null));
}
}

public class TheGetAllLicensesMethod
{
[Fact]
public void EnsuresNonNullArguments()
{
var client = new MiscellaneousClient(Substitute.For<IApiConnection>());

Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAllLicenses(null));
}

[Fact]
public async Task RequestsTheLicensesEndpoint()
{
IReadOnlyList<LicenseMetadata> response = new ReadOnlyCollection<LicenseMetadata>(new List<LicenseMetadata>()
{
new LicenseMetadata("foo1", "node-id-1", "foo2", "something", "http://example.com/foo1", true),
new LicenseMetadata("bar1", "node-id-1", "bar2", "something else", "http://example.com/bar1", false)
});

var connection = Substitute.For<IApiConnection>();
connection.GetAll<LicenseMetadata>(Arg.Is<Uri>(u => u.ToString() == "licenses"), null, "application/vnd.github.drax-preview+json", Args.ApiOptions)
.Returns(Task.FromResult(response));
var client = new MiscellaneousClient(connection);

var licenses = await client.GetAllLicenses();

Assert.Equal(2, licenses.Count);
Assert.Equal("foo1", licenses[0].Key);
Assert.Equal("foo2", licenses[0].Name);
Assert.Equal("http://example.com/foo1", licenses[0].Url);
Assert.Equal("bar1", licenses[1].Key);
Assert.Equal("bar2", licenses[1].Name);
Assert.Equal("http://example.com/bar1", licenses[1].Url);
connection.Received()
.GetAll<LicenseMetadata>(Arg.Is<Uri>(u => u.ToString() == "licenses"), null, AcceptHeaders.LicensesApiPreview, Args.ApiOptions);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public void CallsIntoClient()

client.GetAllLicenses();

gitHubClient.Miscellaneous.Received(1).GetAllLicenses();
gitHubClient.Miscellaneous.Received(1).GetAllLicenses(Args.ApiOptions);
}
}

Expand Down
Loading

0 comments on commit 04c9a9a

Please sign in to comment.