From ec2f1b98330cfdbb7bd08f2dd7a833a117381be9 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 28 Sep 2021 14:20:21 +0200 Subject: [PATCH] add unit tests for findExistingKeys --- src/matrix/storage/idb/QueryTarget.ts | 113 +++++++++++++++++++++++++- src/matrix/storage/idb/Store.ts | 6 +- 2 files changed, 112 insertions(+), 7 deletions(-) diff --git a/src/matrix/storage/idb/QueryTarget.ts b/src/matrix/storage/idb/QueryTarget.ts index 402140f2..1ef3aacd 100644 --- a/src/matrix/storage/idb/QueryTarget.ts +++ b/src/matrix/storage/idb/QueryTarget.ts @@ -15,7 +15,15 @@ limitations under the License. */ import {iterateCursor, DONE, NOT_DONE, reqAsPromise} from "./utils"; -import {Transaction} from "./Transaction"; +import {StorageError} from "../common"; +import {LogItem} from "../../../logging/LogItem.js"; +import {IDBKey} from "./Transaction"; + +export interface ITransaction { + idbFactory: IDBFactory; + IDBKeyRange: typeof IDBKeyRange; + addWriteError(error: StorageError, refItem: LogItem | undefined, operationName: string, keys: IDBKey[] | undefined); +} type Reducer = (acc: B, val: A) => B @@ -32,9 +40,9 @@ interface QueryTargetInterface { export class QueryTarget { protected _target: QueryTargetInterface; - protected _transaction: Transaction; + protected _transaction: ITransaction; - constructor(target: QueryTargetInterface, transaction: Transaction) { + constructor(target: QueryTargetInterface, transaction: ITransaction) { this._target = target; this._transaction = transaction; } @@ -167,7 +175,6 @@ export class QueryTarget { const sortedKeys = keys.slice().sort(compareKeys); const firstKey = sortedKeys[0]; const lastKey = sortedKeys[sortedKeys.length - 1]; - console.log(firstKey, lastKey, sortedKeys); const direction = backwards ? "prev" : "next"; const cursor = this._target.openKeyCursor(this.IDBKeyRange.bound(firstKey, lastKey), direction); let index = 0; @@ -254,3 +261,101 @@ export class QueryTarget { } } } + +import {createMockDatabase, MockIDBImpl} from "../../../mocks/Storage"; +import {txnAsPromise} from "./utils"; +import {QueryTargetWrapper, Store} from "./Store"; + +export function tests() { + + class MockTransaction extends MockIDBImpl { + addWriteError(error: StorageError, refItem: LogItem | undefined, operationName: string, keys: IDBKey[] | undefined) {} + } + + interface TestEntry { + key: string + } + + async function createTestStore(): Promise> { + const mockImpl = new MockTransaction(); + const db = await createMockDatabase("findExistingKeys", (db: IDBDatabase) => { + db.createObjectStore("test", {keyPath: "key"}); + }, mockImpl); + const txn = db.transaction(["test"], "readwrite"); + return new Store(txn.objectStore("test"), mockImpl); + } + + return { + "findExistingKeys should not match on empty store": async assert => { + const store = await createTestStore(); + await store.findExistingKeys(["2db1a709-d8f1-4c40-a835-f312badd277a", "fe7aa5c2-d4ed-4278-b3b0-f49d48d11df2"], false, () => { + assert.fail("no key should match"); + return false; + }); + }, + "findExistingKeys should not match any existing keys (in between sorting order)": async assert => { + const store = await createTestStore(); + store.add({key: "43cd16eb-a6b4-4b9d-ab36-ab87d1b038c3"}); + store.add({key: "b655e7c5-e02d-4823-a7af-4202b12de659"}); + await store.findExistingKeys(["2db1a709-d8f1-4c40-a835-f312badd277a", "fe7aa5c2-d4ed-4278-b3b0-f49d48d11df2"], false, () => { + assert.fail("no key should match"); + return false; + }); + }, + "findExistingKeys should match only existing keys": async assert => { + const store = await createTestStore(); + store.add({key: "2db1a709-d8f1-4c40-a835-f312badd277a"}); + store.add({key: "43cd16eb-a6b4-4b9d-ab36-ab87d1b038c3"}); + store.add({key: "fe7aa5c2-d4ed-4278-b3b0-f49d48d11df2"}); + const found: string[] = []; + await store.findExistingKeys([ + "2db1a709-d8f1-4c40-a835-f312badd277a", + "eac3ef5c-a48f-4e19-b41d-ebd1d84c53f2", + "fe7aa5c2-d4ed-4278-b3b0-f49d48d11df2" + ], false, (key: IDBValidKey) => { + found.push(key as string); + return false; + }); + assert.equal(found.length, 2); + assert.equal(found[0], "2db1a709-d8f1-4c40-a835-f312badd277a"); + assert.equal(found[1], "fe7aa5c2-d4ed-4278-b3b0-f49d48d11df2"); + }, + "findExistingKeys should match all if all exist": async assert => { + const store = await createTestStore(); + store.add({key: "2db1a709-d8f1-4c40-a835-f312badd277a"}); + store.add({key: "fe7aa5c2-d4ed-4278-b3b0-f49d48d11df2"}); + store.add({key: "b655e7c5-e02d-4823-a7af-4202b12de659"}); + const found: string[] = []; + await store.findExistingKeys([ + "2db1a709-d8f1-4c40-a835-f312badd277a", + "b655e7c5-e02d-4823-a7af-4202b12de659", + "fe7aa5c2-d4ed-4278-b3b0-f49d48d11df2" + ], false, (key: IDBValidKey) => { + found.push(key as string); + return false; + }); + assert.equal(found.length, 3); + assert.equal(found[0], "2db1a709-d8f1-4c40-a835-f312badd277a"); + assert.equal(found[1], "b655e7c5-e02d-4823-a7af-4202b12de659"); + assert.equal(found[2], "fe7aa5c2-d4ed-4278-b3b0-f49d48d11df2"); + }, + "findExistingKeys should stop matching when callback returns true": async assert => { + const store = await createTestStore(); + store.add({key: "2db1a709-d8f1-4c40-a835-f312badd277a"}); + store.add({key: "fe7aa5c2-d4ed-4278-b3b0-f49d48d11df2"}); + store.add({key: "b655e7c5-e02d-4823-a7af-4202b12de659"}); + const found: string[] = []; + await store.findExistingKeys([ + "2db1a709-d8f1-4c40-a835-f312badd277a", + "b655e7c5-e02d-4823-a7af-4202b12de659", + "fe7aa5c2-d4ed-4278-b3b0-f49d48d11df2" + ], false, (key: IDBValidKey) => { + found.push(key as string); + return true; + }); + assert.equal(found.length, 1); + assert.equal(found[0], "2db1a709-d8f1-4c40-a835-f312badd277a"); + }, + + } +} diff --git a/src/matrix/storage/idb/Store.ts b/src/matrix/storage/idb/Store.ts index 9c350b98..a4c80426 100644 --- a/src/matrix/storage/idb/Store.ts +++ b/src/matrix/storage/idb/Store.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {QueryTarget, IDBQuery} from "./QueryTarget"; +import {QueryTarget, IDBQuery, ITransaction} from "./QueryTarget"; import {IDBRequestError, IDBRequestAttemptError} from "./error"; import {reqAsPromise} from "./utils"; import {Transaction, IDBKey} from "./Transaction"; @@ -28,7 +28,7 @@ function logRequest(method: string, params: any[], source: any): void { console.info(`${databaseName}.${storeName}.${method}(${params.map(p => JSON.stringify(p)).join(", ")})`); } -class QueryTargetWrapper { +export class QueryTargetWrapper { private _qt: IDBIndex | IDBObjectStore; constructor(qt: IDBIndex | IDBObjectStore) { @@ -133,7 +133,7 @@ class QueryTargetWrapper { } export class Store extends QueryTarget { - constructor(idbStore: IDBObjectStore, transaction: Transaction) { + constructor(idbStore: IDBObjectStore, transaction: ITransaction) { super(new QueryTargetWrapper(idbStore), transaction); }