Skip to content

Commit

Permalink
Merge pull request #587 from octokit/default-timeout-api
Browse files Browse the repository at this point in the history
Set the DefaultTimeout with the Connection
  • Loading branch information
shiftkey committed Dec 4, 2014
2 parents 06e8616 + 987282d commit 7164488
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 3 deletions.
17 changes: 17 additions & 0 deletions Octokit.Tests/Clients/ReleasesClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,23 @@ public async Task EnsuresArgumentsNotNull()
await AssertEx.Throws<ArgumentNullException>(async () => await releasesClient.UploadAsset(null, uploadData));
await AssertEx.Throws<ArgumentNullException>(async () => await releasesClient.UploadAsset(release, null));
}

[Fact]
public async Task OverrideDefaultTimeout()
{
var newTimeout = TimeSpan.FromSeconds(100);

var apiConnection = Substitute.For<IApiConnection>();

var fixture = new ReleasesClient(apiConnection);

var release = new Release { UploadUrl = "https://uploads.github.com/anything" };
var uploadData = new ReleaseAssetUpload { FileName = "good", ContentType = "good/good", RawData = Stream.Null, Timeout = newTimeout };

await fixture.UploadAsset(release, uploadData);

apiConnection.Received().Post<ReleaseAsset>(Arg.Any<Uri>(), uploadData.RawData, Arg.Any<String>(), uploadData.ContentType, newTimeout);
}
}

public class TheGetAssetMethod
Expand Down
11 changes: 11 additions & 0 deletions Octokit/Clients/ReleasesClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,17 @@ public Task<ReleaseAsset> UploadAsset(Release release, ReleaseAssetUpload data)
Ensure.ArgumentNotNull(data, "data");

var endpoint = release.UploadUrl.ExpandUriTemplate(new { name = data.FileName });

if (data.Timeout.HasValue)
{
return ApiConnection.Post<ReleaseAsset>(
endpoint,
data.RawData,
"application/vnd.github.v3",
data.ContentType,
data.Timeout.GetValueOrDefault());
}

return ApiConnection.Post<ReleaseAsset>(
endpoint,
data.RawData,
Expand Down
16 changes: 16 additions & 0 deletions Octokit/Helpers/Ensure.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Diagnostics.CodeAnalysis;

namespace Octokit
{
Expand Down Expand Up @@ -31,6 +32,21 @@ public static void ArgumentNotNullOrEmptyString([ValidatedNotNull]string value,

throw new ArgumentException("String cannot be empty", name);
}

/// <summary>
/// Checks a timespan argument to ensure it is a positive value.
/// </summary>
/// <param name = "value">The argument value to check</param>
/// <param name = "name">The name of the argument</param>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
public static void GreaterThanZero([ValidatedNotNull]TimeSpan value, string name)
{
ArgumentNotNull(value, name);

if (value.TotalMilliseconds > 0) return;

throw new ArgumentException("Timespan must be greater than zero", name);
}
}

[AttributeUsage(AttributeTargets.Parameter)]
Expand Down
14 changes: 14 additions & 0 deletions Octokit/Http/ApiConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,20 @@ public async Task<T> Post<T>(Uri uri, object data, string accepts, string conten
return response.BodyAsObject;
}

public async Task<T> Post<T>(Uri uri, object data, string accepts, string contentType, TimeSpan timeout)
{
Ensure.ArgumentNotNull(uri, "uri");
Ensure.ArgumentNotNull(data, "data");

var response = await Connection.Post<T>(
uri,
data,
accepts,
contentType,
timeout).ConfigureAwait(false);
return response.BodyAsObject;
}

/// <summary>
/// Creates or replaces the API resource at the specified URI
/// </summary>
Expand Down
43 changes: 40 additions & 3 deletions Octokit/Http/Connection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,14 @@ public Task<IResponse<T>> Post<T>(Uri uri, object body, string accepts, string c
return SendData<T>(uri, HttpMethod.Post, body, accepts, contentType, CancellationToken.None);
}

public Task<IResponse<T>> Post<T>(Uri uri, object body, string accepts, string contentType, TimeSpan timeout)
{
Ensure.ArgumentNotNull(uri, "uri");
Ensure.ArgumentNotNull(body, "body");

return SendData<T>(uri, HttpMethod.Post, body, accepts, contentType, timeout, CancellationToken.None);
}

public Task<IResponse<T>> Post<T>(Uri uri, object body, string accepts, string contentType, Uri baseAddress)
{
Ensure.ArgumentNotNull(uri, "uri");
Expand Down Expand Up @@ -223,20 +231,49 @@ Task<IResponse<T>> SendData<T>(
object body,
string accepts,
string contentType,
TimeSpan timeout,
CancellationToken cancellationToken,
string twoFactorAuthenticationCode = null,
Uri baseAddress = null
)
Uri baseAddress = null)
{
Ensure.ArgumentNotNull(uri, "uri");
Ensure.GreaterThanZero(timeout, "timeout");

var request = new Request
{
Method = method,
BaseAddress = baseAddress ?? BaseAddress,
Endpoint = uri,
Timeout = timeout
};

return SendDataInternal<T>(body, accepts, contentType, cancellationToken, twoFactorAuthenticationCode, request);
}

Task<IResponse<T>> SendData<T>(
Uri uri,
HttpMethod method,
object body,
string accepts,
string contentType,
CancellationToken cancellationToken,
string twoFactorAuthenticationCode = null,
Uri baseAddress = null)
{
Ensure.ArgumentNotNull(uri, "uri");

var request = new Request
{
Method = method,
BaseAddress = baseAddress ?? BaseAddress,
Endpoint = uri,
};

return SendDataInternal<T>(body, accepts, contentType, cancellationToken, twoFactorAuthenticationCode, request);
}

Task<IResponse<T>> SendDataInternal<T>(object body, string accepts, string contentType, CancellationToken cancellationToken, string twoFactorAuthenticationCode, Request request)
{
if (!String.IsNullOrEmpty(accepts))
{
request.Headers["Accept"] = accepts;
Expand All @@ -254,7 +291,7 @@ Task<IResponse<T>> SendData<T>(
request.ContentType = contentType ?? "application/x-www-form-urlencoded";
}

return Run<T>(request,cancellationToken);
return Run<T>(request, cancellationToken);
}

/// <summary>
Expand Down
13 changes: 13 additions & 0 deletions Octokit/Http/IApiConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,19 @@ public interface IApiConnection
/// <exception cref="ApiException">Thrown when an API error occurs.</exception>
Task<T> Post<T>(Uri uri, object data, string accepts, string contentType);

/// <summary>
/// Creates a new API resource in the list at the specified URI.
/// </summary>
/// <typeparam name="T">The API resource's type.</typeparam>
/// <param name="uri">URI of the API resource to get</param>
/// <param name="data">Object that describes the new API resource; this will be serialized and used as the request's body</param>
/// <param name="accepts">Accept header to use for the API request</param>
/// <param name="contentType">Content type of the API request</param>
/// <param name="timeout">Timeout for the request</param>
/// <returns>The created API resource.</returns>
/// <exception cref="ApiException">Thrown when an API error occurs.</exception>
Task<T> Post<T>(Uri uri, object data, string accepts, string contentType, TimeSpan timeout);

/// <summary>
/// Creates or replaces the API resource at the specified URI
/// </summary>
Expand Down
14 changes: 14 additions & 0 deletions Octokit/Http/IConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,20 @@ public interface IConnection
/// <returns><seealso cref="IResponse"/> representing the received HTTP response</returns>
Task<IResponse<T>> Post<T>(Uri uri, object body, string accepts, string contentType);

/// <summary>
/// Performs an asynchronous HTTP POST request.
/// Attempts to map the response body to an object of type <typeparamref name="T"/>
/// </summary>
/// <typeparam name="T">The type to map the response to</typeparam>
/// <param name="uri">URI endpoint to send request to</param>
/// <param name="body">The object to serialize as the body of the request</param>
/// <param name="accepts">Specifies accepted response media types.</param>
/// <param name="contentType">Specifies the media type of the request body</param>
/// <param name="timeout"></param>
/// <returns><seealso cref="IResponse"/> representing the received HTTP response</returns>
Task<IResponse<T>> Post<T>(Uri uri, object body, string accepts, string contentType, TimeSpan timeout);


/// <summary>
/// Performs an asynchronous HTTP POST request.
/// Attempts to map the response body to an object of type <typeparamref name="T"/>
Expand Down
1 change: 1 addition & 0 deletions Octokit/Models/Response/ReleaseAssetUpload.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public class ReleaseAssetUpload
public string FileName { get; set; }
public string ContentType { get; set; }
public Stream RawData { get; set; }
public TimeSpan? Timeout { get; set; }

internal string DebuggerDisplay
{
Expand Down

0 comments on commit 7164488

Please sign in to comment.