Use getReactApplicationContextIfActiveOrWarn in modules that access JS or Native modules through ReactApplicationContext

Summary:
In D18032458 we introduce `getReactApplicationContextIfActiveOrWarn`. In this diff, modules that access a JS or Native module through ReactApplicationContext need to check if the CatalystInstance is still alive before continuing.

Changelog: [Internal]

Reviewed By: furdei

Differential Revision: D18032788

fbshipit-source-id: 5152783afd0b93b8ce0970fe4a509ea71396a54a
This commit is contained in:
Joshua Gross
2019-10-21 15:57:31 -07:00
committed by Facebook Github Bot
parent b12a29cfcb
commit 2ea33044bd
14 changed files with 291 additions and 300 deletions
@@ -16,6 +16,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.CatalystInstance;
import com.facebook.react.bridge.JavaOnlyArray;
import com.facebook.react.bridge.JavaOnlyMap;
import com.facebook.react.bridge.ReactApplicationContext;
@@ -36,6 +37,7 @@ import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okio.Buffer;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -66,13 +68,17 @@ import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "androidx.*", "android.*"})
public class NetworkingModuleTest {
private NetworkingModule mNetworkingModule;
private OkHttpClient mHttpClient;
private RCTDeviceEventEmitter mEmitter;
@Rule public PowerMockRule rule = new PowerMockRule();
@Test
public void testGetWithoutHeaders() throws Exception {
OkHttpClient httpClient = mock(OkHttpClient.class);
when(httpClient.newCall(any(Request.class)))
@Before
public void prepareModules() {
mHttpClient = mock(OkHttpClient.class);
when(mHttpClient.cookieJar()).thenReturn(mock(CookieJarContainer.class));
when(mHttpClient.newCall(any(Request.class)))
.thenAnswer(
new Answer<Object>() {
@Override
@@ -82,12 +88,22 @@ public class NetworkingModuleTest {
}
});
OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class);
when(clientBuilder.build()).thenReturn(httpClient);
when(httpClient.newBuilder()).thenReturn(clientBuilder);
NetworkingModule networkingModule =
new NetworkingModule(mock(ReactApplicationContext.class), "", httpClient);
when(clientBuilder.build()).thenReturn(mHttpClient);
when(mHttpClient.newBuilder()).thenReturn(clientBuilder);
networkingModule.sendRequest(
mEmitter = mock(RCTDeviceEventEmitter.class);
CatalystInstance reactInstance = mock(CatalystInstance.class);
ReactApplicationContext reactContext = mock(ReactApplicationContext.class);
when(reactContext.getCatalystInstance()).thenReturn(reactInstance);
when(reactContext.hasActiveCatalystInstance()).thenReturn(true);
when(reactContext.getJSModule(any(Class.class))).thenReturn(mEmitter);
mNetworkingModule = new NetworkingModule(reactContext, "", mHttpClient);
}
@Test
public void testGetWithoutHeaders() throws Exception {
mNetworkingModule.sendRequest(
"GET",
"http://somedomain/foo",
/* requestId */ 0,
@@ -99,7 +115,7 @@ public class NetworkingModuleTest {
/* withCredentials */ false);
ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
verify(httpClient).newCall(argumentCaptor.capture());
verify(mHttpClient).newCall(argumentCaptor.capture());
assertThat(argumentCaptor.getValue().url().toString()).isEqualTo("http://somedomain/foo");
// We set the User-Agent header by default
assertThat(argumentCaptor.getValue().headers().size()).isEqualTo(1);
@@ -108,21 +124,11 @@ public class NetworkingModuleTest {
@Test
public void testFailGetWithInvalidHeadersStruct() throws Exception {
RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class);
ReactApplicationContext context = mock(ReactApplicationContext.class);
when(context.getJSModule(any(Class.class))).thenReturn(emitter);
OkHttpClient httpClient = mock(OkHttpClient.class);
OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class);
when(clientBuilder.build()).thenReturn(httpClient);
when(httpClient.newBuilder()).thenReturn(clientBuilder);
NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient);
List<JavaOnlyArray> invalidHeaders = Arrays.asList(JavaOnlyArray.of("foo"));
mockEvents();
networkingModule.sendRequest(
mNetworkingModule.sendRequest(
"GET",
"http://somedoman/foo",
/* requestId */ 0,
@@ -133,27 +139,17 @@ public class NetworkingModuleTest {
/* timeout */ 0,
/* withCredentials */ false);
verifyErrorEmit(emitter, 0);
verifyErrorEmit(mEmitter, 0);
}
@Test
public void testFailPostWithoutContentType() throws Exception {
RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class);
ReactApplicationContext context = mock(ReactApplicationContext.class);
when(context.getJSModule(any(Class.class))).thenReturn(emitter);
OkHttpClient httpClient = mock(OkHttpClient.class);
OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class);
when(clientBuilder.build()).thenReturn(httpClient);
when(httpClient.newBuilder()).thenReturn(clientBuilder);
NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient);
JavaOnlyMap body = new JavaOnlyMap();
body.putString("string", "This is request body");
mockEvents();
networkingModule.sendRequest(
mNetworkingModule.sendRequest(
"POST",
"http://somedomain/bar",
0,
@@ -164,24 +160,14 @@ public class NetworkingModuleTest {
/* timeout */ 0,
/* withCredentials */ false);
verifyErrorEmit(emitter, 0);
verifyErrorEmit(mEmitter, 0);
}
@Test
public void testFailInvalidUrl() throws Exception {
RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class);
ReactApplicationContext context = mock(ReactApplicationContext.class);
when(context.getJSModule(any(Class.class))).thenReturn(emitter);
OkHttpClient httpClient = mock(OkHttpClient.class);
OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class);
when(clientBuilder.build()).thenReturn(httpClient);
when(httpClient.newBuilder()).thenReturn(clientBuilder);
NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient);
mockEvents();
networkingModule.sendRequest(
mNetworkingModule.sendRequest(
"GET",
"aaa",
/* requestId */ 0,
@@ -192,7 +178,7 @@ public class NetworkingModuleTest {
/* timeout */ 0,
/* withCredentials */ false);
verifyErrorEmit(emitter, 0);
verifyErrorEmit(mEmitter, 0);
}
private static void verifyErrorEmit(RCTDeviceEventEmitter emitter, int requestId) {
@@ -227,31 +213,12 @@ public class NetworkingModuleTest {
@Test
public void testSuccessfulPostRequest() throws Exception {
RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class);
ReactApplicationContext context = mock(ReactApplicationContext.class);
when(context.getJSModule(any(Class.class))).thenReturn(emitter);
OkHttpClient httpClient = mock(OkHttpClient.class);
when(httpClient.newCall(any(Request.class)))
.thenAnswer(
new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Call callMock = mock(Call.class);
return callMock;
}
});
OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class);
when(clientBuilder.build()).thenReturn(httpClient);
when(httpClient.newBuilder()).thenReturn(clientBuilder);
NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient);
JavaOnlyMap body = new JavaOnlyMap();
body.putString("string", "This is request body");
mockEvents();
networkingModule.sendRequest(
mNetworkingModule.sendRequest(
"POST",
"http://somedomain/bar",
0,
@@ -263,7 +230,7 @@ public class NetworkingModuleTest {
/* withCredentials */ false);
ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
verify(httpClient).newCall(argumentCaptor.capture());
verify(mHttpClient).newCall(argumentCaptor.capture());
assertThat(argumentCaptor.getValue().url().toString()).isEqualTo("http://somedomain/bar");
assertThat(argumentCaptor.getValue().headers().size()).isEqualTo(2);
assertThat(argumentCaptor.getValue().method()).isEqualTo("POST");
@@ -276,28 +243,12 @@ public class NetworkingModuleTest {
@Test
public void testHeaders() throws Exception {
OkHttpClient httpClient = mock(OkHttpClient.class);
when(httpClient.newCall(any(Request.class)))
.thenAnswer(
new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Call callMock = mock(Call.class);
return callMock;
}
});
OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class);
when(clientBuilder.build()).thenReturn(httpClient);
when(httpClient.newBuilder()).thenReturn(clientBuilder);
NetworkingModule networkingModule =
new NetworkingModule(mock(ReactApplicationContext.class), "", httpClient);
List<JavaOnlyArray> headers =
Arrays.asList(
JavaOnlyArray.of("Accept", "text/plain"),
JavaOnlyArray.of("User-Agent", "React test agent/1.0"));
networkingModule.sendRequest(
mNetworkingModule.sendRequest(
"GET",
"http://someurl/baz",
0,
@@ -308,7 +259,7 @@ public class NetworkingModuleTest {
/* timeout */ 0,
/* withCredentials */ false);
ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
verify(httpClient).newCall(argumentCaptor.capture());
verify(mHttpClient).newCall(argumentCaptor.capture());
Headers requestHeaders = argumentCaptor.getValue().headers();
assertThat(requestHeaders.size()).isEqualTo(2);
assertThat(requestHeaders.get("Accept")).isEqualTo("text/plain");
@@ -317,26 +268,11 @@ public class NetworkingModuleTest {
@Test
public void testPostJsonContentTypeHeader() throws Exception {
OkHttpClient httpClient = mock(OkHttpClient.class);
when(httpClient.newCall(any(Request.class)))
.thenAnswer(
new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Call callMock = mock(Call.class);
return callMock;
}
});
OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class);
when(clientBuilder.build()).thenReturn(httpClient);
when(httpClient.newBuilder()).thenReturn(clientBuilder);
NetworkingModule networkingModule =
new NetworkingModule(mock(ReactApplicationContext.class), "", httpClient);
JavaOnlyMap body = new JavaOnlyMap();
body.putString("string", "{ \"key\": \"value\" }");
networkingModule.sendRequest(
mNetworkingModule.sendRequest(
"POST",
"http://somedomain/bar",
0,
@@ -348,7 +284,7 @@ public class NetworkingModuleTest {
/* withCredentials */ false);
ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
verify(httpClient).newCall(argumentCaptor.capture());
verify(mHttpClient).newCall(argumentCaptor.capture());
// Verify okhttp does not append "charset=utf-8"
assertThat(argumentCaptor.getValue().body().contentType().toString())
@@ -357,31 +293,12 @@ public class NetworkingModuleTest {
@Test
public void testRespectsExistingCharacterSet() throws Exception {
RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class);
ReactApplicationContext context = mock(ReactApplicationContext.class);
when(context.getJSModule(any(Class.class))).thenReturn(emitter);
OkHttpClient httpClient = mock(OkHttpClient.class);
when(httpClient.newCall(any(Request.class)))
.thenAnswer(
new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Call callMock = mock(Call.class);
return callMock;
}
});
OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class);
when(clientBuilder.build()).thenReturn(httpClient);
when(httpClient.newBuilder()).thenReturn(clientBuilder);
NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient);
JavaOnlyMap body = new JavaOnlyMap();
body.putString("string", "Friðjónsson");
mockEvents();
networkingModule.sendRequest(
mNetworkingModule.sendRequest(
"POST",
"http://somedomain/bar",
0,
@@ -393,7 +310,7 @@ public class NetworkingModuleTest {
/* withCredentials */ false);
ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
verify(httpClient).newCall(argumentCaptor.capture());
verify(mHttpClient).newCall(argumentCaptor.capture());
Buffer contentBuffer = new Buffer();
argumentCaptor.getValue().body().writeTo(contentBuffer);
@@ -402,31 +319,12 @@ public class NetworkingModuleTest {
@Test
public void testGracefullyRecoversFromInvalidContentType() throws Exception {
RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class);
ReactApplicationContext context = mock(ReactApplicationContext.class);
when(context.getJSModule(any(Class.class))).thenReturn(emitter);
OkHttpClient httpClient = mock(OkHttpClient.class);
when(httpClient.newCall(any(Request.class)))
.thenAnswer(
new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Call callMock = mock(Call.class);
return callMock;
}
});
OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class);
when(clientBuilder.build()).thenReturn(httpClient);
when(httpClient.newBuilder()).thenReturn(clientBuilder);
NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient);
JavaOnlyMap body = new JavaOnlyMap();
body.putString("string", "test");
mockEvents();
networkingModule.sendRequest(
mNetworkingModule.sendRequest(
"POST",
"http://somedomain/bar",
0,
@@ -438,7 +336,7 @@ public class NetworkingModuleTest {
/* withCredentials */ false);
ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
verify(httpClient).newCall(argumentCaptor.capture());
verify(mHttpClient).newCall(argumentCaptor.capture());
Buffer contentBuffer = new Buffer();
argumentCaptor.getValue().body().writeTo(contentBuffer);
@@ -467,22 +365,7 @@ public class NetworkingModuleTest {
formData.pushMap(bodyPart);
body.putArray("formData", formData);
OkHttpClient httpClient = mock(OkHttpClient.class);
when(httpClient.newCall(any(Request.class)))
.thenAnswer(
new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Call callMock = mock(Call.class);
return callMock;
}
});
OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class);
when(clientBuilder.build()).thenReturn(httpClient);
when(httpClient.newBuilder()).thenReturn(clientBuilder);
NetworkingModule networkingModule =
new NetworkingModule(mock(ReactApplicationContext.class), "", httpClient);
networkingModule.sendRequest(
mNetworkingModule.sendRequest(
"POST",
"http://someurl/uploadFoo",
0,
@@ -495,7 +378,7 @@ public class NetworkingModuleTest {
// verify url, method, headers
ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
verify(httpClient).newCall(argumentCaptor.capture());
verify(mHttpClient).newCall(argumentCaptor.capture());
assertThat(argumentCaptor.getValue().url().toString()).isEqualTo("http://someurl/uploadFoo");
assertThat(argumentCaptor.getValue().method()).isEqualTo("POST");
assertThat(argumentCaptor.getValue().body().contentType().type())
@@ -532,22 +415,7 @@ public class NetworkingModuleTest {
formData.pushMap(bodyPart);
body.putArray("formData", formData);
OkHttpClient httpClient = mock(OkHttpClient.class);
when(httpClient.newCall(any(Request.class)))
.thenAnswer(
new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Call callMock = mock(Call.class);
return callMock;
}
});
OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class);
when(clientBuilder.build()).thenReturn(httpClient);
when(httpClient.newBuilder()).thenReturn(clientBuilder);
NetworkingModule networkingModule =
new NetworkingModule(mock(ReactApplicationContext.class), "", httpClient);
networkingModule.sendRequest(
mNetworkingModule.sendRequest(
"POST",
"http://someurl/uploadFoo",
0,
@@ -560,7 +428,7 @@ public class NetworkingModuleTest {
// verify url, method, headers
ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
verify(httpClient).newCall(argumentCaptor.capture());
verify(mHttpClient).newCall(argumentCaptor.capture());
assertThat(argumentCaptor.getValue().url().toString()).isEqualTo("http://someurl/uploadFoo");
assertThat(argumentCaptor.getValue().method()).isEqualTo("POST");
assertThat(argumentCaptor.getValue().body().contentType().type())
@@ -638,23 +506,7 @@ public class NetworkingModuleTest {
JavaOnlyArray.of("content-disposition", "filename=photo.jpg"))));
formData.pushMap(imageBodyPart);
OkHttpClient httpClient = mock(OkHttpClient.class);
when(httpClient.newCall(any(Request.class)))
.thenAnswer(
new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Call callMock = mock(Call.class);
return callMock;
}
});
OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class);
when(clientBuilder.build()).thenReturn(httpClient);
when(httpClient.newBuilder()).thenReturn(clientBuilder);
NetworkingModule networkingModule =
new NetworkingModule(mock(ReactApplicationContext.class), "", httpClient);
networkingModule.sendRequest(
mNetworkingModule.sendRequest(
"POST",
"http://someurl/uploadFoo",
0,
@@ -695,15 +547,13 @@ public class NetworkingModuleTest {
@Test
public void testCancelAllCallsOnCatalystInstanceDestroy() throws Exception {
PowerMockito.mockStatic(OkHttpCallUtil.class);
OkHttpClient httpClient = mock(OkHttpClient.class);
final int requests = 3;
final Call[] calls = new Call[requests];
for (int idx = 0; idx < requests; idx++) {
calls[idx] = mock(Call.class);
}
when(httpClient.cookieJar()).thenReturn(mock(CookieJarContainer.class));
when(httpClient.newCall(any(Request.class)))
when(mHttpClient.newCall(any(Request.class)))
.thenAnswer(
new Answer<Object>() {
@Override
@@ -712,15 +562,10 @@ public class NetworkingModuleTest {
return calls[(Integer) request.tag() - 1];
}
});
OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class);
when(clientBuilder.build()).thenReturn(httpClient);
when(httpClient.newBuilder()).thenReturn(clientBuilder);
NetworkingModule networkingModule =
new NetworkingModule(mock(ReactApplicationContext.class), "", httpClient);
networkingModule.initialize();
mNetworkingModule.initialize();
for (int idx = 0; idx < requests; idx++) {
networkingModule.sendRequest(
mNetworkingModule.sendRequest(
"GET",
"http://somedomain/foo",
idx + 1,
@@ -731,9 +576,9 @@ public class NetworkingModuleTest {
/* timeout */ 0,
/* withCredentials */ false);
}
verify(httpClient, times(3)).newCall(any(Request.class));
verify(mHttpClient, times(3)).newCall(any(Request.class));
networkingModule.onCatalystInstanceDestroy();
mNetworkingModule.onCatalystInstanceDestroy();
PowerMockito.verifyStatic(times(3));
ArgumentCaptor<OkHttpClient> clientArguments = ArgumentCaptor.forClass(OkHttpClient.class);
ArgumentCaptor<Integer> requestIdArguments = ArgumentCaptor.forClass(Integer.class);
@@ -748,15 +593,13 @@ public class NetworkingModuleTest {
@Test
public void testCancelSomeCallsOnCatalystInstanceDestroy() throws Exception {
PowerMockito.mockStatic(OkHttpCallUtil.class);
OkHttpClient httpClient = mock(OkHttpClient.class);
final int requests = 3;
final Call[] calls = new Call[requests];
for (int idx = 0; idx < requests; idx++) {
calls[idx] = mock(Call.class);
}
when(httpClient.cookieJar()).thenReturn(mock(CookieJarContainer.class));
when(httpClient.newCall(any(Request.class)))
when(mHttpClient.newCall(any(Request.class)))
.thenAnswer(
new Answer<Object>() {
@Override
@@ -765,14 +608,9 @@ public class NetworkingModuleTest {
return calls[(Integer) request.tag() - 1];
}
});
OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class);
when(clientBuilder.build()).thenReturn(httpClient);
when(httpClient.newBuilder()).thenReturn(clientBuilder);
NetworkingModule networkingModule =
new NetworkingModule(mock(ReactApplicationContext.class), "", httpClient);
for (int idx = 0; idx < requests; idx++) {
networkingModule.sendRequest(
mNetworkingModule.sendRequest(
"GET",
"http://somedomain/foo",
idx + 1,
@@ -783,9 +621,9 @@ public class NetworkingModuleTest {
/* timeout */ 0,
/* withCredentials */ false);
}
verify(httpClient, times(3)).newCall(any(Request.class));
verify(mHttpClient, times(3)).newCall(any(Request.class));
networkingModule.abortRequest(requests);
mNetworkingModule.abortRequest(requests);
PowerMockito.verifyStatic(times(1));
ArgumentCaptor<OkHttpClient> clientArguments = ArgumentCaptor.forClass(OkHttpClient.class);
ArgumentCaptor<Integer> requestIdArguments = ArgumentCaptor.forClass(Integer.class);
@@ -796,7 +634,7 @@ public class NetworkingModuleTest {
// verifyStatic actually does not clear all calls so far, so we have to check for all of them.
// If `cancelTag` would've been called again for the aborted call, we would have had
// `requests + 1` calls.
networkingModule.onCatalystInstanceDestroy();
mNetworkingModule.onCatalystInstanceDestroy();
PowerMockito.verifyStatic(times(requests));
clientArguments = ArgumentCaptor.forClass(OkHttpClient.class);
requestIdArguments = ArgumentCaptor.forClass(Integer.class);
@@ -74,6 +74,7 @@ public class TimingModuleTest {
CatalystInstance reactInstance = mock(CatalystInstance.class);
ReactApplicationContext reactContext = mock(ReactApplicationContext.class);
when(reactContext.getCatalystInstance()).thenReturn(reactInstance);
when(reactContext.hasActiveCatalystInstance()).thenReturn(true);
mCurrentTimeNs = 0;
mPostFrameCallbackHandler = new PostFrameCallbackHandler();