Tests for preferred multi sig choice.

When a single repo provides apks with multiple signatures, then we need
to be able to select the preferred one. This adds tests for this which
fail, because that feature has not yet been implemented.
This commit is contained in:
Peter Serwylo 2017-06-20 11:03:58 +10:00
parent b7b8865325
commit 6b42b802b3
2 changed files with 309 additions and 0 deletions

View File

@ -24,6 +24,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.security.NoSuchAlgorithmException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
@ -54,6 +55,27 @@ public class TestUtils {
}
}
private static String formatSigForDebugging(String sig) {
String suffix;
// Can't use a switch statement here because *_SIG is not a constant, despite beign static final.
if (sig.equals(FDROID_SIG)) {
suffix = "F-Droid";
} else if (sig.equals(UPSTREAM_SIG)) {
suffix = "Upstream";
} else if (sig.equals(THIRD_PARTY_SIG)) {
suffix = "3rd Party";
} else {
suffix = "Unknown";
}
return sig + " [" + suffix + "]";
}
public static void assertSignaturesMatch(String message, String expected, String actual) {
assertEquals(message, formatSigForDebugging(expected), formatSigForDebugging(actual));
}
public static void insertApk(Context context, App app, int versionCode, String signature) {
ContentValues values = new ContentValues();
values.put(Schema.ApkTable.Cols.SIGNATURE, signature);
@ -69,6 +91,14 @@ public class TestUtils {
return Assert.insertApp(context, packageName, appName, values);
}
public static App insertApp(Context context, String packageName, String appName, int upstreamVersionCode,
Repo repo) {
ContentValues values = new ContentValues();
values.put(Schema.AppMetadataTable.Cols.REPO_ID, repo.getId());
values.put(Schema.AppMetadataTable.Cols.UPSTREAM_VERSION_CODE, upstreamVersionCode);
return Assert.insertApp(context, packageName, appName, values);
}
public static Repo ensureRepo(Context context, String repoUrl) {
Repo existing = RepoProvider.Helper.findByAddress(context, repoUrl);
if (existing != null) {

View File

@ -0,0 +1,279 @@
package org.fdroid.fdroid.data;
import android.app.Application;
import android.content.Context;
import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.TestUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import static org.junit.Assert.assertEquals;
@Config(constants = BuildConfig.class, application = Application.class, sdk = 24)
@RunWith(RobolectricTestRunner.class)
public class PreferredSignatureTest extends FDroidProviderTest {
private static final String PACKAGE_NAME = "app.example.com";
@Before
public void setup() {
TestUtils.registerContentProvider(AppProvider.getAuthority(), AppProvider.class);
Preferences.setup(context);
}
@After
public void tearDown() {
Preferences.clearSingletonForTesting();
}
private Repo createFDroidRepo() {
return RepoProviderTest.insertRepo(context, "https://f-droid.org/fdroid/repo", "", "", "");
}
private App populateFDroidRepo(Repo repo) {
App app = TestUtils.insertApp(context, PACKAGE_NAME, "App", 3100, repo);
TestUtils.insertApk(context, app, 1100, TestUtils.FDROID_SIG); // 1.0
TestUtils.insertApk(context, app, 2100, TestUtils.FDROID_SIG); // 2.0
TestUtils.insertApk(context, app, 3100, TestUtils.FDROID_SIG); // 3.0
TestUtils.insertApk(context, app, 2100, TestUtils.UPSTREAM_SIG); // 2.0
TestUtils.insertApk(context, app, 3100, TestUtils.UPSTREAM_SIG); // 3.0
return app;
}
private Repo createDevRepo() {
return RepoProviderTest.insertRepo(context, "https://dev.upstream.com/fdroid/repo", "", "", "");
}
private App populateDevRepo(Repo repo) {
App app = TestUtils.insertApp(context, PACKAGE_NAME, "App", 4100, repo);
TestUtils.insertApk(context, app, 1001, TestUtils.THIRD_PARTY_SIG); // 1.0-rc2
TestUtils.insertApk(context, app, 1100, TestUtils.THIRD_PARTY_SIG); // 1.0
TestUtils.insertApk(context, app, 2001, TestUtils.THIRD_PARTY_SIG); // 2.0-rc1
TestUtils.insertApk(context, app, 2002, TestUtils.THIRD_PARTY_SIG); // 2.0-rc2
TestUtils.insertApk(context, app, 2100, TestUtils.THIRD_PARTY_SIG); // 2.0
TestUtils.insertApk(context, app, 3001, TestUtils.THIRD_PARTY_SIG); // 3.0-rc1
TestUtils.insertApk(context, app, 3100, TestUtils.THIRD_PARTY_SIG); // 3.0
TestUtils.insertApk(context, app, 4001, TestUtils.THIRD_PARTY_SIG); // 4.0-rc1
TestUtils.insertApk(context, app, 4002, TestUtils.THIRD_PARTY_SIG); // 4.0-rc2
TestUtils.insertApk(context, app, 4100, TestUtils.THIRD_PARTY_SIG); // 4.0
TestUtils.insertApk(context, app, 5001, TestUtils.THIRD_PARTY_SIG); // 5.0-rc1
TestUtils.insertApk(context, app, 5002, TestUtils.THIRD_PARTY_SIG); // 5.0-rc2
TestUtils.insertApk(context, app, 5003, TestUtils.THIRD_PARTY_SIG); // 5.0-rc3
return app;
}
private Repo createUpstreamRepo() {
return RepoProviderTest.insertRepo(context, "https://upstream.com/fdroid/repo", "", "", "");
}
private App populateUpstreamRepo(Repo repo) {
App app = TestUtils.insertApp(context, PACKAGE_NAME, "App", 4100, repo);
TestUtils.insertApk(context, app, 2100, TestUtils.UPSTREAM_SIG);
TestUtils.insertApk(context, app, 3100, TestUtils.UPSTREAM_SIG);
TestUtils.insertApk(context, app, 4100, TestUtils.UPSTREAM_SIG);
return app;
}
@Test
public void onlyFDroid() {
populateFDroidRepo(createFDroidRepo());
assertSuggested(context, 3100, TestUtils.UPSTREAM_SIG);
}
/**
* @see #assertFdroidThenDev()
*/
@Test
public void fdroidThenDev1() {
Repo fdroid = createFDroidRepo();
Repo dev = createDevRepo();
populateFDroidRepo(fdroid);
populateDevRepo(dev);
assertFdroidThenDev();
}
/**
* @see #assertFdroidThenDev()
*/
@Test
public void fdroidThenDev2() {
Repo fdroid = createFDroidRepo();
Repo dev = createDevRepo();
populateDevRepo(dev);
populateFDroidRepo(fdroid);
assertFdroidThenDev();
}
/**
* Both {@link #fdroidThenDev1()} and {@link #fdroidThenDev2()} add the same repos, with the same priorities and
* the same apps/apks. The only difference is in the order with which they get added to the database. They both
* then delegate here and assert that everything works as expected. The reason for testing like this is to ensure
* that the order of rows in the database has no bearing on the correct suggestions of signatures.
* @see #fdroidThenDev1()
* @see #fdroidThenDev2()
*/
private void assertFdroidThenDev() {
assertSuggested(context, 4100, TestUtils.THIRD_PARTY_SIG);
Preferences.get().setUnstableUpdates(true);
assertSuggested(context, 5003, TestUtils.THIRD_PARTY_SIG);
Preferences.get().setUnstableUpdates(false);
assertSuggested(context, 4100, TestUtils.THIRD_PARTY_SIG);
}
/**
* @see #assertFdroidThenUpstream()
*/
@Test
public void fdroidThenUpstream1() {
Repo fdroid = createFDroidRepo();
Repo upstream = createUpstreamRepo();
populateUpstreamRepo(upstream);
populateFDroidRepo(fdroid);
assertFdroidThenUpstream();
}
/**
* @see #assertFdroidThenUpstream()
*/
@Test
public void fdroidThenUpstream2() {
Repo fdroid = createFDroidRepo();
Repo upstream = createUpstreamRepo();
populateFDroidRepo(fdroid);
populateUpstreamRepo(upstream);
assertFdroidThenUpstream();
}
/**
* @see #fdroidThenUpstream1()
* @see #fdroidThenUpstream2()
* @see #assertFdroidThenDev()
*/
private void assertFdroidThenUpstream() {
assertSuggested(context, 4100, TestUtils.UPSTREAM_SIG);
}
/**
* @see #assertFdroidThenUpstreamThenDev()
*/
@Test
public void fdroidThenUpstreamThenDev1() {
Repo fdroid = createFDroidRepo();
Repo upstream = createUpstreamRepo();
Repo dev = createDevRepo();
populateFDroidRepo(fdroid);
populateUpstreamRepo(upstream);
populateDevRepo(dev);
assertFdroidThenUpstreamThenDev();
}
/**
* @see #assertFdroidThenUpstreamThenDev()
*/
@Test
public void fdroidThenUpstreamThenDev2() {
Repo fdroid = createFDroidRepo();
Repo upstream = createUpstreamRepo();
Repo dev = createDevRepo();
populateDevRepo(dev);
populateUpstreamRepo(upstream);
populateFDroidRepo(fdroid);
assertFdroidThenUpstreamThenDev();
}
/**
* @see #fdroidThenUpstreamThenDev1()
* @see #fdroidThenUpstreamThenDev2()
* @see #assertFdroidThenDev()
*/
private void assertFdroidThenUpstreamThenDev() {
assertSuggested(context, 4100, TestUtils.THIRD_PARTY_SIG);
Preferences.get().setUnstableUpdates(true);
assertSuggested(context, 5003, TestUtils.THIRD_PARTY_SIG);
Preferences.get().setUnstableUpdates(false);
assertSuggested(context, 4100, TestUtils.THIRD_PARTY_SIG);
}
/**
* @see #assertFdroidThenDevThenUpstream()
*/
@Test
public void fdroidThenDevThenUpstream1() {
Repo fdroid = createFDroidRepo();
Repo dev = createDevRepo();
Repo upstream = createUpstreamRepo();
populateFDroidRepo(fdroid);
populateDevRepo(dev);
populateUpstreamRepo(upstream);
assertFdroidThenDevThenUpstream();
}
/**
* @see #assertFdroidThenDevThenUpstream()
*/
@Test
public void fdroidThenDevThenUpstream2() {
Repo fdroid = createFDroidRepo();
Repo dev = createDevRepo();
Repo upstream = createUpstreamRepo();
populateFDroidRepo(fdroid);
populateDevRepo(dev);
populateUpstreamRepo(upstream);
assertFdroidThenDevThenUpstream();
}
/**
* @see #fdroidThenDevThenUpstream1()
* @see #fdroidThenDevThenUpstream2()
* @see #assertFdroidThenDev()
*/
private void assertFdroidThenDevThenUpstream() {
assertSuggested(context, 4100, TestUtils.UPSTREAM_SIG);
}
private void assertSuggested(Context context, int suggestedVersion, String suggestedSig) {
AppProvider.Helper.calcSuggestedApks(context);
AppProvider.Helper.recalculatePreferredMetadata(context);
App suggestedApp = AppProvider.Helper.findHighestPriorityMetadata(context.getContentResolver(), PACKAGE_NAME);
assertEquals("Suggested version on App", suggestedVersion, suggestedApp.suggestedVersionCode);
Apk suggestedApk = ApkProvider.Helper.findSuggestedApk(context, suggestedApp);
assertEquals("Version on suggested Apk", suggestedVersion, suggestedApk.versionCode);
TestUtils.assertSignaturesMatch("Signature on suggested Apk", suggestedSig, suggestedApk.sig);
}
}