Skip to content

Commit

Permalink
Fix an issue when a listener/handler is removed before react native i…
Browse files Browse the repository at this point in the history
…s initialized

Add tests
  • Loading branch information
deepueg committed Feb 6, 2020
1 parent 1293db1 commit d25a28c
Show file tree
Hide file tree
Showing 2 changed files with 176 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package com.walmartlabs.electrode.reactnative.bridge;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import com.walmartlabs.electrode.reactnative.bridge.helpers.Logger;

import org.junit.Before;
import org.junit.Test;

import java.util.UUID;

import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertNotNull;
import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.assertNull;

public class BridgeHolderTests extends BaseBridgeTestCase {

@Before
public void setUp() {
Logger.overrideLogLevel(Logger.LogLevel.DEBUG);
}

@Test
public void testRequestHandlerQueuing() {
String KEY_HANDLER = "requestHandler";

ElectrodeBridgeRequestHandler<ElectrodeBridgeRequest, Object> requestHandler1 = new ElectrodeBridgeRequestHandler<ElectrodeBridgeRequest, Object>() {
@Override
public void onRequest(@Nullable ElectrodeBridgeRequest payload, @NonNull ElectrodeBridgeResponseListener<Object> responseListener) {

}
};

UUID requestHandler1Uuid = ElectrodeBridgeHolder.registerRequestHandler(KEY_HANDLER, requestHandler1);
assertEquals(1, ElectrodeBridgeHolder.mQueuedRequestHandlersRegistration.size());
assertTrue(ElectrodeBridgeHolder.mQueuedRequestHandlersRegistration.containsKey(KEY_HANDLER));
assertNotNull(ElectrodeBridgeHolder.mQueuedRequestHandlersRegistration.get(KEY_HANDLER));
assertEquals(requestHandler1, ElectrodeBridgeHolder.mQueuedRequestHandlersRegistration.get(KEY_HANDLER).getRequestHandler());


ElectrodeBridgeRequestHandler<ElectrodeBridgeRequest, Object> requestHandler2 = new ElectrodeBridgeRequestHandler<ElectrodeBridgeRequest, Object>() {
@Override
public void onRequest(@Nullable ElectrodeBridgeRequest payload, @NonNull ElectrodeBridgeResponseListener<Object> responseListener) {

}
};

//Add second request handler, this should replace the first one.
UUID requestHandler2Uuid = ElectrodeBridgeHolder.registerRequestHandler(KEY_HANDLER, requestHandler2);
assertEquals(1, ElectrodeBridgeHolder.mQueuedRequestHandlersRegistration.size());
assertTrue(ElectrodeBridgeHolder.mQueuedRequestHandlersRegistration.containsKey(KEY_HANDLER));
assertNotNull(ElectrodeBridgeHolder.mQueuedRequestHandlersRegistration.get(KEY_HANDLER));
assertEquals(requestHandler2, ElectrodeBridgeHolder.mQueuedRequestHandlersRegistration.get(KEY_HANDLER).getRequestHandler());


//Try removing the first request handler which is already replaced by second
assertNull(ElectrodeBridgeHolder.unregisterRequestHandler(requestHandler1Uuid));

//Remove the second request handler
assertEquals(requestHandler2, ElectrodeBridgeHolder.unregisterRequestHandler(requestHandler2Uuid));
assertEquals(0, ElectrodeBridgeHolder.mQueuedRequestHandlersRegistration.size());
assertFalse(ElectrodeBridgeHolder.mQueuedRequestHandlersRegistration.containsKey(KEY_HANDLER));
}

@Test
public void testEventListenerQueuing() {
String KEY_LISTENER = "eventListener";
ElectrodeBridgeEventListener<ElectrodeBridgeEvent> eventListener1 = new ElectrodeBridgeEventListener<ElectrodeBridgeEvent>() {
@Override
public void onEvent(@Nullable ElectrodeBridgeEvent eventPayload) {

}
};

UUID eventListener1Uuid = ElectrodeBridgeHolder.addEventListener(KEY_LISTENER, eventListener1);

assertEquals(1, ElectrodeBridgeHolder.mQueuedEventListenersRegistration.size());
assertTrue(ElectrodeBridgeHolder.mQueuedEventListenersRegistration.containsKey(KEY_LISTENER));
assertNotNull(ElectrodeBridgeHolder.mQueuedEventListenersRegistration.get(KEY_LISTENER));
assertEquals(1, ElectrodeBridgeHolder.mQueuedEventListenersRegistration.get(KEY_LISTENER).size());
assertEquals(eventListener1, ElectrodeBridgeHolder.mQueuedEventListenersRegistration.get(KEY_LISTENER).get(0).getEventListener());


//Add the second listener
ElectrodeBridgeEventListener<ElectrodeBridgeEvent> eventListener2 = new ElectrodeBridgeEventListener<ElectrodeBridgeEvent>() {
@Override
public void onEvent(@Nullable ElectrodeBridgeEvent eventPayload) {
}
};

UUID eventListener2Uuid = ElectrodeBridgeHolder.addEventListener(KEY_LISTENER, eventListener2);
assertEquals(1, ElectrodeBridgeHolder.mQueuedEventListenersRegistration.size());
assertTrue(ElectrodeBridgeHolder.mQueuedEventListenersRegistration.containsKey(KEY_LISTENER));
assertNotNull(ElectrodeBridgeHolder.mQueuedEventListenersRegistration.get(KEY_LISTENER));
assertEquals(2, ElectrodeBridgeHolder.mQueuedEventListenersRegistration.get(KEY_LISTENER).size());
assertEquals(eventListener1, ElectrodeBridgeHolder.mQueuedEventListenersRegistration.get(KEY_LISTENER).get(0).getEventListener());
assertEquals(eventListener2, ElectrodeBridgeHolder.mQueuedEventListenersRegistration.get(KEY_LISTENER).get(1).getEventListener());

//Remove one listener
assertEquals(eventListener2, ElectrodeBridgeHolder.removeEventListener(eventListener2Uuid));
assertEquals(1, ElectrodeBridgeHolder.mQueuedEventListenersRegistration.size());
assertTrue(ElectrodeBridgeHolder.mQueuedEventListenersRegistration.containsKey(KEY_LISTENER));
assertNotNull(ElectrodeBridgeHolder.mQueuedEventListenersRegistration.get(KEY_LISTENER));
assertEquals(1, ElectrodeBridgeHolder.mQueuedEventListenersRegistration.get(KEY_LISTENER).size());
assertEquals(eventListener1, ElectrodeBridgeHolder.mQueuedEventListenersRegistration.get(KEY_LISTENER).get(0).getEventListener());

//Remove all listeners
assertEquals(eventListener1, ElectrodeBridgeHolder.removeEventListener(eventListener1Uuid));
assertEquals(0, ElectrodeBridgeHolder.mQueuedEventListenersRegistration.size());
assertFalse(ElectrodeBridgeHolder.mQueuedEventListenersRegistration.containsKey(KEY_LISTENER));
assertNull(ElectrodeBridgeHolder.mQueuedEventListenersRegistration.get(KEY_LISTENER));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.walmartlabs.electrode.reactnative.bridge;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import com.walmartlabs.electrode.reactnative.bridge.helpers.Logger;

Expand Down Expand Up @@ -48,10 +49,10 @@ public final class ElectrodeBridgeHolder {
// This solution does not really scale in the sense that if the user sends a 1000 requests
// upon native app start, it can become problematic. But I don't see why a user would do that
// unless it's a bug in its app
private static final HashMap<String, RequestHandlerPlaceholder> mQueuedRequestHandlersRegistration = new HashMap<>();
private static final HashMap<String, EventListenerPlaceholder> mQueuedEventListenersRegistration = new HashMap<>();
private static final HashMap<ElectrodeBridgeRequest, ElectrodeBridgeResponseListener<ElectrodeBridgeResponse>> mQueuedRequests = new HashMap<>();
private static final List<ElectrodeBridgeEvent> mQueuedEvents = new ArrayList<>();
static final HashMap<String, RequestHandlerPlaceholder> mQueuedRequestHandlersRegistration = new HashMap<>();
static final HashMap<String, List<EventListenerPlaceholder>> mQueuedEventListenersRegistration = new HashMap<>();
static final HashMap<ElectrodeBridgeRequest, ElectrodeBridgeResponseListener<ElectrodeBridgeResponse>> mQueuedRequests = new HashMap<>();
static final List<ElectrodeBridgeEvent> mQueuedEvents = new ArrayList<>();

static {
ElectrodeBridgeTransceiver.registerReactNativeReadyListener(new ElectrodeBridgeTransceiver.ReactNativeReadyListener() {
Expand Down Expand Up @@ -135,7 +136,12 @@ public static UUID addEventListener(@NonNull String name,
UUID eventUUID = UUID.randomUUID();
if (!isReactNativeReady) {
Logger.d(TAG, "Queuing event handler registration for event(name=%s). Will register once react native initialization is complete.", name);
mQueuedEventListenersRegistration.put(name, new EventListenerPlaceholder(eventUUID, eventListener));
List<EventListenerPlaceholder> placeholderList = mQueuedEventListenersRegistration.get(name);
if (placeholderList == null) {
placeholderList = new ArrayList<>();
mQueuedEventListenersRegistration.put(name, placeholderList);
}
placeholderList.add(new EventListenerPlaceholder(eventUUID, eventListener));
return eventUUID;
}

Expand All @@ -153,8 +159,32 @@ public static void addConstantsProvider(@NonNull ConstantsProvider constantsProv
* @param eventListenerUuid {@link UUID}
* @return
*/
@Nullable
public static ElectrodeBridgeEventListener<ElectrodeBridgeEvent> removeEventListener(@NonNull UUID eventListenerUuid) {
return electrodeNativeBridge.removeEventListener(eventListenerUuid);
if (!isReactNativeReady) {
ElectrodeBridgeEventListener<ElectrodeBridgeEvent> eventListener = null;
synchronized (mQueuedEventListenersRegistration) {
String key = null;
for (Map.Entry<String, List<EventListenerPlaceholder>> entry : mQueuedEventListenersRegistration.entrySet()) {
List<EventListenerPlaceholder> placeholderList = entry.getValue();
for (EventListenerPlaceholder placeholder : placeholderList) {
if (eventListenerUuid == placeholder.getUUID()) {
key = entry.getKey();
eventListener = placeholder.getEventListener();
placeholderList.remove(placeholder);
break;
}
}
if (placeholderList.size() == 0) {
mQueuedEventListenersRegistration.remove(key);
break;
}
}
}
return eventListener;
} else {
return electrodeNativeBridge.removeEventListener(eventListenerUuid);
}
}

/**
Expand All @@ -164,7 +194,20 @@ public static ElectrodeBridgeEventListener<ElectrodeBridgeEvent> removeEventList
* @return registerRequestHandler unregistered
*/
public static ElectrodeBridgeRequestHandler<ElectrodeBridgeRequest, Object> unregisterRequestHandler(@NonNull UUID requestHandlerUuid) {
return electrodeNativeBridge.unregisterRequestHandler(requestHandlerUuid);
if (!isReactNativeReady) {
ElectrodeBridgeRequestHandler<ElectrodeBridgeRequest, Object> requestHandler = null;
synchronized (mQueuedRequestHandlersRegistration) {
for (Map.Entry<String, RequestHandlerPlaceholder> entry : mQueuedRequestHandlersRegistration.entrySet()) {
if (entry.getValue().getUUID() == requestHandlerUuid) {
requestHandler = entry.getValue().getRequestHandler();
mQueuedRequestHandlersRegistration.remove(entry.getKey());
}
}
}
return requestHandler;
} else {
return electrodeNativeBridge.unregisterRequestHandler(requestHandlerUuid);
}
}

private static void registerQueuedRequestHandlers() {
Expand All @@ -178,11 +221,15 @@ private static void registerQueuedRequestHandlers() {
}

private static void registerQueuedEventListeners() {
for (Map.Entry<String, EventListenerPlaceholder> entry : mQueuedEventListenersRegistration.entrySet()) {
electrodeNativeBridge.addEventListener(
entry.getKey(),
entry.getValue().getEventListener(),
entry.getValue().getUUID());
for (Map.Entry<String, List<EventListenerPlaceholder>> entry : mQueuedEventListenersRegistration.entrySet()) {
List<EventListenerPlaceholder> placeholderList = entry.getValue();
for (EventListenerPlaceholder placeholder : placeholderList) {
electrodeNativeBridge.addEventListener(
entry.getKey(),
placeholder.getEventListener(),
placeholder.getUUID());
}

}
mQueuedEventListenersRegistration.clear();
}
Expand Down

0 comments on commit d25a28c

Please sign in to comment.