Skip to content

Commit

Permalink
Test suite updated, VCR implemented, minor patches
Browse files Browse the repository at this point in the history
- Add new tests to .NET (+ VCR, + recorded cassettes), uses env vars for keys, auth keys censored
- Add new tests to .NET Framework (no VCR), uses env vars for keys
- Note in README what does/does not use VCR, API key levels
- Throw exception if URL parameter value is empty in .NET Framework
- Set-and-forget returns boolean for success
- Fix AddressCollection stores Address
- Fix Address creation enforcing `verify` and `verify_strict` parameters
- Fix User-Agent for requests (yes, .NET and .NET Framework look different, but after parsing, they'll come out the same)
- All requests will have, i.e. `User-Agent: EasyPost/v2,CSharpClient/2.8.1,.NET/5.0.13`
- Update CHANGELOG
  • Loading branch information
nwithan8 committed Mar 2, 2022
1 parent fba7809 commit 8872686
Show file tree
Hide file tree
Showing 175 changed files with 11,024 additions and 4,595 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ jobs:
NET_Tests:
# derived from https://dev.to/felipetofoli/github-actions-for-net-full-framework-build-and-test-299h
runs-on: windows-2022
env:
EASYPOST_TEST_API_KEY: ${{ secrets.EASYPOST_TEST_API_KEY }}
EASYPOST_PROD_API_KEY: ${{ secrets.EASYPOST_PROD_API_KEY }}
strategy:
matrix:
dotnet-version: [ 'NetFramework35', 'NetCore31', 'Net50', 'Net60' ]
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@

* Rename method from List() to All() to make our library consistent
* Remove `Rating` class since it's not being used in anywhere
* Removes `shipment.GetRates()` method since the shipment object already has rates. If you need to get new rates for a shipment, please use the `shipment.RegenerateRates()` method.
* Add `RetrieveMe()` convenience function that allow users to retrieve without specifying an ID.
* Adds missing `billing_ref` and `dropoff_type` options
* Adds full test suite for .NET/.NET Core (using VCR) and .NET Framework versions
* Fix bug where AddressCollection was storing Batch objects rather than Address objects
* Adds option to pass in a custom `HttpClient` to the Client constructor (.NET/.NET Core only)
* Fix Address creation respecting `verify` and `verify_strict` parameters

## v2.8.1 (2022-02-17)

Expand Down
20 changes: 20 additions & 0 deletions EasyPost.Net/Address.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,32 @@ public static Address Create(Dictionary<string, object> parameters = null)
verifications = (List<string>)parameters["verifications"];
parameters.Remove("verifications");
}
else if (parameters.ContainsKey("verify"))
{
verifications = new List<string>();
foreach (bool val in (List<bool>)parameters["verify"])
{
verifications.Add(val.ToString());
}

parameters.Remove("verify");
}

if (parameters.ContainsKey("strict_verifications"))
{
strictVerifications = (List<string>)parameters["strict_verifications"];
parameters.Remove("strict_verifications");
}
else if (parameters.ContainsKey("verify_strict"))
{
strictVerifications = new List<string>();
foreach (bool val in (List<bool>)parameters["verify_strict"])
{
strictVerifications.Add(val.ToString());
}

parameters.Remove("verify_strict");
}

return SendCreate(parameters, verifications, strictVerifications);
}
Expand Down
2 changes: 1 addition & 1 deletion EasyPost.Net/AddressCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace EasyPost
public class AddressCollection : Resource
{
[JsonProperty("addresses")]
public List<Batch> addresses { get; set; }
public List<Address> addresses { get; set; }
[JsonProperty("has_more")]
public bool has_more { get; set; }
}
Expand Down
29 changes: 19 additions & 10 deletions EasyPost.Net/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Reflection;
using EasyPost.Utilities;
using RestSharp;
Expand Down Expand Up @@ -40,31 +41,40 @@ public int RequestTimeoutMilliseconds
/// Constructor for the EasyPost client.
/// </summary>
/// <param name="clientConfiguration">EasyPost.ClientConfiguration object instance to use to configure this client.</param>
public Client(ClientConfiguration clientConfiguration)
/// <param name="customHttpClient">Custom HttpClient to pass into RestSharp if needed. Mostly for debug purposes, not advised for general use.</param>
public Client(ClientConfiguration clientConfiguration, HttpClient? customHttpClient = null)
{
ServicePointManager.SecurityProtocol |= Security.GetProtocol();
_configuration = clientConfiguration ?? throw new ArgumentNullException(nameof(clientConfiguration));

Assembly assembly = Assembly.GetExecutingAssembly();
FileVersionInfo info = FileVersionInfo.GetVersionInfo(assembly.Location);
_libraryVersion = info.FileVersion;
try
{
Assembly assembly = typeof(Client).Assembly;
FileVersionInfo info = FileVersionInfo.GetVersionInfo(assembly.Location);
_libraryVersion = info.FileVersion;
}
catch (Exception)
{
_libraryVersion = "Unknown";
}

_dotNetVersion = Environment.Version.ToString();

RestClientOptions clientOptions = new RestClientOptions()
RestClientOptions clientOptions = new RestClientOptions
{
Timeout = ConnectTimeoutMilliseconds,
BaseUrl = new Uri(clientConfiguration.ApiBase)
BaseUrl = new Uri(clientConfiguration.ApiBase),
UserAgent = UserAgent
};

_restClient = new RestClient(clientOptions);
_restClient = customHttpClient != null ? new RestClient(customHttpClient, clientOptions) : new RestClient(clientOptions);
}

/// <summary>
/// Execute a request against the EasyPost API.
/// </summary>
/// <param name="request">EasyPost.Request object instance to execute.</param>
/// <returns>RestSharp.RestResponse instance.</returns>
/// <returns>Whether request was successful.</returns>
internal bool Execute(Request request)
{
RestResponse response = _restClient.ExecuteAsync(PrepareRequest(request)).GetAwaiter().GetResult();
Expand All @@ -81,7 +91,7 @@ internal bool Execute(Request request)
/// <exception cref="HttpException">An error occurred during the API request.</exception>
internal T Execute<T>(Request request, string rootElement = null) where T : new()
{
RestResponse<T> response = (RestResponse<T>)_restClient.ExecuteAsync<T>(PrepareRequest(request)).GetAwaiter().GetResult();
RestResponse<T> response = _restClient.ExecuteAsync<T>(PrepareRequest(request)).GetAwaiter().GetResult();
int statusCode = Convert.ToInt32(response.StatusCode);

List<string> rootElements = null;
Expand Down Expand Up @@ -129,7 +139,6 @@ private RestRequest PrepareRequest(Request request)
{
RestRequest restRequest = (RestRequest)request;
restRequest.Timeout = RequestTimeoutMilliseconds;
restRequest.AddHeader("user_agent", UserAgent);
restRequest.AddHeader("authorization", "Bearer " + _configuration.ApiKey);
restRequest.AddHeader("content_type", "application/json");

Expand Down
60 changes: 22 additions & 38 deletions EasyPost.Net/Shipment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,43 +152,6 @@ public void GenerateLabel(string fileFormat)
Merge(request.Execute<Shipment>());
}

/// <summary>
/// Populate the rates property for this Shipment.
/// </summary>
public void GetRates()
{
if (id == null)
{
Create();
}

Request request = new Request("shipments/{id}/rates");
request.AddUrlSegment("id", id);

rates = request.Execute<Shipment>().rates;
}

/// <summary>
/// Refresh the rates for this Shipment.
/// </summary>
/// <param name="parameters">Optional dictionary of parameters for the API request.</param>
public void RegenerateRates(Dictionary<string, object> parameters = null)
{
if (id == null)
{
Create();
}

Request request = new Request("shipments/{id}/rerate", Method.Post);
request.AddUrlSegment("id", id);
if (parameters != null)
{
request.AddBody(parameters);
}

rates = request.Execute<Shipment>().rates;
}

/// <summary>
/// Get the Smartrates for this shipment.
/// </summary>
Expand Down Expand Up @@ -238,7 +201,7 @@ public Rate LowestRate(IEnumerable<string> includeCarriers = null, IEnumerable<s
{
if (rates == null)
{
GetRates();
return null;
}

List<Rate> result = new List<Rate>(rates);
Expand Down Expand Up @@ -266,6 +229,27 @@ public Rate LowestRate(IEnumerable<string> includeCarriers = null, IEnumerable<s
return result.OrderBy(rate => double.Parse(rate.rate)).FirstOrDefault();
}

/// <summary>
/// Refresh the rates for this Shipment.
/// </summary>
/// <param name="parameters">Optional dictionary of parameters for the API request.</param>
public void RegenerateRates(Dictionary<string, object> parameters = null)
{
if (id == null)
{
Create();
}

Request request = new Request("shipments/{id}/rerate", Method.Post);
request.AddUrlSegment("id", id);
if (parameters != null)
{
request.AddBody(parameters);
}

rates = request.Execute<Shipment>().rates;
}

/// <summary>
/// Send a refund request to the carrier the shipment was purchased from.
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions EasyPost.Net/Verification.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public class Verification : Resource
[JsonProperty("details")]
public VerificationDetails details { get; set; }
[JsonProperty("errors")]
// TODO: handle refactor of Error
public List<Error> errors { get; set; }
[JsonProperty("success")]
public bool success { get; set; }
Expand Down
2 changes: 1 addition & 1 deletion EasyPost.Net/WebhookList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace EasyPost
{
public class WebhookList : Resource
internal class WebhookList : Resource
{
[JsonProperty("webhooks")]
public List<Webhook> webhooks { get; set; }
Expand Down
20 changes: 20 additions & 0 deletions EasyPost.NetFramework/Address.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,32 @@ public static Address Create(Dictionary<string, object> parameters = null)
verifications = (List<string>)parameters["verifications"];
parameters.Remove("verifications");
}
else if (parameters.ContainsKey("verify"))
{
verifications = new List<string>();
foreach (bool val in (List<bool>)parameters["verify"])
{
verifications.Add(val.ToString());
}

parameters.Remove("verify");
}

if (parameters.ContainsKey("strict_verifications"))
{
strictVerifications = (List<string>)parameters["strict_verifications"];
parameters.Remove("strict_verifications");
}
else if (parameters.ContainsKey("verify_strict"))
{
strictVerifications = new List<string>();
foreach (bool val in (List<bool>)parameters["verify_strict"])
{
strictVerifications.Add(val.ToString());
}

parameters.Remove("verify_strict");
}

return SendCreate(parameters, verifications, strictVerifications);
}
Expand Down
2 changes: 1 addition & 1 deletion EasyPost.NetFramework/AddressCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace EasyPost
public class AddressCollection : Resource
{
[JsonProperty("addresses")]
public List<Batch> addresses { get; set; }
public List<Address> addresses { get; set; }
[JsonProperty("has_more")]
public bool has_more { get; set; }
}
Expand Down
5 changes: 3 additions & 2 deletions EasyPost.NetFramework/CarrierAccount.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,13 @@ public class CarrierAccount : Resource
/// <summary>
/// Remove this CarrierAccount from your account.
/// </summary>
public void Destroy()
/// <returns>Whether the request was successful or not.</returns>
public bool Destroy()
{
Request request = new Request("carrier_accounts/{id}", Method.DELETE);
request.AddUrlSegment("id", id);

request.Execute();
return request.Execute();
}

/// <summary>
Expand Down
25 changes: 18 additions & 7 deletions EasyPost.NetFramework/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public int RequestTimeoutMilliseconds
set => _requestTimeoutMilliseconds = value;
}

private string UserAgent => $"EasyPost/v2 CSharpClient/{_libraryVersion} .NET/{_dotNetVersion}";
private string UserAgent => $"EasyPost/v2,CSharpClient/{_libraryVersion},.NET/{_dotNetVersion}";

/// <summary>
/// Constructor for the EasyPost client.
Expand All @@ -47,10 +47,18 @@ public Client(ClientConfiguration clientConfiguration)

_restClient = new RestClient(clientConfiguration.ApiBase);
_restClient.Timeout = ConnectTimeoutMilliseconds;
_restClient.UserAgent = UserAgent;

Assembly assembly = Assembly.GetExecutingAssembly();
FileVersionInfo info = FileVersionInfo.GetVersionInfo(assembly.Location);
_libraryVersion = info.FileVersion;
try
{
Assembly assembly = typeof(Client).Assembly;
FileVersionInfo info = FileVersionInfo.GetVersionInfo(assembly.Location);
_libraryVersion = info.FileVersion;
}
catch (Exception)
{
_libraryVersion = "Unknown";
}

string dotNetVersion = Environment.Version.ToString();
if (dotNetVersion == "4.0.30319.42000")
Expand All @@ -69,8 +77,12 @@ public Client(ClientConfiguration clientConfiguration)
/// Execute a request against the EasyPost API.
/// </summary>
/// <param name="request">EasyPost.Request object instance to execute.</param>
/// <returns>RestSharp.IRestResponse instance.</returns>
internal IRestResponse Execute(Request request) => _restClient.Execute(PrepareRequest(request));
/// <returns>Whether request was successful.</returns>
internal bool Execute(Request request)
{
IRestResponse response = _restClient.Execute(PrepareRequest(request));
return response.ResponseStatus == ResponseStatus.Completed || response.ResponseStatus == ResponseStatus.None;
}

/// <summary>
/// Execute a request against the EasyPost API.
Expand Down Expand Up @@ -120,7 +132,6 @@ private RestRequest PrepareRequest(Request request)
{
RestRequest restRequest = (RestRequest)request;
restRequest.Timeout = RequestTimeoutMilliseconds;
restRequest.AddHeader("user_agent", UserAgent);
restRequest.AddHeader("authorization", "Bearer " + _configuration.ApiKey);
restRequest.AddHeader("content_type", "application/json");

Expand Down
2 changes: 1 addition & 1 deletion EasyPost.NetFramework/Exception.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class HttpException : Exception
/// <param name="statusCode">Status code.</param>
/// <param name="code">Error code.</param>
/// <param name="message">Error message.</param>
/// <param name="errors">A list of EasyPost.Error instances.</param>
/// <param name="errors">An EasyPost.Error instances.</param>
public HttpException(int statusCode, string code, string message, List<Error> errors) : base(message)
{
StatusCode = statusCode;
Expand Down
15 changes: 12 additions & 3 deletions EasyPost.NetFramework/Request.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using Newtonsoft.Json;
using RestSharp;
using RestSharp.Extensions;

namespace EasyPost
{
Expand Down Expand Up @@ -53,7 +54,15 @@ public void AddQueryString(IDictionary<string, object> parameters)
/// </summary>
/// <param name="name">Name of segment.</param>
/// <param name="value">Value of segment.</param>
public void AddUrlSegment(string name, string value) => restRequest.AddUrlSegment(name, value);
public void AddUrlSegment(string name, string value)
{
if (!value.HasValue())
{
throw new ArgumentNullException(name);
}

restRequest.AddUrlSegment(name, value);
}

/// <summary>
/// Execute the request.
Expand All @@ -69,8 +78,8 @@ public void AddQueryString(IDictionary<string, object> parameters)
/// <summary>
/// Execute the request.
/// </summary>
/// <returns>An IRestResponse object instance.</returns>
public IRestResponse Execute()
/// <returns>Whether the request was successful or not.</returns>
public bool Execute()
{
Client client = ClientManager.Build();
return client.Execute(this);
Expand Down
Loading

0 comments on commit 8872686

Please sign in to comment.