Fixed repo updater tests. Fix to temp app/apk providers.
The repo xml handler now has a different mechanism for returning data about the parsed xml file. This is done via a callback, rather than storing the data in member variables. The tests now deal with this correctly. The update/delete operations of the TempAp[pk]Provider's didn't work, so that has now been fixed.
This commit is contained in:
parent
b34853a776
commit
1d951e7689
@ -46,7 +46,6 @@ import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* Responsible for updating an individual repository. This will:
|
||||
* * Download the index.jar
|
||||
* * Verify that it is signed correctly and by the correct certificate
|
||||
@ -75,18 +74,22 @@ public class RepoUpdater {
|
||||
*/
|
||||
private static final String[] APP_FIELDS_TO_IGNORE = {
|
||||
AppProvider.DataColumns.IGNORE_ALLUPDATES,
|
||||
AppProvider.DataColumns.IGNORE_THISUPDATE
|
||||
AppProvider.DataColumns.IGNORE_THISUPDATE,
|
||||
};
|
||||
|
||||
@NonNull protected final Context context;
|
||||
@NonNull protected final Repo repo;
|
||||
protected boolean hasChanged = false;
|
||||
@Nullable protected ProgressListener progressListener;
|
||||
@NonNull
|
||||
protected final Context context;
|
||||
@NonNull
|
||||
protected final Repo repo;
|
||||
protected boolean hasChanged;
|
||||
@Nullable
|
||||
protected ProgressListener progressListener;
|
||||
private String cacheTag;
|
||||
private X509Certificate signingCertFromJar;
|
||||
|
||||
/**
|
||||
* Updates an app repo as read out of the database into a {@link Repo} instance.
|
||||
*
|
||||
* @param repo A {@link Repo} read out of the local database
|
||||
*/
|
||||
public RepoUpdater(@NonNull Context context, @NonNull Repo repo) {
|
||||
@ -160,8 +163,8 @@ public class RepoUpdater {
|
||||
}
|
||||
}
|
||||
|
||||
private ContentValues repoDetailsToSave = null;
|
||||
private String signingCertFromIndexXml = null;
|
||||
private ContentValues repoDetailsToSave;
|
||||
private String signingCertFromIndexXml;
|
||||
|
||||
private RepoXMLHandler.IndexReceiver createIndexReceiver() {
|
||||
return new RepoXMLHandler.IndexReceiver() {
|
||||
|
@ -45,12 +45,12 @@ public class RepoXMLHandler extends DefaultHandler {
|
||||
private App curapp;
|
||||
private Apk curapk;
|
||||
|
||||
private String currentApkHashType = null;
|
||||
private String currentApkHashType;
|
||||
|
||||
// After processing the XML, these will be -1 if the index didn't specify
|
||||
// them - otherwise it will be the value specified.
|
||||
private int repoMaxAge = -1;
|
||||
private int repoVersion = 0;
|
||||
private int repoVersion;
|
||||
private String repoDescription;
|
||||
private String repoName;
|
||||
|
||||
@ -61,6 +61,7 @@ public class RepoXMLHandler extends DefaultHandler {
|
||||
|
||||
interface IndexReceiver {
|
||||
void receiveRepo(String name, String description, String signingCert, int maxage, int version);
|
||||
|
||||
void receiveApp(App app, List<Apk> packages);
|
||||
}
|
||||
|
||||
@ -104,12 +105,12 @@ public class RepoXMLHandler extends DefaultHandler {
|
||||
curapk.size = Utils.parseInt(str, 0);
|
||||
break;
|
||||
case "hash":
|
||||
if (currentApkHashType == null || currentApkHashType.equals("md5")) {
|
||||
if (currentApkHashType == null || "md5".equals(currentApkHashType)) {
|
||||
if (curapk.hash == null) {
|
||||
curapk.hash = str;
|
||||
curapk.hashType = "SHA-256";
|
||||
}
|
||||
} else if (currentApkHashType.equals("sha256")) {
|
||||
} else if ("sha256".equals(currentApkHashType)) {
|
||||
curapk.hash = str;
|
||||
curapk.hashType = "SHA-256";
|
||||
}
|
||||
|
@ -285,6 +285,7 @@ public class UpdateService extends IntentService implements ProgressListener {
|
||||
* when that would occur)
|
||||
* - Last update was too recent
|
||||
* - Not on wifi, but the property for "Only auto update on wifi" is set.
|
||||
*
|
||||
* @return True if we are due for a scheduled update.
|
||||
*/
|
||||
private boolean verifyIsTimeForScheduledRun() {
|
||||
|
@ -411,7 +411,7 @@ public class ApkProvider extends FDroidProvider {
|
||||
return new QuerySelection(selection, args);
|
||||
}
|
||||
|
||||
private QuerySelection queryRepo(long repoId) {
|
||||
protected QuerySelection queryRepo(long repoId) {
|
||||
final String selection = DataColumns.REPO_ID + " = ? ";
|
||||
final String[] args = {Long.toString(repoId)};
|
||||
return new QuerySelection(selection, args);
|
||||
@ -421,7 +421,7 @@ public class ApkProvider extends FDroidProvider {
|
||||
return queryRepo(repoId).add(AppProvider.queryApps(appIds, DataColumns.APK_ID));
|
||||
}
|
||||
|
||||
private QuerySelection queryApks(String apkKeys) {
|
||||
protected QuerySelection queryApks(String apkKeys) {
|
||||
final String[] apkDetails = apkKeys.split(",");
|
||||
if (apkDetails.length > MAX_APKS_TO_QUERY) {
|
||||
throw new IllegalArgumentException(
|
||||
@ -561,11 +561,13 @@ public class ApkProvider extends FDroidProvider {
|
||||
|
||||
@Override
|
||||
public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
|
||||
|
||||
if (matcher.match(uri) != CODE_SINGLE) {
|
||||
throw new UnsupportedOperationException("Cannot update anything other than a single apk.");
|
||||
}
|
||||
return performUpdateUnchecked(uri, values, where, whereArgs);
|
||||
}
|
||||
|
||||
protected int performUpdateUnchecked(Uri uri, ContentValues values, String where, String[] whereArgs) {
|
||||
validateFields(DataColumns.ALL, values);
|
||||
removeRepoFields(values);
|
||||
|
||||
@ -577,7 +579,6 @@ public class ApkProvider extends FDroidProvider {
|
||||
getContext().getContentResolver().notifyChange(uri, null);
|
||||
}
|
||||
return numRows;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -286,7 +286,7 @@ public class AppProvider extends FDroidProvider {
|
||||
|
||||
}
|
||||
|
||||
private static class Query extends QueryBuilder {
|
||||
private class Query extends QueryBuilder {
|
||||
|
||||
private boolean isSuggestedApkTableAdded;
|
||||
private boolean requiresInstalledTable;
|
||||
@ -366,14 +366,14 @@ public class AppProvider extends FDroidProvider {
|
||||
if (field.equals(DataColumns.CATEGORIES)) {
|
||||
categoryFieldAdded = true;
|
||||
}
|
||||
appendField(field, "fdroid_app");
|
||||
appendField(field, getTableName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void appendCountField() {
|
||||
countFieldAppended = true;
|
||||
appendField("COUNT( DISTINCT fdroid_app.id ) AS " + DataColumns._COUNT);
|
||||
appendField("COUNT( DISTINCT " + getTableName() + ".id ) AS " + DataColumns._COUNT);
|
||||
}
|
||||
|
||||
private void addSuggestedApkVersionField() {
|
||||
@ -388,7 +388,7 @@ public class AppProvider extends FDroidProvider {
|
||||
leftJoin(
|
||||
DBHelper.TABLE_APK,
|
||||
"suggestedApk",
|
||||
"fdroid_app.suggestedVercode = suggestedApk.vercode AND fdroid_app.id = suggestedApk.id");
|
||||
getTableName() + ".suggestedVercode = suggestedApk.vercode AND " + getTableName() + ".id = suggestedApk.id");
|
||||
}
|
||||
appendField(fieldName, "suggestedApk", alias);
|
||||
}
|
||||
@ -570,15 +570,15 @@ public class AppProvider extends FDroidProvider {
|
||||
}
|
||||
|
||||
private AppQuerySelection queryCanUpdate() {
|
||||
final String ignoreCurrent = " fdroid_app.ignoreThisUpdate != fdroid_app.suggestedVercode ";
|
||||
final String ignoreAll = " fdroid_app.ignoreAllUpdates != 1 ";
|
||||
final String ignoreCurrent = getTableName() + ".ignoreThisUpdate != " + getTableName() + ".suggestedVercode ";
|
||||
final String ignoreAll = getTableName() + ".ignoreAllUpdates != 1 ";
|
||||
final String ignore = " ( " + ignoreCurrent + " AND " + ignoreAll + " ) ";
|
||||
final String where = ignore + " AND fdroid_app." + DataColumns.SUGGESTED_VERSION_CODE + " > installed.versionCode";
|
||||
final String where = ignore + " AND " + getTableName() + "." + DataColumns.SUGGESTED_VERSION_CODE + " > installed.versionCode";
|
||||
return new AppQuerySelection(where).requireNaturalInstalledTable();
|
||||
}
|
||||
|
||||
private AppQuerySelection queryRepo(long repoId) {
|
||||
final String selection = " fdroid_apk.repo = ? ";
|
||||
final String selection = DBHelper.TABLE_APK + ".repo = ? ";
|
||||
final String[] args = {String.valueOf(repoId)};
|
||||
return new AppQuerySelection(selection, args);
|
||||
}
|
||||
@ -589,10 +589,10 @@ public class AppProvider extends FDroidProvider {
|
||||
|
||||
private AppQuerySelection querySearch(String query) {
|
||||
final String[] columns = {
|
||||
"fdroid_app.id",
|
||||
"fdroid_app.name",
|
||||
"fdroid_app.summary",
|
||||
"fdroid_app.description",
|
||||
getTableName() + ".id",
|
||||
getTableName() + ".name",
|
||||
getTableName() + ".summary",
|
||||
getTableName() + ".description",
|
||||
};
|
||||
|
||||
// Remove duplicates, surround in % for case insensitive searching
|
||||
@ -632,15 +632,16 @@ public class AppProvider extends FDroidProvider {
|
||||
return new AppQuerySelection(selection.toString(), selectionKeywords);
|
||||
}
|
||||
|
||||
private AppQuerySelection querySingle(String id) {
|
||||
final String selection = "fdroid_app.id = ?";
|
||||
protected AppQuerySelection querySingle(String id) {
|
||||
final String selection = getTableName() + ".id = ?";
|
||||
final String[] args = {id};
|
||||
return new AppQuerySelection(selection, args);
|
||||
}
|
||||
|
||||
private AppQuerySelection queryIgnored() {
|
||||
final String selection = "fdroid_app.ignoreAllUpdates = 1 OR " +
|
||||
"fdroid_app.ignoreThisUpdate >= fdroid_app.suggestedVercode";
|
||||
final String table = getTableName();
|
||||
final String selection = table + ".ignoreAllUpdates = 1 OR " +
|
||||
table + ".ignoreThisUpdate >= " + table + ".suggestedVercode";
|
||||
return new AppQuerySelection(selection);
|
||||
}
|
||||
|
||||
@ -653,13 +654,13 @@ public class AppProvider extends FDroidProvider {
|
||||
}
|
||||
|
||||
private AppQuerySelection queryNewlyAdded() {
|
||||
final String selection = "fdroid_app.added > ?";
|
||||
final String selection = getTableName() + ".added > ?";
|
||||
final String[] args = {Utils.formatDate(Preferences.get().calcMaxHistory(), "")};
|
||||
return new AppQuerySelection(selection, args);
|
||||
}
|
||||
|
||||
private AppQuerySelection queryRecentlyUpdated() {
|
||||
final String selection = "fdroid_app.added != fdroid_app.lastUpdated AND fdroid_app.lastUpdated > ?";
|
||||
final String selection = getTableName() + ".added != fdroid_app.lastUpdated AND fdroid_app.lastUpdated > ?";
|
||||
final String[] args = {Utils.formatDate(Preferences.get().calcMaxHistory(), "")};
|
||||
return new AppQuerySelection(selection, args);
|
||||
}
|
||||
@ -668,10 +669,10 @@ public class AppProvider extends FDroidProvider {
|
||||
// TODO: In the future, add a new table for categories,
|
||||
// so we can join onto it.
|
||||
final String selection =
|
||||
" fdroid_app.categories = ? OR " + // Only category e.g. "internet"
|
||||
" fdroid_app.categories LIKE ? OR " + // First category e.g. "internet,%"
|
||||
" fdroid_app.categories LIKE ? OR " + // Last category e.g. "%,internet"
|
||||
" fdroid_app.categories LIKE ? "; // One of many categories e.g. "%,internet,%"
|
||||
getTableName() + ".categories = ? OR " + // Only category e.g. "internet"
|
||||
getTableName() + ".categories LIKE ? OR " + // First category e.g. "internet,%"
|
||||
getTableName() + ".categories LIKE ? OR " + // Last category e.g. "%,internet"
|
||||
getTableName() + ".categories LIKE ? "; // One of many categories e.g. "%,internet,%"
|
||||
final String[] args = {
|
||||
category,
|
||||
category + ",%",
|
||||
@ -682,7 +683,7 @@ public class AppProvider extends FDroidProvider {
|
||||
}
|
||||
|
||||
private AppQuerySelection queryNoApks() {
|
||||
String selection = "(SELECT COUNT(*) FROM fdroid_apk WHERE fdroid_apk.id = fdroid_app.id) = 0";
|
||||
String selection = "(SELECT COUNT(*) FROM " + DBHelper.TABLE_APK + " WHERE " + DBHelper.TABLE_APK + ".id = " + getTableName() + ".id) = 0";
|
||||
return new AppQuerySelection(selection);
|
||||
}
|
||||
|
||||
@ -692,8 +693,8 @@ public class AppProvider extends FDroidProvider {
|
||||
return new AppQuerySelection(selection, args);
|
||||
}
|
||||
|
||||
private static AppQuerySelection queryApps(String appIds) {
|
||||
return queryApps(appIds, "fdroid_app.id");
|
||||
private AppQuerySelection queryApps(String appIds) {
|
||||
return queryApps(appIds, getTableName() + ".id");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -754,13 +755,13 @@ public class AppProvider extends FDroidProvider {
|
||||
break;
|
||||
|
||||
case RECENTLY_UPDATED:
|
||||
sortOrder = " fdroid_app.lastUpdated DESC";
|
||||
sortOrder = getTableName() + ".lastUpdated DESC";
|
||||
selection = selection.add(queryRecentlyUpdated());
|
||||
includeSwap = false;
|
||||
break;
|
||||
|
||||
case NEWLY_ADDED:
|
||||
sortOrder = " fdroid_app.added DESC";
|
||||
sortOrder = getTableName() + ".added DESC";
|
||||
selection = selection.add(queryNewlyAdded());
|
||||
includeSwap = false;
|
||||
break;
|
||||
@ -775,7 +776,7 @@ public class AppProvider extends FDroidProvider {
|
||||
}
|
||||
|
||||
if (AppProvider.DataColumns.NAME.equals(sortOrder)) {
|
||||
sortOrder = " fdroid_app." + sortOrder + " COLLATE LOCALIZED ";
|
||||
sortOrder = getTableName() + sortOrder + " COLLATE LOCALIZED ";
|
||||
}
|
||||
|
||||
Query query = new Query();
|
||||
|
@ -88,7 +88,6 @@ public class TempApkProvider extends ApkProvider {
|
||||
@Override
|
||||
public Uri insert(Uri uri, ContentValues values) {
|
||||
int code = matcher.match(uri);
|
||||
|
||||
if (code == CODE_INIT) {
|
||||
initTable();
|
||||
return null;
|
||||
@ -100,6 +99,40 @@ public class TempApkProvider extends ApkProvider {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
|
||||
|
||||
if (matcher.match(uri) != CODE_SINGLE) {
|
||||
throw new UnsupportedOperationException("Cannot update anything other than a single apk.");
|
||||
}
|
||||
|
||||
return performUpdateUnchecked(uri, values, where, whereArgs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(Uri uri, String where, String[] whereArgs) {
|
||||
|
||||
QuerySelection query = new QuerySelection(where, whereArgs);
|
||||
|
||||
switch (matcher.match(uri)) {
|
||||
case CODE_REPO_APK:
|
||||
List<String> pathSegments = uri.getPathSegments();
|
||||
query = query.add(queryRepo(Long.parseLong(pathSegments.get(1)))).add(queryApks(pathSegments.get(2)));
|
||||
break;
|
||||
|
||||
default:
|
||||
Log.e(TAG, "Invalid URI for apk content provider: " + uri);
|
||||
throw new UnsupportedOperationException("Invalid URI for apk content provider: " + uri);
|
||||
}
|
||||
|
||||
int rowsAffected = write().delete(getTableName(), query.getSelection(), query.getArgs());
|
||||
if (!isApplyingBatch()) {
|
||||
getContext().getContentResolver().notifyChange(uri, null);
|
||||
}
|
||||
return rowsAffected;
|
||||
|
||||
}
|
||||
|
||||
private void initTable() {
|
||||
write().execSQL("DROP TABLE IF EXISTS " + getTableName());
|
||||
write().execSQL("CREATE TEMPORARY TABLE " + getTableName() + " AS SELECT * FROM " + DBHelper.TABLE_APK);
|
||||
@ -109,5 +142,6 @@ public class TempApkProvider extends ApkProvider {
|
||||
Log.d(TAG, "Deleting all apks from " + DBHelper.TABLE_APK + " so they can be copied from " + getTableName());
|
||||
write().execSQL("DELETE FROM " + DBHelper.TABLE_APK);
|
||||
write().execSQL("INSERT INTO " + DBHelper.TABLE_APK + " SELECT * FROM " + getTableName());
|
||||
getContext().getContentResolver().notifyChange(ApkProvider.getContentUri(), null);
|
||||
}
|
||||
}
|
||||
|
@ -83,6 +83,25 @@ public class TempAppProvider extends AppProvider {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
|
||||
QuerySelection query = new QuerySelection(where, whereArgs);
|
||||
switch (matcher.match(uri)) {
|
||||
case CODE_SINGLE:
|
||||
query = query.add(querySingle(uri.getLastPathSegment()));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new UnsupportedOperationException("Update not supported for " + uri + ".");
|
||||
}
|
||||
|
||||
int count = write().update(getTableName(), values, query.getSelection(), query.getArgs());
|
||||
if (!isApplyingBatch()) {
|
||||
getContext().getContentResolver().notifyChange(uri, null);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private void initTable() {
|
||||
write().execSQL("DROP TABLE IF EXISTS " + getTableName());
|
||||
write().execSQL("CREATE TEMPORARY TABLE " + getTableName() + " AS SELECT * FROM " + DBHelper.TABLE_APP);
|
||||
@ -92,5 +111,6 @@ public class TempAppProvider extends AppProvider {
|
||||
Log.d(TAG, "Deleting all apks from " + DBHelper.TABLE_APP + " so they can be copied from " + getTableName());
|
||||
write().execSQL("DELETE FROM " + DBHelper.TABLE_APP);
|
||||
write().execSQL("INSERT INTO " + DBHelper.TABLE_APP + " SELECT * FROM " + getTableName());
|
||||
getContext().getContentResolver().notifyChange(AppProvider.getContentUri(), null);
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ import org.fdroid.fdroid.data.ApkProvider;
|
||||
import org.fdroid.fdroid.data.AppProvider;
|
||||
import org.fdroid.fdroid.data.Repo;
|
||||
import org.fdroid.fdroid.data.RepoProvider;
|
||||
import org.fdroid.fdroid.data.TempApkProvider;
|
||||
import org.fdroid.fdroid.data.TempAppProvider;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
@ -82,6 +84,8 @@ public class MultiRepoUpdaterTest extends InstrumentationTestCase {
|
||||
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) {
|
||||
|
@ -8,7 +8,6 @@ import org.fdroid.fdroid.RepoUpdater.UpdateException;
|
||||
import org.fdroid.fdroid.data.Repo;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.UUID;
|
||||
|
||||
public class RepoUpdaterTest extends InstrumentationTestCase {
|
||||
private static final String TAG = "RepoUpdaterTest";
|
||||
|
@ -1,6 +1,7 @@
|
||||
|
||||
package org.fdroid.fdroid;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
@ -8,6 +9,7 @@ import android.util.Log;
|
||||
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.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
@ -25,34 +27,7 @@ import javax.xml.parsers.SAXParserFactory;
|
||||
public class RepoXMLHandlerTest extends AndroidTestCase {
|
||||
private static final String TAG = "RepoXMLHandlerTest";
|
||||
|
||||
private final Repo actualRepo = new Repo();
|
||||
|
||||
public final List<App> actualApps = new ArrayList<>();
|
||||
public final List<Apk> actualApks = new ArrayList<>();
|
||||
|
||||
private final static String FAKE_PUBKEY = "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345";
|
||||
|
||||
private RepoXMLHandler.IndexReceiver indexReceiver = new RepoXMLHandler.IndexReceiver() {
|
||||
|
||||
private boolean hasReceivedRepo;
|
||||
|
||||
@Override
|
||||
public void receiveRepo(String name, String description, String signingCert, int maxage, int version) {
|
||||
assertFalse("Repo XML contains more than one <repo>.", hasReceivedRepo);
|
||||
actualRepo.name = name;
|
||||
actualRepo.description = description;
|
||||
actualRepo.pubkey = signingCert;
|
||||
actualRepo.maxage = maxage;
|
||||
actualRepo.version = version;
|
||||
hasReceivedRepo = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveApp(App app, List<Apk> packages) {
|
||||
actualApps.add(app);
|
||||
actualApks.addAll(packages);
|
||||
}
|
||||
};
|
||||
private static final String FAKE_PUBKEY = "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345";
|
||||
|
||||
public RepoXMLHandlerTest() {
|
||||
}
|
||||
@ -67,10 +42,8 @@ public class RepoXMLHandlerTest extends AndroidTestCase {
|
||||
expectedRepo.name = "F-Droid";
|
||||
expectedRepo.pubkey = "308201ee30820157a0030201020204300d845b300d06092a864886f70d01010b0500302a3110300e060355040b1307462d44726f6964311630140603550403130d70616c6174736368696e6b656e301e170d3134303432373030303633315a170d3431303931323030303633315a302a3110300e060355040b1307462d44726f6964311630140603550403130d70616c6174736368696e6b656e30819f300d06092a864886f70d010101050003818d0030818902818100a439472e4b6d01141bfc94ecfe131c7c728fdda670bb14c57ca60bd1c38a8b8bc0879d22a0a2d0bc0d6fdd4cb98d1d607c2caefbe250a0bd0322aedeb365caf9b236992fac13e6675d3184a6c7c6f07f73410209e399a9da8d5d7512bbd870508eebacff8b57c3852457419434d34701ccbf692267cbc3f42f1c5d1e23762d790203010001a321301f301d0603551d0e041604140b1840691dab909746fde4bfe28207d1cae15786300d06092a864886f70d01010b05000381810062424c928ffd1b6fd419b44daafef01ca982e09341f7077fb865905087aeac882534b3bd679b51fdfb98892cef38b63131c567ed26c9d5d9163afc775ac98ad88c405d211d6187bde0b0d236381cc574ba06ef9080721a92ae5a103a7301b2c397eecc141cc850dd3e123813ebc41c59d31ddbcb6e984168280c53272f6a442b";
|
||||
expectedRepo.description = "The official repository of the F-Droid client. Applications in this repository are either official binaries built by the original application developers, or are binaries built from source by the admin of f-droid.org using the tools on https://gitorious.org/f-droid.";
|
||||
processFile("simpleIndex.xml");
|
||||
handlerTestSuite(expectedRepo, 0, 0);
|
||||
assertEquals(actualRepo.maxage, -1);
|
||||
assertEquals(actualRepo.version, 12);
|
||||
RepoDetails actualDetails = getFromFile("simpleIndex.xml");
|
||||
handlerTestSuite(expectedRepo, actualDetails, 0, 0, -1, 12);
|
||||
}
|
||||
|
||||
public void testSmallRepo() {
|
||||
@ -78,11 +51,9 @@ public class RepoXMLHandlerTest extends AndroidTestCase {
|
||||
expectedRepo.name = "Android-Nexus-7-20139453 on UNSET";
|
||||
expectedRepo.pubkey = "308202da308201c2a00302010202080eb08c796fec91aa300d06092a864886f70d0101050500302d3111300f060355040a0c084b6572706c61707031183016060355040b0c0f477561726469616e50726f6a656374301e170d3134313030333135303631325a170d3135313030333135303631325a302d3111300f060355040a0c084b6572706c61707031183016060355040b0c0f477561726469616e50726f6a65637430820122300d06092a864886f70d01010105000382010f003082010a0282010100c7ab44b130be5c00eedcc3625462f6f6ac26e502641cd641f3e30cbb0ff1ba325158611e7fc2448a35b6a6df30dc6e23602cf6909448befcf11e2fe486b580f1e76fe5887d159050d00afd2c4079f6538896bb200627f4b3e874f011ce5df0fef5d150fcb0b377b531254e436eaf4083ea72fe3b8c3ef450789fa858f2be8f6c5335bb326aff3dda689fbc7b5ba98dea53651dbea7452c38d294985ac5dd8a9e491a695de92c706d682d6911411fcaef3b0a08a030fe8a84e47acaab0b7edcda9d190ce39e810b79b1d8732eca22b15f0d048c8d6f00503a7ee81ab6e08919ff465883432304d95238b95e95c5f74e0a421809e2a6a85825aed680e0d6939e8f0203010001300d06092a864886f70d010105050003820101006d17aad3271b8b2c299dbdb7b1182849b0d5ddb9f1016dcb3487ae0db02b6be503344c7d066e2050bcd01d411b5ee78c7ed450f0ff9da5ce228f774cbf41240361df53d9c6078159d16f4d34379ab7dedf6186489397c83b44b964251a2ebb42b7c4689a521271b1056d3b5a5fa8f28ba64fb8ce5e2226c33c45d27ba3f632dc266c12abf582b8438c2abcf3eae9de9f31152b4158ace0ef33435c20eb809f1b3988131db6e5a1442f2617c3491d9565fedb3e320e8df4236200d3bd265e47934aa578f84d0d1a5efeb49b39907e876452c46996d0feff9404b41aa5631b4482175d843d5512ded45e12a514690646492191e7add434afce63dbff8f0b03ec0c";
|
||||
expectedRepo.description = "A local FDroid repo generated from apps installed on Android-Nexus-7-20139453";
|
||||
processFile("smallRepo.xml");
|
||||
handlerTestSuite(expectedRepo, 12, 12);
|
||||
assertEquals(actualRepo.maxage, 14);
|
||||
assertEquals(actualRepo.version, -1);
|
||||
checkIncludedApps(new String[] {
|
||||
RepoDetails actualDetails = getFromFile("smallRepo.xml");
|
||||
handlerTestSuite(expectedRepo, actualDetails, 12, 12, 14, -1);
|
||||
checkIncludedApps(actualDetails.apps, new String[]{
|
||||
"org.mozilla.firefox",
|
||||
"com.koushikdutta.superuser",
|
||||
"info.guardianproject.courier",
|
||||
@ -103,11 +74,9 @@ public class RepoXMLHandlerTest extends AndroidTestCase {
|
||||
expectedRepo.name = "Guardian Project Official Releases";
|
||||
expectedRepo.pubkey = "308205d8308203c0020900a397b4da7ecda034300d06092a864886f70d01010505003081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f301e170d3134303632363139333931385a170d3431313131303139333931385a3081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f30820222300d06092a864886f70d01010105000382020f003082020a0282020100b3cd79121b9b883843be3c4482e320809106b0a23755f1dd3c7f46f7d315d7bb2e943486d61fc7c811b9294dcc6b5baac4340f8db2b0d5e14749e7f35e1fc211fdbc1071b38b4753db201c314811bef885bd8921ad86facd6cc3b8f74d30a0b6e2e6e576f906e9581ef23d9c03e926e06d1f033f28bd1e21cfa6a0e3ff5c9d8246cf108d82b488b9fdd55d7de7ebb6a7f64b19e0d6b2ab1380a6f9d42361770d1956701a7f80e2de568acd0bb4527324b1e0973e89595d91c8cc102d9248525ae092e2c9b69f7414f724195b81427f28b1d3d09a51acfe354387915fd9521e8c890c125fc41a12bf34d2a1b304067ab7251e0e9ef41833ce109e76963b0b256395b16b886bca21b831f1408f836146019e7908829e716e72b81006610a2af08301de5d067c9e114a1e5759db8a6be6a3cc2806bcfe6fafd41b5bc9ddddb3dc33d6f605b1ca7d8a9e0ecdd6390d38906649e68a90a717bea80fa220170eea0c86fc78a7e10dac7b74b8e62045a3ecca54e035281fdc9fe5920a855fde3c0be522e3aef0c087524f13d973dff3768158b01a5800a060c06b451ec98d627dd052eda804d0556f60dbc490d94e6e9dea62ffcafb5beffbd9fc38fb2f0d7050004fe56b4dda0a27bc47554e1e0a7d764e17622e71f83a475db286bc7862deee1327e2028955d978272ea76bf0b88e70a18621aba59ff0c5993ef5f0e5d6b6b98e68b70203010001300d06092a864886f70d0101050500038202010079c79c8ef408a20d243d8bd8249fb9a48350dc19663b5e0fce67a8dbcb7de296c5ae7bbf72e98a2020fb78f2db29b54b0e24b181aa1c1d333cc0303685d6120b03216a913f96b96eb838f9bff125306ae3120af838c9fc07ebb5100125436bd24ec6d994d0bff5d065221871f8410daf536766757239bf594e61c5432c9817281b985263bada8381292e543a49814061ae11c92a316e7dc100327b59e3da90302c5ada68c6a50201bda1fcce800b53f381059665dbabeeb0b50eb22b2d7d2d9b0aa7488ca70e67ac6c518adb8e78454a466501e89d81a45bf1ebc350896f2c3ae4b6679ecfbf9d32960d4f5b493125c7876ef36158562371193f600bc511000a67bdb7c664d018f99d9e589868d103d7e0994f166b2ba18ff7e67d8c4da749e44dfae1d930ae5397083a51675c409049dfb626a96246c0015ca696e94ebb767a20147834bf78b07fece3f0872b057c1c519ff882501995237d8206b0b3832f78753ebd8dcbd1d3d9f5ba733538113af6b407d960ec4353c50eb38ab29888238da843cd404ed8f4952f59e4bbc0035fc77a54846a9d419179c46af1b4a3b7fc98e4d312aaa29b9b7d79e739703dc0fa41c7280d5587709277ffa11c3620f5fba985b82c238ba19b17ebd027af9424be0941719919f620dd3bb3c3f11638363708aa11f858e153cf3a69bce69978b90e4a273836100aa1e617ba455cd00426847f";
|
||||
expectedRepo.description = "The official app repository of The Guardian Project. Applications in this repository are official binaries build by the original application developers and signed by the same key as the APKs that are released in the Google Play store.";
|
||||
processFile("mediumRepo.xml");
|
||||
handlerTestSuite(expectedRepo, 15, 36);
|
||||
assertEquals(expectedRepo.maxage, 60);
|
||||
assertEquals(expectedRepo.version, 12);
|
||||
checkIncludedApps(new String[] {
|
||||
RepoDetails actualDetails = getFromFile("mediumRepo.xml");
|
||||
handlerTestSuite(expectedRepo, actualDetails, 15, 36, 60, 12);
|
||||
checkIncludedApps(actualDetails.apps, new String[]{
|
||||
"info.guardianproject.cacert",
|
||||
"info.guardianproject.otr.app.im",
|
||||
"info.guardianproject.soundrecorder",
|
||||
@ -131,15 +100,13 @@ public class RepoXMLHandlerTest extends AndroidTestCase {
|
||||
expectedRepo.name = "F-Droid";
|
||||
expectedRepo.pubkey = "3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef";
|
||||
expectedRepo.description = "The official FDroid repository. Applications in this repository are mostly built directory from the source code. Some are official binaries built by the original application developers - these will be replaced by source-built versions over time.";
|
||||
processFile("largeRepo.xml");
|
||||
handlerTestSuite(expectedRepo, 1211, 2381);
|
||||
assertEquals("Repo max age", 14, expectedRepo.maxage);
|
||||
assertEquals("Repo version", 12, expectedRepo.version);
|
||||
RepoDetails actualDetails = getFromFile("largeRepo.xml");
|
||||
handlerTestSuite(expectedRepo, actualDetails, 1211, 2381, 14, 12);
|
||||
/*
|
||||
* generated using: sed 's,<application,\n<application,g' largeRepo.xml
|
||||
* | sed -n 's,.*id="\(.[^"]*\)".*,"\1"\,,p'
|
||||
*/
|
||||
checkIncludedApps(new String[]{
|
||||
checkIncludedApps(actualDetails.apps, new String[]{
|
||||
"org.zeroxlab.zeroxbenchmark", "com.uberspot.a2048", "com.traffar.a24game",
|
||||
"info.staticfree.android.twentyfourhour", "nerd.tuxmobil.fahrplan.congress",
|
||||
"com.jecelyin.editor", "com.markuspage.android.atimetracker", "a2dp.Vol",
|
||||
@ -622,11 +589,11 @@ public class RepoXMLHandlerTest extends AndroidTestCase {
|
||||
});
|
||||
}
|
||||
|
||||
private void checkIncludedApps(String[] packageNames) {
|
||||
private void checkIncludedApps(List<App> actualApps, String[] expctedAppIds) {
|
||||
assertNotNull(actualApps);
|
||||
assertNotNull(packageNames);
|
||||
assertEquals(actualApps.size(), packageNames.length);
|
||||
for (String id : packageNames) {
|
||||
assertNotNull(expctedAppIds);
|
||||
assertEquals(actualApps.size(), expctedAppIds.length);
|
||||
for (String id : expctedAppIds) {
|
||||
boolean thisAppMissing = true;
|
||||
for (App app : actualApps) {
|
||||
if (TextUtils.equals(app.id, id)) {
|
||||
@ -638,53 +605,84 @@ public class RepoXMLHandlerTest extends AndroidTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
private void handlerTestSuite(Repo expectedRepo, int appCount, int apkCount) {
|
||||
assertFalse(TextUtils.isEmpty(actualRepo.pubkey));
|
||||
assertEquals(expectedRepo.pubkey.length(), actualRepo.pubkey.length());
|
||||
assertEquals(expectedRepo.pubkey, actualRepo.pubkey);
|
||||
assertFalse(FAKE_PUBKEY.equals(actualRepo.pubkey));
|
||||
private void handlerTestSuite(Repo expectedRepo, RepoDetails actualDetails, int appCount, int apkCount, int maxAge, int version) {
|
||||
assertNotNull(actualDetails);
|
||||
assertFalse(TextUtils.isEmpty(actualDetails.signingCert));
|
||||
assertEquals(expectedRepo.pubkey.length(), actualDetails.signingCert.length());
|
||||
assertEquals(expectedRepo.pubkey, actualDetails.signingCert);
|
||||
assertFalse(FAKE_PUBKEY.equals(actualDetails.signingCert));
|
||||
|
||||
assertFalse(TextUtils.isEmpty(actualRepo.name));
|
||||
assertEquals(expectedRepo.name.length(), actualRepo.name.length());
|
||||
assertEquals(expectedRepo.name, actualRepo.name);
|
||||
assertFalse(TextUtils.isEmpty(actualDetails.name));
|
||||
assertEquals(expectedRepo.name.length(), actualDetails.name.length());
|
||||
assertEquals(expectedRepo.name, actualDetails.name);
|
||||
|
||||
assertFalse(TextUtils.isEmpty(actualRepo.description));
|
||||
assertEquals(expectedRepo.description.length(), actualRepo.description.length());
|
||||
assertEquals(expectedRepo.description, actualRepo.description);
|
||||
assertFalse(TextUtils.isEmpty(actualDetails.description));
|
||||
assertEquals(expectedRepo.description.length(), actualDetails.description.length());
|
||||
assertEquals(expectedRepo.description, actualDetails.description);
|
||||
|
||||
assertNotNull(actualApps);
|
||||
assertEquals(actualApps.size(), appCount);
|
||||
assertEquals(actualDetails.maxAge, maxAge);
|
||||
assertEquals(actualDetails.version, version);
|
||||
|
||||
List<Apk> apks = actualApks;
|
||||
List<App> apps = actualDetails.apps;
|
||||
assertNotNull(apps);
|
||||
assertEquals(apps.size(), appCount);
|
||||
|
||||
List<Apk> apks = actualDetails.apks;
|
||||
assertNotNull(apks);
|
||||
assertEquals(apks.size(), apkCount);
|
||||
}
|
||||
|
||||
private static class MockRepo extends Repo {
|
||||
private static class RepoDetails implements RepoXMLHandler.IndexReceiver {
|
||||
|
||||
public String name;
|
||||
public String description;
|
||||
public String signingCert;
|
||||
public int maxAge;
|
||||
public int version;
|
||||
|
||||
public List<Apk> apks = new ArrayList<>();
|
||||
public List<App> apps = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return 10000;
|
||||
}
|
||||
public void receiveRepo(String name, String description, String signingCert, int maxage, int version) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.signingCert = signingCert;
|
||||
this.maxAge = maxage;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
private RepoXMLHandler processFile(String indexFilename) {
|
||||
@Override
|
||||
public void receiveApp(App app, List<Apk> packages) {
|
||||
apks.addAll(packages);
|
||||
apps.add(app);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private RepoDetails getFromFile(String indexFilename) {
|
||||
SAXParser parser;
|
||||
try {
|
||||
parser = SAXParserFactory.newInstance().newSAXParser();
|
||||
XMLReader reader = parser.getXMLReader();
|
||||
RepoXMLHandler handler = new RepoXMLHandler(new MockRepo(), indexReceiver);
|
||||
RepoDetails repoDetails = new RepoDetails();
|
||||
RepoXMLHandler handler = new RepoXMLHandler(new MockRepo(100), repoDetails);
|
||||
reader.setContentHandler(handler);
|
||||
String resName = "assets/" + indexFilename;
|
||||
Log.i(TAG, "test file: " + getClass().getClassLoader().getResource(resName));
|
||||
InputStream input = getClass().getClassLoader().getResourceAsStream(resName);
|
||||
InputSource is = new InputSource(new BufferedInputStream(input));
|
||||
reader.parse(is);
|
||||
return handler;
|
||||
return repoDetails;
|
||||
} catch (ParserConfigurationException | SAXException | IOException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
}
|
||||
|
||||
// Satisfies the compiler, but fail() will always throw a runtime exception so we never
|
||||
// reach this return statement.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user