Multi-repo updater ported to robolectric.
The tests pass, but there is a lingering message that gets logged: ``` Jun 08, 2016 7:31:13 AM com.almworks.sqlite4java.Internal log WARNING: [sqlite] [DETACH DATABASE temp_update_db]DB[1][C]: exception when clearing com.almworks.sqlite4java.SQLiteException: [1] DB[1] reset [no such database: temp_update_db] at com.almworks.sqlite4java.SQLiteConnection.throwResult(SQLiteConnection.java:1309) at com.almworks.sqlite4java.SQLiteConnection.throwResult(SQLiteConnection.java:1282) at com.almworks.sqlite4java.SQLiteConnection.cacheStatementHandle(SQLiteConnection.java:1211) at com.almworks.sqlite4java.SQLiteConnection.access$900(SQLiteConnection.java:54) at com.almworks.sqlite4java.SQLiteConnection$CachedController.dispose(SQLiteConnection.java:1606) at com.almworks.sqlite4java.SQLiteStatement.dispose(SQLiteStatement.java:187) at org.robolectric.shadows.ShadowSQLiteConnection$Connections$4.call(ShadowSQLiteConnection.java:421) at org.robolectric.shadows.ShadowSQLiteConnection$Connections$6.call(ShadowSQLiteConnection.java:449) at org.robolectric.shadows.ShadowSQLiteConnection$Connections$6.call(ShadowSQLiteConnection.java:443) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) ``` The `temp_update_db` is the one used for repo updates, but I thought that it correctly gets dropped/detached by the `TempAppProvider` when required. In fact, given the nature of the error message (no such database: temp_update_db), that hints at the fact that it is indeed dropped. I'm struggling to figure out what causes this, but it should not be harmful to the running of the tests. If a test actually fails, then it is picked up correctly by JUnit.
This commit is contained in:
parent
660ebc5ec8
commit
253900e927
@ -36,8 +36,8 @@ public class FileCompatTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
|
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
|
||||||
File dir = TestUtils.getWriteableDir(instrumentation);
|
File dir = TestUtilsOld.getWriteableDir(instrumentation);
|
||||||
sourceFile = SanitizedFile.knownSanitized(TestUtils.copyAssetToDir(instrumentation.getContext(), "simpleIndex.jar", dir));
|
sourceFile = SanitizedFile.knownSanitized(TestUtilsOld.copyAssetToDir(instrumentation.getContext(), "simpleIndex.jar", dir));
|
||||||
destFile = new SanitizedFile(dir, "dest-" + UUID.randomUUID() + ".testproduct");
|
destFile = new SanitizedFile(dir, "dest-" + UUID.randomUUID() + ".testproduct");
|
||||||
assertFalse(destFile.exists());
|
assertFalse(destFile.exists());
|
||||||
assertTrue(sourceFile.getAbsolutePath() + " should exist.", sourceFile.exists());
|
assertTrue(sourceFile.getAbsolutePath() + " should exist.", sourceFile.exists());
|
||||||
|
@ -12,9 +12,9 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
public class TestUtils {
|
public class TestUtilsOld {
|
||||||
|
|
||||||
private static final String TAG = "TestUtils";
|
private static final String TAG = "TestUtilsOld";
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static File copyAssetToDir(Context context, String assetName, File directory) {
|
public static File copyAssetToDir(Context context, String assetName, File directory) {
|
@ -146,7 +146,7 @@ public class UtilsTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testClearOldFiles() throws IOException, InterruptedException {
|
public void testClearOldFiles() throws IOException, InterruptedException {
|
||||||
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
|
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
|
||||||
File dir = new File(TestUtils.getWriteableDir(instrumentation), "clearOldFiles");
|
File dir = new File(TestUtilsOld.getWriteableDir(instrumentation), "clearOldFiles");
|
||||||
FileUtils.deleteQuietly(dir);
|
FileUtils.deleteQuietly(dir);
|
||||||
dir.mkdirs();
|
dir.mkdirs();
|
||||||
assertTrue(dir.isDirectory());
|
assertTrue(dir.isDirectory());
|
||||||
|
@ -372,6 +372,17 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh
|
|||||||
|
|
||||||
private static Preferences instance;
|
private static Preferences instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should only be used for unit testing, whereby separate tests are required to invoke `setup()`.
|
||||||
|
* The reason we don't instead ask for the singleton to be lazily loaded in the {@link Preferences#get()}
|
||||||
|
* method is because that would require each call to that method to require a {@link Context}.
|
||||||
|
* While it is likely that most places asking for preferences have access to a {@link Context},
|
||||||
|
* it is a minor convenience to be able to ask for preferences without.
|
||||||
|
*/
|
||||||
|
public static void clearSingletonForTesting() {
|
||||||
|
instance = null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Needs to be setup before anything else tries to access it.
|
* Needs to be setup before anything else tries to access it.
|
||||||
*/
|
*/
|
||||||
|
@ -190,7 +190,9 @@ public class RepoUpdater {
|
|||||||
processXmlProgressListener, new URL(repo.address), (int) indexEntry.getSize());
|
processXmlProgressListener, new URL(repo.address), (int) indexEntry.getSize());
|
||||||
|
|
||||||
// Process the index...
|
// Process the index...
|
||||||
final SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
|
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||||
|
factory.setNamespaceAware(true);
|
||||||
|
final SAXParser parser = factory.newSAXParser();
|
||||||
final XMLReader reader = parser.getXMLReader();
|
final XMLReader reader = parser.getXMLReader();
|
||||||
final RepoXMLHandler repoXMLHandler = new RepoXMLHandler(repo, createIndexReceiver());
|
final RepoXMLHandler repoXMLHandler = new RepoXMLHandler(repo, createIndexReceiver());
|
||||||
reader.setContentHandler(repoXMLHandler);
|
reader.setContentHandler(repoXMLHandler);
|
||||||
|
@ -1,16 +1,9 @@
|
|||||||
|
|
||||||
package org.fdroid.fdroid;
|
package org.fdroid.fdroid;
|
||||||
|
|
||||||
import android.content.ContentProvider;
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.AssetManager;
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.test.InstrumentationTestCase;
|
|
||||||
import android.test.RenamingDelegatingContext;
|
|
||||||
import android.test.mock.MockContentResolver;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
@ -18,29 +11,37 @@ import org.fdroid.fdroid.RepoUpdater.UpdateException;
|
|||||||
import org.fdroid.fdroid.data.Apk;
|
import org.fdroid.fdroid.data.Apk;
|
||||||
import org.fdroid.fdroid.data.ApkProvider;
|
import org.fdroid.fdroid.data.ApkProvider;
|
||||||
import org.fdroid.fdroid.data.AppProvider;
|
import org.fdroid.fdroid.data.AppProvider;
|
||||||
import org.fdroid.fdroid.data.FDroidProvider;
|
import org.fdroid.fdroid.data.FDroidProviderTest;
|
||||||
import org.fdroid.fdroid.data.Repo;
|
import org.fdroid.fdroid.data.Repo;
|
||||||
import org.fdroid.fdroid.data.RepoProvider;
|
import org.fdroid.fdroid.data.RepoProvider;
|
||||||
import org.fdroid.fdroid.data.TempApkProvider;
|
import org.junit.After;
|
||||||
import org.fdroid.fdroid.data.TempAppProvider;
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.RobolectricGradleTestRunner;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@SuppressWarnings("PMD") // TODO port this to JUnit 4 semantics
|
import static org.fdroid.fdroid.TestUtils.copyResourceToTempFile;
|
||||||
public class MultiRepoUpdaterTest extends InstrumentationTestCase {
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
@Config(constants = BuildConfig.class)
|
||||||
|
@RunWith(RobolectricGradleTestRunner.class)
|
||||||
|
public class MultiRepoUpdaterTest extends FDroidProviderTest {
|
||||||
private static final String TAG = "MultiRepoUpdaterTest";
|
private static final String TAG = "MultiRepoUpdaterTest";
|
||||||
|
|
||||||
private static final String REPO_MAIN = "Test F-Droid repo";
|
private static final String REPO_MAIN = "Test F-Droid repo";
|
||||||
private static final String REPO_ARCHIVE = "Test F-Droid repo (Archive)";
|
private static final String REPO_ARCHIVE = "Test F-Droid repo (Archive)";
|
||||||
private static final String REPO_CONFLICTING = "Test F-Droid repo with different apps";
|
private static final String REPO_CONFLICTING = "Test F-Droid repo with different apps";
|
||||||
|
|
||||||
private Context context;
|
|
||||||
private RepoUpdater conflictingRepoUpdater;
|
private RepoUpdater conflictingRepoUpdater;
|
||||||
private RepoUpdater mainRepoUpdater;
|
private RepoUpdater mainRepoUpdater;
|
||||||
private RepoUpdater archiveRepoUpdater;
|
private RepoUpdater archiveRepoUpdater;
|
||||||
private File testFilesDir;
|
|
||||||
|
|
||||||
private static final String PUB_KEY =
|
private static final String PUB_KEY =
|
||||||
"3082050b308202f3a003020102020420d8f212300d06092a864886f70d01010b050030363110300e0603" +
|
"3082050b308202f3a003020102020420d8f212300d06092a864886f70d01010b050030363110300e0603" +
|
||||||
@ -75,73 +76,8 @@ public class MultiRepoUpdaterTest extends InstrumentationTestCase {
|
|||||||
"98f848e0dbfce5a0f2da0198c47e6935a47fda12c518ef45adfb66ddf5aebaab13948a66c004b8592d22" +
|
"98f848e0dbfce5a0f2da0198c47e6935a47fda12c518ef45adfb66ddf5aebaab13948a66c004b8592d22" +
|
||||||
"e8af60597c4ae2977977cf61dc715a572e241ae717cafdb4f71781943945ac52e0f50b";
|
"e8af60597c4ae2977977cf61dc715a572e241ae717cafdb4f71781943945ac52e0f50b";
|
||||||
|
|
||||||
public class TestContext extends RenamingDelegatingContext {
|
@Before
|
||||||
|
public void setup() throws Exception {
|
||||||
private MockContentResolver resolver;
|
|
||||||
|
|
||||||
public TestContext() {
|
|
||||||
super(getInstrumentation().getTargetContext(), "test.");
|
|
||||||
|
|
||||||
resolver = new MockContentResolver();
|
|
||||||
resolver.addProvider(AppProvider.getAuthority(), prepareProvider(new AppProvider()));
|
|
||||||
resolver.addProvider(ApkProvider.getAuthority(), prepareProvider(new ApkProvider()));
|
|
||||||
resolver.addProvider(RepoProvider.getAuthority(), prepareProvider(new RepoProvider()));
|
|
||||||
resolver.addProvider(TempAppProvider.getAuthority(), prepareProvider(new TempAppProvider()));
|
|
||||||
resolver.addProvider(TempApkProvider.getAuthority(), prepareProvider(new TempApkProvider()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private ContentProvider prepareProvider(ContentProvider provider) {
|
|
||||||
provider.attachInfo(this, null);
|
|
||||||
provider.onCreate();
|
|
||||||
return provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public File getFilesDir() {
|
|
||||||
return getInstrumentation().getTargetContext().getFilesDir();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* String resources used during testing (e.g. when bootstraping the database) are from
|
|
||||||
* the real org.fdroid.fdroid app, not the test org.fdroid.fdroid.test app.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Resources getResources() {
|
|
||||||
return getInstrumentation().getTargetContext().getResources();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ContentResolver getContentResolver() {
|
|
||||||
return resolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AssetManager getAssets() {
|
|
||||||
return getInstrumentation().getContext().getAssets();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public File getDatabasePath(String name) {
|
|
||||||
return new File(getInstrumentation().getContext().getFilesDir(), "fdroid_test.db");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Context getApplicationContext() {
|
|
||||||
// Used by the DBHelper singleton instance.
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
|
|
||||||
FDroidProvider.clearDbHelperSingleton();
|
|
||||||
|
|
||||||
context = new TestContext();
|
|
||||||
|
|
||||||
testFilesDir = TestUtils.getWriteableDir(getInstrumentation());
|
|
||||||
|
|
||||||
// On a fresh database install, there will be F-Droid + GP repos, including their Archive
|
// On a fresh database install, there will be F-Droid + GP repos, including their Archive
|
||||||
// repos that we are not interested in.
|
// repos that we are not interested in.
|
||||||
RepoProvider.Helper.remove(context, 1);
|
RepoProvider.Helper.remove(context, 1);
|
||||||
@ -152,6 +88,13 @@ public class MultiRepoUpdaterTest extends InstrumentationTestCase {
|
|||||||
conflictingRepoUpdater = createUpdater(REPO_CONFLICTING, context);
|
conflictingRepoUpdater = createUpdater(REPO_CONFLICTING, context);
|
||||||
mainRepoUpdater = createUpdater(REPO_MAIN, context);
|
mainRepoUpdater = createUpdater(REPO_MAIN, context);
|
||||||
archiveRepoUpdater = createUpdater(REPO_ARCHIVE, context);
|
archiveRepoUpdater = createUpdater(REPO_ARCHIVE, context);
|
||||||
|
|
||||||
|
Preferences.setup(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
Preferences.clearSingletonForTesting();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -169,9 +112,6 @@ public class MultiRepoUpdaterTest extends InstrumentationTestCase {
|
|||||||
assertConflictingRepo(repos);
|
assertConflictingRepo(repos);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private void assertSomewhatAcceptable() {
|
private void assertSomewhatAcceptable() {
|
||||||
Log.i(TAG, "Asserting at least one versions of each .apk is in index.");
|
Log.i(TAG, "Asserting at least one versions of each .apk is in index.");
|
||||||
List<Repo> repos = RepoProvider.Helper.all(context);
|
List<Repo> repos = RepoProvider.Helper.all(context);
|
||||||
@ -361,6 +301,7 @@ public class MultiRepoUpdaterTest extends InstrumentationTestCase {
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testAcceptableConflictingThenMainThenArchive() throws UpdateException {
|
public void testAcceptableConflictingThenMainThenArchive() throws UpdateException {
|
||||||
assertEmpty();
|
assertEmpty();
|
||||||
if (updateConflicting() && updateMain() && updateArchive()) {
|
if (updateConflicting() && updateMain() && updateArchive()) {
|
||||||
@ -368,6 +309,7 @@ public class MultiRepoUpdaterTest extends InstrumentationTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testAcceptableConflictingThenArchiveThenMain() throws UpdateException {
|
public void testAcceptableConflictingThenArchiveThenMain() throws UpdateException {
|
||||||
assertEmpty();
|
assertEmpty();
|
||||||
if (updateConflicting() && updateArchive() && updateMain()) {
|
if (updateConflicting() && updateArchive() && updateMain()) {
|
||||||
@ -375,6 +317,7 @@ public class MultiRepoUpdaterTest extends InstrumentationTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testAcceptableArchiveThenMainThenConflicting() throws UpdateException {
|
public void testAcceptableArchiveThenMainThenConflicting() throws UpdateException {
|
||||||
assertEmpty();
|
assertEmpty();
|
||||||
if (updateArchive() && updateMain() && updateConflicting()) {
|
if (updateArchive() && updateMain() && updateConflicting()) {
|
||||||
@ -382,6 +325,7 @@ public class MultiRepoUpdaterTest extends InstrumentationTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testAcceptableArchiveThenConflictingThenMain() throws UpdateException {
|
public void testAcceptableArchiveThenConflictingThenMain() throws UpdateException {
|
||||||
assertEmpty();
|
assertEmpty();
|
||||||
if (updateArchive() && updateConflicting() && updateMain()) {
|
if (updateArchive() && updateConflicting() && updateMain()) {
|
||||||
@ -389,6 +333,7 @@ public class MultiRepoUpdaterTest extends InstrumentationTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testAcceptableMainThenArchiveThenConflicting() throws UpdateException {
|
public void testAcceptableMainThenArchiveThenConflicting() throws UpdateException {
|
||||||
assertEmpty();
|
assertEmpty();
|
||||||
if (updateMain() && updateArchive() && updateConflicting()) {
|
if (updateMain() && updateArchive() && updateConflicting()) {
|
||||||
@ -396,6 +341,7 @@ public class MultiRepoUpdaterTest extends InstrumentationTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testAcceptableMainThenConflictingThenArchive() throws UpdateException {
|
public void testAcceptableMainThenConflictingThenArchive() throws UpdateException {
|
||||||
assertEmpty();
|
assertEmpty();
|
||||||
if (updateMain() && updateConflicting() && updateArchive()) {
|
if (updateMain() && updateConflicting() && updateArchive()) {
|
||||||
@ -434,12 +380,14 @@ public class MultiRepoUpdaterTest extends InstrumentationTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean updateRepo(RepoUpdater updater, String indexJarPath) throws UpdateException {
|
private boolean updateRepo(RepoUpdater updater, String indexJarPath) throws UpdateException {
|
||||||
if (!testFilesDir.canWrite()) {
|
File indexJar = copyResourceToTempFile(indexJarPath);
|
||||||
return false;
|
try {
|
||||||
|
updater.processDownloadedFile(indexJar);
|
||||||
|
} finally {
|
||||||
|
if (indexJar != null && indexJar.exists()) {
|
||||||
|
indexJar.delete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File indexJar = TestUtils.copyAssetToDir(context, indexJarPath, testFilesDir);
|
|
||||||
updater.processDownloadedFile(indexJar);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
38
app/src/test/java/org/fdroid/fdroid/TestUtils.java
Normal file
38
app/src/test/java/org/fdroid/fdroid/TestUtils.java
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package org.fdroid.fdroid;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
public class TestUtils {
|
||||||
|
|
||||||
|
private static final String TAG = "TestUtils";
|
||||||
|
|
||||||
|
public static File copyResourceToTempFile(String resourceName) {
|
||||||
|
File tempFile = null;
|
||||||
|
InputStream input = null;
|
||||||
|
OutputStream output = null;
|
||||||
|
try {
|
||||||
|
tempFile = File.createTempFile(resourceName + "-", ".testasset");
|
||||||
|
input = TestUtils.class.getClassLoader().getResourceAsStream(resourceName);
|
||||||
|
output = new FileOutputStream(tempFile);
|
||||||
|
Utils.copy(input, output);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
if (tempFile != null && tempFile.exists()) {
|
||||||
|
tempFile.delete();
|
||||||
|
}
|
||||||
|
fail();
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
Utils.closeQuietly(output);
|
||||||
|
Utils.closeQuietly(input);
|
||||||
|
}
|
||||||
|
return tempFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user