diff options
author | cyBerta <cyberta@riseup.net> | 2018-12-27 19:10:46 +0100 |
---|---|---|
committer | cyBerta <cyberta@riseup.net> | 2018-12-27 19:10:46 +0100 |
commit | 678024d9be61e6b0bb55b826c4c488521e16de8d (patch) | |
tree | a86d8a37cd82f5cd825686ee1fcb0ca05519c761 | |
parent | 3609af508119f4d27b148e6f6f296c112943eafe (diff) |
add test and minor refactoring for gateway selection
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 |