From c2e61f548f613c8585e881c6abbc5880b4146c57 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 10 Oct 2021 16:37:26 +0100 Subject: [PATCH] Tools: Added a few tools to make testing server easier --- packages/server/src/db.ts | 19 +++++++++++++++++- .../server/src/models/ChangeModel.test.ts | 20 ++++++------------- packages/server/src/models/ItemModel.ts | 16 +++++++++++++++ 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/packages/server/src/db.ts b/packages/server/src/db.ts index dd0dde916..dc02cba8f 100644 --- a/packages/server/src/db.ts +++ b/packages/server/src/db.ts @@ -1,5 +1,5 @@ import { knex, Knex } from 'knex'; -import { DatabaseConfig } from './utils/types'; +import { DatabaseConfig, DatabaseConfigClient } from './utils/types'; import * as pathUtils from 'path'; import time from '@joplin/lib/time'; import Logger from '@joplin/lib/Logger'; @@ -112,6 +112,23 @@ export async function waitForConnection(dbConfig: DatabaseConfig): Promise { + return db.client.config.client; +}; + +export const isPostgres = (db: DbConnection) => { + return clientType(db) === DatabaseConfigClient.PostgreSQL; +}; + +export const isSqlite = (db: DbConnection) => { + return clientType(db) === DatabaseConfigClient.SQLite; +}; + +export const setCollateC = async (db: DbConnection, tableName: string, columnName: string): Promise => { + if (!isPostgres(db)) return; + await db.raw(`ALTER TABLE ${tableName} ALTER COLUMN ${columnName} SET DATA TYPE character varying(32) COLLATE "C"`); +}; + function makeSlowQueryHandler(duration: number, connection: any, sql: string, bindings: any[]) { return setTimeout(() => { try { diff --git a/packages/server/src/models/ChangeModel.test.ts b/packages/server/src/models/ChangeModel.test.ts index bd70f7f8a..05f56e17d 100644 --- a/packages/server/src/models/ChangeModel.test.ts +++ b/packages/server/src/models/ChangeModel.test.ts @@ -1,15 +1,9 @@ import { createUserAndSession, beforeAllDb, afterAllTests, beforeEachDb, models, expectThrow, createFolder, createItemTree3, expectNotThrow } from '../utils/testing/testUtils'; -import { ChangeType, Item, Uuid } from '../services/database/types'; +import { ChangeType } from '../services/database/types'; import { msleep } from '../utils/time'; import { ChangePagination } from './ChangeModel'; import { SqliteMaxVariableNum } from '../db'; -async function makeTestItem(userId: Uuid, num: number): Promise { - return models().item().saveForUser(userId, { - name: `${num.toString().padStart(32, '0')}.md`, - }); -} - describe('ChangeModel', function() { beforeAll(async () => { @@ -43,14 +37,14 @@ describe('ChangeModel', function() { const itemModel = models().item(); const changeModel = models().change(); - await msleep(1); const item1 = await makeTestItem(user.id, 1); // [1] CREATE 1 + await msleep(1); const item1 = await models().item().makeTestItem(user.id, 1); // [1] CREATE 1 await msleep(1); await itemModel.saveForUser(user.id, { id: item1.id, name: '0000000000000000000000000000001A.md' }); // [2] UPDATE 1a await msleep(1); await itemModel.saveForUser(user.id, { id: item1.id, name: '0000000000000000000000000000001B.md' }); // [3] UPDATE 1b - await msleep(1); const item2 = await makeTestItem(user.id, 2); // [4] CREATE 2 + await msleep(1); const item2 = await models().item().makeTestItem(user.id, 2); // [4] CREATE 2 await msleep(1); await itemModel.saveForUser(user.id, { id: item2.id, name: '0000000000000000000000000000002A.md' }); // [5] UPDATE 2a await msleep(1); await itemModel.delete(item1.id); // [6] DELETE 1 await msleep(1); await itemModel.saveForUser(user.id, { id: item2.id, name: '0000000000000000000000000000002B.md' }); // [7] UPDATE 2b - await msleep(1); const item3 = await makeTestItem(user.id, 3); // [8] CREATE 3 + await msleep(1); const item3 = await models().item().makeTestItem(user.id, 3); // [8] CREATE 3 // Check that the 8 changes were created const allUncompressedChanges = await changeModel.all(); @@ -125,7 +119,7 @@ describe('ChangeModel', function() { const changeModel = models().change(); let i = 1; - await msleep(1); const item1 = await makeTestItem(user.id, 1); // CREATE 1 + await msleep(1); const item1 = await models().item().makeTestItem(user.id, 1); // CREATE 1 await msleep(1); await itemModel.saveForUser(user.id, { id: item1.id, name: `test_mod${i++}` }); // UPDATE 1 await expectThrow(async () => changeModel.delta(user.id, { limit: 1, cursor: 'invalid' }), 'resyncRequired'); @@ -173,9 +167,7 @@ describe('ChangeModel', function() { const { user } = await createUserAndSession(1, true); - for (let i = 0; i < 1010; i++) { - await makeTestItem(user.id, i); - } + await models().item().makeTestItems(user.id, 1010); let changeCount = 0; await expectNotThrow(async () => { diff --git a/packages/server/src/models/ItemModel.ts b/packages/server/src/models/ItemModel.ts index 7f4136040..0dfa4db38 100644 --- a/packages/server/src/models/ItemModel.ts +++ b/packages/server/src/models/ItemModel.ts @@ -549,6 +549,22 @@ export default class ItemModel extends BaseModel { } } + public async makeTestItem(userId: Uuid, num: number) { + return this.saveForUser(userId, { + name: `${num.toString().padStart(32, '0')}.md`, + }); + } + + public async makeTestItems(userId: Uuid, count: number) { + await this.withTransaction(async () => { + for (let i = 1; i <= count; i++) { + await this.saveForUser(userId, { + name: `${i.toString().padStart(32, '0')}.md`, + }); + } + }, 'ItemModel::makeTestItems'); + } + public async saveForUser(userId: Uuid, item: Item, options: SaveOptions = {}): Promise { if (!userId) throw new Error('userId is required');