Skip to content

Commit e5da261

Browse files
Fix: Handle NoContent and null response in DeserializeResponseAsync
1 parent d247fe9 commit e5da261

File tree

3 files changed

+159
-8
lines changed

3 files changed

+159
-8
lines changed

src/CheckoutSdk/ApiClient.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,9 @@ private async Task<TResult> DeserializeResponseAsync<TResult>(HttpResponseMessag
314314
private async Task<dynamic> DeserializeResponseAsync(HttpResponseMessage httpResponse, Type resultType)
315315
{
316316
dynamic deserializedObject;
317-
if (httpResponse.StatusCode == HttpStatusCode.NoContent || httpResponse.Content.Headers.ContentLength == 0)
317+
if (httpResponse.StatusCode == HttpStatusCode.NoContent ||
318+
httpResponse.Content == null ||
319+
(httpResponse.Content.Headers.ContentLength.HasValue && httpResponse.Content.Headers.ContentLength.Value == 0))
318320
{
319321
deserializedObject = Activator.CreateInstance(resultType);
320322
}
@@ -328,7 +330,10 @@ private async Task<dynamic> DeserializeResponseAsync(HttpResponseMessage httpRes
328330
deserializedObject = _serializer.Deserialize(json, resultType);
329331
}
330332

331-
await SetHttpMetadata(httpResponse, deserializedObject);
333+
if (deserializedObject != null)
334+
{
335+
await SetHttpMetadata(httpResponse, deserializedObject);
336+
}
332337

333338
return deserializedObject;
334339
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
using System;
2+
using System.Net;
3+
using System.Net.Http;
4+
using System.Text;
5+
using System.Threading;
6+
using System.Threading.Tasks;
7+
using Moq;
8+
using Moq.Protected;
9+
using Xunit;
10+
11+
namespace Checkout
12+
{
13+
public class ApiClientTests : UnitTestFixture, IDisposable
14+
{
15+
private readonly ApiClient _apiClient;
16+
private readonly Mock<HttpMessageHandler> _httpMessageHandlerMock;
17+
private readonly HttpClient _httpClient;
18+
19+
public ApiClientTests()
20+
{
21+
_httpMessageHandlerMock = new Mock<HttpMessageHandler>();
22+
_httpClient = new HttpClient(_httpMessageHandlerMock.Object);
23+
24+
var httpClientFactoryMock = new Mock<IHttpClientFactory>();
25+
httpClientFactoryMock
26+
.Setup(factory => factory.CreateClient())
27+
.Returns(_httpClient);
28+
29+
_apiClient = new ApiClient(httpClientFactoryMock.Object, new Uri("https://api.example.com"), false);
30+
}
31+
32+
[Fact]
33+
public async Task ShouldGetReturnDeserializedObject()
34+
{
35+
// Arrange
36+
var jsonResponse = "{\"message\":\"success\"}";
37+
var httpResponse = new HttpResponseMessage(HttpStatusCode.OK)
38+
{
39+
Content = new StringContent(jsonResponse, Encoding.UTF8, "application/json")
40+
};
41+
42+
_httpMessageHandlerMock
43+
.Protected()
44+
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(),
45+
ItExpr.IsAny<CancellationToken>())
46+
.ReturnsAsync(httpResponse);
47+
48+
var authorization = new SdkAuthorization(PlatformType.Default, ValidDefaultSk);
49+
50+
// Act
51+
var result = await _apiClient.Get<FakeResponse>("/test", authorization);
52+
53+
// Assert
54+
Assert.NotNull(result);
55+
Assert.IsType<FakeResponse>(result);
56+
Assert.Equal("success", result.Message);
57+
}
58+
59+
[Fact]
60+
public async Task ShouldPostReturnDeserializedObject()
61+
{
62+
// Arrange
63+
var jsonResponse = "{\"message\":\"created\"}";
64+
var httpResponse = new HttpResponseMessage(HttpStatusCode.Created)
65+
{
66+
Content = new StringContent(jsonResponse, Encoding.UTF8, "application/json")
67+
};
68+
69+
_httpMessageHandlerMock
70+
.Protected()
71+
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(),
72+
ItExpr.IsAny<CancellationToken>())
73+
.ReturnsAsync(httpResponse);
74+
75+
var authorization = new SdkAuthorization(PlatformType.Default, ValidDefaultSk);
76+
var requestData = new { name = "new item" };
77+
78+
// Act
79+
var result = await _apiClient.Post<FakeResponse>("/test", authorization, requestData);
80+
81+
// Assert
82+
Assert.NotNull(result);
83+
Assert.IsType<FakeResponse>(result);
84+
Assert.Equal("created", result.Message);
85+
}
86+
87+
[Fact]
88+
public async Task ShouldDeleteReturnDeserializedObject()
89+
{
90+
// Arrange
91+
var jsonResponse = "{\"message\":\"deleted\"}";
92+
var httpResponse = new HttpResponseMessage(HttpStatusCode.OK)
93+
{
94+
Content = new StringContent(jsonResponse, Encoding.UTF8, "application/json")
95+
};
96+
97+
_httpMessageHandlerMock
98+
.Protected()
99+
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(),
100+
ItExpr.IsAny<CancellationToken>())
101+
.ReturnsAsync(httpResponse);
102+
103+
var authorization = new SdkAuthorization(PlatformType.Default, ValidDefaultSk);
104+
105+
// Act
106+
var result = await _apiClient.Delete<FakeResponse>("/test", authorization);
107+
108+
// Assert
109+
Assert.NotNull(result);
110+
Assert.IsType<FakeResponse>(result);
111+
Assert.Equal("deleted", result.Message);
112+
}
113+
114+
[Fact]
115+
public async Task ShouldGetHandleNoContentResponse()
116+
{
117+
// Arrange
118+
var httpResponse = new HttpResponseMessage(HttpStatusCode.NoContent) { Content = null };
119+
120+
_httpMessageHandlerMock
121+
.Protected()
122+
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(),
123+
ItExpr.IsAny<CancellationToken>())
124+
.ReturnsAsync(httpResponse);
125+
126+
var authorization = new SdkAuthorization(PlatformType.Default, ValidDefaultSk);
127+
128+
// Act
129+
var result = await _apiClient.Get<FakeResponse>("/test", authorization);
130+
131+
// Assert
132+
Assert.NotNull(result);
133+
Assert.IsType<FakeResponse>(result);
134+
}
135+
136+
public void Dispose()
137+
{
138+
_httpClient.Dispose();
139+
}
140+
}
141+
142+
public class FakeResponse : HttpMetadata
143+
{
144+
public string Message { get; set; }
145+
}
146+
}

test/CheckoutSdkTest/UnitTestFixture.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ namespace Checkout
33
public abstract class UnitTestFixture
44
{
55
// Previous
6-
protected const string ValidPreviousSk = "sk_test_fde517a8-3f01-41ef-b4bd-4282384b0a64";
7-
protected const string ValidPreviousPk = "pk_test_fe70ff27-7c32-4ce1-ae90-5691a188ee7b";
8-
protected const string InvalidPreviousSk = "sk_test_asdsad3q4dq";
6+
protected static readonly string ValidPreviousPk = System.Environment.GetEnvironmentVariable("CHECKOUT_PREVIOUS_PUBLIC_KEY");
7+
protected static readonly string ValidPreviousSk = System.Environment.GetEnvironmentVariable("CHECKOUT_PREVIOUS_SECRET_KEY");
98
protected const string InvalidPreviousPk = "pk_test_q414dasds";
9+
protected const string InvalidPreviousSk = "sk_test_asdsad3q4dq";
1010

1111
// Default
12-
protected const string ValidDefaultSk = "sk_sbox_m73dzbpy7cf3gfd46xr4yj5xo4e";
13-
protected const string ValidDefaultPk = "pk_sbox_sderftvmkgf7hdnpwnbhw7r2uic";
14-
protected const string InvalidDefaultSk = "sk_sbox_m73dzbpy7c-f3gfd46xr4yj5xo4e";
12+
protected static readonly string ValidDefaultPk = System.Environment.GetEnvironmentVariable("CHECKOUT_DEFAULT_PUBLIC_KEY");
13+
protected static readonly string ValidDefaultSk = System.Environment.GetEnvironmentVariable("CHECKOUT_DEFAULT_SECRET_KEY");
1514
protected const string InvalidDefaultPk = "pk_sbox_pkh";
15+
protected const string InvalidDefaultSk = "sk_sbox_m73dzbpy7c-f3gfd46xr4yj5xo4e";
1616
}
1717
}

0 commit comments

Comments
 (0)