mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-08-28 10:18:39 +09:00
434 lines
24 KiB
Swift
434 lines
24 KiB
Swift
/* 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/. */
|
|
|
|
import Foundation
|
|
import Shared
|
|
import Deferred
|
|
@testable import Sync
|
|
@testable import Storage
|
|
|
|
import XCTest
|
|
import SwiftyJSON
|
|
|
|
class MockStorage: LocalItemSource, MirrorItemSource, SyncableBookmarks {
|
|
var local: [GUID: BookmarkMirrorItem] = [:]
|
|
var localAdditions: [GUID] = []
|
|
var localDeletions: [GUID] = []
|
|
var lastBufferUpdatedCompletionOpApplied: BufferUpdatedCompletionOp?
|
|
|
|
// LocalItemSource methods.
|
|
|
|
func getLocalItemWithGUID(_ guid: GUID) -> Deferred<Maybe<BookmarkMirrorItem>> {
|
|
guard let item = self.local[guid] else {
|
|
return deferMaybe(DatabaseError(description: "Couldn't find item \(guid)."))
|
|
}
|
|
return deferMaybe(item)
|
|
}
|
|
|
|
func getLocalItemsWithGUIDs<T: Collection>(_ guids: T) -> Deferred<Maybe<[GUID: BookmarkMirrorItem]>> where T.Iterator.Element == GUID {
|
|
var acc: [GUID: BookmarkMirrorItem] = [:]
|
|
guids.forEach { guid in
|
|
if let item = self.local[guid] {
|
|
acc[guid] = item
|
|
}
|
|
}
|
|
return deferMaybe(acc)
|
|
}
|
|
|
|
func prefetchLocalItemsWithGUIDs<T: Collection>(_ guids: T) -> Success where T.Iterator.Element == GUID {
|
|
return succeed()
|
|
}
|
|
|
|
// MirrorItemSource methods (not implemented!).
|
|
|
|
func getMirrorItemWithGUID(_ guid: GUID) -> Deferred<Maybe<BookmarkMirrorItem>> {
|
|
return deferMaybe(DatabaseError(description: "Not implemented"))
|
|
}
|
|
|
|
func getMirrorItemsWithGUIDs<T>(_ guids: T) -> Deferred<Maybe<[GUID : BookmarkMirrorItem]>> where T : Collection, T.Iterator.Element == GUID {
|
|
return deferMaybe(DatabaseError(description: "Not implemented"))
|
|
}
|
|
|
|
func prefetchMirrorItemsWithGUIDs<T: Collection>(_ guids: T) -> Success where T.Iterator.Element == GUID {
|
|
return succeed()
|
|
}
|
|
|
|
// SyncableBookmarks methods (partialy implemented!).
|
|
|
|
func isUnchanged() -> Deferred<Maybe<Bool>> {
|
|
return deferMaybe(DatabaseError(description: "Not implemented"))
|
|
}
|
|
|
|
func getLocalBookmarksModifications(limit: Int) -> Deferred<Maybe<(deletions: [GUID], additions: [BookmarkMirrorItem])>> {
|
|
let deletions = Array(self.localDeletions.prefix(limit))
|
|
let additions = Array(self.localAdditions.prefix(limit - deletions.count)).map { self.local[$0]! }
|
|
return deferMaybe((deletions: deletions, additions: additions))
|
|
}
|
|
|
|
func getLocalDeletions() -> Deferred<Maybe<[(GUID, Timestamp)]>> {
|
|
return deferMaybe(DatabaseError(description: "Not implemented"))
|
|
}
|
|
|
|
func treesForEdges() -> Deferred<Maybe<(local: BookmarkTree, buffer: BookmarkTree)>> {
|
|
return deferMaybe(DatabaseError(description: "Not implemented"))
|
|
}
|
|
|
|
func treeForMirror() -> Deferred<Maybe<BookmarkTree>> {
|
|
return deferMaybe(DatabaseError(description: "Not implemented"))
|
|
}
|
|
|
|
func applyLocalOverrideCompletionOp(_ op: LocalOverrideCompletionOp, itemSources: ItemSources) -> Success {
|
|
return deferMaybe(DatabaseError(description: "Not implemented"))
|
|
}
|
|
|
|
func applyBufferUpdatedCompletionOp(_ op: BufferUpdatedCompletionOp) -> Success {
|
|
self.lastBufferUpdatedCompletionOpApplied = op
|
|
return succeed()
|
|
}
|
|
|
|
// Misc methods.
|
|
|
|
func resetClient() -> Success {
|
|
return deferMaybe(DatabaseError(description: "Not implemented"))
|
|
}
|
|
|
|
func onRemovedAccount() -> Success {
|
|
return deferMaybe(DatabaseError(description: "Not implemented"))
|
|
}
|
|
}
|
|
|
|
class MockBuffer: BookmarkBufferStorage, BufferItemSource {
|
|
var buffer: [GUID: BookmarkMirrorItem] = [:]
|
|
var children: [GUID: [GUID]] = [:]
|
|
|
|
// BufferItemSource methods.
|
|
|
|
func getBufferItemWithGUID(_ guid: GUID) -> Deferred<Maybe<BookmarkMirrorItem>> {
|
|
guard let item = self.buffer[guid] else {
|
|
return deferMaybe(DatabaseError(description: "Couldn't find item \(guid)."))
|
|
}
|
|
return deferMaybe(item)
|
|
}
|
|
|
|
func getBufferItemsWithGUIDs<T>(_ guids: T) -> Deferred<Maybe<[GUID : BookmarkMirrorItem]>> where T : Collection, T.Iterator.Element == GUID {
|
|
return deferMaybe(DatabaseError(description: "Not implemented"))
|
|
}
|
|
|
|
func getBufferChildrenGUIDsForParent(_ guid: GUID) -> Deferred<Maybe<[GUID]>> {
|
|
guard let children = self.children[guid] else {
|
|
return deferMaybe(DatabaseError(description: "Couldn't find children for \(guid)."))
|
|
}
|
|
return deferMaybe(children)
|
|
}
|
|
|
|
func prefetchBufferItemsWithGUIDs<T>(_ guids: T) -> Success where T : Collection, T.Iterator.Element == GUID {
|
|
return succeed()
|
|
}
|
|
|
|
// BookmarkBufferStorage methods.
|
|
|
|
func isEmpty() -> Deferred<Maybe<Bool>> {
|
|
return deferMaybe(DatabaseError(description: "Not implemented"))
|
|
}
|
|
|
|
func applyRecords(_ records: [BookmarkMirrorItem]) -> Success {
|
|
return deferMaybe(DatabaseError(description: "Not implemented"))
|
|
}
|
|
|
|
func doneApplyingRecordsAfterDownload() -> Success {
|
|
return deferMaybe(DatabaseError(description: "Not implemented"))
|
|
}
|
|
|
|
func validate() -> Success {
|
|
return deferMaybe(DatabaseError(description: "Not implemented"))
|
|
}
|
|
|
|
func getBufferedDeletions() -> Deferred<Maybe<[(GUID, Timestamp)]>> {
|
|
return deferMaybe(DatabaseError(description: "Not implemented"))
|
|
}
|
|
|
|
func applyBufferCompletionOp(_ op: BufferCompletionOp, itemSources: ItemSources) -> Success {
|
|
return deferMaybe(DatabaseError(description: "Not implemented"))
|
|
}
|
|
|
|
func synchronousBufferCount() -> Int? {
|
|
return nil
|
|
}
|
|
|
|
func getUpstreamRecordCount() -> Deferred<Int?> {
|
|
return Deferred(value: nil)
|
|
}
|
|
}
|
|
|
|
class TestBookmarksSynchronizer: XCTestCase {
|
|
func testBuildMobileRootAndChildrenRecords_noMobileRootInBuffer() {
|
|
let delegate = MockSyncDelegate()
|
|
let prefs = MockProfilePrefs()
|
|
let scratchpad = Scratchpad(b: KeyBundle.random(), persistingTo: prefs)
|
|
|
|
let buffer = MockBuffer()
|
|
let storage = MockStorage()
|
|
storage.local[BookmarkRoots.MobileFolderGUID] = BookmarkMirrorItem.folder(BookmarkRoots.MobileFolderGUID, dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: nil, title: "Mobile Bookmarks", description: nil, children: ["bk1"])
|
|
storage.local["bk1"] = BookmarkMirrorItem.bookmark("bk1", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.MobileFolderGUID, parentName: nil, title: "Bookmark 1", description: nil, URI: "https://example.com/1", tags: "", keyword: nil)
|
|
storage.local["bk1"] = BookmarkMirrorItem.bookmark("bk1", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.MobileFolderGUID, parentName: nil, title: "Bookmark 1", description: nil, URI: "https://example.com/1", tags: "", keyword: nil)
|
|
let bk2 = BookmarkMirrorItem.bookmark("bk2", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.MobileFolderGUID, parentName: nil, title: "Bookmark 2", description: nil, URI: "https://example.com/2", tags: "", keyword: nil)
|
|
let bk3 = BookmarkMirrorItem.bookmark("bk3", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.MobileFolderGUID, parentName: nil, title: "Bookmark 3", description: nil, URI: "https://example.com/3", tags: "", keyword: nil)
|
|
storage.local["bk2"] = bk2
|
|
storage.local["bk3"] = bk3
|
|
|
|
let synchronizer = BufferingBookmarksSynchronizer(scratchpad: scratchpad, delegate: delegate, basePrefs: prefs, why: .scheduled)
|
|
let (mobileRootRecord, childrenRecords) = synchronizer.buildMobileRootAndChildrenRecords(storage, buffer, additionalChildren: [bk2, bk3], deletedChildren: []).value.successValue!
|
|
XCTAssertEqual(mobileRootRecord.id, BookmarkRoots.translateOutgoingRootGUID(BookmarkRoots.MobileFolderGUID))
|
|
XCTAssertEqual(mobileRootRecord.payload.json["title"], "Mobile Bookmarks")
|
|
// We are not including bk1 in the call to buildMobileRootRecord() therefore it should NOT be included in the returned record
|
|
XCTAssertEqual(mobileRootRecord.payload.json["children"], ["bk2", "bk3"])
|
|
|
|
XCTAssertEqual(childrenRecords.count, 2)
|
|
XCTAssertEqual(childrenRecords[0].id, "bk2")
|
|
XCTAssertEqual(childrenRecords[1].id, "bk3")
|
|
}
|
|
|
|
func testBuildMobileRootAndChildrenRecords_mobileRootInBuffer() {
|
|
let delegate = MockSyncDelegate()
|
|
let prefs = MockProfilePrefs()
|
|
let scratchpad = Scratchpad(b: KeyBundle.random(), persistingTo: prefs)
|
|
|
|
let buffer = MockBuffer()
|
|
buffer.buffer[BookmarkRoots.MobileFolderGUID] = BookmarkMirrorItem.folder(BookmarkRoots.MobileFolderGUID, dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: nil, title: "Mobile Bookmarks", description: nil, children: ["bk1", "bkmdeleteme"])
|
|
buffer.children[BookmarkRoots.MobileFolderGUID] = ["bk1", "bkmdeleteme"]
|
|
buffer.buffer["bk1"] = BookmarkMirrorItem.bookmark("bk1", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.MobileFolderGUID, parentName: nil, title: "Bookmark 1", description: nil, URI: "https://example.com/1", tags: "", keyword: nil)
|
|
buffer.buffer["bkmdeleteme"] = BookmarkMirrorItem.bookmark("bkmdeleteme", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.MobileFolderGUID, parentName: nil, title: "Bookmark to delete", description: nil, URI: "https://example.com/todelete", tags: "", keyword: nil)
|
|
|
|
let storage = MockStorage()
|
|
storage.local["bk1"] = BookmarkMirrorItem.bookmark("bk1", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.MobileFolderGUID, parentName: nil, title: "Bookmark 1", description: nil, URI: "https://example.com/1", tags: "", keyword: nil)
|
|
let bk2 = BookmarkMirrorItem.bookmark("bk2", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.MobileFolderGUID, parentName: nil, title: "Bookmark 2", description: nil, URI: "https://example.com/2", tags: "", keyword: nil)
|
|
let bk3 = BookmarkMirrorItem.bookmark("bk3", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.MobileFolderGUID, parentName: nil, title: "Bookmark 3", description: nil, URI: "https://example.com/3", tags: "", keyword: nil)
|
|
storage.local["bk2"] = bk2
|
|
storage.local["bk3"] = bk3
|
|
|
|
let synchronizer = BufferingBookmarksSynchronizer(scratchpad: scratchpad, delegate: delegate, basePrefs: prefs, why: .scheduled)
|
|
let (mobileRootRecord, childrenRecords) = synchronizer.buildMobileRootAndChildrenRecords(storage, buffer, additionalChildren: [bk2, bk3], deletedChildren: ["bkmdeleteme"]).value.successValue!
|
|
XCTAssertEqual(mobileRootRecord.id, BookmarkRoots.translateOutgoingRootGUID(BookmarkRoots.MobileFolderGUID))
|
|
XCTAssertEqual(mobileRootRecord.payload.json["title"], "Mobile Bookmarks")
|
|
// bk1 is a children of mobile root in the buffer, therefore it should be included here.
|
|
XCTAssertEqual(mobileRootRecord.payload.json["children"], ["bk1", "bk2", "bk3"])
|
|
|
|
// We are only sending the new/deleted records though!
|
|
XCTAssertEqual(childrenRecords.count, 3)
|
|
XCTAssertEqual(childrenRecords[0].id, "bk2")
|
|
XCTAssertEqual(childrenRecords[1].id, "bk3")
|
|
XCTAssertEqual(childrenRecords[2].id, "bkmdeleteme")
|
|
XCTAssertTrue(childrenRecords[2].payload.deleted)
|
|
}
|
|
|
|
func testUploadSomeLocalRecords_batched_ok() {
|
|
let delegate = MockSyncDelegate()
|
|
let prefs = MockProfilePrefs()
|
|
let scratchpad = Scratchpad(b: KeyBundle.random(), persistingTo: prefs)
|
|
|
|
let storage = MockStorage()
|
|
let buffer = MockBuffer()
|
|
|
|
let records = createMobileRootAndChildrenRecords(numChildren: 80)
|
|
|
|
var numPosts = 0
|
|
let now = Date.now()
|
|
var firstPostLastModified: Timestamp?
|
|
var secondPostLastModified: Timestamp?
|
|
let uploader: BatchUploadFunction = { lines, ifUnmodifiedSince, queryParams in
|
|
numPosts += 1
|
|
var headers = [String: Any]()
|
|
|
|
let result: POSTResult
|
|
if numPosts == 1 {
|
|
result = POSTResult(success: records.childrenRecords.map { $0.id } + ["mobile"], failed: [:], batchToken: "toktok")
|
|
firstPostLastModified = now
|
|
headers["X-Last-Modified"] = firstPostLastModified
|
|
} else {
|
|
XCTAssertEqual(queryParams![0].name, "batch")
|
|
XCTAssertEqual(queryParams![0].value, "toktok")
|
|
XCTAssertEqual(queryParams![1].name, "commit")
|
|
XCTAssertEqual(queryParams![1].value, "true")
|
|
result = POSTResult(success: [], failed: [:])
|
|
secondPostLastModified = now + 5000
|
|
headers["X-Last-Modified"] = secondPostLastModified
|
|
}
|
|
let response = StorageResponse<POSTResult>(value: result, metadata: ResponseMetadata(status: 200, headers: headers))
|
|
return deferMaybe(response)
|
|
}
|
|
|
|
let miniConfig = InfoConfiguration(maxRequestBytes: 1_048_576, maxPostRecords: 100, maxPostBytes: 1_048_576, maxTotalRecords: 250, maxTotalBytes: 104_857_600)
|
|
let collectionClient = MockSyncCollectionClient(uploader: uploader, infoConfig: miniConfig, collection: "bookmarks", encrypter: getBookmarksEncrypter())
|
|
let mirrorer = BookmarksMirrorer(storage: buffer, client: collectionClient, basePrefs: prefs, collection: "bookmarks", statsSession: SyncEngineStatsSession(collection: "bookmarks"))
|
|
|
|
let synchronizer = BufferingBookmarksSynchronizer(scratchpad: scratchpad, delegate: delegate, basePrefs: prefs, why: .scheduled)
|
|
synchronizer.uploadSomeLocalRecords(storage, mirrorer, collectionClient, mobileRootRecord: records.mobileRootRecord, childrenRecords: records.childrenRecords).succeeded()
|
|
XCTAssertEqual(storage.lastBufferUpdatedCompletionOpApplied?.bufferValuesToMoveFromLocal.count, 81)
|
|
XCTAssertEqual(numPosts, 2)
|
|
XCTAssertEqual(mirrorer.lastModified / 1000, secondPostLastModified)
|
|
}
|
|
|
|
func testUploadSomeLocalRecords_batched_someFailed() {
|
|
let delegate = MockSyncDelegate()
|
|
let prefs = MockProfilePrefs()
|
|
let scratchpad = Scratchpad(b: KeyBundle.random(), persistingTo: prefs)
|
|
|
|
let storage = MockStorage()
|
|
let buffer = MockBuffer()
|
|
|
|
let records = createMobileRootAndChildrenRecords(numChildren: 80)
|
|
|
|
var numPosts = 0
|
|
let uploader: BatchUploadFunction = { lines, ifUnmodifiedSince, queryParams in
|
|
numPosts += 1
|
|
var headers = [String: Any]()
|
|
headers["X-Last-Modified"] = Date.now()
|
|
|
|
let result = POSTResult(success: records.childrenRecords.map { $0.id }.dropFirst(20) + ["mobile"], failed: [:], batchToken: "toktok")
|
|
let response = StorageResponse<POSTResult>(value: result, metadata: ResponseMetadata(status: 200, headers: headers))
|
|
return deferMaybe(response)
|
|
}
|
|
|
|
let miniConfig = InfoConfiguration(maxRequestBytes: 1_048_576, maxPostRecords: 100, maxPostBytes: 1_048_576, maxTotalRecords: 250, maxTotalBytes: 104_857_600)
|
|
let collectionClient = MockSyncCollectionClient(uploader: uploader, infoConfig: miniConfig, collection: "bookmarks", encrypter: getBookmarksEncrypter())
|
|
let mirrorer = BookmarksMirrorer(storage: buffer, client: collectionClient, basePrefs: prefs, collection: "bookmarks", statsSession: SyncEngineStatsSession(collection: "bookmarks"))
|
|
|
|
let synchronizer = BufferingBookmarksSynchronizer(scratchpad: scratchpad, delegate: delegate, basePrefs: prefs, why: .scheduled)
|
|
let error = synchronizer.uploadSomeLocalRecords(storage, mirrorer, collectionClient, mobileRootRecord: records.mobileRootRecord, childrenRecords: records.childrenRecords).value.failureValue!
|
|
XCTAssertTrue(error is RecordsFailedToUpload)
|
|
XCTAssertNil(storage.lastBufferUpdatedCompletionOpApplied)
|
|
XCTAssertEqual(numPosts, 1)
|
|
}
|
|
|
|
func testUploadSomeLocalRecords_nobatch_ok() {
|
|
let delegate = MockSyncDelegate()
|
|
let prefs = MockProfilePrefs()
|
|
let scratchpad = Scratchpad(b: KeyBundle.random(), persistingTo: prefs)
|
|
|
|
let storage = MockStorage()
|
|
let buffer = MockBuffer()
|
|
|
|
let records = createMobileRootAndChildrenRecords(numChildren: 80)
|
|
|
|
var numPosts = 0
|
|
let uploader: BatchUploadFunction = { lines, ifUnmodifiedSince, queryParams in
|
|
numPosts += 1
|
|
var headers = [String: Any]()
|
|
headers["X-Last-Modified"] = Date.now()
|
|
|
|
let result = POSTResult(success: records.childrenRecords.map { $0.id } + ["mobile"], failed: [:])
|
|
let response = StorageResponse<POSTResult>(value: result, metadata: ResponseMetadata(status: 200, headers: headers))
|
|
return deferMaybe(response)
|
|
}
|
|
|
|
let miniConfig = InfoConfiguration(maxRequestBytes: 1_048_576, maxPostRecords: 100, maxPostBytes: 1_048_576, maxTotalRecords: 250, maxTotalBytes: 104_857_600)
|
|
let collectionClient = MockSyncCollectionClient(uploader: uploader, infoConfig: miniConfig, collection: "bookmarks", encrypter: getBookmarksEncrypter())
|
|
let mirrorer = BookmarksMirrorer(storage: buffer, client: collectionClient, basePrefs: prefs, collection: "bookmarks", statsSession: SyncEngineStatsSession(collection: "bookmarks"))
|
|
|
|
let synchronizer = BufferingBookmarksSynchronizer(scratchpad: scratchpad, delegate: delegate, basePrefs: prefs, why: .scheduled)
|
|
synchronizer.uploadSomeLocalRecords(storage, mirrorer, collectionClient, mobileRootRecord: records.mobileRootRecord, childrenRecords: records.childrenRecords).succeeded()
|
|
XCTAssertEqual(storage.lastBufferUpdatedCompletionOpApplied?.bufferValuesToMoveFromLocal.count, 81)
|
|
XCTAssertEqual(numPosts, 1)
|
|
}
|
|
|
|
func testUploadSomeLocalRecords_nobatch_someFailed() {
|
|
let delegate = MockSyncDelegate()
|
|
let prefs = MockProfilePrefs()
|
|
let scratchpad = Scratchpad(b: KeyBundle.random(), persistingTo: prefs)
|
|
|
|
let storage = MockStorage()
|
|
let buffer = MockBuffer()
|
|
|
|
let records = createMobileRootAndChildrenRecords(numChildren: 80)
|
|
|
|
var numPosts = 0
|
|
let uploader: BatchUploadFunction = { lines, ifUnmodifiedSince, queryParams in
|
|
numPosts += 1
|
|
var headers = [String: Any]()
|
|
headers["X-Last-Modified"] = Date.now()
|
|
|
|
let result = POSTResult(success: records.childrenRecords.map { $0.id }.dropFirst(20) + ["mobile"], failed: [:])
|
|
let response = StorageResponse<POSTResult>(value: result, metadata: ResponseMetadata(status: 200, headers: headers))
|
|
return deferMaybe(response)
|
|
}
|
|
|
|
let miniConfig = InfoConfiguration(maxRequestBytes: 1_048_576, maxPostRecords: 100, maxPostBytes: 1_048_576, maxTotalRecords: 250, maxTotalBytes: 104_857_600)
|
|
let collectionClient = MockSyncCollectionClient(uploader: uploader, infoConfig: miniConfig, collection: "bookmarks", encrypter: getBookmarksEncrypter())
|
|
let mirrorer = BookmarksMirrorer(storage: buffer, client: collectionClient, basePrefs: prefs, collection: "bookmarks", statsSession: SyncEngineStatsSession(collection: "bookmarks"))
|
|
|
|
let synchronizer = BufferingBookmarksSynchronizer(scratchpad: scratchpad, delegate: delegate, basePrefs: prefs, why: .scheduled)
|
|
synchronizer.uploadSomeLocalRecords(storage, mirrorer, collectionClient, mobileRootRecord: records.mobileRootRecord, childrenRecords: records.childrenRecords).succeeded()
|
|
XCTAssertEqual(storage.lastBufferUpdatedCompletionOpApplied?.bufferValuesToMoveFromLocal.count, 61)
|
|
XCTAssertEqual(numPosts, 1)
|
|
}
|
|
|
|
func testUploadSomeLocalRecords_tooManyRecords() {
|
|
let delegate = MockSyncDelegate()
|
|
let prefs = MockProfilePrefs()
|
|
let scratchpad = Scratchpad(b: KeyBundle.random(), persistingTo: prefs)
|
|
|
|
let storage = MockStorage()
|
|
let buffer = MockBuffer()
|
|
|
|
let uploader: BatchUploadFunction = { _, _, _ in
|
|
// Should never happen
|
|
XCTFail()
|
|
return deferMaybe(NSError())
|
|
}
|
|
|
|
let miniConfig = InfoConfiguration(maxRequestBytes: 1_048_576, maxPostRecords: 100, maxPostBytes: 1_048_576, maxTotalRecords: 250, maxTotalBytes: 104_857_600)
|
|
let collectionClient = MockSyncCollectionClient(uploader: uploader, infoConfig: miniConfig, collection: "bookmarks", encrypter: getBookmarksEncrypter())
|
|
let mirrorer = BookmarksMirrorer(storage: buffer, client: collectionClient, basePrefs: prefs, collection: "bookmarks", statsSession: SyncEngineStatsSession(collection: "bookmarks"))
|
|
|
|
let records = createMobileRootAndChildrenRecords(numChildren: 120)
|
|
|
|
let synchronizer = BufferingBookmarksSynchronizer(scratchpad: scratchpad, delegate: delegate, basePrefs: prefs, why: .scheduled)
|
|
let error = synchronizer.uploadSomeLocalRecords(storage, mirrorer, collectionClient, mobileRootRecord: records.mobileRootRecord, childrenRecords: records.childrenRecords).value.failureValue!
|
|
XCTAssertTrue(error is TooManyRecordsError)
|
|
}
|
|
|
|
func testUploadSomeLocalRecords_tooBig() {
|
|
let delegate = MockSyncDelegate()
|
|
let prefs = MockProfilePrefs()
|
|
let scratchpad = Scratchpad(b: KeyBundle.random(), persistingTo: prefs)
|
|
|
|
let storage = MockStorage()
|
|
let buffer = MockBuffer()
|
|
|
|
let uploader: BatchUploadFunction = { _, _, _ in
|
|
// Should never happen
|
|
XCTFail()
|
|
return deferMaybe(NSError())
|
|
}
|
|
|
|
let miniConfig = InfoConfiguration(maxRequestBytes: 1_048_576, maxPostRecords: 100, maxPostBytes: 5000, maxTotalRecords: 250, maxTotalBytes: 104_857_600)
|
|
let collectionClient = MockSyncCollectionClient(uploader: uploader, infoConfig: miniConfig, collection: "bookmarks", encrypter: getBookmarksEncrypter())
|
|
let mirrorer = BookmarksMirrorer(storage: buffer, client: collectionClient, basePrefs: prefs, collection: "bookmarks", statsSession: SyncEngineStatsSession(collection: "bookmarks"))
|
|
|
|
let records = createMobileRootAndChildrenRecords(numChildren: 80)
|
|
|
|
let synchronizer = BufferingBookmarksSynchronizer(scratchpad: scratchpad, delegate: delegate, basePrefs: prefs, why: .scheduled)
|
|
let error = synchronizer.uploadSomeLocalRecords(storage, mirrorer, collectionClient, mobileRootRecord: records.mobileRootRecord, childrenRecords: records.childrenRecords).value.failureValue!
|
|
XCTAssertTrue(error is TooManyRecordsError)
|
|
}
|
|
|
|
func getBookmarksEncrypter() -> RecordEncrypter<BookmarkBasePayload> {
|
|
let serializer: (Record<BookmarkBasePayload>) -> JSON? = { $0.payload.json }
|
|
let factory: (String) -> BookmarkBasePayload = { BookmarkBasePayload($0) }
|
|
return RecordEncrypter(serializer: serializer, factory: factory)
|
|
}
|
|
|
|
func createMobileRootAndChildrenRecords(numChildren: Int) -> (mobileRootRecord: Record<BookmarkBasePayload>, childrenRecords: [Record<BookmarkBasePayload>]) {
|
|
var childrenRecords: [Record<BookmarkBasePayload>] = []
|
|
for i in 0...numChildren {
|
|
let item = BookmarkMirrorItem.bookmark("bk1\(i)", dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.MobileFolderGUID, parentName: nil, title: "bk1\(i)", description: nil, URI: "https://example.com/\(i)", tags: "", keyword: nil)
|
|
let record = Record<BookmarkBasePayload>(id: item.guid, payload: item.asPayload())
|
|
childrenRecords.append(record)
|
|
}
|
|
let mobileRoot = BookmarkMirrorItem.folder(BookmarkRoots.MobileFolderGUID, dateAdded: Date.now(), modified: Date.now(), hasDupe: false, parentID: BookmarkRoots.RootGUID, parentName: nil, title: "Mobile Bookmarks", description: nil, children: [])
|
|
let mobileRootRecord = Record<BookmarkBasePayload>(id: BookmarkRoots.translateOutgoingRootGUID(BookmarkRoots.MobileFolderGUID), payload: mobileRoot.asPayloadWithChildren(childrenRecords.map { $0.id }))
|
|
|
|
return (mobileRootRecord: mobileRootRecord, childrenRecords: childrenRecords)
|
|
}
|
|
}
|