summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/ProviderManager.java47
-rw-r--r--app/src/test/java/se/leap/bitmaskclient/ProviderManagerTest.java189
2 files changed, 225 insertions, 11 deletions
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java b/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java
index 97ba3b98..a36c2dec 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java
+++ b/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java
@@ -1,6 +1,7 @@
package se.leap.bitmaskclient;
import android.content.res.AssetManager;
+import android.support.annotation.VisibleForTesting;
import com.pedrogomez.renderers.AdapteeCollection;
@@ -8,9 +9,7 @@ import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
-import java.io.FileInputStream;
import java.io.FileNotFoundException;
-import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
@@ -22,6 +21,11 @@ import java.util.Iterator;
import java.util.List;
import java.util.Set;
+import static se.leap.bitmaskclient.utils.FileHelper.createFile;
+import static se.leap.bitmaskclient.utils.FileHelper.persistFile;
+import static se.leap.bitmaskclient.utils.InputStreamHelper.getInputStreamFrom;
+import static se.leap.bitmaskclient.utils.InputStreamHelper.loadInputStreamAsString;
+
/**
* Created by parmegv on 4/12/14.
*/
@@ -37,6 +41,8 @@ public class ProviderManager implements AdapteeCollection<Provider> {
private static ProviderManager instance;
final private static String URLS = "urls";
+ final private static String EXT_JSON = ".json";
+ final private static String EXT_PEM = ".pem";
public static ProviderManager getInstance(AssetManager assetsManager, File externalFilesDir) {
if (instance == null)
@@ -45,6 +51,11 @@ public class ProviderManager implements AdapteeCollection<Provider> {
return instance;
}
+ @VisibleForTesting
+ static void reset() {
+ instance = null;
+ }
+
private ProviderManager(AssetManager assetManager, File externalFilesDir) {
this.assetsManager = assetManager;
addDefaultProviders(assetManager);
@@ -79,8 +90,8 @@ public class ProviderManager implements AdapteeCollection<Provider> {
String provider = file.substring(0, file.length() - ".url".length());
InputStream provider_file = assetsManager.open(directory + "/" + file);
mainUrl = extractMainUrlFromInputStream(provider_file);
- certificate = ConfigHelper.loadInputStreamAsString(assetsManager.open(provider + ".pem"));
- providerDefinition = ConfigHelper.loadInputStreamAsString(assetsManager.open(provider + ".json"));
+ certificate = loadInputStreamAsString(assetsManager.open(provider + EXT_PEM));
+ providerDefinition = loadInputStreamAsString(assetsManager.open(provider + EXT_JSON));
} catch (IOException e) {
e.printStackTrace();
}
@@ -107,7 +118,7 @@ public class ProviderManager implements AdapteeCollection<Provider> {
Set<Provider> providers = new HashSet<>();
try {
for (String file : files) {
- String mainUrl = extractMainUrlFromInputStream(ConfigHelper.getInputStreamFrom(externalFilesDir.getAbsolutePath() + "/" + file));
+ String mainUrl = extractMainUrlFromInputStream(getInputStreamFrom(externalFilesDir.getAbsolutePath() + "/" + file));
providers.add(new Provider(new URL(mainUrl)));
}
} catch (MalformedURLException | FileNotFoundException e) {
@@ -219,19 +230,33 @@ public class ProviderManager implements AdapteeCollection<Provider> {
defaultProviderURLs.clear();
}
- //FIXME: removed custom providers should be deleted here as well
void saveCustomProvidersToFile() {
try {
+ deleteLegacyCustomProviders();
+
for (Provider provider : customProviders) {
- File providerFile = new File(externalFilesDir, provider.getName() + ".json");
+ File providerFile = createFile(externalFilesDir, provider.getName() + EXT_JSON);
if (!providerFile.exists()) {
- FileWriter writer = new FileWriter(providerFile);
- writer.write(provider.toJson().toString());
- writer.close();
+ persistFile(providerFile, provider.toJson().toString());
}
}
- } catch (IOException e) {
+ } catch (IOException | SecurityException e) {
e.printStackTrace();
}
}
+
+ /**
+ * Deletes persisted custom providers from from internal storage that are not in customProviders list anymore
+ */
+ private void deleteLegacyCustomProviders() throws IOException, SecurityException {
+ Set<Provider> persistedCustomProviders = externalFilesDir != null && externalFilesDir.isDirectory() ?
+ providersFromFiles(externalFilesDir.list()) : new HashSet<Provider>();
+ persistedCustomProviders.removeAll(customProviders);
+ for (Provider providerToDelete : persistedCustomProviders) {
+ File providerFile = createFile(externalFilesDir, providerToDelete.getName() + EXT_JSON);
+ if (providerFile.exists()) {
+ providerFile.delete();
+ }
+ }
+ }
}
diff --git a/app/src/test/java/se/leap/bitmaskclient/ProviderManagerTest.java b/app/src/test/java/se/leap/bitmaskclient/ProviderManagerTest.java
new file mode 100644
index 00000000..1914f989
--- /dev/null
+++ b/app/src/test/java/se/leap/bitmaskclient/ProviderManagerTest.java
@@ -0,0 +1,189 @@
+package se.leap.bitmaskclient;
+
+import android.content.res.AssetManager;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.ArrayList;
+
+import se.leap.bitmaskclient.utils.ConfigHelper;
+import se.leap.bitmaskclient.utils.FileHelper;
+import se.leap.bitmaskclient.utils.InputStreamHelper;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.powermock.api.mockito.PowerMockito.verifyStatic;
+import static se.leap.bitmaskclient.testutils.MockHelper.mockFileHelper;
+import static se.leap.bitmaskclient.testutils.MockHelper.mockInputStreamHelper;
+
+/**
+ * Created by cyberta on 20.02.18.
+ */
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({ConfigHelper.class, FileHelper.class, InputStreamHelper.class})
+public class ProviderManagerTest {
+
+ @Mock
+ private AssetManager assetManager;
+ @Mock
+ private File file;
+ private ProviderManager providerManager;
+
+ @Before
+ public void setup() throws Exception {
+ //mock assetManager methods
+ //--------------------------
+ when(assetManager.open(anyString())).thenAnswer(new Answer<InputStream>() {
+ @Override
+ public InputStream answer(InvocationOnMock invocation) throws Throwable {
+ String filename = "preconfigured/" + invocation.getArguments()[0];
+ return getClass().getClassLoader().getResourceAsStream(filename);
+ }
+ });
+ when(assetManager.list(anyString())).thenAnswer(new Answer<String[]>() {
+ @Override
+ public String[] answer(InvocationOnMock invocation) throws Throwable {
+ String path = (String) invocation.getArguments()[0];
+ if ("urls".equals(path)) {
+ String[] preconfiguredUrls = new String[3];
+ preconfiguredUrls[0] = "calyx.net.url";
+ preconfiguredUrls[1] = "demo.bitmask.net.url";
+ preconfiguredUrls[2] = "riseup.net.url";
+ return preconfiguredUrls;
+ } else
+ throw new IllegalArgumentException("You need to implement the expected path manually!");
+ }
+ });
+
+ //mock File methods
+ //------------------
+ when(file.isDirectory()).thenReturn(true);
+
+ ArrayList<String> mockedCustomProviderList = new ArrayList<>();
+ mockedCustomProviderList.add("leapcolombia.json");
+ String[] mockedCustomProviderArray = new String[mockedCustomProviderList.size()];
+ mockedCustomProviderArray = mockedCustomProviderList.toArray(mockedCustomProviderArray);
+ when(file.list()).thenReturn(mockedCustomProviderArray);
+
+ when(file.getAbsolutePath()).thenReturn("externalDir");
+ when(file.getPath()).thenReturn("externalDir");
+ mockFileHelper(file);
+
+ // mock inputStream
+ //-----------------------------------
+ mockInputStreamHelper();
+
+ }
+
+ @After
+ public void tearDown() {
+ ProviderManager.reset();
+ }
+
+ @Test
+ public void testSize_has5ProvidersWithCurrentTestSetup() {
+ providerManager = ProviderManager.getInstance(assetManager, file);
+ assertEquals("3 preconfigured, 1 custom provider, 1 dummy provider", 5, providerManager.size());
+ }
+
+ @Test
+ public void testAdd_newCustomProviderThatIsNotPartOfDefaultNorCustomList_returnTrue() throws Exception {
+ providerManager = ProviderManager.getInstance(assetManager, file);
+ Provider customProvider = new Provider("https://anewprovider.org");
+ assertTrue("custom provider added: ", providerManager.add(customProvider));
+ assertEquals("3 preconfigured, 2 custom providers, 1 dummy provider", 6, providerManager.providers().size());
+ }
+
+ @Test
+ public void testAdd_newCustomProviderThatIsNotPartOfDefaultButOfCustomList_returnFalse() throws Exception {
+ providerManager = ProviderManager.getInstance(assetManager, file);
+ Provider customProvider = new Provider("https://leapcolombia.org");
+ assertFalse("custom provider added: ", providerManager.add(customProvider));
+ assertEquals("3 preconfigured, 1 custom provider, 1 dummy provider", 5, providerManager.providers().size());
+ }
+
+ @Test
+ public void testAdd_newCustomProviderThatIsPartOfDefaultButNotOfCustomList_returnFalse() throws Exception {
+ providerManager = ProviderManager.getInstance(assetManager, file);
+ Provider customProvider = new Provider("https://demo.bitmask.net");
+ assertFalse("custom provider added: ", providerManager.add(customProvider));
+ assertEquals("3 preconfigured, 1 custom provider, 1 dummy provider", 5, providerManager.providers().size());
+ }
+
+ @Test
+ public void testRemove_ProviderIsPartOfDefaultButNotCustomList_returnsFalse() throws Exception {
+ providerManager = ProviderManager.getInstance(assetManager, file);
+ Provider customProvider = new Provider("https://demo.bitmask.net");
+ assertFalse("custom provider not removed: ", providerManager.remove(customProvider));
+ assertEquals("3 preconfigured, 1 custom provider, 1 dummy provider", 5, providerManager.providers().size());
+ }
+
+ @Test
+ public void testRemove_ProviderIsNotPartOfDefaultButOfCustomList_returnsTrue() throws Exception {
+ providerManager = ProviderManager.getInstance(assetManager, file);
+ Provider customProvider = new Provider("https://leapcolombia.org");
+ assertTrue("custom provider not removed: ", providerManager.remove(customProvider));
+ assertEquals("3 preconfigured, 0 custom providers, 1 dummy provider", 4, providerManager.providers().size());
+ }
+
+ @Test
+ public void testRemove_ProviderIsNotPartOfDefaultNorOfCustomList_returnsFalse() throws Exception {
+ providerManager = ProviderManager.getInstance(assetManager, file);
+ Provider customProvider = new Provider("https://anotherprovider.org");
+ assertFalse("custom provider not removed: ", providerManager.remove(customProvider));
+ assertEquals("3 preconfigured, 1 custom providers, 1 dummy provider", 5, providerManager.providers().size());
+ }
+
+ @Test
+ public void testClear_ProvidersListHasOnlyDummyProvider() throws Exception {
+ providerManager = ProviderManager.getInstance(assetManager, file);
+ providerManager.clear();
+ assertEquals("1 providers", 1, providerManager.providers().size());
+ assertEquals("provider is dummy element", "https://example.net", providerManager.get(0).getMainUrlString());
+ }
+
+ @Test
+ public void testSaveCustomProvidersToFile_CustomProviderDeleted_deletesFromDir() throws Exception {
+ when(file.exists()).thenReturn(true);
+ providerManager = ProviderManager.getInstance(assetManager, file);
+ //leapcolombia is mocked custom provider from setup
+ Provider customProvider = new Provider("https://leapcolombia.org");
+ providerManager.remove(customProvider);
+ providerManager.saveCustomProvidersToFile();
+ verify(file, times(1)).delete();
+ }
+
+
+ @Test
+ public void testSaveCustomProvidersToFile_newCustomProviders_persistNew() throws Exception {
+ when(file.list()).thenReturn(new String[0]);
+ when(file.exists()).thenReturn(false);
+ providerManager = ProviderManager.getInstance(assetManager, file);
+ Provider customProvider = new Provider("https://anotherprovider.org");
+ Provider secondCustomProvider = new Provider("https://yetanotherprovider.org");
+ providerManager.add(customProvider);
+ providerManager.add(secondCustomProvider);
+ providerManager.saveCustomProvidersToFile();
+
+ verifyStatic(FileHelper.class, times(2));
+ FileHelper.persistFile(any(File.class), anyString());
+ }
+
+
+} \ No newline at end of file