Commit 678024d9 authored by cyberta's avatar cyberta

add test and minor refactoring for gateway selection

parent 3609af50
......@@ -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'
......
......@@ -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) ?
......
......@@ -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;
}
}
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
{
"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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment