From c4a1295095a57a8f0b224d4922576e412572eb11 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 8 Apr 2016 12:25:48 -0400 Subject: [PATCH 1/6] move Theme handling to Preferences class This is one of the last instances of direct SharedPreferences manipulation in the code. Moving it to Preferences like the rest. --- .../main/java/org/fdroid/fdroid/FDroidApp.java | 16 +++------------- .../main/java/org/fdroid/fdroid/Preferences.java | 11 +++++++++++ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java index df06334e8..57862494b 100644 --- a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java +++ b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java @@ -49,6 +49,7 @@ import org.acra.ReportingInteractionMode; import org.acra.annotation.ReportsCrashes; import org.apache.commons.net.util.SubnetUtils; import org.fdroid.fdroid.Preferences.ChangeListener; +import org.fdroid.fdroid.Preferences.Theme; import org.fdroid.fdroid.compat.PRNGFixes; import org.fdroid.fdroid.data.AppProvider; import org.fdroid.fdroid.data.InstalledAppCacheUpdater; @@ -96,19 +97,10 @@ public class FDroidApp extends Application { enableSpongyCastle(); } - public enum Theme { - light, - dark, - night, - lightWithDarkActionBar, // Obsolete - } - private static Theme curTheme = Theme.light; public void reloadTheme() { - curTheme = Theme.valueOf(PreferenceManager - .getDefaultSharedPreferences(getBaseContext()) - .getString(Preferences.PREF_THEME, Preferences.DEFAULT_THEME)); + curTheme = Preferences.get().getTheme(); } public void applyTheme(Activity activity) { @@ -194,6 +186,7 @@ public class FDroidApp extends Application { // Perhaps the constructor is a better place, but then again, // it is more deterministic as to when this gets called... Preferences.setup(this); + curTheme = Preferences.get().getTheme(); // Apply the Google PRNG fixes to properly seed SecureRandom PRNGFixes.apply(); @@ -241,9 +234,6 @@ public class FDroidApp extends Application { // been installed, but this causes problems for proprietary gapps // users since the introduction of verification (on pre-4.2 Android), // because the install intent says it's finished when it hasn't. - SharedPreferences prefs = PreferenceManager - .getDefaultSharedPreferences(getBaseContext()); - curTheme = Theme.valueOf(prefs.getString(Preferences.PREF_THEME, Preferences.DEFAULT_THEME)); Utils.deleteFiles(Utils.getApkDownloadDir(this), null, ".apk"); if (!Preferences.get().shouldCacheApks()) { Utils.deleteFiles(Utils.getApkCacheDir(this), null, ".apk"); diff --git a/app/src/main/java/org/fdroid/fdroid/Preferences.java b/app/src/main/java/org/fdroid/fdroid/Preferences.java index 17fd38081..99670579f 100644 --- a/app/src/main/java/org/fdroid/fdroid/Preferences.java +++ b/app/src/main/java/org/fdroid/fdroid/Preferences.java @@ -85,6 +85,13 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh private static final boolean DEFAULT_FIRST_TIME = true; private static final boolean DEFAULT_POST_PRIVILEGED_INSTALL = false; + public enum Theme { + light, + dark, + night, + lightWithDarkActionBar, // Obsolete + } + private boolean filterAppsRequiringRoot = DEFAULT_ROOTED; private final Map initialized = new HashMap<>(); @@ -155,6 +162,10 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh return preferences.getBoolean(PREF_EXPERT, DEFAULT_EXPERT); } + public Theme getTheme() { + return Theme.valueOf(preferences.getString(Preferences.PREF_THEME, Preferences.DEFAULT_THEME)); + } + public boolean isLocalRepoHttpsEnabled() { return false; // disabled until it works well } From b86a30d40f1459bc40e78f6aa848560beded4854 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 11 Apr 2016 10:32:55 -0400 Subject: [PATCH 2/6] fix expert mode version display when maxSdkVersion is MAX_VALUE closes #616 https://gitlab.com/fdroid/fdroidclient/issues/616 --- app/src/main/java/org/fdroid/fdroid/AppDetails.java | 2 +- app/src/main/java/org/fdroid/fdroid/data/Apk.java | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/AppDetails.java b/app/src/main/java/org/fdroid/fdroid/AppDetails.java index 5cda16ec3..26668808c 100644 --- a/app/src/main/java/org/fdroid/fdroid/AppDetails.java +++ b/app/src/main/java/org/fdroid/fdroid/AppDetails.java @@ -247,7 +247,7 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A if (!Preferences.get().expertMode()) { holder.api.setVisibility(View.GONE); - } else if (apk.minSdkVersion > 0 && apk.maxSdkVersion > 0) { + } else if (apk.minSdkVersion > 0 && apk.maxSdkVersion < Apk.SDK_VERSION_MAX_VALUE) { holder.api.setText(getString(R.string.minsdk_up_to_maxsdk, Utils.getAndroidVersionName(apk.minSdkVersion), Utils.getAndroidVersionName(apk.maxSdkVersion))); diff --git a/app/src/main/java/org/fdroid/fdroid/data/Apk.java b/app/src/main/java/org/fdroid/fdroid/data/Apk.java index 09f694bf0..1e7dc633f 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/Apk.java +++ b/app/src/main/java/org/fdroid/fdroid/data/Apk.java @@ -11,6 +11,9 @@ import java.util.Date; public class Apk extends ValueObject implements Comparable { + // Using only byte-range keeps it only 8-bits in the SQLite database + public static final int SDK_VERSION_MAX_VALUE = Byte.MAX_VALUE; + public String packageName; public String version; public int vercode; @@ -19,7 +22,7 @@ public class Apk extends ValueObject implements Comparable { public String hash; public String hashType; public int minSdkVersion; // 0 if unknown - public int maxSdkVersion = Byte.MAX_VALUE; // "infinity" if not set + public int maxSdkVersion = SDK_VERSION_MAX_VALUE; // "infinity" if not set public Date added; public Utils.CommaSeparatedList permissions; // null if empty or // unknown From eb93a38cf56358df3b1aa5f8feb1f60e861ba5d2 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 5 Apr 2016 22:12:44 +0200 Subject: [PATCH 3/6] HttpDownloader: handle SSL errors like any other download error Since SSLHandshakeException is a subclass of IOException, and all that is happening is rethrowing an Exception, instead pass this one through so it will be handled by the central Downloader error handling. That's currently just a Toast, but it can easily be expanded in the future. --- .../org/fdroid/fdroid/net/HttpDownloader.java | 30 +++++++------------ 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/net/HttpDownloader.java b/app/src/main/java/org/fdroid/fdroid/net/HttpDownloader.java index f9d7ece2b..20dc237f2 100644 --- a/app/src/main/java/org/fdroid/fdroid/net/HttpDownloader.java +++ b/app/src/main/java/org/fdroid/fdroid/net/HttpDownloader.java @@ -1,7 +1,5 @@ package org.fdroid.fdroid.net; -import android.util.Log; - import com.nostra13.universalimageloader.core.download.BaseImageDownloader; import org.fdroid.fdroid.FDroidApp; @@ -18,7 +16,6 @@ import java.net.MalformedURLException; import java.net.URL; import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLHandshakeException; import info.guardianproject.netcipher.NetCipher; @@ -72,25 +69,18 @@ public class HttpDownloader extends Downloader { return new BufferedInputStream(connection.getInputStream()); } - // Get a remote file. Returns the HTTP response code. - // If 'etag' is not null, it's passed to the server as an If-None-Match - // header, in which case expect a 304 response if nothing changed. - // In the event of a 200 response ONLY, 'retag' (which should be passed - // empty) may contain an etag value for the response, or it may be left - // empty if none was available. + /** + * Get a remote file, checking the HTTP response code. If 'etag' is not + * {@code null}, it's passed to the server as an If-None-Match header, in + * which case expect a 304 response if nothing changed. In the event of a + * 200 response ONLY, 'retag' (which should be passed empty) may contain + * an etag value for the response, or it may be left empty if none was + * available. + */ @Override public void download() throws IOException, InterruptedException { - try { - setupConnection(); - doDownload(); - } catch (SSLHandshakeException e) { - // TODO this should be handled better, it is not internationalised here - throw new IOException( - "A problem occurred while establishing an SSL " + - "connection. If this problem persists, AND you have a " + - "very old device, you could try using http instead of " + - "https for the repo URL." + Log.getStackTraceString(e)); - } + setupConnection(); + doDownload(); } private boolean isSwapUrl() { From 6b3004160fcce346e3836dc4f424653a826fb833 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 5 Apr 2016 23:30:59 +0200 Subject: [PATCH 4/6] HttpDownloaderTest: delete test files only if test succeeds This helps with debugging. And since these tests run on the JVM, deleteOnExit() actually works. --- .../fdroid/fdroid/net/HttpDownloaderTest.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/test/java/org/fdroid/fdroid/net/HttpDownloaderTest.java b/app/src/test/java/org/fdroid/fdroid/net/HttpDownloaderTest.java index 7075e3260..9d92fa74e 100644 --- a/app/src/test/java/org/fdroid/fdroid/net/HttpDownloaderTest.java +++ b/app/src/test/java/org/fdroid/fdroid/net/HttpDownloaderTest.java @@ -32,11 +32,11 @@ public class HttpDownloaderTest { for (String urlString : urls) { URL url = new URL(urlString); File destFile = File.createTempFile("dl-", ""); - destFile.deleteOnExit(); // this probably does nothing, but maybe... HttpDownloader httpDownloader = new HttpDownloader(url, destFile); httpDownloader.download(); assertTrue(destFile.exists()); assertTrue(destFile.canRead()); + destFile.deleteOnExit(); } } @@ -46,7 +46,6 @@ public class HttpDownloaderTest { receivedProgress = false; URL url = new URL(urlString); File destFile = File.createTempFile("dl-", ""); - destFile.deleteOnExit(); // this probably does nothing, but maybe... HttpDownloader httpDownloader = new HttpDownloader(url, destFile); httpDownloader.setListener(new Downloader.DownloaderProgressListener() { @Override @@ -58,6 +57,7 @@ public class HttpDownloaderTest { assertTrue(destFile.exists()); assertTrue(destFile.canRead()); assertTrue(receivedProgress); + destFile.deleteOnExit(); } } @@ -65,39 +65,38 @@ public class HttpDownloaderTest { public void downloadHttpBasicAuth() throws IOException, InterruptedException { URL url = new URL("https://httpbin.org/basic-auth/myusername/supersecretpassword"); File destFile = File.createTempFile("dl-", ""); - destFile.deleteOnExit(); // this probably does nothing, but maybe... HttpDownloader httpDownloader = new HttpDownloader(url, destFile, "myusername", "supersecretpassword"); httpDownloader.download(); assertTrue(destFile.exists()); assertTrue(destFile.canRead()); + destFile.deleteOnExit(); } @Test(expected = IOException.class) public void downloadHttpBasicAuthWrongPassword() throws IOException, InterruptedException { URL url = new URL("https://httpbin.org/basic-auth/myusername/supersecretpassword"); File destFile = File.createTempFile("dl-", ""); - destFile.deleteOnExit(); // this probably does nothing, but maybe... HttpDownloader httpDownloader = new HttpDownloader(url, destFile, "myusername", "wrongpassword"); httpDownloader.download(); assertFalse(destFile.exists()); + destFile.deleteOnExit(); } @Test(expected = IOException.class) public void downloadHttpBasicAuthWrongUsername() throws IOException, InterruptedException { URL url = new URL("https://httpbin.org/basic-auth/myusername/supersecretpassword"); File destFile = File.createTempFile("dl-", ""); - destFile.deleteOnExit(); // this probably does nothing, but maybe... HttpDownloader httpDownloader = new HttpDownloader(url, destFile, "wrongusername", "supersecretpassword"); httpDownloader.download(); assertFalse(destFile.exists()); + destFile.deleteOnExit(); } @Test public void downloadThenCancel() throws IOException, InterruptedException { - final CountDownLatch latch = new CountDownLatch(5); + final CountDownLatch latch = new CountDownLatch(2); URL url = new URL("https://f-droid.org/repo/index.jar"); File destFile = File.createTempFile("dl-", ""); - destFile.deleteOnExit(); // this probably does nothing, but maybe... final HttpDownloader httpDownloader = new HttpDownloader(url, destFile); httpDownloader.setListener(new Downloader.DownloaderProgressListener() { @Override @@ -121,8 +120,9 @@ public class HttpDownloaderTest { } } }.start(); - latch.await(100, TimeUnit.SECONDS); // either 5 progress reports or 100 seconds + latch.await(100, TimeUnit.SECONDS); // either 2 progress reports or 100 seconds httpDownloader.cancelDownload(); assertTrue(receivedProgress); + destFile.deleteOnExit(); } } From 22e40bfee15953989ee57936fe11542a71298c8f Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 25 Mar 2016 12:25:25 +0100 Subject: [PATCH 5/6] port all but Provider tests to JUnit4 semantics Android recently switched from JUnit 3 to 4 for its base testing classes. It doesn't seem to support the old JUnit3 methods with gradle and AS. So all the tests need to be ported to JUnit4 to work again. #607 https://gitlab.com/fdroid/fdroidclient/issues/607 --- app/build.gradle | 8 +++ .../java/org/fdroid/fdroid/FDroidTest.java | 14 ----- .../org/fdroid/fdroid/FileCompatTest.java | 31 +++++++++-- .../org/fdroid/fdroid/RepoUpdaterTest.java | 46 ++++++++++------ .../org/fdroid/fdroid/RepoXMLHandlerTest.java | 25 +++++---- .../java/org/fdroid/fdroid/UtilsTest.java | 52 +++++++++++-------- 6 files changed, 108 insertions(+), 68 deletions(-) delete mode 100644 app/src/androidTest/java/org/fdroid/fdroid/FDroidTest.java diff --git a/app/build.gradle b/app/build.gradle index ae3c59e49..168b59458 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,6 +30,10 @@ dependencies { compile 'io.reactivex:rxandroid:0.23.0' testCompile 'junit:junit:4.12' + + androidTestCompile 'com.android.support:support-annotations:23.2.1' + androidTestCompile 'com.android.support.test:runner:0.5' + androidTestCompile 'com.android.support.test:rules:0.5' } if (!hasProperty('sourceDeps')) { @@ -147,6 +151,10 @@ android { targetCompatibility JavaVersion.VERSION_1_7 } + defaultConfig { + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + testOptions { // prevent tests from dying on android.util.Log calls unitTests.returnDefaultValues = true diff --git a/app/src/androidTest/java/org/fdroid/fdroid/FDroidTest.java b/app/src/androidTest/java/org/fdroid/fdroid/FDroidTest.java deleted file mode 100644 index 07d9f3ee3..000000000 --- a/app/src/androidTest/java/org/fdroid/fdroid/FDroidTest.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.fdroid.fdroid; - -import android.annotation.TargetApi; -import android.os.Build; -import android.test.ActivityInstrumentationTestCase2; - -@TargetApi(Build.VERSION_CODES.CUPCAKE) -public class FDroidTest extends ActivityInstrumentationTestCase2 { - - public FDroidTest() { - super("org.fdroid.fdroid", FDroid.class); - } - -} diff --git a/app/src/androidTest/java/org/fdroid/fdroid/FileCompatTest.java b/app/src/androidTest/java/org/fdroid/fdroid/FileCompatTest.java index 53be0b601..97fe44ecf 100644 --- a/app/src/androidTest/java/org/fdroid/fdroid/FileCompatTest.java +++ b/app/src/androidTest/java/org/fdroid/fdroid/FileCompatTest.java @@ -1,17 +1,32 @@ package org.fdroid.fdroid; +import android.app.Instrumentation; import android.os.Build; -import android.test.InstrumentationTestCase; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; import android.util.Log; import org.fdroid.fdroid.compat.FileCompatForTest; import org.fdroid.fdroid.data.SanitizedFile; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; import java.io.File; import java.util.UUID; -@SuppressWarnings("PMD") // TODO port this to JUnit 4 semantics -public class FileCompatTest extends InstrumentationTestCase { +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + + +/** + * This test needs to run on the emulator, even though it technically could + * run as a plain JUnit test, because it is testing the specifics of + * Android's symlink handling. + */ +@RunWith(AndroidJUnit4.class) +public class FileCompatTest { private static final String TAG = "FileCompatTest"; @@ -19,14 +34,17 @@ public class FileCompatTest extends InstrumentationTestCase { private SanitizedFile sourceFile; private SanitizedFile destFile; + @Before public void setUp() { - dir = TestUtils.getWriteableDir(getInstrumentation()); - sourceFile = SanitizedFile.knownSanitized(TestUtils.copyAssetToDir(getInstrumentation().getContext(), "simpleIndex.jar", dir)); + Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); + dir = TestUtils.getWriteableDir(instrumentation); + sourceFile = SanitizedFile.knownSanitized(TestUtils.copyAssetToDir(instrumentation.getContext(), "simpleIndex.jar", dir)); destFile = new SanitizedFile(dir, "dest-" + UUID.randomUUID() + ".testproduct"); assertFalse(destFile.exists()); assertTrue(sourceFile.getAbsolutePath() + " should exist.", sourceFile.exists()); } + @After public void tearDown() { if (!sourceFile.delete()) { System.out.println("Can't delete " + sourceFile.getAbsolutePath() + "."); @@ -37,11 +55,13 @@ public class FileCompatTest extends InstrumentationTestCase { } } + @Test public void testSymlinkRuntime() { FileCompatForTest.symlinkRuntimeTest(sourceFile, destFile); assertTrue(destFile.getAbsolutePath() + " should exist after symlinking", destFile.exists()); } + @Test public void testSymlinkLibcore() { if (Build.VERSION.SDK_INT >= 19) { @@ -52,6 +72,7 @@ public class FileCompatTest extends InstrumentationTestCase { } } + @Test public void testSymlinkOs() { if (Build.VERSION.SDK_INT >= 21) { diff --git a/app/src/androidTest/java/org/fdroid/fdroid/RepoUpdaterTest.java b/app/src/androidTest/java/org/fdroid/fdroid/RepoUpdaterTest.java index 8aa99a9e1..95c95b65f 100644 --- a/app/src/androidTest/java/org/fdroid/fdroid/RepoUpdaterTest.java +++ b/app/src/androidTest/java/org/fdroid/fdroid/RepoUpdaterTest.java @@ -1,16 +1,23 @@ package org.fdroid.fdroid; +import android.app.Instrumentation; import android.content.Context; -import android.test.InstrumentationTestCase; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; import org.fdroid.fdroid.RepoUpdater.UpdateException; import org.fdroid.fdroid.data.Repo; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; import java.io.File; -@SuppressWarnings("PMD") // TODO port this to JUnit 4 semantics -public class RepoUpdaterTest extends InstrumentationTestCase { +import static org.junit.Assert.fail; + +@RunWith(AndroidJUnit4.class) +public class RepoUpdaterTest { private static final String TAG = "RepoUpdaterTest"; private Context context; @@ -19,15 +26,17 @@ public class RepoUpdaterTest extends InstrumentationTestCase { String simpleIndexPubkey = "308201ee30820157a0030201020204300d845b300d06092a864886f70d01010b0500302a3110300e060355040b1307462d44726f6964311630140603550403130d70616c6174736368696e6b656e301e170d3134303432373030303633315a170d3431303931323030303633315a302a3110300e060355040b1307462d44726f6964311630140603550403130d70616c6174736368696e6b656e30819f300d06092a864886f70d010101050003818d0030818902818100a439472e4b6d01141bfc94ecfe131c7c728fdda670bb14c57ca60bd1c38a8b8bc0879d22a0a2d0bc0d6fdd4cb98d1d607c2caefbe250a0bd0322aedeb365caf9b236992fac13e6675d3184a6c7c6f07f73410209e399a9da8d5d7512bbd870508eebacff8b57c3852457419434d34701ccbf692267cbc3f42f1c5d1e23762d790203010001a321301f301d0603551d0e041604140b1840691dab909746fde4bfe28207d1cae15786300d06092a864886f70d01010b05000381810062424c928ffd1b6fd419b44daafef01ca982e09341f7077fb865905087aeac882534b3bd679b51fdfb98892cef38b63131c567ed26c9d5d9163afc775ac98ad88c405d211d6187bde0b0d236381cc574ba06ef9080721a92ae5a103a7301b2c397eecc141cc850dd3e123813ebc41c59d31ddbcb6e984168280c53272f6a442b"; - @Override - protected void setUp() { - context = getInstrumentation().getContext(); - testFilesDir = TestUtils.getWriteableDir(getInstrumentation()); + @Before + public void setUp() { + Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); + context = instrumentation.getContext(); + testFilesDir = TestUtils.getWriteableDir(instrumentation); Repo repo = new Repo(); repo.pubkey = this.simpleIndexPubkey; repoUpdater = new RepoUpdater(context, repo); } + @Test public void testExtractIndexFromJar() { if (!testFilesDir.canWrite()) { return; @@ -43,20 +52,17 @@ public class RepoUpdaterTest extends InstrumentationTestCase { } } - public void testExtractIndexFromJarWithoutSignatureJar() { + @Test(expected = UpdateException.class) + public void testExtractIndexFromJarWithoutSignatureJar() throws UpdateException { if (!testFilesDir.canWrite()) { return; } // this is supposed to fail - try { - File jarFile = TestUtils.copyAssetToDir(context, "simpleIndexWithoutSignature.jar", testFilesDir); - repoUpdater.processDownloadedFile(jarFile); - fail(); - } catch (UpdateException e) { - // success! - } + File jarFile = TestUtils.copyAssetToDir(context, "simpleIndexWithoutSignature.jar", testFilesDir); + repoUpdater.processDownloadedFile(jarFile); } + @Test public void testExtractIndexFromJarWithCorruptedManifestJar() { if (!testFilesDir.canWrite()) { return; @@ -74,6 +80,7 @@ public class RepoUpdaterTest extends InstrumentationTestCase { } } + @Test public void testExtractIndexFromJarWithCorruptedSignature() { if (!testFilesDir.canWrite()) { return; @@ -91,6 +98,7 @@ public class RepoUpdaterTest extends InstrumentationTestCase { } } + @Test public void testExtractIndexFromJarWithCorruptedCertificate() { if (!testFilesDir.canWrite()) { return; @@ -108,6 +116,7 @@ public class RepoUpdaterTest extends InstrumentationTestCase { } } + @Test public void testExtractIndexFromJarWithCorruptedEverything() { if (!testFilesDir.canWrite()) { return; @@ -125,6 +134,7 @@ public class RepoUpdaterTest extends InstrumentationTestCase { } } + @Test public void testExtractIndexFromMasterKeyIndexJar() { if (!testFilesDir.canWrite()) { return; @@ -133,8 +143,10 @@ public class RepoUpdaterTest extends InstrumentationTestCase { try { File jarFile = TestUtils.copyAssetToDir(context, "masterKeyIndex.jar", testFilesDir); repoUpdater.processDownloadedFile(jarFile); - fail(); - } catch (UpdateException | SecurityException e) { + fail(); //NOPMD + } catch (UpdateException e) { + // success! + } catch (SecurityException e) { // success! } } diff --git a/app/src/androidTest/java/org/fdroid/fdroid/RepoXMLHandlerTest.java b/app/src/androidTest/java/org/fdroid/fdroid/RepoXMLHandlerTest.java index dcbb8bd43..041f5b0e8 100644 --- a/app/src/androidTest/java/org/fdroid/fdroid/RepoXMLHandlerTest.java +++ b/app/src/androidTest/java/org/fdroid/fdroid/RepoXMLHandlerTest.java @@ -2,7 +2,7 @@ package org.fdroid.fdroid; import android.support.annotation.NonNull; -import android.test.AndroidTestCase; +import android.support.test.runner.AndroidJUnit4; import android.text.TextUtils; import android.util.Log; @@ -10,6 +10,8 @@ import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.Repo; import org.fdroid.fdroid.mock.MockRepo; +import org.junit.Test; +import org.junit.runner.RunWith; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; @@ -24,20 +26,18 @@ import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; -@SuppressWarnings("PMD") // TODO port this to JUnit 4 semantics -public class RepoXMLHandlerTest extends AndroidTestCase { +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +@RunWith(AndroidJUnit4.class) +public class RepoXMLHandlerTest { private static final String TAG = "RepoXMLHandlerTest"; private static final String FAKE_PUBKEY = "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345"; - public RepoXMLHandlerTest() { - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - } - + @Test public void testSimpleIndex() { Repo expectedRepo = new Repo(); expectedRepo.name = "F-Droid"; @@ -47,6 +47,7 @@ public class RepoXMLHandlerTest extends AndroidTestCase { handlerTestSuite(expectedRepo, actualDetails, 0, 0, -1, 12); } + @Test public void testSmallRepo() { Repo expectedRepo = new Repo(); expectedRepo.name = "Android-Nexus-7-20139453 on UNSET"; @@ -70,6 +71,7 @@ public class RepoXMLHandlerTest extends AndroidTestCase { }); } + @Test public void testMediumRepo() { Repo expectedRepo = new Repo(); expectedRepo.name = "Guardian Project Official Releases"; @@ -96,6 +98,7 @@ public class RepoXMLHandlerTest extends AndroidTestCase { }); } + @Test public void testLargeRepo() { Repo expectedRepo = new Repo(); expectedRepo.name = "F-Droid"; diff --git a/app/src/androidTest/java/org/fdroid/fdroid/UtilsTest.java b/app/src/androidTest/java/org/fdroid/fdroid/UtilsTest.java index 7e4265f56..da038dd10 100644 --- a/app/src/androidTest/java/org/fdroid/fdroid/UtilsTest.java +++ b/app/src/androidTest/java/org/fdroid/fdroid/UtilsTest.java @@ -1,10 +1,19 @@ package org.fdroid.fdroid; -import android.test.AndroidTestCase; +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; -@SuppressWarnings("PMD") // TODO port this to JUnit 4 semantics -public class UtilsTest extends AndroidTestCase { +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +@RunWith(AndroidJUnit4.class) +public class UtilsTest { String fdroidFingerprint = "43238D512C1E5EB2D6569F4A3AFBF5523418B82E0A3ED1552770ABB9A9C9CCAB"; String fdroidPubkey = "3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef"; @@ -34,57 +43,60 @@ public class UtilsTest extends AndroidTestCase { String fingerprintLongByOneFingerprint = "59050C8155DCA377F23D5A15B77D37134000CDBD8B42FBFBE0E3F38096E68CECE"; String fingerprintLongByOnePubkey = "308203c5308202ada00302010202047b7cf549300d06092a864886f70d01010b0500308192310b30090603550406130255533111300f060355040813084e657720596f726b3111300f060355040713084e657720596f726b311d301b060355040a131454686520477561726469616e2050726f6a656374311f301d060355040b1316477561726469616e20462d44726f6964204275696c64311d301b06035504031314677561726469616e70726f6a6563742e696e666f301e170d3132313032393130323530305a170d3430303331363130323530305a308192310b30090603550406130255533111300f060355040813084e657720596f726b3111300f060355040713084e657720596f726b311d301b060355040a131454686520477561726469616e2050726f6a656374311f301d060355040b1316477561726469616e20462d44726f6964204275696c64311d301b06035504031314677561726469616e70726f6a6563742e696e666f30820122300d06092a864886f70d01010105000382010f003082010a0282010100b7f1f635fa3fce1a8042aaa960c2dc557e4ad2c082e5787488cba587fd26207cf59507919fc4dcebda5c8c0959d14146d0445593aa6c29dc639570b71712451fd5c231b0c9f5f0bec380503a1c2a3bc00048bc5db682915afa54d1ecf67b45e1e05c0934b3037a33d3a565899131f27a72c03a5de93df17a2376cc3107f03ee9d124c474dfab30d4053e8f39f292e2dcb6cc131bce12a0c5fc307985195d256bf1d7a2703d67c14bf18ed6b772bb847370b20335810e337c064fef7e2795a524c664a853cd46accb8494f865164dabfb698fa8318236432758bc40d52db00d5ce07fe2210dc06cd95298b4f09e6c9b7b7af61c1d62ea43ea36a2331e7b2d4e250203010001a321301f301d0603551d0e0416041404d763e981cf3a295b94a790d8536a783097232b300d06092a864886f70d01010b05000382010100654e6484ff032c54fed1d96d3c8e731302be9dbd7bb4fe635f2dac05b69f3ecbb5acb7c9fe405e2a066567a8f5c2beb8b199b5a4d5bb1b435cf02df026d4fb4edd9d8849078f085b00950083052d57467d65c6eebd98f037cff9b148d621cf8819c4f7dc1459bf8fc5c7d76f901495a7caf35d1e5c106e1d50610c4920c3c1b50adcfbd4ad83ce7353cdea7d856bba0419c224f89a2f3ebc203d20eb6247711ad2b55fd4737936dc42ced7a047cbbd24012079204a2883b6d55d5d5b66d9fd82fb51fca9a5db5fad9af8564cb380ff30ae8263dbbf01b46e01313f53279673daa3f893380285646b244359203e7eecde94ae141b7dfa8e6499bb8e7e0b25ab85"; + @Test public void testFormatFingerprint() { - String badResult = Utils.formatFingerprint(getContext(), ""); + Context context = InstrumentationRegistry.getTargetContext(); + String badResult = Utils.formatFingerprint(context, ""); // real fingerprints String formatted; - formatted = Utils.formatFingerprint(getContext(), fdroidFingerprint); + formatted = Utils.formatFingerprint(context, fdroidFingerprint); assertFalse(formatted.equals(badResult)); assertTrue(formatted.matches("[A-Z0-9][A-Z0-9] [A-Z0-9 ]+")); - formatted = Utils.formatFingerprint(getContext(), gpRepoFingerprint); + formatted = Utils.formatFingerprint(context, gpRepoFingerprint); assertFalse(formatted.equals(badResult)); assertTrue(formatted.matches("[A-Z0-9][A-Z0-9] [A-Z0-9 ]+")); - formatted = Utils.formatFingerprint(getContext(), gpTest1Fingerprint); + formatted = Utils.formatFingerprint(context, gpTest1Fingerprint); assertFalse(formatted.equals(badResult)); assertTrue(formatted.matches("[A-Z0-9][A-Z0-9] [A-Z0-9 ]+")); // random garbage assertEquals( badResult, - Utils.formatFingerprint(getContext(), "234k2lk3jljwlk4j2lk3jlkmqwekljrlkj34lk2jlk2j34lkjl2k3j4lk2j34lja")); + Utils.formatFingerprint(context, "234k2lk3jljwlk4j2lk3jlkmqwekljrlkj34lk2jlk2j34lkjl2k3j4lk2j34lja")); assertEquals( badResult, - Utils.formatFingerprint(getContext(), "g000000000000000000000000000000000000000000000000000000000000000")); + Utils.formatFingerprint(context, "g000000000000000000000000000000000000000000000000000000000000000")); assertEquals( badResult, - Utils.formatFingerprint(getContext(), "98273498723948728934789237489273p1928731982731982739182739817238")); + Utils.formatFingerprint(context, "98273498723948728934789237489273p1928731982731982739182739817238")); // too short assertEquals( badResult, - Utils.formatFingerprint(getContext(), "C63AED1AC79D37C7B0474472AC6EFA6C3AB2B11A767A4F42CF360FA5496E3C5")); + Utils.formatFingerprint(context, "C63AED1AC79D37C7B0474472AC6EFA6C3AB2B11A767A4F42CF360FA5496E3C5")); assertEquals( badResult, - Utils.formatFingerprint(getContext(), "C63AED1")); + Utils.formatFingerprint(context, "C63AED1")); assertEquals( badResult, - Utils.formatFingerprint(getContext(), "f")); + Utils.formatFingerprint(context, "f")); assertEquals( badResult, - Utils.formatFingerprint(getContext(), "")); + Utils.formatFingerprint(context, "")); assertEquals( badResult, - Utils.formatFingerprint(getContext(), null)); + Utils.formatFingerprint(context, null)); // real digits but too long assertEquals( badResult, - Utils.formatFingerprint(getContext(), "43238D512C1E5EB2D6569F4A3AFBF5523418B82E0A3ED1552770ABB9A9C9CCAB43238D512C1E5EB2D6569F4A3AFBF5523418B82E0A3ED1552770ABB9A9C9CCAB")); + Utils.formatFingerprint(context, "43238D512C1E5EB2D6569F4A3AFBF5523418B82E0A3ED1552770ABB9A9C9CCAB43238D512C1E5EB2D6569F4A3AFBF5523418B82E0A3ED1552770ABB9A9C9CCAB")); assertEquals( badResult, - Utils.formatFingerprint(getContext(), "C63AED1AC79D37C7B0474472AC6EFA6C3AB2B11A767A4F42CF360FA5496E3C50F")); + Utils.formatFingerprint(context, "C63AED1AC79D37C7B0474472AC6EFA6C3AB2B11A767A4F42CF360FA5496E3C50F")); assertEquals( badResult, - Utils.formatFingerprint(getContext(), "3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef")); + Utils.formatFingerprint(context, "3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef")); } + @Test public void testCalcFingerprintString() { // these should pass assertEquals(fdroidFingerprint, Utils.calcFingerprint(fdroidPubkey)); @@ -124,7 +136,5 @@ public class UtilsTest extends AndroidTestCase { } } - public void testCalcFingerprintCertificate() { - // TODO write tests that work with a Certificate - } + // TODO write tests that work with a Certificate } From ed09b1af2dcb014f3b7c6a436c5cff552e749d10 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Wed, 6 Apr 2016 15:42:36 +0200 Subject: [PATCH 6/6] run UpdateService at lowest priority possible Currently, UpdateService is running at default priority, which is the same as the UI tasks, since it is a regular IntentService. That means it would put a noticable load on the device when running, especially on older devices. This should help with that. #563 https://gitlab.com/fdroid/fdroidclient/issues/563 --- app/src/main/java/org/fdroid/fdroid/UpdateService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/org/fdroid/fdroid/UpdateService.java b/app/src/main/java/org/fdroid/fdroid/UpdateService.java index f95dae114..8f045744b 100644 --- a/app/src/main/java/org/fdroid/fdroid/UpdateService.java +++ b/app/src/main/java/org/fdroid/fdroid/UpdateService.java @@ -31,6 +31,7 @@ import android.database.Cursor; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Build; +import android.os.Process; import android.os.SystemClock; import android.preference.PreferenceManager; import android.support.v4.app.NotificationCompat; @@ -338,6 +339,7 @@ public class UpdateService extends IntentService implements ProgressListener { @Override protected void onHandleIntent(Intent intent) { + Process.setThreadPriority(Process.THREAD_PRIORITY_LOWEST); final long startTime = System.currentTimeMillis(); String address = intent.getStringExtra(EXTRA_ADDRESS);