Skip to content

Commit ba48c90

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

File tree

3 files changed

+167
-8
lines changed

3 files changed

+167
-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: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
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+
httpResponse.Dispose();
59+
}
60+
61+
[Fact]
62+
public async Task ShouldPostReturnDeserializedObject()
63+
{
64+
// Arrange
65+
var jsonResponse = "{\"message\":\"created\"}";
66+
var httpResponse = new HttpResponseMessage(HttpStatusCode.Created)
67+
{
68+
Content = new StringContent(jsonResponse, Encoding.UTF8, "application/json")
69+
};
70+
71+
_httpMessageHandlerMock
72+
.Protected()
73+
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(),
74+
ItExpr.IsAny<CancellationToken>())
75+
.ReturnsAsync(httpResponse);
76+
77+
var authorization = new SdkAuthorization(PlatformType.Default, ValidDefaultSk);
78+
var requestData = new { name = "new item" };
79+
80+
// Act
81+
var result = await _apiClient.Post<FakeResponse>("/test", authorization, requestData);
82+
83+
// Assert
84+
Assert.NotNull(result);
85+
Assert.IsType<FakeResponse>(result);
86+
Assert.Equal("created", result.Message);
87+
88+
httpResponse.Dispose();
89+
}
90+
91+
[Fact]
92+
public async Task ShouldDeleteReturnDeserializedObject()
93+
{
94+
// Arrange
95+
var jsonResponse = "{\"message\":\"deleted\"}";
96+
var httpResponse = new HttpResponseMessage(HttpStatusCode.OK)
97+
{
98+
Content = new StringContent(jsonResponse, Encoding.UTF8, "application/json")
99+
};
100+
101+
_httpMessageHandlerMock
102+
.Protected()
103+
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(),
104+
ItExpr.IsAny<CancellationToken>())
105+
.ReturnsAsync(httpResponse);
106+
107+
var authorization = new SdkAuthorization(PlatformType.Default, ValidDefaultSk);
108+
109+
// Act
110+
var result = await _apiClient.Delete<FakeResponse>("/test", authorization);
111+
112+
// Assert
113+
Assert.NotNull(result);
114+
Assert.IsType<FakeResponse>(result);
115+
Assert.Equal("deleted", result.Message);
116+
117+
httpResponse.Dispose();
118+
}
119+
120+
[Fact]
121+
public async Task ShouldGetHandleNoContentResponse()
122+
{
123+
// Arrange
124+
var httpResponse = new HttpResponseMessage(HttpStatusCode.NoContent) { Content = null };
125+
126+
_httpMessageHandlerMock
127+
.Protected()
128+
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(),
129+
ItExpr.IsAny<CancellationToken>())
130+
.ReturnsAsync(httpResponse);
131+
132+
var authorization = new SdkAuthorization(PlatformType.Default, ValidDefaultSk);
133+
134+
// Act
135+
var result = await _apiClient.Get<FakeResponse>("/test", authorization);
136+
137+
// Assert
138+
Assert.NotNull(result);
139+
Assert.IsType<FakeResponse>(result);
140+
141+
httpResponse.Dispose();
142+
}
143+
144+
public void Dispose()
145+
{
146+
_httpClient.Dispose();
147+
}
148+
}
149+
150+
public class FakeResponse : HttpMetadata
151+
{
152+
public string Message { get; set; }
153+
}
154+
}

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)