Skip to content

Commit 03046d3

Browse files
committed
fix(RN): correctly deserialize request/response entities from ReactNative
1 parent a4862e4 commit 03046d3

6 files changed

Lines changed: 307 additions & 0 deletions

File tree

bugsnag-plugin-react-native/detekt-baseline.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
<SmellBaseline>
33
<ManuallySuppressedIssues/>
44
<CurrentIssues>
5+
<ID>LongMethod:EventDeserializer.kt$EventDeserializer$@Suppress("UNCHECKED_CAST") override fun deserialize(map: MutableMap&lt;String, Any?>): Event</ID>
56
<ID>TooManyFunctions:BugsnagReactNativePlugin.kt$BugsnagReactNativePlugin : Plugin</ID>
67
</CurrentIssues>
78
</SmellBaseline>

bugsnag-plugin-react-native/src/main/java/com/bugsnag/android/EventDeserializer.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ internal class EventDeserializer(
1818
)
1919
private val threadDeserializer = ThreadDeserializer(stackframeDeserializer, client.getLogger())
2020
private val breadcrumbDeserializer = BreadcrumbDeserializer(client.getLogger())
21+
private val requestDeserializer = RequestDeserializer()
22+
private val responseDeserializer = ResponseDeserializer()
2123

2224
@Suppress("UNCHECKED_CAST")
2325
override fun deserialize(map: MutableMap<String, Any?>): Event {
@@ -77,6 +79,16 @@ internal class EventDeserializer(
7779
}
7880
}
7981

82+
val request = map["request"] as? Map<String, Any?>
83+
if (request != null) {
84+
event.request = requestDeserializer.deserialize(request)
85+
}
86+
87+
val response = map["response"] as? Map<String, Any?>
88+
if (response != null) {
89+
event.response = responseDeserializer.deserialize(response)
90+
}
91+
8092
// threads
8193
val threads = map["threads"] as List<Map<String, Any?>>
8294
event.threads.clear()
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.bugsnag.android;
2+
3+
import java.util.Map;
4+
5+
class RequestDeserializer implements MapDeserializer<Request> {
6+
@Override
7+
public Request deserialize(Map<String, Object> map) {
8+
String httpVersion = MapUtils.getOrNull(map, "httpVersion");
9+
String httpMethod = MapUtils.getOrNull(map, "httpMethod");
10+
String url = MapUtils.getOrNull(map, "url");
11+
12+
Request request = new Request(httpVersion, httpMethod, url);
13+
14+
// Deserialize body
15+
String body = MapUtils.getOrNull(map, "body");
16+
if (body != null) {
17+
request.setBody(body);
18+
}
19+
20+
// Deserialize bodyLength
21+
Long bodyLength = MapUtils.getLong(map, "bodyLength");
22+
if (bodyLength != null) {
23+
request.setBodyLength(bodyLength);
24+
}
25+
26+
// Deserialize headers
27+
Map<String, String> headers = MapUtils.getOrNull(map, "headers");
28+
if (headers != null) {
29+
for (Map.Entry<String, String> entry : headers.entrySet()) {
30+
request.addHeader(entry.getKey(), entry.getValue());
31+
}
32+
}
33+
34+
// Deserialize query parameters
35+
Map<String, String> params = MapUtils.getOrNull(map, "params");
36+
if (params != null) {
37+
for (Map.Entry<String, String> entry : params.entrySet()) {
38+
request.addQueryParameter(entry.getKey(), entry.getValue());
39+
}
40+
}
41+
42+
return request;
43+
}
44+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.bugsnag.android;
2+
3+
import java.util.Map;
4+
5+
class ResponseDeserializer implements MapDeserializer<Response> {
6+
@Override
7+
public Response deserialize(Map<String, Object> map) {
8+
Integer statusCode = MapUtils.getInt(map, "statusCode");
9+
if (statusCode == null) {
10+
statusCode = 0;
11+
}
12+
13+
Response response = new Response(statusCode);
14+
15+
// Deserialize body
16+
String body = MapUtils.getOrNull(map, "body");
17+
if (body != null) {
18+
response.setBody(body);
19+
}
20+
21+
// Deserialize bodyLength
22+
Long bodyLength = MapUtils.getLong(map, "bodyLength");
23+
if (bodyLength != null) {
24+
response.setBodyLength(bodyLength);
25+
}
26+
27+
// Deserialize headers
28+
Map<String, String> headers = MapUtils.getOrNull(map, "headers");
29+
if (headers != null) {
30+
for (Map.Entry<String, String> entry : headers.entrySet()) {
31+
response.addHeader(entry.getKey(), entry.getValue());
32+
}
33+
}
34+
35+
return response;
36+
}
37+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package com.bugsnag.android;
2+
3+
import static org.junit.Assert.assertEquals;
4+
import static org.junit.Assert.assertNotNull;
5+
import static org.junit.Assert.assertNull;
6+
7+
import org.junit.Before;
8+
import org.junit.Test;
9+
10+
import java.util.HashMap;
11+
import java.util.Map;
12+
13+
public class RequestDeserializerTest {
14+
15+
private Map<String, Object> map;
16+
17+
/**
18+
* Generates a map for verifying the deserializer
19+
*/
20+
@Before
21+
public void setup() {
22+
map = new HashMap<>();
23+
map.put("httpVersion", "HTTP/1.1");
24+
map.put("httpMethod", "GET");
25+
map.put("url", "https://example.com/api/users");
26+
map.put("body", "request body");
27+
map.put("bodyLength", 12L);
28+
29+
Map<String, String> headers = new HashMap<>();
30+
headers.put("Content-Type", "application/json");
31+
headers.put("Authorization", "Bearer token");
32+
map.put("headers", headers);
33+
34+
Map<String, String> params = new HashMap<>();
35+
params.put("id", "123");
36+
params.put("name", "test");
37+
map.put("params", params);
38+
}
39+
40+
@Test
41+
public void deserialize() {
42+
Request request = new RequestDeserializer().deserialize(map);
43+
44+
assertEquals("HTTP/1.1", request.getHttpVersion());
45+
assertEquals("GET", request.getHttpMethod());
46+
assertEquals("https://example.com/api/users", request.getUrl());
47+
assertEquals("request body", request.getBody());
48+
assertEquals(12L, request.getBodyLength());
49+
50+
// Check headers
51+
assertEquals("application/json", request.getHeader("Content-Type"));
52+
assertEquals("Bearer token", request.getHeader("Authorization"));
53+
54+
// Check query params
55+
assertEquals("123", request.getQueryParameter("id"));
56+
assertEquals("test", request.getQueryParameter("name"));
57+
}
58+
59+
@Test
60+
public void deserializeWithNullValues() {
61+
Map<String, Object> nullMap = new HashMap<>();
62+
nullMap.put("httpVersion", null);
63+
nullMap.put("httpMethod", null);
64+
nullMap.put("url", null);
65+
66+
Request request = new RequestDeserializer().deserialize(nullMap);
67+
68+
assertNull(request.getHttpVersion());
69+
assertNull(request.getHttpMethod());
70+
assertEquals("", request.getUrl()); // setUrl with null sets empty string
71+
}
72+
73+
@Test
74+
public void deserializeWithMissingOptionalFields() {
75+
Map<String, Object> minimalMap = new HashMap<>();
76+
minimalMap.put("httpMethod", "POST");
77+
minimalMap.put("url", "https://example.com/api");
78+
79+
Request request = new RequestDeserializer().deserialize(minimalMap);
80+
81+
assertNull(request.getHttpVersion());
82+
assertEquals("POST", request.getHttpMethod());
83+
assertEquals("https://example.com/api", request.getUrl());
84+
assertNull(request.getBody());
85+
assertEquals(-1L, request.getBodyLength()); // Default value
86+
}
87+
88+
@Test
89+
public void deserializeWithEmptyMaps() {
90+
Map<String, Object> mapWithEmptyCollections = new HashMap<>();
91+
mapWithEmptyCollections.put("httpMethod", "GET");
92+
mapWithEmptyCollections.put("url", "https://example.com");
93+
mapWithEmptyCollections.put("headers", new HashMap<String, String>());
94+
mapWithEmptyCollections.put("params", new HashMap<String, String>());
95+
96+
Request request = new RequestDeserializer().deserialize(mapWithEmptyCollections);
97+
98+
assertNotNull(request);
99+
assertEquals("GET", request.getHttpMethod());
100+
assertEquals(0, request.getHeaderNames().size());
101+
assertEquals(0, request.getQueryParameterNames().size());
102+
}
103+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package com.bugsnag.android;
2+
3+
import static org.junit.Assert.assertEquals;
4+
import static org.junit.Assert.assertNotNull;
5+
import static org.junit.Assert.assertNull;
6+
7+
import org.junit.Before;
8+
import org.junit.Test;
9+
10+
import java.util.HashMap;
11+
import java.util.Map;
12+
13+
public class ResponseDeserializerTest {
14+
15+
private Map<String, Object> map;
16+
17+
/**
18+
* Generates a map for verifying the deserializer
19+
*/
20+
@Before
21+
public void setup() {
22+
map = new HashMap<>();
23+
map.put("statusCode", 200);
24+
map.put("body", "response body");
25+
map.put("bodyLength", 13L);
26+
27+
Map<String, String> headers = new HashMap<>();
28+
headers.put("Content-Type", "application/json");
29+
headers.put("Cache-Control", "no-cache");
30+
map.put("headers", headers);
31+
}
32+
33+
@Test
34+
public void deserialize() {
35+
Response response = new ResponseDeserializer().deserialize(map);
36+
37+
assertEquals(200, response.getStatusCode());
38+
assertEquals("response body", response.getBody());
39+
assertEquals(13L, response.getBodyLength());
40+
41+
// Check headers
42+
assertEquals("application/json", response.getHeader("Content-Type"));
43+
assertEquals("no-cache", response.getHeader("Cache-Control"));
44+
}
45+
46+
@Test
47+
public void deserializeWithNullStatusCode() {
48+
Map<String, Object> nullMap = new HashMap<>();
49+
nullMap.put("statusCode", null);
50+
nullMap.put("body", "test body");
51+
52+
Response response = new ResponseDeserializer().deserialize(nullMap);
53+
54+
assertEquals(0, response.getStatusCode()); // Default value when null
55+
assertEquals("test body", response.getBody());
56+
}
57+
58+
@Test
59+
public void deserializeWithMissingOptionalFields() {
60+
Map<String, Object> minimalMap = new HashMap<>();
61+
minimalMap.put("statusCode", 404);
62+
63+
Response response = new ResponseDeserializer().deserialize(minimalMap);
64+
65+
assertEquals(404, response.getStatusCode());
66+
assertNull(response.getBody());
67+
assertEquals(-1L, response.getBodyLength()); // Default value
68+
}
69+
70+
@Test
71+
public void deserializeWithEmptyHeaders() {
72+
Map<String, Object> mapWithEmptyHeaders = new HashMap<>();
73+
mapWithEmptyHeaders.put("statusCode", 500);
74+
mapWithEmptyHeaders.put("headers", new HashMap<String, String>());
75+
76+
Response response = new ResponseDeserializer().deserialize(mapWithEmptyHeaders);
77+
78+
assertNotNull(response);
79+
assertEquals(500, response.getStatusCode());
80+
assertEquals(0, response.getHeaderNames().size());
81+
}
82+
83+
@Test
84+
public void deserializeWithVariousStatusCodes() {
85+
Map<String, Object> successMap = new HashMap<>();
86+
successMap.put("statusCode", 201);
87+
assertEquals(201, new ResponseDeserializer().deserialize(successMap).getStatusCode());
88+
89+
Map<String, Object> redirectMap = new HashMap<>();
90+
redirectMap.put("statusCode", 302);
91+
assertEquals(302, new ResponseDeserializer().deserialize(redirectMap).getStatusCode());
92+
93+
Map<String, Object> errorMap = new HashMap<>();
94+
errorMap.put("statusCode", 503);
95+
assertEquals(503, new ResponseDeserializer().deserialize(errorMap).getStatusCode());
96+
}
97+
98+
@Test
99+
public void deserializeWithBodyLength() {
100+
Map<String, Object> mapWithBodyLength = new HashMap<>();
101+
mapWithBodyLength.put("statusCode", 200);
102+
mapWithBodyLength.put("body", "Hello World");
103+
mapWithBodyLength.put("bodyLength", 11L);
104+
105+
Response response = new ResponseDeserializer().deserialize(mapWithBodyLength);
106+
107+
assertEquals("Hello World", response.getBody());
108+
assertEquals(11L, response.getBodyLength());
109+
}
110+
}

0 commit comments

Comments
 (0)