From b715aeba40bfb62de2f6a158609dfd81126da25a Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 19 Oct 2019 02:24:39 +0200 Subject: unit tests for gateway manager's gateway selection --- .../leap/bitmaskclient/eip/VpnConfigGenerator.java | 5 +- .../bitmaskclient/eip/GatewaySelectorTest.java | 32 ---- .../bitmaskclient/eip/GatewaysManagerTest.java | 189 ++++++++++++++++----- .../leap/bitmaskclient/testutils/MockHelper.java | 20 +++ .../resources/ptdemo_misconfigured_gateway.json | 38 ----- 5 files changed, 174 insertions(+), 110 deletions(-) (limited to 'app/src') diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java index a62daca1..075aac71 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java @@ -16,6 +16,8 @@ */ package se.leap.bitmaskclient.eip; +import android.support.annotation.VisibleForTesting; + import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -111,7 +113,8 @@ public class VpnConfigGenerator { + secretsConfiguration(); } - private VpnProfile createProfile(Connection.TransportType transportType) throws IOException, ConfigParser.ConfigParseError, JSONException { + @VisibleForTesting + protected VpnProfile createProfile(Connection.TransportType transportType) throws IOException, ConfigParser.ConfigParseError, JSONException { String configuration = getConfigurationString(transportType); ConfigParser icsOpenvpnConfigParser = new ConfigParser(); icsOpenvpnConfigParser.parseConfig(new StringReader(configuration)); diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaySelectorTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaySelectorTest.java index 5089de54..5d5a959b 100644 --- a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaySelectorTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaySelectorTest.java @@ -1,32 +1,5 @@ package se.leap.bitmaskclient.eip; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.IntentSender; -import android.content.ServiceConnection; -import android.content.SharedPreferences; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.res.AssetManager; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.database.DatabaseErrorHandler; -import android.database.sqlite.SQLiteDatabase; -import android.graphics.Bitmap; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.os.UserHandle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.view.Display; - import com.tngtech.java.junit.dataprovider.DataProvider; import com.tngtech.java.junit.dataprovider.DataProviderRunner; import com.tngtech.java.junit.dataprovider.UseDataProvider; @@ -41,12 +14,7 @@ import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import org.powermock.modules.junit4.PowerMockRunnerDelegate; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; import java.util.ArrayList; import de.blinkt.openvpn.core.ConfigParser; diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java index 12e95a47..47db3e09 100644 --- a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java @@ -2,6 +2,7 @@ package se.leap.bitmaskclient.eip; import android.content.Context; import android.content.SharedPreferences; +import android.util.Log; import org.json.JSONException; import org.json.JSONObject; @@ -10,95 +11,205 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; import java.io.IOException; +import de.blinkt.openvpn.VpnProfile; +import de.blinkt.openvpn.core.ConfigParser; import de.blinkt.openvpn.core.connection.Connection; -import se.leap.bitmaskclient.Constants; import se.leap.bitmaskclient.Provider; +import se.leap.bitmaskclient.ProviderObservable; +import se.leap.bitmaskclient.testutils.MockHelper; +import se.leap.bitmaskclient.testutils.MockSharedPreferences; import se.leap.bitmaskclient.testutils.TestSetupHelper; +import se.leap.bitmaskclient.utils.ConfigHelper; +import se.leap.bitmaskclient.utils.PreferenceHelper; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNull; +import static org.junit.Assert.assertNotEquals; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +import static se.leap.bitmaskclient.Constants.GATEWAYS; +import static se.leap.bitmaskclient.Constants.PROVIDER_EIP_DEFINITION; +import static se.leap.bitmaskclient.Constants.PROVIDER_PRIVATE_KEY; +import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.Provider.CA_CERT; +import static se.leap.bitmaskclient.testutils.TestSetupHelper.getProvider; /** * Created by cyberta on 09.10.17. */ -@RunWith(MockitoJUnitRunner.class) +@RunWith(PowerMockRunner.class) +@PrepareForTest({ProviderObservable.class, Log.class, PreferenceHelper.class, ConfigHelper.class}) public class GatewaysManagerTest { private GatewaysManager gatewaysManager; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mockContext; - @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private SharedPreferences sharedPreferences; + private JSONObject secrets; + @Before public void setUp() throws IOException, JSONException { + mockStatic(Log.class); + mockStatic(ConfigHelper.class); + when(ConfigHelper.getCurrentTimezone()).thenReturn(-1); + when(ConfigHelper.stringEqual(anyString(), anyString())).thenCallRealMethod(); + secrets = new JSONObject(getJsonStringFor("secrets.json")); + sharedPreferences = new MockSharedPreferences(); + sharedPreferences.edit(). + putString(PROVIDER_PRIVATE_KEY, secrets.getString(PROVIDER_PRIVATE_KEY)). + putString(CA_CERT, secrets.getString(CA_CERT)). + putString(PROVIDER_VPN_CERTIFICATE, secrets.getString(PROVIDER_VPN_CERTIFICATE)) + .commit(); + } + @Test + public void testFromEipServiceJson_emptyJson() throws Exception { + gatewaysManager = new GatewaysManager(mockContext, sharedPreferences); + assertEquals(0, gatewaysManager.size()); + } - JSONObject secrets = new JSONObject(getJsonStringFor("secrets.json")); - - when(sharedPreferences.getString(eq(Constants.PROVIDER_PRIVATE_KEY), anyString())).thenReturn(secrets.getString(Constants.PROVIDER_PRIVATE_KEY)); - when(sharedPreferences.getString(eq(Provider.CA_CERT), anyString())).thenReturn(secrets.getString(Provider.CA_CERT)); - when(sharedPreferences.getString(eq(Constants.PROVIDER_VPN_CERTIFICATE), anyString())).thenReturn(secrets.getString(Constants.PROVIDER_VPN_CERTIFICATE)); - + @Test + public void testFromEipServiceJson_ignoreGatewaysWithMisconfiguredTransportsWhileAddingValidOnes() throws Exception { + updateEipServiceJson("ptdemo_misconfigured_mixed_gateways.json"); + gatewaysManager = new GatewaysManager(mockContext, sharedPreferences); + assertEquals(1, gatewaysManager.size()); + assertNull(gatewaysManager.select(0).getProfile(OBFS4)); + assertNotNull(gatewaysManager.select(0).getProfile(Connection.TransportType.OPENVPN)); + } + @Test + public void testClearGatewaysAndProfiles_resetGateways() throws Exception { + updateEipServiceJson("eip-service-two-gateways.json"); gatewaysManager = new GatewaysManager(mockContext, sharedPreferences); + assertEquals(2, gatewaysManager.size()); + gatewaysManager.clearGateways(); + assertEquals(0, gatewaysManager.size()); } @Test - public void testFromEipServiceJson_emptyJson() throws Exception { - gatewaysManager.fromEipServiceJson(new JSONObject()); - assertEquals(0, gatewaysManager.size()); + public void testGatewayManagerFromCurrentProvider_noProvider_noGateways() { + gatewaysManager = new GatewaysManager(mockContext); + assertEquals(0, gatewaysManager.size()); } @Test - public void testFromEipServiceJson_ignoreDuplicateGateways_apiv3() throws Exception { - String eipServiceJson = TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_three_mixed_gateways.json")); - gatewaysManager.fromEipServiceJson(new JSONObject(eipServiceJson)); - assertEquals(3, gatewaysManager.size()); - eipServiceJson = TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo.bitmask.eip-service.json")); - gatewaysManager.fromEipServiceJson(new JSONObject(eipServiceJson)); + public void testGatewayManagerFromCurrentProvider_misconfiguredProvider_noGateways() throws IOException, NullPointerException { + Provider provider = getProvider(null, null, null, "ptdemo_misconfigured_gateway.json"); + MockHelper.mockProviderObserver(provider); + gatewaysManager = new GatewaysManager(mockContext); + assertEquals(0, gatewaysManager.size()); + } + + @Test + public void testGatewayManagerFromCurrentProvider_threeGateways() { + Provider provider = getProvider(null, null, null, "ptdemo_three_mixed_gateways.json"); + MockHelper.mockProviderObserver(provider); + gatewaysManager = new GatewaysManager(mockContext); assertEquals(3, gatewaysManager.size()); } @Test - public void testFromEipServiceJson_ignoreGatewaysWithMisconfiguredTransportsWhileAddingValidOnes() throws Exception { - String eipServiceJson = TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_misconfigured_mixed_gateways.json")); - gatewaysManager.fromEipServiceJson(new JSONObject(eipServiceJson)); - assertEquals(1, gatewaysManager.size()); - assertNull(gatewaysManager.select(0).getProfile(Connection.TransportType.OBFS4)); - assertNotNull(gatewaysManager.select(0).getProfile(Connection.TransportType.OPENVPN)); + public void TestGetPosition_VpnProfileExtistingObfs4_returnPositionZero() throws JSONException, ConfigParser.ConfigParseError, IOException { + Provider provider = getProvider(null, null, null, "ptdemo_three_mixed_gateways.json"); + JSONObject eipServiceJson = provider.getEipServiceJson(); + JSONObject gateway1 = eipServiceJson.getJSONArray(GATEWAYS).getJSONObject(0); + MockHelper.mockProviderObserver(provider); + mockStatic(PreferenceHelper.class); + when(PreferenceHelper.getUsePluggableTransports(any(Context.class))).thenReturn(true); + gatewaysManager = new GatewaysManager(mockContext); + + VpnConfigGenerator configGenerator = new VpnConfigGenerator(provider.getDefinition(), secrets, gateway1, 3); + VpnProfile profile = configGenerator.createProfile(OBFS4); + profile.mGatewayIp = "37.218.247.60"; + + assertEquals(0, gatewaysManager.getPosition(profile)); } @Test - public void testFromEipServiceJson_ignoreDuplicateGateways() throws Exception { - String eipServiceJson = TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("eip-service-two-gateways.json")); - gatewaysManager.fromEipServiceJson(new JSONObject(eipServiceJson)); - assertEquals(2, gatewaysManager.size()); - eipServiceJson = TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("eip-service-one-gateway.json")); - gatewaysManager.fromEipServiceJson(new JSONObject(eipServiceJson)); - assertEquals(2, gatewaysManager.size()); + public void TestGetPosition_VpnProfileExtistingOpenvpn_returnPositionZero() throws JSONException, ConfigParser.ConfigParseError, IOException { + Provider provider = getProvider(null, null, null, "ptdemo_three_mixed_gateways.json"); + JSONObject eipServiceJson = provider.getEipServiceJson(); + JSONObject gateway1 = eipServiceJson.getJSONArray(GATEWAYS).getJSONObject(0); + MockHelper.mockProviderObserver(provider); + mockStatic(PreferenceHelper.class); + when(PreferenceHelper.getUsePluggableTransports(any(Context.class))).thenReturn(false); + gatewaysManager = new GatewaysManager(mockContext); + + VpnConfigGenerator configGenerator = new VpnConfigGenerator(provider.getDefinition(), secrets, gateway1, 3); + VpnProfile profile = configGenerator.createProfile(OPENVPN); + profile.mGatewayIp = "37.218.247.60"; + + assertEquals(0, gatewaysManager.getPosition(profile)); } @Test - public void testClearGatewaysAndProfiles_resetGateways() throws Exception { - String eipServiceJson = TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("eip-service-two-gateways.json")); - gatewaysManager.fromEipServiceJson(new JSONObject(eipServiceJson)); - assertEquals(2, gatewaysManager.size()); - gatewaysManager.clearGateways(); - assertEquals(0, gatewaysManager.size()); + public void TestGetPosition_VpnProfileDifferentIp_returnMinusOne() throws JSONException, ConfigParser.ConfigParseError, IOException { + Provider provider = getProvider(null, null, null, "ptdemo_three_mixed_gateways.json"); + JSONObject eipServiceJson = provider.getEipServiceJson(); + JSONObject gateway1 = eipServiceJson.getJSONArray(GATEWAYS).getJSONObject(0); + MockHelper.mockProviderObserver(provider); + mockStatic(PreferenceHelper.class); + when(PreferenceHelper.getUsePluggableTransports(any(Context.class))).thenReturn(true); + gatewaysManager = new GatewaysManager(mockContext); + + VpnConfigGenerator configGenerator = new VpnConfigGenerator(provider.getDefinition(), secrets, gateway1, 3); + VpnProfile profile = configGenerator.createProfile(OBFS4); + profile.mGatewayIp = "37.218.247.61"; + + assertEquals(-1, gatewaysManager.getPosition(profile)); + } + + @Test + public void TestGetPosition_VpnProfileMoscow_returnOne() throws JSONException, ConfigParser.ConfigParseError, IOException { + Provider provider = getProvider(null, null, null, "ptdemo_three_mixed_gateways.json"); + JSONObject eipServiceJson = provider.getEipServiceJson(); + JSONObject gateway1 = eipServiceJson.getJSONArray(GATEWAYS).getJSONObject(1); + MockHelper.mockProviderObserver(provider); + mockStatic(PreferenceHelper.class); + when(PreferenceHelper.getUsePluggableTransports(any(Context.class))).thenReturn(true); + gatewaysManager = new GatewaysManager(mockContext); + + VpnConfigGenerator configGenerator = new VpnConfigGenerator(provider.getDefinition(), secrets, gateway1, 3); + VpnProfile profile = configGenerator.createProfile(OBFS4); + profile.mGatewayIp = "3.21.247.89"; + + assertEquals(1, gatewaysManager.getPosition(profile)); + } + + @Test + public void TestSelectN_selectFirstObfs4Connection_returnThirdGateway() throws JSONException, ConfigParser.ConfigParseError, IOException { + Provider provider = getProvider(null, null, null, "ptdemo_two_openvpn_one_pt_gateways.json"); + JSONObject eipServiceJson = provider.getEipServiceJson(); + JSONObject gateway3 = eipServiceJson.getJSONArray(GATEWAYS).getJSONObject(2); + + MockHelper.mockProviderObserver(provider); + mockStatic(PreferenceHelper.class); + when(PreferenceHelper.getUsePluggableTransports(any(Context.class))).thenReturn(true); + gatewaysManager = new GatewaysManager(mockContext); + + assertEquals("37.12.247.10", gatewaysManager.select(0).getRemoteIP()); } private String getJsonStringFor(String filename) throws IOException { return TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream(filename)); } + private void updateEipServiceJson(String filename) throws IOException { + String eipServiceJson = getJsonStringFor(filename); + sharedPreferences.edit().putString(PROVIDER_EIP_DEFINITION, eipServiceJson).commit(); + } } \ No newline at end of file diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java b/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java index 24801b58..481c87cb 100644 --- a/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java @@ -35,6 +35,7 @@ import java.util.Set; import okhttp3.OkHttpClient; import se.leap.bitmaskclient.OkHttpClientGenerator; import se.leap.bitmaskclient.Provider; +import se.leap.bitmaskclient.ProviderObservable; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider; import se.leap.bitmaskclient.testutils.matchers.BundleMatcher; @@ -58,6 +59,7 @@ import static org.powermock.api.mockito.PowerMockito.mockStatic; import static se.leap.bitmaskclient.Constants.PROVIDER_PRIVATE_KEY; import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE; import static se.leap.bitmaskclient.utils.FileHelper.createFile; +import static se.leap.bitmaskclient.utils.PreferenceHelper.getEipDefinitionFromPreferences; import static se.leap.bitmaskclient.utils.PreferenceHelper.getFromPersistedProvider; /** @@ -402,6 +404,24 @@ public class MockHelper { }); } + public static void mockPreferenceHelper(MockSharedPreferences preferences) { + mockStatic(PreferenceHelper.class); + + when(getEipDefinitionFromPreferences(any(SharedPreferences.class))).thenAnswer(new Answer() { + @Override + public JSONObject answer(InvocationOnMock invocation) throws Throwable { + return getEipDefinitionFromPreferences(preferences); + } + }); + } + + public static void mockProviderObserver(Provider provider) { + ProviderObservable observable = ProviderObservable.getInstance(); + observable.updateProvider(provider); + mockStatic(ProviderObservable.class); + when(ProviderObservable.getInstance()).thenAnswer((Answer) invocation -> observable); + } + public static void mockFingerprintForCertificate(String mockedFingerprint) throws CertificateEncodingException, NoSuchAlgorithmException { mockStatic(ConfigHelper.class); when(ConfigHelper.getFingerprintFromCertificate(any(X509Certificate.class), anyString())).thenReturn(mockedFingerprint); diff --git a/app/src/test/resources/ptdemo_misconfigured_gateway.json b/app/src/test/resources/ptdemo_misconfigured_gateway.json index 8308157d..38008880 100644 --- a/app/src/test/resources/ptdemo_misconfigured_gateway.json +++ b/app/src/test/resources/ptdemo_misconfigured_gateway.json @@ -18,15 +18,6 @@ "cert": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX2", "iat-mode": "0" } - }, - { - "type":"openvpn", - "protocols":[ - "tcp" - ], - "ports":[ - "1195" - ] } ], "user_ips":false @@ -34,29 +25,6 @@ "host":"moscow.bitmask.net", "ip_address":"3.21.247.89", "location":"moscow" - }, - { - "capabilities":{ - "adblock":false, - "filter_dns":false, - "limited":false, - "transport":[ - { - "type":"openvpn", - "protocols":[ - "tcp", - "udp" - ], - "ports":[ - "1195" - ] - } - ], - "user_ips":false - }, - "host":"manila.bitmask.net", - "ip_address":"37.12.247.10", - "location":"manila" } ], "locations":{ @@ -65,12 +33,6 @@ "hemisphere":"N", "name":"Amsterdam", "timezone":"-1" - }, - "moscow": { - "country_code": "RU", - "hemisphere": "N", - "name": "Moscow", - "timezone": "+3" } }, "openvpn_configuration":{ -- cgit v1.2.3