Bug 1280855 - Read original metadata from attachment key; r?sebastian
MozReview-Commit-ID: Kgdc6Nl6hho
--- a/mobile/android/base/java/org/mozilla/gecko/dlc/SyncAction.java
+++ b/mobile/android/base/java/org/mozilla/gecko/dlc/SyncAction.java
@@ -29,16 +29,18 @@ import java.net.HttpURLConnection;
* Sync: Synchronize catalog from a Kinto instance.
*/
public class SyncAction extends BaseAction {
private static final String LOGTAG = "DLCSyncAction";
private static final String KINTO_KEY_ID = "id";
private static final String KINTO_KEY_DELETED = "deleted";
private static final String KINTO_KEY_DATA = "data";
+ private static final String KINTO_KEY_ATTACHMENT = "attachment";
+ private static final String KINTO_KEY_ORIGINAL = "original";
private static final String KINTO_PARAMETER_SINCE = "_since";
private static final String KINTO_PARAMETER_FIELDS = "_fields";
private static final String KINTO_PARAMETER_SORT = "_sort";
/**
* Kinto endpoint with online version of downloadable content catalog
*
@@ -68,16 +70,22 @@ public class SyncAction extends BaseActi
Log.d(LOGTAG, "Server returned " + rawCatalog.length() + " records (since " + lastModified + ")");
for (int i = 0; i < rawCatalog.length(); i++) {
JSONObject object = rawCatalog.getJSONObject(i);
String id = object.getString(KINTO_KEY_ID);
final boolean isDeleted = object.optBoolean(KINTO_KEY_DELETED, false);
+ if (!isDeleted) {
+ JSONObject attachment = object.getJSONObject(KINTO_KEY_ATTACHMENT);
+ if (attachment.isNull(KINTO_KEY_ORIGINAL))
+ throw new JSONException(String.format("Old Attachment Format"));
+ }
+
DownloadContent existingContent = catalog.getContentById(id);
if (isDeleted) {
cleanupRequired |= deleteContent(catalog, id);
} else if (existingContent != null) {
studyRequired |= updateContent(catalog, object, existingContent);
} else {
studyRequired |= createContent(catalog, object);
@@ -117,17 +125,17 @@ public class SyncAction extends BaseActi
try {
Uri.Builder builder = Uri.parse(CATALOG_ENDPOINT).buildUpon();
if (lastModified > 0) {
builder.appendQueryParameter(KINTO_PARAMETER_SINCE, String.valueOf(lastModified));
}
// Only select the fields we are actually going to read.
builder.appendQueryParameter(KINTO_PARAMETER_FIELDS,
- "attachment.location,original.filename,original.hash,attachment.hash,type,kind,original.size,match");
+ "attachment.location,attachment.original.filename,attachment.original.hash,attachment.hash,type,kind,attachment.original.size,match");
// We want to process items in the order they have been modified. This is to ensure that
// our last_modified values are correct if we processing is interrupted and not all items
// have been processed.
builder.appendQueryParameter(KINTO_PARAMETER_SORT, "last_modified");
connection = buildHttpURLConnection(builder.build().toString());
--- a/mobile/android/base/java/org/mozilla/gecko/dlc/catalog/DownloadContentBuilder.java
+++ b/mobile/android/base/java/org/mozilla/gecko/dlc/catalog/DownloadContentBuilder.java
@@ -211,24 +211,23 @@ public class DownloadContentBuilder {
} else if (!id.equals(objectId)) {
throw new JSONException(String.format("Record ids do not match: Expected=%s, Actual=%s", id, objectId));
}
setType(object.getString(KINTO_KEY_TYPE));
setKind(object.getString(KINTO_KEY_KIND));
setLastModified(object.getLong(KINTO_KEY_LAST_MODIFIED));
- JSONObject original = object.getJSONObject(KINTO_KEY_ORIGINAL);
+ JSONObject attachment = object.getJSONObject(KINTO_KEY_ATTACHMENT);
+ JSONObject original = attachment.getJSONObject(KINTO_KEY_ORIGINAL);
setFilename(original.getString(KINTO_KEY_FILENAME));
setChecksum(original.getString(KINTO_KEY_HASH));
setSize(original.getLong(KINTO_KEY_SIZE));
- JSONObject attachment = object.getJSONObject(KINTO_KEY_ATTACHMENT);
-
setLocation(attachment.getString(KINTO_KEY_LOCATION));
setDownloadChecksum(attachment.getString(KINTO_KEY_HASH));
JSONObject match = object.optJSONObject(KINTO_KEY_MATCH);
if (match != null) {
setAndroidApiPattern(match.optString(KINTO_KEY_ANDROID_API));
setAppIdPattern(match.optString(KINTO_KEY_APP_ID));
setAppVersionPattern(match.optString(KINTO_KEY_APP_VERSION));
new file mode 100644
--- /dev/null
+++ b/mobile/android/tests/background/junit4/resources/dlc_sync_old_format.json
@@ -0,0 +1,23 @@
+{
+ "data":[
+ {
+ "kind":"font",
+ "original": {
+ "mimetype":"application/x-font-ttf",
+ "filename":"CharisSILCompact-R.ttf",
+ "hash":"4ed509317f1bb441b185ea13bf1c9d19d1a0b396962efa3b5dc3190ad88f2067",
+ "size":1727656
+ },
+ "last_modified":1455710632607,
+ "attachment": {
+ "mimetype":"application/x-gzip",
+ "size":548720,
+ "hash":"960be4fc5a92c1dc488582b215d5d75429fd4ffbee463105d29992cd792a912e",
+ "location":"/attachments/0d28a72d-a51f-46f8-9e5a-f95c61de904e.gz",
+ "filename":"CharisSILCompact-R.ttf.gz"
+ },
+ "type":"asset-archive",
+ "id":"c906275c-3747-fe27-426f-6187526a6f06"
+ }
+ ]
+}
--- a/mobile/android/tests/background/junit4/resources/dlc_sync_single_font.json
+++ b/mobile/android/tests/background/junit4/resources/dlc_sync_single_font.json
@@ -1,23 +1,23 @@
{
"data":[
{
"kind":"font",
- "original": {
- "mimetype":"application/x-font-ttf",
- "filename":"CharisSILCompact-R.ttf",
- "hash":"4ed509317f1bb441b185ea13bf1c9d19d1a0b396962efa3b5dc3190ad88f2067",
- "size":1727656
- },
"last_modified":1455710632607,
"attachment": {
"mimetype":"application/x-gzip",
"size":548720,
"hash":"960be4fc5a92c1dc488582b215d5d75429fd4ffbee463105d29992cd792a912e",
"location":"/attachments/0d28a72d-a51f-46f8-9e5a-f95c61de904e.gz",
- "filename":"CharisSILCompact-R.ttf.gz"
+ "filename":"CharisSILCompact-R.ttf.gz",
+ "original": {
+ "mimetype":"application/x-font-ttf",
+ "filename":"CharisSILCompact-R.ttf",
+ "hash":"4ed509317f1bb441b185ea13bf1c9d19d1a0b396962efa3b5dc3190ad88f2067",
+ "size":1727656
+ }
},
"type":"asset-archive",
"id":"c906275c-3747-fe27-426f-6187526a6f06"
}
]
}
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/TestSyncAction.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/TestSyncAction.java
@@ -99,16 +99,38 @@ public class TestSyncAction {
Assert.assertEquals("/attachments/0d28a72d-a51f-46f8-9e5a-f95c61de904e.gz", content.getLocation());
Assert.assertEquals(DownloadContent.TYPE_ASSET_ARCHIVE, content.getType());
Assert.assertEquals(1455710632607L, content.getLastModified());
Assert.assertEquals(1727656L, content.getSize());
Assert.assertEquals(DownloadContent.STATE_NONE, content.getState());
}
/**
+ * Scenario: The catalog is using the old format, we want to make sure we abort cleanly.
+ */
+ @Test
+ public void testUpdatingWithOldCatalog() throws Exception{
+ SyncAction action = spy(new SyncAction());
+ doReturn(true).when(action).isSyncEnabledForClient(RuntimeEnvironment.application);
+ doReturn(fromFile("dlc_sync_old_format.json")).when(action).fetchRawCatalog(anyLong());
+
+ DownloadContent existingContent = createTestContent("c906275c-3747-fe27-426f-6187526a6f06");
+ DownloadContentCatalog catalog = spy(new MockedContentCatalog(existingContent));
+
+ action.perform(RuntimeEnvironment.application, catalog);
+
+ // make sure nothing was done
+ verify(action, never()).createContent(anyCatalog(), anyJSONObject());
+ verify(action, never()).updateContent(anyCatalog(), anyJSONObject(), anyContent());
+ verify(action, never()).deleteContent(anyCatalog(), anyString());
+ verify(action, never()).startStudyAction(anyContext());
+ }
+
+
+ /**
* Scenario: The catalog contains one item and the server returns a new version.
*/
@Test
public void testUpdatingExistingContent() throws Exception{
SyncAction action = spy(new SyncAction());
doReturn(true).when(action).isSyncEnabledForClient(RuntimeEnvironment.application);
doReturn(fromFile("dlc_sync_single_font.json")).when(action).fetchRawCatalog(anyLong());