Skip to content

Commit

Permalink
[fix] Invalid CarrierFields structure (#558)
Browse files Browse the repository at this point in the history
- Fix CarrierFields serialization structure
- Add unit test to confirm de/serialization works as expected
  • Loading branch information
nwithan8 committed Apr 12, 2024
1 parent bde13a4 commit a584bca
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Next Release

- Fix `CarrierFields` serialization bug causing carrier account operations to fail
- Fix accessibility for `CreateFedExSmartPost` parameter set

## v6.3.0 (2024-04-10)
Expand Down
94 changes: 94 additions & 0 deletions EasyPost.Tests/ServicesTests/CarrierAccountServiceTest.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using EasyPost.Exceptions.API;
using EasyPost.Http;
using EasyPost.Models.API;
using EasyPost.Tests._Utilities;
using EasyPost.Tests._Utilities.Attributes;
using EasyPost.Utilities.Internal.Attributes;
using Newtonsoft.Json.Linq;
using Xunit;

namespace EasyPost.Tests.ServicesTests
Expand Down Expand Up @@ -144,6 +147,97 @@ public async Task TestDelete()

#endregion

/// <summary>
/// Test that the CarrierAccount fields are correctly deserialized from the API response.
/// None of the demo carrier accounts used in the above tests have credentials or test credentials fields, so we need to use some mock data.
/// </summary>
[Fact]
[Testing.EdgeCase]
public async Task TestCarrierFieldsJsonDeserialization()
{
UseMockClient(new List<TestUtils.MockRequest>
{
new(
new TestUtils.MockRequestMatchRules(Method.Get, @"v2\/carrier_accounts$"),
new TestUtils.MockRequestResponseInfo(HttpStatusCode.OK, content: "[{\"id\":\"ca_123\",\"object\":\"CarrierAccount\",\"fields\":{\"credentials\":{\"account_number\":{\"visibility\":\"visible\",\"label\":\"DHL Account Number\",\"value\":\"123456\"},\"country\":{\"visibility\":\"visible\",\"label\":\"Account Country Code (2 Letter)\",\"value\":\"US\"},\"site_id\":{\"visibility\":\"visible\",\"label\":\"Site ID (Optional)\",\"value\": null },\"password\":{\"visibility\":\"password\",\"label\":\"Password (Optional)\",\"value\":\"\"},\"is_reseller\":{\"visibility\":\"checkbox\",\"label\":\"Reseller Account? (check if yes)\",\"value\":null}}}}]")
)
});

List<CarrierAccount> carrierAccounts = await Client.CarrierAccount.All();

Assert.NotEmpty(carrierAccounts);
Assert.Single(carrierAccounts);

CarrierAccount carrierAccount = carrierAccounts[0];
Assert.NotNull(carrierAccount.Fields);
Assert.NotNull(carrierAccount.Fields.Credentials);
Assert.NotNull(carrierAccount.Fields.Credentials["account_number"]);

CarrierField accountNumberField = carrierAccount.Fields.Credentials["account_number"];
Assert.Equal("visible", accountNumberField.Visibility);
Assert.Equal("DHL Account Number", accountNumberField.Label);
Assert.Equal("123456", accountNumberField.Value);
}

/// <summary>
/// Test that the CarrierAccount fields are correctly serialized to the API request.
/// </summary>
[Fact]
[Testing.EdgeCase]
public async Task TestCarrierFieldsJsonSerialization()
{
UseMockClient(new List<TestUtils.MockRequest>
{
new(
new TestUtils.MockRequestMatchRules(Method.Post, @"v2\/pickups"),
new TestUtils.MockRequestResponseInfo(HttpStatusCode.OK, content: "{}")
)
}
);

CarrierAccount carrierAccount = new()
{
Id = "ca_123",
Fields = new CarrierFields
{
Credentials = new Dictionary<string, CarrierField>
{
{
"account_number",
new CarrierField
{
Visibility = "visible",
Label = "DHL Account Number",
Value = "123456"
}
}
}
}
};

EasyPost.Parameters.Pickup.Create parameters = new()
{
Shipment = new Shipment(),
CarrierAccounts = new List<CarrierAccount> { carrierAccount }
};

// Confirm that the CarrierAccount fields are serialized correctly
Dictionary<string, object> json = parameters.ToDictionary();
Dictionary<string, object> pickupJson = json["pickup"] as Dictionary<string, object>;
List<object> carrierAccountsJson = pickupJson["carrier_accounts"] as List<object>;
Dictionary<string, object> carrierAccountJson = carrierAccountsJson[0] as Dictionary<string, object>;
JObject fieldsJson = carrierAccountJson["fields"] as JObject;
JObject credentialsJson = fieldsJson["credentials"] as JObject;
JObject accountNumberJson = credentialsJson["account_number"] as JObject;
JToken visibility = accountNumberJson["visibility"];
Assert.Equal("visible", visibility);

// Test serialization again via an actual API call attempt
// This will throw an exception if the CarrierAccount fields are not serialized correctly
Exception? possibleException = await Record.ExceptionAsync(async () => await Client.Pickup.Create(parameters));
Assert.Null(possibleException);
}

#endregion
}
}
7 changes: 6 additions & 1 deletion EasyPost/Models/API/CarrierAccount.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ public class CarrierAccount : EasyPostObject, Parameters.ICarrierAccountParamete
[JsonProperty("fields")]
public CarrierFields? Fields { get; set; }

/// <summary>
/// The logo for the associated carrier.
/// </summary>
[JsonProperty("logo")]
public string? Logo { get; set; }

/// <summary>
/// The name used when displaying a readable value for the type of the carrier account.
/// </summary>
Expand All @@ -69,7 +75,6 @@ public class CarrierAccount : EasyPostObject, Parameters.ICarrierAccountParamete
public string? Type { get; set; }

#endregion

}
}
#pragma warning disable CA1724 // Naming conflicts with Parameters.CarrierAccount
11 changes: 3 additions & 8 deletions EasyPost/Models/API/CarrierFields.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using EasyPost._base;
using Newtonsoft.Json;

Expand All @@ -14,7 +15,7 @@ public class CarrierFields : EasyPostObject
/// The credentials used in the production environment.
/// </summary>
[JsonProperty("credentials")]
public CarrierField? Credentials { get; set; }
public Dictionary<string, CarrierField>? Credentials { get; set; }

/// <summary>
/// The credentials used in the test environment.
Expand All @@ -23,7 +24,7 @@ public class CarrierFields : EasyPostObject
#pragma warning disable SA1515
// ReSharper disable once InconsistentNaming
#pragma warning restore SA1515
public CarrierField? TestCredentials { get; set; }
public Dictionary<string, CarrierField>? TestCredentials { get; set; }

/// <summary>
/// For USPS, this designates that no credentials are required.
Expand All @@ -47,12 +48,6 @@ public class CarrierField : EasyPostObject
{
#region JSON Properties

/// <summary>
/// The key of the field.
/// </summary>
[JsonProperty("key")]
public string? Key { get; set; }

/// <summary>
/// The visibility value is used to control form field types.
/// See <see cref="CarrierType"/> for more details.
Expand Down

0 comments on commit a584bca

Please sign in to comment.