summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcyBerta <cyberta@riseup.net>2018-12-27 19:10:46 +0100
committercyBerta <cyberta@riseup.net>2018-12-27 19:10:46 +0100
commit678024d9be61e6b0bb55b826c4c488521e16de8d (patch)
treea86d8a37cd82f5cd825686ee1fcb0ca05519c761
parent3609af508119f4d27b148e6f6f296c112943eafe (diff)
add test and minor refactoring for gateway selection
-rw-r--r--app/build.gradle1
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java20
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/utils/ConfigHelper.java5
-rw-r--r--app/src/test/java/se/leap/bitmaskclient/eip/GatewaySelectorTest.java172
-rw-r--r--app/src/test/resources/eip-service-four-gateways.json123
5 files changed, 313 insertions, 8 deletions
diff --git a/app/build.gradle b/app/build.gradle
index 33f8baa1..6dff8e34 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -159,6 +159,7 @@ dependencies {
testImplementation 'org.powermock:powermock-module-junit4:1.7.3'
testImplementation 'org.powermock:powermock-core:1.7.3'
testImplementation 'org.powermock:powermock-module-junit4-rule:1.7.3'
+ testImplementation group: 'com.tngtech.java', name: 'junit-dataprovider', version: '1.10.0'
androidTestImplementation 'org.mockito:mockito-core:2.8.9'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java
index 078e3fd5..2bd666bf 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java
@@ -2,7 +2,13 @@ package se.leap.bitmaskclient.eip;
import android.util.Log;
-import java.util.*;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import static se.leap.bitmaskclient.utils.ConfigHelper.getCurrentTimezone;
public class GatewaySelector {
private final static String TAG = GatewaySelector.class.getSimpleName();
@@ -19,16 +25,14 @@ public class GatewaySelector {
return closestGateway();
}
- public Gateway select(int nClosest) throws IndexOutOfBoundsException{
+ public Gateway select(int nClosest) {
int i = 0;
for (Map.Entry<Integer,Set<Gateway>> entrySet : offsets.entrySet()) {
- Iterator<Gateway> iterator = entrySet.getValue().iterator();
- while (iterator.hasNext()) {
- Gateway gateway = iterator.next();
- if (i == nClosest) {
+ for (Gateway gateway : entrySet.getValue()) {
+ if (i == nClosest) {
return gateway;
}
- i = i+1;
+ i = i + 1;
}
}
@@ -42,7 +46,7 @@ public class GatewaySelector {
private TreeMap<Integer, Set<Gateway>> calculateOffsets() {
TreeMap<Integer, Set<Gateway>> offsets = new TreeMap<Integer, Set<Gateway>>();
- int localOffset = Calendar.getInstance().get(Calendar.ZONE_OFFSET) / 3600000;
+ int localOffset = getCurrentTimezone();
for (Gateway gateway : gateways) {
int dist = timezoneDistance(localOffset, gateway.getTimezone());
Set<Gateway> set = (offsets.get(dist) != null) ?
diff --git a/app/src/main/java/se/leap/bitmaskclient/utils/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/utils/ConfigHelper.java
index 326139c0..d1ac0eb3 100644
--- a/app/src/main/java/se/leap/bitmaskclient/utils/ConfigHelper.java
+++ b/app/src/main/java/se/leap/bitmaskclient/utils/ConfigHelper.java
@@ -39,6 +39,7 @@ import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Calendar;
import se.leap.bitmaskclient.BuildConfig;
import se.leap.bitmaskclient.ProviderAPI;
@@ -177,4 +178,8 @@ public class ConfigHelper {
public static boolean preferAnonymousUsage() {
return BuildConfig.priotize_anonymous_usage;
}
+
+ public static int getCurrentTimezone() {
+ return Calendar.getInstance().get(Calendar.ZONE_OFFSET) / 3600000;
+ }
}
diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaySelectorTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaySelectorTest.java
new file mode 100644
index 00000000..6d858d39
--- /dev/null
+++ b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaySelectorTest.java
@@ -0,0 +1,172 @@
+package se.leap.bitmaskclient.eip;
+
+import com.tngtech.java.junit.dataprovider.DataProvider;
+import com.tngtech.java.junit.dataprovider.DataProviderRunner;
+import com.tngtech.java.junit.dataprovider.UseDataProvider;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.modules.junit4.PowerMockRunnerDelegate;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import se.leap.bitmaskclient.Provider;
+import se.leap.bitmaskclient.utils.ConfigHelper;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+import static org.powermock.api.mockito.PowerMockito.mockStatic;
+import static org.powermock.api.mockito.PowerMockito.when;
+import static se.leap.bitmaskclient.Constants.PROVIDER_PRIVATE_KEY;
+import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.testutils.TestSetupHelper.getInputAsString;
+
+/**
+ * Created by cyberta on 18.12.18.
+ */
+@RunWith(PowerMockRunner.class)
+@PowerMockRunnerDelegate(DataProviderRunner.class)
+@PrepareForTest({ConfigHelper.class})
+public class GatewaySelectorTest {
+ public static final String TAG = GatewaySelectorTest.class.getSimpleName();
+
+ /**
+ * locations": {
+ "name": ""Frankfurt"",
+ "timezone": "+1"
+ },
+ ""Seattle, WA"__wa": {
+ "name": ""Seattle, WA", WA",
+ "timezone": "-7"
+ },
+ ""Moscow"": {
+ "country_code": "RU",
+ "hemisphere": "N",
+ "name": ""Moscow"",
+ "timezone": "+3"
+ },
+ ""Manila"": {
+ "country_code": "PH",
+ "hemisphere": "N",
+ "name": ""Manila"",
+ "timezone": "+8"
+ }
+ },
+ */
+
+
+ GatewaySelector gatewaySelector;
+ JSONObject eipDefinition;
+ ArrayList<Gateway> gatewayList = new ArrayList<>();
+
+ @Before
+ public void setup() throws IOException, JSONException {
+ mockStatic(ConfigHelper.class);
+ eipDefinition = new JSONObject(getInputAsString(getClass().getClassLoader().getResourceAsStream("eip-service-four-gateways.json")));
+ JSONArray gateways = eipDefinition.getJSONArray("gateways");
+ for (int i = 0; i < gateways.length(); i++) {
+ JSONObject gw = gateways.getJSONObject(i);
+ JSONObject secrets = secretsConfiguration();
+ Gateway aux = new Gateway(eipDefinition, secrets, gw);
+ gatewayList.add(aux);
+ }
+
+ }
+
+ private JSONObject secretsConfiguration() throws IOException, JSONException {
+ JSONObject result = new JSONObject();
+ result.put(Provider.CA_CERT, getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.pem")));
+ result.put(PROVIDER_PRIVATE_KEY, getInputAsString(getClass().getClassLoader().getResourceAsStream("private_rsa_key.pem")));
+ result.put(PROVIDER_VPN_CERTIFICATE, getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.vpn_cert.pem")));
+ return result;
+ }
+
+ @DataProvider
+ public static Object[][] dataProviderTimezones() {
+ // @formatter:off
+ return new Object[][] {
+ //{ -12, "Seattle, WA" }
+ { -11, "Seattle, WA" },
+ { -10, "Seattle, WA" },
+ { -9, "Seattle, WA" },
+ { -8, "Seattle, WA" },
+ { -7, "Seattle, WA" }, // <-"Seattle, WA"
+ { -6, "Seattle, WA" },
+ { -5, "Seattle, WA" },
+ { -4, "Seattle, WA" },
+ // { -3, "Seattle, WA" },
+ { -2, "Frankfurt" },
+ { -1, "Frankfurt" },
+ { 0, "Frankfurt" },
+ { 1, "Frankfurt" }, // <- "Frankfurt"
+ // { 2, "Moscow" },
+ { 3, "Moscow" }, // <- "Moscow"
+ { 4, "Moscow" },
+ { 5, "Moscow" },
+ { 6, "Manila" },
+ { 7, "Manila" },
+ { 8, "Manila" }, // <- "Manila"
+ { 9, "Manila" },
+ { 10, "Manila" },
+ { 11, "Manila" },
+ { 12, "Manila" }
+ };
+ // @formatter:on
+ }
+
+ @DataProvider
+ public static Object[][] dataProviderSameDistanceTimezones() {
+ // @formatter:off
+ return new Object[][] {
+ { -12, "Seattle, WA", "Manila" },
+ { -3, "Seattle, WA", "Frankfurt" },
+ { 2, "Moscow", "Frankfurt" },
+
+ };
+ // @formatter:on
+ }
+
+ @Test
+ @UseDataProvider("dataProviderTimezones")
+ public void testSelect(int timezone, String expected) {
+ when(ConfigHelper.getCurrentTimezone()).thenReturn(timezone);
+ gatewaySelector = new GatewaySelector(gatewayList);
+ assertEquals(expected, gatewaySelector.select().getName());
+ }
+
+ @Test
+ @UseDataProvider("dataProviderSameDistanceTimezones")
+ public void testSelectSameTimezoneDistance(int timezone, String expected1, String expected2) {
+ when(ConfigHelper.getCurrentTimezone()).thenReturn(timezone);
+ gatewaySelector = new GatewaySelector(gatewayList);
+ assertTrue(gatewaySelector.select().getName().equals(expected1) || gatewaySelector.select().getName().equals(expected2));
+ }
+
+ @Test
+ @UseDataProvider("dataProviderSameDistanceTimezones")
+ public void testNClostest_SameTimezoneDistance_chooseGatewayWithSameDistance(int timezone, String expected1, String expected2) {
+ when(ConfigHelper.getCurrentTimezone()).thenReturn(timezone);
+ gatewaySelector = new GatewaySelector(gatewayList);
+ ArrayList<String> gateways = new ArrayList<>();
+ gateways.add(gatewaySelector.select(0).getName());
+ gateways.add(gatewaySelector.select(1).getName());
+
+ assertTrue(gateways.contains(expected1) && gateways.contains(expected2));
+
+ }
+
+ @Test
+ public void testNClostest_OneTimezonePerSet_choseSecondClosestTimezone() {
+ when(ConfigHelper.getCurrentTimezone()).thenReturn(-4);
+ gatewaySelector = new GatewaySelector(gatewayList);
+
+ assertTrue("Frankfurt".equals(gatewaySelector.select(1).getName()));
+ }
+} \ No newline at end of file
diff --git a/app/src/test/resources/eip-service-four-gateways.json b/app/src/test/resources/eip-service-four-gateways.json
new file mode 100644
index 00000000..a3395b72
--- /dev/null
+++ b/app/src/test/resources/eip-service-four-gateways.json
@@ -0,0 +1,123 @@
+{
+ "gateways": [
+ {
+ "capabilities": {
+ "adblock": false,
+ "filter_dns": false,
+ "limited": false,
+ "ports": [
+ "443"
+ ],
+ "protocols": [
+ "tcp",
+ "udp"
+ ],
+ "transport": [
+ "openvpn"
+ ],
+ "user_ips": false
+ },
+ "host": "millipede.demo.bitmask.net",
+ "ip_address": "198.252.153.84",
+ "location": "seattle__wa"
+ },
+ {
+ "capabilities": {
+ "adblock": false,
+ "filter_dns": false,
+ "limited": false,
+ "ports": [
+ "443"
+ ],
+ "protocols": [
+ "tcp",
+ "udp"
+ ],
+ "transport": [
+ "openvpn"
+ ],
+ "user_ips": false
+ },
+ "host": "otter.demo.bitmask.net",
+ "ip_address": "46.165.242.169",
+ "location": "frankfurt"
+ },
+ {
+ "capabilities": {
+ "adblock": false,
+ "filter_dns": false,
+ "limited": false,
+ "ports": [
+ "443"
+ ],
+ "protocols": [
+ "tcp",
+ "udp"
+ ],
+ "transport": [
+ "openvpn"
+ ],
+ "user_ips": false
+ },
+ "host": "orca.demo.bitmask.net",
+ "ip_address": "46.172.242.101",
+ "location": "moscow"
+ },
+ {
+ "capabilities": {
+ "adblock": false,
+ "filter_dns": false,
+ "limited": false,
+ "ports": [
+ "443"
+ ],
+ "protocols": [
+ "tcp",
+ "udp"
+ ],
+ "transport": [
+ "openvpn"
+ ],
+ "user_ips": false
+ },
+ "host": "duck.demo.bitmask.net",
+ "ip_address": "104.165.142.132",
+ "location": "manila"
+ }
+ ],
+ "locations": {
+ "seattle__wa": {
+ "country_code": "US",
+ "hemisphere": "N",
+ "name": "Seattle, WA",
+ "timezone": "-7"
+ },
+ "frankfurt": {
+ "country_code": "DE",
+ "hemisphere": "N",
+ "name": "Frankfurt",
+ "timezone": "+1"
+ },
+ "moscow": {
+ "country_code": "RU",
+ "hemisphere": "N",
+ "name": "Moscow",
+ "timezone": "+3"
+ },
+ "manila": {
+ "country_code": "PH",
+ "hemisphere": "N",
+ "name": "Manila",
+ "timezone": "+8"
+ }
+ },
+ "openvpn_configuration": {
+ "auth": "SHA1",
+ "cipher": "AES-128-CBC",
+ "keepalive": "10 30",
+ "tls-cipher": "DHE-RSA-AES128-SHA",
+ "tun-ipv6": true
+ },
+ "serial": 1,
+ "version": 1
+} \ No newline at end of file