It's Riseup's twentieth year, help keep us going! If you can afford it, please contribute to our winter fundraising drive.

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