Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
933
gaia/apps/sync/test/unit/adapters/bookmarks_test.js
Executable file
933
gaia/apps/sync/test/unit/adapters/bookmarks_test.js
Executable file
|
|
@ -0,0 +1,933 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
'use strict';
|
||||
|
||||
/* global
|
||||
asyncStorage,
|
||||
BOOKMARKS_COLLECTION_MTIME,
|
||||
BOOKMARKS_LAST_REVISIONID,
|
||||
BOOKMARKS_SYNCTOID_PREFIX,
|
||||
BookmarksHelper,
|
||||
DataAdapters,
|
||||
ERROR_SYNC_APP_RACE_CONDITION,
|
||||
MockasyncStorage,
|
||||
MockDatastore,
|
||||
MockLazyLoader,
|
||||
MockNavigatorDatastore
|
||||
*/
|
||||
|
||||
require('/shared/js/sync/errors.js');
|
||||
require('/shared/test/unit/mocks/mock_lazy_loader.js');
|
||||
require('/shared/test/unit/mocks/mock_navigator_datastore.js');
|
||||
require('/apps/system/test/unit/mock_asyncStorage.js');
|
||||
requireApp('sync/js/adapters/bookmarks.js');
|
||||
|
||||
window.DataAdapters = {};
|
||||
|
||||
suite('sync/adapters/bookmarks >', function() {
|
||||
var realDatastore, realLazyLoader, realAsyncStorage, testCollectionData;
|
||||
var kintoCollection = {
|
||||
list() {
|
||||
return Promise.resolve({
|
||||
data: testCollectionData
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function getBookmarksStore() {
|
||||
return navigator.getDataStores().then(stores => {
|
||||
return Promise.resolve(stores[0]);
|
||||
});
|
||||
}
|
||||
|
||||
function verifyBookmarks(collectionItem, bookmarksItem) {
|
||||
var payload = collectionItem.payload;
|
||||
var keys = [
|
||||
'id',
|
||||
'type',
|
||||
'iconable',
|
||||
'icon',
|
||||
'createdLocally',
|
||||
'fxsyncRecords'
|
||||
];
|
||||
if (payload.type !== 'separator') {
|
||||
keys.push('name');
|
||||
}
|
||||
if (['bookmark', 'query'].indexOf(payload.type) !== -1) {
|
||||
keys.push('url');
|
||||
}
|
||||
assert.equal(Object.keys(bookmarksItem).length, keys.length);
|
||||
keys.forEach(key => assert.equal(bookmarksItem.hasOwnProperty(key), true));
|
||||
|
||||
switch (payload.type) {
|
||||
case 'bookmark':
|
||||
assert.equal(payload.bmkUri, bookmarksItem.id);
|
||||
assert.equal(payload.bmkUri, bookmarksItem.url);
|
||||
assert.equal(payload.title, bookmarksItem.name);
|
||||
assert.deepEqual(payload, bookmarksItem.fxsyncRecords[payload.id]);
|
||||
assert.equal('url', bookmarksItem.type);
|
||||
break;
|
||||
case 'query':
|
||||
assert.equal(payload.type + '|' + payload.id, bookmarksItem.id);
|
||||
assert.equal(payload.bmkUri, bookmarksItem.url);
|
||||
assert.equal(payload.title, bookmarksItem.name);
|
||||
assert.deepEqual(payload, bookmarksItem.fxsyncRecords[payload.id]);
|
||||
assert.equal('others', bookmarksItem.type);
|
||||
break;
|
||||
case 'folder':
|
||||
assert.equal(payload.type + '|' + payload.id, bookmarksItem.id);
|
||||
assert.equal(payload.title, bookmarksItem.name);
|
||||
assert.deepEqual(payload, bookmarksItem.fxsyncRecords[payload.id]);
|
||||
assert.equal('others', bookmarksItem.type);
|
||||
break;
|
||||
case 'livemark':
|
||||
assert.equal(payload.type + '|' + payload.id, bookmarksItem.id);
|
||||
assert.equal(payload.title, bookmarksItem.name);
|
||||
assert.deepEqual(payload, bookmarksItem.fxsyncRecords[payload.id]);
|
||||
assert.equal('others', bookmarksItem.type);
|
||||
break;
|
||||
case 'separator':
|
||||
assert.equal(payload.type + '|' + payload.id, bookmarksItem.id);
|
||||
assert.deepEqual(payload, bookmarksItem.fxsyncRecords[payload.id]);
|
||||
assert.equal('others', bookmarksItem.type);
|
||||
break;
|
||||
case 'microsummary':
|
||||
console.warn('microsummary is OBSOLETED ', payload);
|
||||
break;
|
||||
default:
|
||||
assert.ok(false, 'Unknown type');
|
||||
}
|
||||
}
|
||||
|
||||
function testDataGenerator(initIndex, initDate, count) {
|
||||
var list = [];
|
||||
for (var i = initIndex; i < initIndex + count; i++) {
|
||||
var visits = [];
|
||||
var startData = initDate + i * 100;
|
||||
for (var j = 0; j < 3; j++) {
|
||||
visits.push({
|
||||
date: (startData + j * 10) * 1000, type: 3
|
||||
});
|
||||
}
|
||||
|
||||
list.unshift({
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
last_modified: initDate + i * 10,
|
||||
payload: {
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
bmkUri: 'http://example' + i + '.com/',
|
||||
title: 'Example ' + i + ' Title',
|
||||
type: 'bookmark'
|
||||
}
|
||||
});
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
suiteSetup(() => {
|
||||
realDatastore = navigator.getDataStores;
|
||||
|
||||
realAsyncStorage = window.asyncStorage;
|
||||
window.asyncStorage = MockasyncStorage;
|
||||
|
||||
realLazyLoader = window.LazyLoader;
|
||||
window.LazyLoader = MockLazyLoader;
|
||||
});
|
||||
|
||||
suiteTeardown(() => {
|
||||
navigator.getDataStores = realDatastore;
|
||||
|
||||
window.LazyLoader = realLazyLoader;
|
||||
|
||||
window.asyncStorage = realAsyncStorage;
|
||||
});
|
||||
|
||||
setup(() => {
|
||||
navigator.getDataStores = MockNavigatorDatastore.getDataStores;
|
||||
testCollectionData = [];
|
||||
MockDatastore._tasks[1].revisionId = 'latest-not-cleared';
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
MockDatastore._inError = false;
|
||||
MockDatastore._records = Object.create(null);
|
||||
window.asyncStorage.mTeardown();
|
||||
});
|
||||
|
||||
test('update - empty records', function(done) {
|
||||
var bookmarksAdapter = DataAdapters.bookmarks;
|
||||
bookmarksAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
|
||||
.then(result => {
|
||||
assert.equal(result, false);
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
|
||||
null);
|
||||
assert.equal(asyncStorage.mItems[BOOKMARKS_LAST_REVISIONID], null);
|
||||
}).then(done, reason => {
|
||||
done(reason || new Error('Rejected by undefined reason.'));
|
||||
});
|
||||
});
|
||||
|
||||
['clear', 'remove'].forEach(task => {
|
||||
suite(`after a DataStore ${task}`, function() {
|
||||
suiteSetup(function() {
|
||||
MockDatastore._taskCounter = 0;
|
||||
MockDatastore._tasks = [
|
||||
{
|
||||
operation: 'clear',
|
||||
id: 0,
|
||||
data: {}
|
||||
},
|
||||
{
|
||||
operation: 'add',
|
||||
id: 0,
|
||||
data: {}
|
||||
},
|
||||
{
|
||||
operation: task,
|
||||
id: 0,
|
||||
data: {}
|
||||
},
|
||||
{
|
||||
operation: 'done',
|
||||
id: 0,
|
||||
revisionId: `latest-after-${task}`,
|
||||
data: null
|
||||
}
|
||||
];
|
||||
});
|
||||
suiteTeardown(function() {
|
||||
MockDatastore._taskCounter = 0;
|
||||
MockDatastore._tasks = [
|
||||
{
|
||||
operation: 'update',
|
||||
id: 0,
|
||||
data: {}
|
||||
},
|
||||
{
|
||||
operation: 'done',
|
||||
id: 0,
|
||||
data: null,
|
||||
revisionId: 'latest-not-cleared'
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
test('update - refills the DataStore', function(done) {
|
||||
var bookmarksAdapter = DataAdapters.bookmarks;
|
||||
testCollectionData = testDataGenerator(1, 1440000000, 5);
|
||||
asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME] =
|
||||
testCollectionData[0].last_modified;
|
||||
bookmarksAdapter.update(kintoCollection,
|
||||
{ readonly: true, userid: 'foo' })
|
||||
.then(() => {
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
|
||||
testCollectionData[0].last_modified);
|
||||
getBookmarksStore().then(bookmarksStore => {
|
||||
var ids = testCollectionData.map(item => {
|
||||
return item.payload.bmkUri;
|
||||
});
|
||||
bookmarksStore.get.apply(bookmarksStore, ids).then(list => {
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
verifyBookmarks(testCollectionData[i], list[i]);
|
||||
assert.equal(
|
||||
asyncStorage.mItems['foo' + BOOKMARKS_SYNCTOID_PREFIX +
|
||||
testCollectionData[i].id],
|
||||
testCollectionData[i].payload.bmkUri);
|
||||
}
|
||||
assert.equal(asyncStorage.mItems[
|
||||
'foo' + BOOKMARKS_LAST_REVISIONID], `latest-after-${task}`);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('update - does not refill the DataStore if nothing removed locally',
|
||||
function(done) {
|
||||
var bookmarksAdapter = DataAdapters.bookmarks;
|
||||
testCollectionData = testDataGenerator(1, 1440000000, 5);
|
||||
asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME] =
|
||||
testCollectionData[0].last_modified;
|
||||
bookmarksAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
|
||||
.then(() => {
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
|
||||
testCollectionData[0].last_modified);
|
||||
getBookmarksStore().then(bookmarksStore => {
|
||||
var ids = testCollectionData.map(item => {
|
||||
return item.payload.bmkUri;
|
||||
});
|
||||
bookmarksStore.get.apply(bookmarksStore, ids).then(list => {
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
assert.equal(list[i], null);
|
||||
}
|
||||
assert.equal(asyncStorage.mItems[
|
||||
'foo' + BOOKMARKS_LAST_REVISIONID], 'latest-not-cleared');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('if a DataStore race condition occurs', function() {
|
||||
setup(function() {
|
||||
MockDatastore._raceCondition = true;
|
||||
});
|
||||
teardown(function() {
|
||||
delete MockDatastore._raceCondition;
|
||||
});
|
||||
|
||||
test('update - rejects its promise', function(done) {
|
||||
var bookmarksAdapter = DataAdapters.bookmarks;
|
||||
var lazyLoaderSpy = this.sinon.spy(MockLazyLoader, 'load');
|
||||
|
||||
testCollectionData = testDataGenerator(1, 1440000000, 5);
|
||||
bookmarksAdapter.update(kintoCollection,
|
||||
{ readonly: true, userid: 'foo' }).catch(error => {
|
||||
assert.equal(lazyLoaderSpy.calledWith(['shared/js/sync/errors.js']),
|
||||
true);
|
||||
assert.equal(error.message, ERROR_SYNC_APP_RACE_CONDITION);
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
|
||||
null);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('update - 1 sync request with 5 new records', function(done) {
|
||||
var bookmarksAdapter = DataAdapters.bookmarks;
|
||||
var lazyLoaderSpy = this.sinon.spy(MockLazyLoader, 'load');
|
||||
testCollectionData = testDataGenerator(1, 1440000000, 5);
|
||||
bookmarksAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
|
||||
.then(result => {
|
||||
var mTime = testCollectionData[0].last_modified;
|
||||
assert.equal(result, false);
|
||||
assert.equal(lazyLoaderSpy.calledWith(['shared/js/async_storage.js']),
|
||||
true);
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
|
||||
mTime);
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
|
||||
'latest-not-cleared');
|
||||
return Promise.resolve();
|
||||
}).then(getBookmarksStore).then(bookmarksStore => {
|
||||
var ids = testCollectionData.map(item => {
|
||||
return item.payload.bmkUri;
|
||||
});
|
||||
return bookmarksStore.get.apply(bookmarksStore, ids).then(list => {
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
verifyBookmarks(testCollectionData[i], list[i]);
|
||||
assert.equal(
|
||||
asyncStorage.mItems['foo' + BOOKMARKS_SYNCTOID_PREFIX +
|
||||
testCollectionData[i].id],
|
||||
testCollectionData[i].payload.bmkUri);
|
||||
}
|
||||
});
|
||||
}).then(done, reason => {
|
||||
done(reason || new Error('Rejected by undefined reason.'));
|
||||
});
|
||||
});
|
||||
|
||||
test('update - 2 sync requests', function(done) {
|
||||
var bookmarksAdapter = DataAdapters.bookmarks;
|
||||
Promise.resolve().then(() => {
|
||||
testCollectionData = testDataGenerator(1, 100, 5)
|
||||
.concat(testCollectionData);
|
||||
return bookmarksAdapter.update(kintoCollection,
|
||||
{ readonly: true, userid: 'foo' });
|
||||
}).then(result => {
|
||||
assert.equal(result, false);
|
||||
var mTime = testCollectionData[0].last_modified;
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
|
||||
mTime);
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
|
||||
'latest-not-cleared');
|
||||
return Promise.resolve();
|
||||
}).then(() => {
|
||||
testCollectionData = testDataGenerator(6, 500, 5)
|
||||
.concat(testCollectionData);
|
||||
return bookmarksAdapter.update(kintoCollection,
|
||||
{ readonly: true, userid: 'foo' });
|
||||
}).then(result => {
|
||||
assert.equal(result, false);
|
||||
var mTime = testCollectionData[0].last_modified;
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
|
||||
mTime);
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
|
||||
'latest-not-cleared');
|
||||
return Promise.resolve();
|
||||
}).then(getBookmarksStore).then(bookmarksStore => {
|
||||
var ids = testCollectionData.map(item => {
|
||||
return item.payload.bmkUri;
|
||||
});
|
||||
return bookmarksStore.get.apply(bookmarksStore, ids).then(list => {
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
verifyBookmarks(testCollectionData[i], list[i]);
|
||||
assert.equal(
|
||||
asyncStorage.mItems['foo' + BOOKMARKS_SYNCTOID_PREFIX +
|
||||
testCollectionData[i].id],
|
||||
testCollectionData[i].payload.bmkUri);
|
||||
}
|
||||
});
|
||||
}).then(done, reason => {
|
||||
done(reason || new Error('Rejected by undefined reason.'));
|
||||
});
|
||||
});
|
||||
|
||||
test('update - 2 sync requests with 2 deleted: true records', function(done) {
|
||||
var bookmarksAdapter = DataAdapters.bookmarks, store;
|
||||
var deletedQueue = ['UNIQUE_ID_1', 'UNIQUE_ID_4'];
|
||||
Promise.resolve().then(() => {
|
||||
testCollectionData = testDataGenerator(1, 100, 5)
|
||||
.concat(testCollectionData);
|
||||
return bookmarksAdapter.update(kintoCollection,
|
||||
{ readonly: true, userid: 'foo' });
|
||||
}).then(result => {
|
||||
assert.equal(result, false);
|
||||
var mTime = testCollectionData[0].last_modified;
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
|
||||
mTime);
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
|
||||
'latest-not-cleared');
|
||||
return Promise.resolve();
|
||||
}).then(() => {
|
||||
testCollectionData = testDataGenerator(6, 500, 5)
|
||||
.concat(testCollectionData);
|
||||
var latestModified = testCollectionData[0].last_modified + 10000;
|
||||
var deletedRecords = [];
|
||||
deletedQueue.forEach((synctoId, i) => {
|
||||
deletedRecords.push({
|
||||
id: synctoId,
|
||||
last_modified: latestModified + 10000 * i,
|
||||
payload: {
|
||||
deleted: true,
|
||||
id: synctoId
|
||||
}
|
||||
});
|
||||
});
|
||||
testCollectionData = deletedRecords.concat(testCollectionData);
|
||||
return bookmarksAdapter.update(kintoCollection,
|
||||
{ readonly: true, userid: 'foo' });
|
||||
}).then(result => {
|
||||
assert.equal(result, false);
|
||||
var mTime = testCollectionData[0].last_modified;
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
|
||||
mTime);
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
|
||||
'latest-not-cleared');
|
||||
return Promise.resolve();
|
||||
}).then(getBookmarksStore).then(bookmarksStore => {
|
||||
store = bookmarksStore;
|
||||
var ids = testCollectionData.map(item => {
|
||||
return item.payload.bmkUri;
|
||||
});
|
||||
return store.get.apply(store, ids).then(list => {
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
if (list[i]) {
|
||||
verifyBookmarks(testCollectionData[i], list[i]);
|
||||
assert.equal(
|
||||
asyncStorage.mItems['foo' + BOOKMARKS_SYNCTOID_PREFIX +
|
||||
testCollectionData[i].id],
|
||||
testCollectionData[i].payload.bmkUri);
|
||||
} else {
|
||||
assert.notEqual(deletedQueue.indexOf(testCollectionData[i].id), -1);
|
||||
}
|
||||
}
|
||||
});
|
||||
}).then(done, reason => {
|
||||
done(reason || new Error('Rejected by undefined reason.'));
|
||||
});
|
||||
});
|
||||
|
||||
test('update - Add three records with the same URL and delete one',
|
||||
function(done) {
|
||||
var bookmarksAdapter = DataAdapters.bookmarks, store;
|
||||
Promise.resolve().then(() => {
|
||||
for (var i = 1; i <= 3; i++) {
|
||||
testCollectionData.unshift({
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
last_modified: 100 + i * 10,
|
||||
payload: {
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
type: 'bookmark',
|
||||
bmkUri: 'http://example.com/',
|
||||
title: 'Example ' + i + ' Title'
|
||||
}
|
||||
});
|
||||
}
|
||||
return bookmarksAdapter.update(kintoCollection,
|
||||
{ readonly: true, userid: 'foo' });
|
||||
}).then(result => {
|
||||
assert.equal(result, false);
|
||||
var mTime = testCollectionData[0].last_modified;
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
|
||||
mTime);
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
|
||||
'latest-not-cleared');
|
||||
return Promise.resolve();
|
||||
}).then(() => {
|
||||
testCollectionData = [
|
||||
{
|
||||
id: 'UNIQUE_ID_2',
|
||||
last_modified: testCollectionData[0].last_modified + 10000,
|
||||
payload: {
|
||||
deleted: true,
|
||||
id: 'UNIQUE_ID_2'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'UNIQUE_ID_3',
|
||||
last_modified: 130,
|
||||
payload: {
|
||||
id: 'UNIQUE_ID_3',
|
||||
type: 'bookmark',
|
||||
bmkUri: 'http://example.com/',
|
||||
title: 'Example 3 Title'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'UNIQUE_ID_1',
|
||||
last_modified: 110,
|
||||
payload: {
|
||||
id: 'UNIQUE_ID_1',
|
||||
type: 'bookmark',
|
||||
bmkUri: 'http://example.com/',
|
||||
title: 'Example 1 Title'
|
||||
}
|
||||
}
|
||||
];
|
||||
return bookmarksAdapter.update(kintoCollection,
|
||||
{ readonly: true, userid: 'foo' });
|
||||
}).then(result => {
|
||||
assert.equal(result, false);
|
||||
var mTime = testCollectionData[0].last_modified;
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
|
||||
mTime);
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
|
||||
'latest-not-cleared');
|
||||
return Promise.resolve();
|
||||
}).then(getBookmarksStore).then(bookmarksStore => {
|
||||
store = bookmarksStore;
|
||||
return store.get.apply(store, ['http://example.com/']).then(item => {
|
||||
var expectedBookmark = {
|
||||
id: 'http://example.com/',
|
||||
url: 'http://example.com/',
|
||||
name: 'Example 1 Title',
|
||||
type: 'url',
|
||||
iconable: false,
|
||||
icon: '',
|
||||
createdLocally: false,
|
||||
fxsyncRecords: {
|
||||
UNIQUE_ID_1: {
|
||||
id: 'UNIQUE_ID_1',
|
||||
type: 'bookmark',
|
||||
bmkUri: 'http://example.com/',
|
||||
title: 'Example 1 Title',
|
||||
timestamp: 110
|
||||
},
|
||||
UNIQUE_ID_2: {
|
||||
id: 'UNIQUE_ID_2',
|
||||
deleted: true
|
||||
},
|
||||
UNIQUE_ID_3: {
|
||||
id: 'UNIQUE_ID_3',
|
||||
type: 'bookmark',
|
||||
bmkUri: 'http://example.com/',
|
||||
title: 'Example 3 Title',
|
||||
timestamp: 130
|
||||
}
|
||||
}
|
||||
};
|
||||
for(var i=1; i <= 3; i++) {
|
||||
assert.equal(
|
||||
asyncStorage.mItems[
|
||||
'foo' + BOOKMARKS_SYNCTOID_PREFIX + 'UNIQUE_ID_' + i],
|
||||
item.url);
|
||||
}
|
||||
assert.deepEqual(item, expectedBookmark);
|
||||
});
|
||||
}).then(done, reason => {
|
||||
done(reason || new Error('Rejected by undefined reason.'));
|
||||
});
|
||||
});
|
||||
|
||||
test('update - Add two records and add one, all with the same URL',
|
||||
function(done) {
|
||||
var bookmarksAdapter = DataAdapters.bookmarks, store;
|
||||
Promise.resolve().then(() => {
|
||||
for (var i = 1; i <= 2; i++) {
|
||||
testCollectionData.unshift({
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
last_modified: 100 + i * 10,
|
||||
payload: {
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
type: 'bookmark',
|
||||
bmkUri: 'http://example.com/',
|
||||
title: 'Example ' + i + ' Title'
|
||||
}
|
||||
});
|
||||
}
|
||||
return bookmarksAdapter.update(kintoCollection,
|
||||
{ readonly: true, userid: 'foo' });
|
||||
}).then(result => {
|
||||
assert.equal(result, false);
|
||||
var mTime = testCollectionData[0].last_modified;
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
|
||||
mTime);
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
|
||||
'latest-not-cleared');
|
||||
return Promise.resolve();
|
||||
}).then(() => {
|
||||
testCollectionData.unshift({
|
||||
id: 'UNIQUE_ID_3',
|
||||
last_modified: 130,
|
||||
payload: {
|
||||
id: 'UNIQUE_ID_3',
|
||||
type: 'bookmark',
|
||||
bmkUri: 'http://example.com/',
|
||||
title: 'Example 3 Title'
|
||||
}
|
||||
});
|
||||
return bookmarksAdapter.update(kintoCollection,
|
||||
{ readonly: true, userid: 'foo' });
|
||||
}).then(result => {
|
||||
assert.equal(result, false);
|
||||
var mTime = testCollectionData[0].last_modified;
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
|
||||
mTime);
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
|
||||
'latest-not-cleared');
|
||||
return Promise.resolve();
|
||||
}).then(getBookmarksStore).then(bookmarksStore => {
|
||||
store = bookmarksStore;
|
||||
return store.get.apply(store, ['http://example.com/']).then(item => {
|
||||
var expectedBookmark = {
|
||||
id: 'http://example.com/',
|
||||
url: 'http://example.com/',
|
||||
name: 'Example 3 Title',
|
||||
type: 'url',
|
||||
iconable: false,
|
||||
icon: '',
|
||||
createdLocally: false,
|
||||
fxsyncRecords: {
|
||||
UNIQUE_ID_1: {
|
||||
id: 'UNIQUE_ID_1',
|
||||
type: 'bookmark',
|
||||
bmkUri: 'http://example.com/',
|
||||
title: 'Example 1 Title',
|
||||
timestamp: 110
|
||||
},
|
||||
UNIQUE_ID_2: {
|
||||
id: 'UNIQUE_ID_2',
|
||||
type: 'bookmark',
|
||||
bmkUri: 'http://example.com/',
|
||||
title: 'Example 2 Title',
|
||||
timestamp: 120
|
||||
},
|
||||
UNIQUE_ID_3: {
|
||||
id: 'UNIQUE_ID_3',
|
||||
type: 'bookmark',
|
||||
bmkUri: 'http://example.com/',
|
||||
title: 'Example 3 Title',
|
||||
timestamp: 130
|
||||
}
|
||||
}
|
||||
};
|
||||
for(var i=1; i <= 3; i++) {
|
||||
assert.equal(
|
||||
asyncStorage.mItems[
|
||||
'foo' + BOOKMARKS_SYNCTOID_PREFIX + 'UNIQUE_ID_' + i],
|
||||
item.url);
|
||||
}
|
||||
assert.deepEqual(item, expectedBookmark);
|
||||
});
|
||||
}).then(done, reason => {
|
||||
done(reason || new Error('Rejected by undefined reason.'));
|
||||
});
|
||||
});
|
||||
|
||||
test('update - query, folder, livemark, and separator record',
|
||||
function(done) {
|
||||
var bookmarksAdapter = DataAdapters.bookmarks, store;
|
||||
var i = 1;
|
||||
testCollectionData.unshift({
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
last_modified: 100 + i * 10,
|
||||
payload: {
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
type: 'query',
|
||||
bmkUri: 'place:type=3&sort=4',
|
||||
title: 'Example ' + i + ' Title'
|
||||
}
|
||||
});
|
||||
i++;
|
||||
testCollectionData.unshift({
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
last_modified: 100 + i * 10,
|
||||
payload: {
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
type: 'folder',
|
||||
title: 'Example ' + i + ' Title'
|
||||
}
|
||||
});
|
||||
i++;
|
||||
testCollectionData.unshift({
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
last_modified: 100 + i * 10,
|
||||
payload: {
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
type: 'livemark',
|
||||
title: 'Example ' + i + ' Title'
|
||||
}
|
||||
});
|
||||
i++;
|
||||
testCollectionData.unshift({
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
last_modified: 100 + i * 10,
|
||||
payload: {
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
type: 'separator'
|
||||
}
|
||||
});
|
||||
bookmarksAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
|
||||
.then(result => {
|
||||
assert.equal(result, false);
|
||||
var mTime = testCollectionData[0].last_modified;
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
|
||||
mTime);
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
|
||||
'latest-not-cleared');
|
||||
return Promise.resolve();
|
||||
}).then(getBookmarksStore).then(bookmarksStore => {
|
||||
store = bookmarksStore;
|
||||
var ids = testCollectionData.map(item => {
|
||||
return item.payload.type + '|' + item.payload.id;
|
||||
});
|
||||
return store.get.apply(store, ids).then(list => {
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
if (list[i]) {
|
||||
verifyBookmarks(testCollectionData[i], list[i]);
|
||||
for (var fxsyncId in testCollectionData[i].fxsyncRecords) {
|
||||
assert.equal(asyncStorage.mItems[
|
||||
'foo' + BOOKMARKS_SYNCTOID_PREFIX + fxsyncId],list[i].id);
|
||||
}
|
||||
} else {
|
||||
assert.ok(false, 'Empty Record!');
|
||||
}
|
||||
}
|
||||
});
|
||||
}).then(done, reason => {
|
||||
done(reason || new Error('Rejected by undefined reason.'));
|
||||
});
|
||||
});
|
||||
|
||||
test('update - empty bookmarks-uri record', function(done) {
|
||||
var bookmarksAdapter = DataAdapters.bookmarks;
|
||||
var i = 1;
|
||||
testCollectionData.unshift({
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
last_modified: 100 + i * 10,
|
||||
payload: {
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
type: 'bookmark',
|
||||
bmkUri: '',
|
||||
title: 'Example ' + i + ' Title'
|
||||
}
|
||||
});
|
||||
bookmarksAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
|
||||
.then(result => {
|
||||
assert.equal(result, false);
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
|
||||
110);
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
|
||||
'latest-not-cleared');
|
||||
return Promise.resolve();
|
||||
}).then(done, reason => {
|
||||
done(reason || new Error('Rejected by undefined reason.'));
|
||||
});
|
||||
});
|
||||
|
||||
test('update - empty query-uri record', function(done) {
|
||||
var bookmarksAdapter = DataAdapters.bookmarks;
|
||||
var i = 1;
|
||||
testCollectionData.unshift({
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
last_modified: 100 + i * 10,
|
||||
payload: {
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
type: 'query',
|
||||
bmkUri: '',
|
||||
title: 'Example ' + i + ' Title'
|
||||
}
|
||||
});
|
||||
bookmarksAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
|
||||
.then(result => {
|
||||
assert.equal(result, false);
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
|
||||
110);
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
|
||||
'latest-not-cleared');
|
||||
return Promise.resolve();
|
||||
}).then(done, reason => {
|
||||
done(reason || new Error('Rejected by undefined reason.'));
|
||||
});
|
||||
});
|
||||
|
||||
test('update - empty last_modified record', function(done) {
|
||||
var bookmarksAdapter = DataAdapters.bookmarks;
|
||||
var i = 1;
|
||||
testCollectionData.unshift({
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
last_modified: null,
|
||||
payload: {
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
type: 'bookmark',
|
||||
bmkUri: '',
|
||||
title: 'Example ' + i + ' Title'
|
||||
}
|
||||
});
|
||||
bookmarksAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
|
||||
.then(result => {
|
||||
assert.equal(result, false);
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
|
||||
null);
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
|
||||
'latest-not-cleared');
|
||||
return Promise.resolve();
|
||||
}).then(done, reason => {
|
||||
done(reason || new Error('Rejected by undefined reason.'));
|
||||
});
|
||||
});
|
||||
|
||||
test('update - unknown type record', function(done) {
|
||||
var bookmarksAdapter = DataAdapters.bookmarks;
|
||||
var i = 1;
|
||||
testCollectionData.unshift({
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
last_modified: 1000,
|
||||
payload: {
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
type: 'unknown',
|
||||
bmkUri: null,
|
||||
title: 'Example ' + i + ' Title'
|
||||
}
|
||||
});
|
||||
bookmarksAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
|
||||
.then(result => {
|
||||
assert.equal(result, false);
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
|
||||
1000);
|
||||
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
|
||||
'latest-not-cleared');
|
||||
return Promise.resolve();
|
||||
}).then(done, reason => {
|
||||
done(reason || new Error('Rejected by undefined reason.'));
|
||||
});
|
||||
});
|
||||
|
||||
test('BookmarksHelper - merge remote record into local record',
|
||||
function(done) {
|
||||
var bookmark1 = {
|
||||
url: 'http://www.mozilla.org/en-US/',
|
||||
name: '',
|
||||
type: 'url'
|
||||
};
|
||||
|
||||
var bookmark2 = {
|
||||
url: 'http://www.mozilla.org/en-US/',
|
||||
name: 'Mozilla',
|
||||
type: 'url',
|
||||
fxsyncRecords: {
|
||||
'XXXXX_ID_XXXXX': {}
|
||||
}
|
||||
};
|
||||
|
||||
var result = BookmarksHelper.mergeRecordsToDataStore(bookmark1, bookmark2,
|
||||
'XXXXX_ID_XXXXX');
|
||||
var expectedBookmark = {
|
||||
url: 'http://www.mozilla.org/en-US/',
|
||||
name: 'Mozilla',
|
||||
type: 'url',
|
||||
createdLocally: true,
|
||||
fxsyncRecords: {
|
||||
'XXXXX_ID_XXXXX': {}
|
||||
}
|
||||
};
|
||||
|
||||
assert.equal(result.name, expectedBookmark.name);
|
||||
assert.equal(result.url, expectedBookmark.url);
|
||||
assert.deepEqual(result, expectedBookmark);
|
||||
done();
|
||||
});
|
||||
|
||||
test('BookmarksHelper - merge two records with incorrect URL',
|
||||
function(done) {
|
||||
var bookmark1 = {
|
||||
url: 'dummy',
|
||||
name: '',
|
||||
type: 'url'
|
||||
};
|
||||
|
||||
var bookmark2 = {
|
||||
url: 'http://www.mozilla.org/en-US/',
|
||||
name: 'Mozilla',
|
||||
type: 'url'
|
||||
};
|
||||
|
||||
assert.throws(() => {
|
||||
BookmarksHelper.mergeRecordsToDataStore(bookmark1, bookmark2,
|
||||
'XXXXX_ID_XXXXX');
|
||||
});
|
||||
done();
|
||||
});
|
||||
|
||||
test('BookmarksHelper - merge two records with fxsyncRecords',
|
||||
function(done) {
|
||||
var bookmark1 = {
|
||||
url: 'http://www.mozilla.org/en-US/',
|
||||
name: '',
|
||||
type: 'url',
|
||||
createdLocally: false,
|
||||
fxsyncRecords: {
|
||||
'XXXXX_ID_XXXXX_A': {
|
||||
id: 'XXXXX_ID_XXXXX_A'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var bookmark2 = {
|
||||
url: 'http://www.mozilla.org/en-US/',
|
||||
name: 'Mozilla',
|
||||
type: 'url',
|
||||
fxsyncRecords: {
|
||||
'XXXXX_ID_XXXXX_B': {
|
||||
id: 'XXXXX_ID_XXXXX_B'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var result = BookmarksHelper.mergeRecordsToDataStore(bookmark1, bookmark2,
|
||||
'XXXXX_ID_XXXXX_B');
|
||||
var expectedBookmark = {
|
||||
url: 'http://www.mozilla.org/en-US/',
|
||||
name: 'Mozilla',
|
||||
type: 'url',
|
||||
createdLocally: false,
|
||||
fxsyncRecords: {
|
||||
'XXXXX_ID_XXXXX_A': {
|
||||
id: 'XXXXX_ID_XXXXX_A'
|
||||
},
|
||||
'XXXXX_ID_XXXXX_B': {
|
||||
id: 'XXXXX_ID_XXXXX_B'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
assert.equal(result.name, expectedBookmark.name);
|
||||
assert.equal(result.url, expectedBookmark.url);
|
||||
assert.deepEqual(result, expectedBookmark);
|
||||
done();
|
||||
});
|
||||
});
|
||||
671
gaia/apps/sync/test/unit/adapters/history_test.js
Executable file
671
gaia/apps/sync/test/unit/adapters/history_test.js
Executable file
|
|
@ -0,0 +1,671 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
/* global
|
||||
asyncStorage,
|
||||
DataAdapters,
|
||||
ERROR_SYNC_APP_RACE_CONDITION,
|
||||
HISTORY_COLLECTION_MTIME,
|
||||
HISTORY_LAST_REVISIONID,
|
||||
HISTORY_SYNCTOID_PREFIX,
|
||||
HistoryHelper,
|
||||
MockasyncStorage,
|
||||
MockDatastore,
|
||||
MockLazyLoader,
|
||||
MockNavigatorDatastore
|
||||
*/
|
||||
|
||||
require('/shared/js/sync/errors.js');
|
||||
require('/shared/test/unit/mocks/mock_lazy_loader.js');
|
||||
require('/shared/test/unit/mocks/mock_navigator_datastore.js');
|
||||
require('/apps/system/test/unit/mock_asyncStorage.js');
|
||||
requireApp('sync/js/adapters/history.js');
|
||||
|
||||
window.DataAdapters = {};
|
||||
|
||||
suite('sync/adapters/history >', function() {
|
||||
var realDatastore, realLazyLoader, realAsyncStorage, testCollectionData;
|
||||
var dataStoreRemoveSpy;
|
||||
|
||||
var kintoCollection = {
|
||||
list() {
|
||||
return Promise.resolve({
|
||||
data: testCollectionData
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function getPlacesStore() {
|
||||
return navigator.getDataStores().then(stores => {
|
||||
return Promise.resolve(stores[0]);
|
||||
});
|
||||
}
|
||||
|
||||
function verifyPlaces(collectionItem, placesItem) {
|
||||
var payload = collectionItem.payload;
|
||||
assert.equal(payload.histUri, placesItem.url);
|
||||
assert.equal(payload.title, placesItem.title);
|
||||
for (var i = 0; i < payload.visits.length; i++) {
|
||||
assert.equal(payload.visits[i].date, placesItem.visits[i] * 1000);
|
||||
}
|
||||
assert.equal(payload.id, placesItem.fxsyncId);
|
||||
}
|
||||
|
||||
function testDataGenerator(initIndex, initDate, count) {
|
||||
var list = [];
|
||||
for (var i = initIndex; i < initIndex + count; i++) {
|
||||
var visits = [];
|
||||
var startData = initDate + i * 100;
|
||||
for (var j = 0; j < 3; j++) {
|
||||
// Visits from FxSync will be in anti-chronological order
|
||||
visits.unshift({
|
||||
date: (startData + j * 10) * 1000, type: 3
|
||||
});
|
||||
}
|
||||
|
||||
list.unshift({
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
last_modified: initDate + i * 10,
|
||||
payload: {
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
histUri: 'http://example' + i + '.com/',
|
||||
title: 'Example ' + i + ' Title',
|
||||
visits: visits
|
||||
}
|
||||
});
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
suiteSetup(() => {
|
||||
realDatastore = navigator.getDataStores;
|
||||
|
||||
realAsyncStorage = window.asyncStorage;
|
||||
window.asyncStorage = MockasyncStorage;
|
||||
|
||||
realLazyLoader = window.LazyLoader;
|
||||
window.LazyLoader = MockLazyLoader;
|
||||
});
|
||||
|
||||
suiteTeardown(() => {
|
||||
navigator.getDataStores = realDatastore;
|
||||
|
||||
window.LazyLoader = realLazyLoader;
|
||||
|
||||
window.asyncStorage = realAsyncStorage;
|
||||
});
|
||||
|
||||
setup(() => {
|
||||
navigator.getDataStores = MockNavigatorDatastore.getDataStores;
|
||||
dataStoreRemoveSpy = sinon.spy(MockDatastore, 'remove');
|
||||
testCollectionData = [];
|
||||
MockDatastore._tasks[1].revisionId = 'latest-not-cleared';
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
dataStoreRemoveSpy.restore();
|
||||
MockDatastore._inError = false;
|
||||
MockDatastore._records = Object.create(null);
|
||||
window.asyncStorage.mTeardown();
|
||||
});
|
||||
|
||||
test('update - empty records', function(done) {
|
||||
var historyAdapter = DataAdapters.history;
|
||||
historyAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
|
||||
.then((result) => {
|
||||
assert.equal(result, false);
|
||||
assert.equal(asyncStorage.mItems['foo' + HISTORY_LAST_REVISIONID],
|
||||
'latest-not-cleared');
|
||||
}).then(done, reason => {
|
||||
assert.ok(false, reason);
|
||||
});
|
||||
});
|
||||
|
||||
['clear', 'remove'].forEach(task => {
|
||||
suite(`after a DataStore ${task}`, function() {
|
||||
suiteSetup(function() {
|
||||
MockDatastore._taskCounter = 0;
|
||||
MockDatastore._tasks = [
|
||||
{
|
||||
operation: 'clear',
|
||||
id: 0,
|
||||
data: {}
|
||||
},
|
||||
{
|
||||
operation: 'add',
|
||||
id: 0,
|
||||
data: {}
|
||||
},
|
||||
{
|
||||
operation: task,
|
||||
id: 0,
|
||||
data: {}
|
||||
},
|
||||
{
|
||||
operation: 'done',
|
||||
id: 0,
|
||||
revisionId: `latest-after-${task}`,
|
||||
data: null
|
||||
}
|
||||
];
|
||||
});
|
||||
suiteTeardown(function() {
|
||||
MockDatastore._taskCounter = 0;
|
||||
MockDatastore._tasks = [
|
||||
{
|
||||
operation: 'update',
|
||||
id: 0,
|
||||
data: {}
|
||||
},
|
||||
{
|
||||
operation: 'done',
|
||||
id: 0,
|
||||
data: null,
|
||||
revisionId: 'latest-not-cleared'
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
test('update - refills the DataStore', function(done) {
|
||||
var historyAdapter = DataAdapters.history;
|
||||
testCollectionData = testDataGenerator(1, 1440000000, 5);
|
||||
asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME] =
|
||||
testCollectionData[0].last_modified;
|
||||
historyAdapter.update(kintoCollection,
|
||||
{ readonly: true, userid: 'foo' })
|
||||
.then(() => {
|
||||
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME],
|
||||
testCollectionData[0].last_modified);
|
||||
getPlacesStore().then(placesStore => {
|
||||
var ids = testCollectionData.map(item => {
|
||||
return item.payload.histUri;
|
||||
});
|
||||
placesStore.get.apply(placesStore, ids).then(list => {
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
verifyPlaces(testCollectionData[i], list[i]);
|
||||
assert.equal(
|
||||
asyncStorage.mItems[
|
||||
'foo' + HISTORY_SYNCTOID_PREFIX + list[i].fxsyncId],
|
||||
list[i].url);
|
||||
}
|
||||
assert.equal(asyncStorage.mItems[
|
||||
'foo' + HISTORY_LAST_REVISIONID], `latest-after-${task}`);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('update - does not refill the DataStore if nothing removed locally',
|
||||
function(done) {
|
||||
var historyAdapter = DataAdapters.history;
|
||||
testCollectionData = testDataGenerator(1, 1440000000, 5);
|
||||
asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME] =
|
||||
testCollectionData[0].last_modified;
|
||||
historyAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
|
||||
.then(() => {
|
||||
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME],
|
||||
testCollectionData[0].last_modified);
|
||||
getPlacesStore().then(placesStore => {
|
||||
var ids = testCollectionData.map(item => {
|
||||
return item.payload.histUri;
|
||||
});
|
||||
placesStore.get.apply(placesStore, ids).then(list => {
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
assert.equal(list[i], null);
|
||||
}
|
||||
assert.equal(asyncStorage.mItems[
|
||||
'foo' + HISTORY_LAST_REVISIONID], 'latest-not-cleared');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('update - 1 sync request with 5 new records', function(done) {
|
||||
var historyAdapter = DataAdapters.history;
|
||||
var lazyLoaderSpy = this.sinon.spy(MockLazyLoader, 'load');
|
||||
|
||||
testCollectionData = testDataGenerator(1, 1440000000, 5);
|
||||
historyAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
|
||||
.then((result) => {
|
||||
var mTime = testCollectionData[0].last_modified;
|
||||
assert.equal(lazyLoaderSpy.calledWith(['shared/js/async_storage.js']),
|
||||
true);
|
||||
assert.equal(result, false);
|
||||
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME],
|
||||
mTime);
|
||||
return Promise.resolve();
|
||||
}).then(getPlacesStore).then(placesStore => {
|
||||
var ids = testCollectionData.map(item => {
|
||||
return item.payload.histUri;
|
||||
});
|
||||
return placesStore.get.apply(placesStore, ids).then(list => {
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
verifyPlaces(testCollectionData[i], list[i]);
|
||||
assert.equal(
|
||||
asyncStorage.mItems[
|
||||
'foo' + HISTORY_SYNCTOID_PREFIX + list[i].fxsyncId],
|
||||
list[i].url);
|
||||
}
|
||||
});
|
||||
}).then(done, reason => {
|
||||
assert.ok(false, reason);
|
||||
});
|
||||
});
|
||||
|
||||
suite('if a DataStore race condition occurs', function() {
|
||||
setup(function() {
|
||||
MockDatastore._raceCondition = true;
|
||||
});
|
||||
teardown(function() {
|
||||
delete MockDatastore._raceCondition;
|
||||
});
|
||||
|
||||
test('update - rejects its promise', function(done) {
|
||||
var historyAdapter = DataAdapters.history;
|
||||
var lazyLoaderSpy = this.sinon.spy(MockLazyLoader, 'load');
|
||||
|
||||
testCollectionData = testDataGenerator(1, 1440000000, 5);
|
||||
historyAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
|
||||
.catch(error => {
|
||||
assert.equal(lazyLoaderSpy.calledWith(['shared/js/sync/errors.js']),
|
||||
true);
|
||||
assert.equal(error.message, ERROR_SYNC_APP_RACE_CONDITION);
|
||||
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME],
|
||||
null);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('update - 1 sync request with 5 pre-existing records', function(done) {
|
||||
var historyAdapter = DataAdapters.history;
|
||||
getPlacesStore().then(store => {
|
||||
for (var i=1; i<=5; i++) {
|
||||
store._records['http://example' + i + '.com/'] = {
|
||||
url: 'http://example' + i + '.com/',
|
||||
title: 'old',
|
||||
visits: []
|
||||
};
|
||||
}
|
||||
}).then(() => {
|
||||
testCollectionData = testDataGenerator(1, 1440000000, 5);
|
||||
return historyAdapter.update(kintoCollection,
|
||||
{ readonly: true, userid: 'foo' });
|
||||
}).then((result) => {
|
||||
assert.equal(result, false);
|
||||
var mTime = testCollectionData[0].last_modified;
|
||||
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME],
|
||||
mTime);
|
||||
return Promise.resolve();
|
||||
}).then(getPlacesStore).then(placesStore => {
|
||||
var ids = testCollectionData.map(item => {
|
||||
return item.payload.histUri;
|
||||
});
|
||||
return placesStore.get.apply(placesStore, ids).then(list => {
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
verifyPlaces(testCollectionData[i], list[i]);
|
||||
assert.equal(
|
||||
asyncStorage.mItems[
|
||||
'foo' + HISTORY_SYNCTOID_PREFIX + list[i].fxsyncId],
|
||||
list[i].url);
|
||||
}
|
||||
});
|
||||
}).then(done, reason => {
|
||||
assert.ok(false, reason);
|
||||
});
|
||||
});
|
||||
|
||||
test('update - 2 sync requests', function(done) {
|
||||
var historyAdapter = DataAdapters.history;
|
||||
Promise.resolve().then(() => {
|
||||
testCollectionData = testDataGenerator(1, 100, 5)
|
||||
.concat(testCollectionData);
|
||||
return historyAdapter.update(kintoCollection,
|
||||
{ readonly: true, userid: 'foo' });
|
||||
}).then((result) => {
|
||||
assert.equal(result, false);
|
||||
var mTime = testCollectionData[0].last_modified;
|
||||
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME],
|
||||
mTime);
|
||||
return Promise.resolve();
|
||||
}).then(() => {
|
||||
testCollectionData = testDataGenerator(6, 500, 5)
|
||||
.concat(testCollectionData);
|
||||
return historyAdapter.update(kintoCollection,
|
||||
{ readonly: true, userid: 'foo' });
|
||||
}).then((result) => {
|
||||
assert.equal(result, false);
|
||||
var mTime = testCollectionData[0].last_modified;
|
||||
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME],
|
||||
mTime);
|
||||
return Promise.resolve();
|
||||
}).then(getPlacesStore).then(placesStore => {
|
||||
var ids = testCollectionData.map(item => {
|
||||
return item.payload.histUri;
|
||||
});
|
||||
return placesStore.get.apply(placesStore, ids).then(list => {
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
verifyPlaces(testCollectionData[i], list[i]);
|
||||
assert.equal(
|
||||
asyncStorage.mItems[
|
||||
'foo' + HISTORY_SYNCTOID_PREFIX + list[i].fxsyncId],
|
||||
list[i].url);
|
||||
}
|
||||
});
|
||||
}).then(done, reason => {
|
||||
assert.ok(false, reason);
|
||||
});
|
||||
});
|
||||
|
||||
test('update - 2 sync requests with 2 deleted: true records', function(done) {
|
||||
var historyAdapter = DataAdapters.history, store;
|
||||
var deletedQueue = ['UNIQUE_ID_1', 'UNIQUE_ID_4'];
|
||||
Promise.resolve().then(() => {
|
||||
testCollectionData = testDataGenerator(1, 100, 5)
|
||||
.concat(testCollectionData);
|
||||
return historyAdapter.update(kintoCollection,
|
||||
{ readonly: true, userid: 'foo' });
|
||||
}).then((result) => {
|
||||
assert.equal(result, false);
|
||||
var mTime = testCollectionData[0].last_modified;
|
||||
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME],
|
||||
mTime);
|
||||
return Promise.resolve();
|
||||
}).then(() => {
|
||||
testCollectionData = testDataGenerator(6, 500, 5)
|
||||
.concat(testCollectionData);
|
||||
var latestModified = testCollectionData[0].last_modified + 10000;
|
||||
var deletedRecords = [];
|
||||
deletedQueue.forEach((synctoId, i) => {
|
||||
deletedRecords.push({
|
||||
id: synctoId,
|
||||
last_modified: latestModified + 10000 * i,
|
||||
payload: {
|
||||
deleted: true,
|
||||
id: synctoId
|
||||
}
|
||||
});
|
||||
});
|
||||
testCollectionData = deletedRecords.concat(testCollectionData);
|
||||
return historyAdapter.update(kintoCollection,
|
||||
{ readonly: true, userid: 'foo' });
|
||||
}).then((result) => {
|
||||
assert.equal(result, false);
|
||||
var mTime = testCollectionData[0].last_modified;
|
||||
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME],
|
||||
mTime);
|
||||
assert.equal(asyncStorage.mItems['foo' + HISTORY_LAST_REVISIONID],
|
||||
'latest-not-cleared');
|
||||
return Promise.resolve();
|
||||
}).then(getPlacesStore).then(placesStore => {
|
||||
store = placesStore;
|
||||
var ids = testCollectionData.map(item => {
|
||||
return item.payload.histUri;
|
||||
});
|
||||
return store.get.apply(store, ids).then(list => {
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
if (list[i]) {
|
||||
verifyPlaces(testCollectionData[i], list[i]);
|
||||
assert.equal(
|
||||
asyncStorage.mItems[
|
||||
'foo' + HISTORY_SYNCTOID_PREFIX + list[i].fxsyncId],
|
||||
list[i].url);
|
||||
} else {
|
||||
assert.notEqual(deletedQueue.indexOf(testCollectionData[i].id), -1);
|
||||
}
|
||||
}
|
||||
});
|
||||
}).then(done, reason => {
|
||||
assert.ok(false, reason);
|
||||
});
|
||||
});
|
||||
|
||||
test('update - non-array visits record', function(done) {
|
||||
var historyAdapter = DataAdapters.history;
|
||||
var i = 1;
|
||||
testCollectionData.unshift({
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
last_modified: 100 + i * 10,
|
||||
payload: {
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
histUri: 'http://example' + i + '.com/',
|
||||
title: 'Example ' + i + ' Title',
|
||||
visits: null
|
||||
}
|
||||
});
|
||||
historyAdapter.update(kintoCollection,
|
||||
{ readonly: true, userid: 'foo' }).then((result) => {
|
||||
assert.equal(result, false);
|
||||
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME], 110);
|
||||
assert.equal(asyncStorage.mItems['foo' + HISTORY_LAST_REVISIONID],
|
||||
'latest-not-cleared');
|
||||
return Promise.resolve();
|
||||
}).then(done, reason => {
|
||||
assert.ok(false, reason);
|
||||
});
|
||||
});
|
||||
|
||||
test('update - empty visits array record (not created locally)',
|
||||
function(done) {
|
||||
var historyAdapter = DataAdapters.history;
|
||||
var i = 1;
|
||||
testCollectionData.unshift({
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
last_modified: 100 + i * 10,
|
||||
payload: {
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
histUri: 'http://example' + i + '.com/',
|
||||
title: 'Example ' + i + ' Title',
|
||||
visits: []
|
||||
}
|
||||
});
|
||||
MockDatastore._records = {
|
||||
'http://example1.com/': {}
|
||||
};
|
||||
historyAdapter.update(kintoCollection,
|
||||
{ readonly: true, userid: 'foo' }).then((result) => {
|
||||
assert.equal(result, false);
|
||||
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME], 110);
|
||||
assert.equal(dataStoreRemoveSpy.callCount, 1);
|
||||
assert.equal(dataStoreRemoveSpy.args[0][0], 'http://example1.com/');
|
||||
return Promise.resolve();
|
||||
}).then(done, reason => {
|
||||
assert.ok(false, reason);
|
||||
});
|
||||
});
|
||||
|
||||
test('update - empty visits array record (created locally)', function(done) {
|
||||
var historyAdapter = DataAdapters.history;
|
||||
var i = 1;
|
||||
testCollectionData.unshift({
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
last_modified: 100 + i * 10,
|
||||
payload: {
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
histUri: 'http://example' + i + '.com/',
|
||||
title: 'Example ' + i + ' Title',
|
||||
visits: []
|
||||
}
|
||||
});
|
||||
MockDatastore._records = {
|
||||
'http://example1.com/': {
|
||||
createdLocally: true
|
||||
}
|
||||
};
|
||||
historyAdapter.update(kintoCollection,
|
||||
{ readonly: true, userid: 'foo' }).then((result) => {
|
||||
assert.equal(result, false);
|
||||
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME], 110);
|
||||
assert.equal(dataStoreRemoveSpy.callCount, 0);
|
||||
return Promise.resolve();
|
||||
}).then(done, reason => {
|
||||
assert.ok(false, reason);
|
||||
});
|
||||
});
|
||||
|
||||
test('update - empty history-uri record', function(done) {
|
||||
var historyAdapter = DataAdapters.history;
|
||||
var i = 1;
|
||||
testCollectionData.unshift({
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
last_modified: 100 + i * 10,
|
||||
payload: {
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
histUri: '',
|
||||
title: 'Example ' + i + ' Title',
|
||||
visits: [10000, 20000]
|
||||
}
|
||||
});
|
||||
historyAdapter.update(kintoCollection,
|
||||
{ readonly: true, userid: 'foo' }).then((result) => {
|
||||
assert.equal(result, false);
|
||||
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME], 110);
|
||||
assert.equal(asyncStorage.mItems['foo' + HISTORY_LAST_REVISIONID],
|
||||
'latest-not-cleared');
|
||||
return Promise.resolve();
|
||||
}).then(done, reason => {
|
||||
assert.ok(false, reason);
|
||||
});
|
||||
});
|
||||
|
||||
test('update - empty last_modified record', function(done) {
|
||||
var historyAdapter = DataAdapters.history;
|
||||
var i = 1;
|
||||
testCollectionData.unshift({
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
last_modified: null,
|
||||
payload: {
|
||||
id: 'UNIQUE_ID_' + i,
|
||||
histUri: 'http://example' + i + '.com/',
|
||||
title: 'Example ' + i + ' Title',
|
||||
visits: [10000, 20000]
|
||||
}
|
||||
});
|
||||
historyAdapter.update(kintoCollection,
|
||||
{ readonly: true, userid: 'foo' }).then((result) => {
|
||||
assert.equal(result, false);
|
||||
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME], null);
|
||||
assert.equal(asyncStorage.mItems['foo' + HISTORY_LAST_REVISIONID],
|
||||
'latest-not-cleared');
|
||||
return Promise.resolve();
|
||||
}).then(done, reason => {
|
||||
assert.ok(false, reason);
|
||||
});
|
||||
});
|
||||
|
||||
test('HistoryHelper - merge two remote records', function(done) {
|
||||
var place1 = {
|
||||
url: 'http://www.mozilla.org/en-US/',
|
||||
title: '',
|
||||
fxsyncId: '',
|
||||
createdLocally: false,
|
||||
visits: [ 1501000000000, 1502000000000 ]
|
||||
};
|
||||
|
||||
var place2 = {
|
||||
url: 'http://www.mozilla.org/en-US/',
|
||||
title: 'Mozilla',
|
||||
fxsyncId: 'XXXXX_ID_XXXXX',
|
||||
visits: [ 1502000000000, 1503000000000 ]
|
||||
};
|
||||
|
||||
var result = HistoryHelper.mergeRecordsToDataStore(place1, place2);
|
||||
var expectedPlace = {
|
||||
url: 'http://www.mozilla.org/en-US/',
|
||||
title: 'Mozilla',
|
||||
fxsyncId: 'XXXXX_ID_XXXXX',
|
||||
createdLocally: false,
|
||||
visits: [1503000000000, 1502000000000, 1501000000000]
|
||||
};
|
||||
|
||||
assert.equal(result.title, expectedPlace.title);
|
||||
assert.equal(result.url, expectedPlace.url);
|
||||
assert.equal(result.visits.length, expectedPlace.visits.length);
|
||||
for(var i = 0; i < result.visits.length; i++){
|
||||
assert.equal(result.visits[i], expectedPlace.visits[i]);
|
||||
}
|
||||
done();
|
||||
});
|
||||
|
||||
test('HistoryHelper - merge remote record into local record', function(done) {
|
||||
var place1 = {
|
||||
url: 'http://www.mozilla.org/en-US/',
|
||||
title: '',
|
||||
fxsyncId: '',
|
||||
visits: [ 1501000000000, 1502000000000 ]
|
||||
};
|
||||
|
||||
var place2 = {
|
||||
url: 'http://www.mozilla.org/en-US/',
|
||||
title: 'Mozilla',
|
||||
fxsyncId: 'XXXXX_ID_XXXXX',
|
||||
visits: [ 1502000000000, 1503000000000 ]
|
||||
};
|
||||
|
||||
var result = HistoryHelper.mergeRecordsToDataStore(place1, place2);
|
||||
var expectedPlace = {
|
||||
url: 'http://www.mozilla.org/en-US/',
|
||||
title: 'Mozilla',
|
||||
fxsyncId: 'XXXXX_ID_XXXXX',
|
||||
createdLocally: true,
|
||||
visits: [1503000000000, 1502000000000, 1501000000000]
|
||||
};
|
||||
|
||||
assert.equal(result.title, expectedPlace.title);
|
||||
assert.equal(result.url, expectedPlace.url);
|
||||
assert.equal(result.visits.length, expectedPlace.visits.length);
|
||||
for(var i = 0; i < result.visits.length; i++){
|
||||
assert.equal(result.visits[i], expectedPlace.visits[i]);
|
||||
}
|
||||
done();
|
||||
});
|
||||
|
||||
test('HistoryHelper - merge two records with incorrect URL', function(done) {
|
||||
var place1 = {
|
||||
url: 'dummy',
|
||||
title: '',
|
||||
fxsyncId: '',
|
||||
visits: [ 1501000000000, 1502000000000 ]
|
||||
};
|
||||
|
||||
var place2 = {
|
||||
url: 'http://www.mozilla.org/en-US/',
|
||||
title: 'Mozilla',
|
||||
fxsyncId: 'XXXXX_ID_XXXXX',
|
||||
visits: [ 1502000000000, 1503000000000 ]
|
||||
};
|
||||
|
||||
assert.throws(() => {
|
||||
HistoryHelper.mergeRecordsToDataStore(place1, place2);
|
||||
});
|
||||
done();
|
||||
});
|
||||
|
||||
test('HistoryHelper - merge two records with incorrect fxsyncId',
|
||||
function(done) {
|
||||
var place1 = {
|
||||
url: 'http://www.mozilla.org/en-US/',
|
||||
title: '',
|
||||
fxsyncId: 'dummy',
|
||||
visits: [ 1501000000000, 1502000000000 ]
|
||||
};
|
||||
|
||||
var place2 = {
|
||||
url: 'http://www.mozilla.org/en-US/',
|
||||
title: 'Mozilla',
|
||||
fxsyncId: 'XXXXX_ID_XXXXX',
|
||||
visits: [ 1502000000000, 1503000000000 ]
|
||||
};
|
||||
|
||||
assert.throws(() => {
|
||||
HistoryHelper.mergeRecordsToDataStore(place1, place2);
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
Loading…
Reference in a new issue