From c92dc3d39f8c25d3ad7d0a91b25baa33dc458ada Mon Sep 17 00:00:00 2001
From: akwizgran <michael@briarproject.org>
Date: Tue, 28 Mar 2023 15:33:55 +0100
Subject: [PATCH] Add unit test for CircumventionProviderImpl.

---
 onionwrapper-core/build.gradle                |  2 +
 .../briarproject/onionwrapper/BaseTest.java   | 41 +++++++++
 .../CircumventionProviderImplTest.java        | 91 +++++++++++++++++++
 3 files changed, 134 insertions(+)
 create mode 100644 onionwrapper-core/src/test/java/org/briarproject/onionwrapper/BaseTest.java
 create mode 100644 onionwrapper-core/src/test/java/org/briarproject/onionwrapper/CircumventionProviderImplTest.java

diff --git a/onionwrapper-core/build.gradle b/onionwrapper-core/build.gradle
index 7b9afdf..0a83e78 100644
--- a/onionwrapper-core/build.gradle
+++ b/onionwrapper-core/build.gradle
@@ -12,4 +12,6 @@ dependencies {
     api 'com.google.code.findbugs:jsr305:3.0.2'
     api 'javax.inject:javax.inject:1'
     api 'org.briarproject:jtorctl:0.5'
+
+    testImplementation "junit:junit:4.13.2"
 }
diff --git a/onionwrapper-core/src/test/java/org/briarproject/onionwrapper/BaseTest.java b/onionwrapper-core/src/test/java/org/briarproject/onionwrapper/BaseTest.java
new file mode 100644
index 0000000..dcc9950
--- /dev/null
+++ b/onionwrapper-core/src/test/java/org/briarproject/onionwrapper/BaseTest.java
@@ -0,0 +1,41 @@
+package org.briarproject.onionwrapper;
+
+import org.junit.After;
+import org.junit.Before;
+
+import java.util.logging.Logger;
+
+import javax.annotation.Nullable;
+
+import static java.util.logging.Level.WARNING;
+import static java.util.logging.Logger.getLogger;
+
+class BaseTest {
+
+	private static final Logger LOG = getLogger(BaseTest.class.getName());
+
+	@Nullable
+	protected volatile Throwable exceptionInBackgroundThread = null;
+
+	BaseTest() {
+		// Ensure exceptions thrown on worker threads cause tests to fail
+		Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
+			LOG.log(WARNING, "Caught unhandled exception", throwable);
+			exceptionInBackgroundThread = throwable;
+		});
+	}
+
+	@Before
+	public void beforeTestCase() {
+		exceptionInBackgroundThread = null;
+	}
+
+	@After
+	public void afterTestCase() {
+		Throwable thrown = exceptionInBackgroundThread;
+		if (thrown != null) {
+			LOG.log(WARNING, "Background thread has thrown an exception unexpectedly", thrown);
+			throw new AssertionError(thrown);
+		}
+	}
+}
diff --git a/onionwrapper-core/src/test/java/org/briarproject/onionwrapper/CircumventionProviderImplTest.java b/onionwrapper-core/src/test/java/org/briarproject/onionwrapper/CircumventionProviderImplTest.java
new file mode 100644
index 0000000..187f396
--- /dev/null
+++ b/onionwrapper-core/src/test/java/org/briarproject/onionwrapper/CircumventionProviderImplTest.java
@@ -0,0 +1,91 @@
+package org.briarproject.onionwrapper;
+
+import org.junit.Test;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import static java.util.Arrays.asList;
+import static org.briarproject.onionwrapper.CircumventionProvider.BLOCKED;
+import static org.briarproject.onionwrapper.CircumventionProvider.BRIDGES;
+import static org.briarproject.onionwrapper.CircumventionProvider.BridgeType.DEFAULT_OBFS4;
+import static org.briarproject.onionwrapper.CircumventionProvider.BridgeType.MEEK;
+import static org.briarproject.onionwrapper.CircumventionProvider.BridgeType.NON_DEFAULT_OBFS4;
+import static org.briarproject.onionwrapper.CircumventionProvider.BridgeType.SNOWFLAKE;
+import static org.briarproject.onionwrapper.CircumventionProvider.BridgeType.VANILLA;
+import static org.briarproject.onionwrapper.CircumventionProvider.DEFAULT_BRIDGES;
+import static org.briarproject.onionwrapper.CircumventionProvider.DPI_BRIDGES;
+import static org.briarproject.onionwrapper.CircumventionProvider.NON_DEFAULT_BRIDGES;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+public class CircumventionProviderImplTest extends BaseTest {
+
+	private final CircumventionProviderImpl provider =
+			new CircumventionProviderImpl();
+
+	@Test
+	public void testInvariants() {
+		Set<String> blocked = new HashSet<>(asList(BLOCKED));
+		Set<String> bridges = new HashSet<>(asList(BRIDGES));
+		Set<String> defaultBridges = new HashSet<>(asList(DEFAULT_BRIDGES));
+		Set<String> nonDefaultBridges =
+				new HashSet<>(asList(NON_DEFAULT_BRIDGES));
+		Set<String> dpiBridges = new HashSet<>(asList(DPI_BRIDGES));
+		// BRIDGES should be a subset of BLOCKED
+		assertTrue(blocked.containsAll(bridges));
+		// BRIDGES should be the union of the bridge type sets
+		Set<String> union = new HashSet<>(defaultBridges);
+		union.addAll(nonDefaultBridges);
+		union.addAll(dpiBridges);
+		assertEquals(bridges, union);
+		// The bridge type sets should not overlap
+		assertEmptyIntersection(defaultBridges, nonDefaultBridges);
+		assertEmptyIntersection(defaultBridges, dpiBridges);
+		assertEmptyIntersection(nonDefaultBridges, dpiBridges);
+	}
+
+	@Test
+	public void testGetBestBridgeType() {
+		for (String country : DEFAULT_BRIDGES) {
+			assertEquals(asList(DEFAULT_OBFS4, VANILLA),
+					provider.getSuitableBridgeTypes(country));
+		}
+		for (String country : NON_DEFAULT_BRIDGES) {
+			assertEquals(asList(NON_DEFAULT_OBFS4, VANILLA),
+					provider.getSuitableBridgeTypes(country));
+		}
+		for (String country : DPI_BRIDGES) {
+			assertEquals(asList(NON_DEFAULT_OBFS4, MEEK, SNOWFLAKE),
+					provider.getSuitableBridgeTypes(country));
+		}
+		assertEquals(asList(DEFAULT_OBFS4, VANILLA),
+				provider.getSuitableBridgeTypes("ZZ"));
+	}
+
+	@Test
+	public void testHasSnowflakeParamsWithLetsEncrypt() {
+		testHasSnowflakeParams(true);
+	}
+
+	@Test
+	public void testHasSnowflakeParamsWithoutLetsEncrypt() {
+		testHasSnowflakeParams(false);
+	}
+
+	private void testHasSnowflakeParams(boolean letsEncrypt) {
+		String tmParams = provider.getSnowflakeParams("TM", letsEncrypt);
+		String defaultParams = provider.getSnowflakeParams("ZZ", letsEncrypt);
+		assertFalse(tmParams.isEmpty());
+		assertFalse(defaultParams.isEmpty());
+		assertNotEquals(defaultParams, tmParams);
+	}
+
+	private <T> void assertEmptyIntersection(Set<T> a, Set<T> b) {
+		Set<T> intersection = new HashSet<>(a);
+		intersection.retainAll(b);
+		assertTrue(intersection.isEmpty());
+	}
+}
-- 
GitLab