/** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.react.cxxbridge; import java.util.ArrayList; import java.util.Arrays; import org.junit.Before; import org.junit.Test; import com.facebook.common.logging.FLog; import com.facebook.common.logging.FakeLoggingDelegate; import com.facebook.common.logging.LoggingDelegate; import static org.fest.assertions.api.Assertions.assertThat; import static org.fest.assertions.api.Assertions.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public class FallbackJSBundleLoaderTest { private static final String UNRECOVERABLE; static { String prefix = FallbackJSBundleLoader.RECOVERABLE; char first = prefix.charAt(0); UNRECOVERABLE = prefix.replace(first, (char) (first + 1)); } private FakeLoggingDelegate mLoggingDelegate; @Before public void setup() { mLoggingDelegate = new FakeLoggingDelegate(); FLog.setLoggingDelegate(mLoggingDelegate); } @Test public void firstLoaderSucceeds() { JSBundleLoader delegates[] = new JSBundleLoader[] { successfulLoader("url1"), successfulLoader("url2") }; FallbackJSBundleLoader fallbackLoader = new FallbackJSBundleLoader(new ArrayList<>(Arrays.asList(delegates))); assertThat(fallbackLoader.loadScript(null)).isEqualTo("url1"); verify(delegates[0], times(1)).loadScript(null); verify(delegates[1], never()).loadScript(null); assertThat(mLoggingDelegate.logContains( FakeLoggingDelegate.WTF, FallbackJSBundleLoader.TAG, null)) .isFalse(); } @Test public void fallingBackSuccessfully() { JSBundleLoader delegates[] = new JSBundleLoader[] { recoverableLoader("url1", "error1"), successfulLoader("url2"), successfulLoader("url3") }; FallbackJSBundleLoader fallbackLoader = new FallbackJSBundleLoader(new ArrayList<>(Arrays.asList(delegates))); assertThat(fallbackLoader.loadScript(null)).isEqualTo("url2"); verify(delegates[0], times(1)).loadScript(null); verify(delegates[1], times(1)).loadScript(null); verify(delegates[2], never()).loadScript(null); assertThat(mLoggingDelegate.logContains( FakeLoggingDelegate.WTF, FallbackJSBundleLoader.TAG, recoverableMsg("error1"))) .isTrue(); } @Test public void fallingbackUnsuccessfully() { JSBundleLoader delegates[] = new JSBundleLoader[] { recoverableLoader("url1", "error1"), recoverableLoader("url2", "error2") }; FallbackJSBundleLoader fallbackLoader = new FallbackJSBundleLoader(new ArrayList<>(Arrays.asList(delegates))); try { fallbackLoader.loadScript(null); fail("expect throw"); } catch (Exception e) { assertThat(e).isInstanceOf(RuntimeException.class); Throwable cause = e.getCause(); ArrayList<String> msgs = new ArrayList<>(); while (cause != null) { msgs.add(cause.getMessage()); cause = cause.getCause(); } assertThat(msgs).containsExactly( recoverableMsg("error1"), recoverableMsg("error2")); } verify(delegates[0], times(1)).loadScript(null); verify(delegates[1], times(1)).loadScript(null); assertThat(mLoggingDelegate.logContains( FakeLoggingDelegate.WTF, FallbackJSBundleLoader.TAG, recoverableMsg("error1"))) .isTrue(); assertThat(mLoggingDelegate.logContains( FakeLoggingDelegate.WTF, FallbackJSBundleLoader.TAG, recoverableMsg("error2"))) .isTrue(); } @Test public void unrecoverable() { JSBundleLoader delegates[] = new JSBundleLoader[] { fatalLoader("url1", "error1"), recoverableLoader("url2", "error2") }; FallbackJSBundleLoader fallbackLoader = new FallbackJSBundleLoader(new ArrayList(Arrays.asList(delegates))); try { fallbackLoader.loadScript(null); fail("expect throw"); } catch (Exception e) { assertThat(e.getMessage()).isEqualTo(fatalMsg("error1")); } verify(delegates[0], times(1)).loadScript(null); verify(delegates[1], never()).loadScript(null); assertThat(mLoggingDelegate.logContains( FakeLoggingDelegate.WTF, FallbackJSBundleLoader.TAG, null)) .isFalse(); } private static JSBundleLoader successfulLoader(String url) { JSBundleLoader loader = mock(JSBundleLoader.class); when(loader.loadScript(null)).thenReturn(url); return loader; } private static String recoverableMsg(String errMsg) { return FallbackJSBundleLoader.RECOVERABLE + errMsg; } private static JSBundleLoader recoverableLoader(String url, String errMsg) { JSBundleLoader loader = mock(JSBundleLoader.class); when(loader.loadScript(null)) .thenThrow(new RuntimeException(FallbackJSBundleLoader.RECOVERABLE + errMsg)); return loader; } private static String fatalMsg(String errMsg) { return UNRECOVERABLE + errMsg; } private static JSBundleLoader fatalLoader(String url, String errMsg) { JSBundleLoader loader = mock(JSBundleLoader.class); when(loader.loadScript(null)) .thenThrow(new RuntimeException(UNRECOVERABLE + errMsg)); return loader; } }