From 2a25ca7fc8fa206155e01851614eb295351634b5 Mon Sep 17 00:00:00 2001 From: Kevin De Porre Date: Thu, 14 Mar 2024 18:07:33 +0100 Subject: [PATCH] (WIP) Porting e2e tests for PG --- .../typescript/src/client/model/builder.ts | 17 +-- .../src/drivers/node-postgres/database.ts | 101 +++++++++--------- .../src/drivers/node-postgres/index.ts | 15 ++- .../src/drivers/tauri-postgres/index.ts | 7 +- clients/typescript/src/electric/index.ts | 2 +- clients/typescript/src/migrators/builder.ts | 4 +- clients/typescript/src/satellite/oplog.ts | 2 +- clients/typescript/src/satellite/process.ts | 5 + .../typescript/test/support/node-postgres.ts | 5 +- e2e/Makefile | 6 ++ e2e/common.mk | 4 + e2e/init.sql | 3 + e2e/satellite_client/package.json | 1 + e2e/satellite_client/src/client.ts | 47 ++++++-- ....13_node_satellite_can_sync_timestamps.lux | 4 +- ...ode_satellite_can_sync_dates_and_times.lux | 2 +- ..._is_informed_when_jwt_expires.lux.disabled | 2 +- ...node_satellite_authentication.lux.disabled | 2 +- e2e/tests/Makefile | 3 + e2e/tests/_satellite_macros.luxinc | 14 ++- 20 files changed, 163 insertions(+), 83 deletions(-) diff --git a/clients/typescript/src/client/model/builder.ts b/clients/typescript/src/client/model/builder.ts index 95572049fe..1318468a7d 100644 --- a/clients/typescript/src/client/model/builder.ts +++ b/clients/typescript/src/client/model/builder.ts @@ -26,6 +26,8 @@ squelPostgres.registerValueHandler('bigint', function (bigint) { type AnyFindInput = FindInput export class Builder { + private _fullyQualifiedTableName: string + constructor( private _tableName: string, private _fields: string[], @@ -44,23 +46,26 @@ export class Builder { >, public dialect: Dialect ) { + this._fullyQualifiedTableName = `"${this._tableName}"` if (dialect === 'Postgres') { squelPostgres.cls.DefaultQueryBuilderOptions.nameQuoteCharacter = '"' - squelPostgres.cls.DefaultQueryBuilderOptions.autoQuoteTableNames = true + //squelPostgres.cls.DefaultQueryBuilderOptions.autoQuoteTableNames = true squelPostgres.cls.DefaultQueryBuilderOptions.autoQuoteFieldNames = true squelPostgres.cls.DefaultQueryBuilderOptions.autoQuoteAliasNames = true // need to register it, otherwise squel complains that the Date type is not registered // as Squel does not support it out-of-the-box but our Postgres drivers do support it. squelPostgres.registerValueHandler(Date, (date) => date) + //this._fullyQualifiedTableName = `public."${this._tableName}"` } else { // Don't use numbered parameters if dialect is SQLite squelPostgres.cls.DefaultQueryBuilderOptions.numberedParameters = false + //this._fullyQualifiedTableName = `main."${this._tableName}"` } } create(i: CreateInput): QueryBuilder { // Make a SQL query out of the data - const query = squelPostgres.insert().into(this._tableName).setFields(i.data) + const query = squelPostgres.insert().into(this._fullyQualifiedTableName).setFields(i.data) // Adds a `RETURNING` statement that returns all known fields const queryWithReturn = this.returnAllFields(query) @@ -70,7 +75,7 @@ export class Builder { createMany(i: CreateManyInput): QueryBuilder { const insert = squelPostgres .insert() - .into(this._tableName) + .into(this._fullyQualifiedTableName) .setFieldsRows(i.data) return i.skipDuplicates ? insert.onConflict() // adds "ON CONFLICT DO NOTHING" to the query @@ -115,7 +120,7 @@ export class Builder { i: DeleteManyInput, idRequired = false ): QueryBuilder { - const deleteQuery = squel.delete().from(this._tableName) + const deleteQuery = squel.delete().from(this._fullyQualifiedTableName) const whereObject = i.where // safe because the schema for `where` adds an empty object as default which is provided if the `where` field is absent const fields = this.getFields(whereObject, idRequired) return addFilters(fields, whereObject, deleteQuery) @@ -138,7 +143,7 @@ export class Builder { const query = squelPostgres .update() - .table(this._tableName) + .table(this._fullyQualifiedTableName) .setFields(i.data) // Adds a `RETURNING` statement that returns all known fields @@ -170,7 +175,7 @@ export class Builder { if (!this.shapeManager.hasBeenSubscribed(this._tableName)) Log.debug('Reading from unsynced table ' + this._tableName) - const query = squelPostgres.select().from(this._tableName) // specify from which table to select + const query = squelPostgres.select().from(this._fullyQualifiedTableName) // specify from which table to select // only select the fields provided in `i.select` and the ones in `i.where` const addFieldSelectionP = this.addFieldSelection.bind( this, diff --git a/clients/typescript/src/drivers/node-postgres/database.ts b/clients/typescript/src/drivers/node-postgres/database.ts index 49ee7b79df..58d74280d8 100644 --- a/clients/typescript/src/drivers/node-postgres/database.ts +++ b/clients/typescript/src/drivers/node-postgres/database.ts @@ -1,6 +1,5 @@ import pg from 'pg' import type { Client } from 'pg' -import EmbeddedPostgres from 'embedded-postgres' import { Row, Statement } from '../../util' const originalGetTypeParser = pg.types.getTypeParser @@ -13,67 +12,73 @@ export type QueryResult = { export interface Database { name: string exec(statement: Statement): Promise - stop(): Promise } export class ElectricDatabase implements Database { - // Do not use this constructor directly. - // Create a Database instance using the static `init` method instead. - private constructor( + constructor( public name: string, - private postgres: EmbeddedPostgres, + //private postgres: EmbeddedPostgres, private db: Client ) {} async exec(statement: Statement): Promise { - const { rows, rowCount } = await this.db.query({ - text: statement.sql, - values: statement.args, - types: { - // Modify the parser to not parse JSON values - // Instead, return them as strings - // our conversions will correctly parse them - getTypeParser: ((oid: number) => { - if ( - oid === pg.types.builtins.JSON || - oid === pg.types.builtins.JSONB - ) { - return (val) => val - } - return originalGetTypeParser(oid) - }) as typeof pg.types.getTypeParser, - }, - }) - return { - rows, - rowsModified: rowCount ?? 0, + try { + const { rows, rowCount } = await this.db.query({ + text: statement.sql, + values: statement.args, + types: { + // Modify the parser to not parse JSON values + // Instead, return them as strings + // our conversions will correctly parse them + getTypeParser: ((oid: number) => { + if ( + oid === pg.types.builtins.JSON || + oid === pg.types.builtins.JSONB + ) { + return (val) => val + } + return originalGetTypeParser(oid) + }) as typeof pg.types.getTypeParser, + }, + }) + return { + rows, + rowsModified: rowCount ?? 0, + } + } catch (e) { + console.log("EXEC failed: " + JSON.stringify(e) + "\n" + "Statement was: " + JSON.stringify(statement)) + throw e } } +} - async stop() { - await this.postgres.stop() - } +type StopFn = () => Promise - // Creates and opens a DB backed by Postgres - static async init(config: PostgresConfig) { - // Initialize Postgres - const pg = new EmbeddedPostgres({ - databaseDir: config.databaseDir, - user: config.user ?? 'postgres', - password: config.password ?? 'password', - port: config.port ?? 54321, - persistent: config.persistent ?? true, - }) +/** + * Creates and opens a DB backed by Postgres + */ +export async function createEmbeddedPostgres(config: PostgresConfig): Promise<{ db: ElectricDatabase, stop: StopFn }> { + const EmbeddedPostgres = (await import('embedded-postgres')).default + // Initialize Postgres + const pg = new EmbeddedPostgres({ + databaseDir: config.databaseDir, + user: config.user ?? 'postgres', + password: config.password ?? 'password', + port: config.port ?? 54321, + persistent: config.persistent ?? true, + }) - await pg.initialise() - await pg.start() - await pg.createDatabase(config.name) - const db = pg.getPgClient() - await db.connect() + await pg.initialise() + await pg.start() + await pg.createDatabase(config.name) + const db = pg.getPgClient() + await db.connect() - // We use the database directory as the name - // because it uniquely identifies the DB - return new ElectricDatabase(config.databaseDir, pg, db) + // We use the database directory as the name + // because it uniquely identifies the DB + return { + db: new ElectricDatabase(config.databaseDir, db), + stop: () => pg.stop() } } diff --git a/clients/typescript/src/drivers/node-postgres/index.ts b/clients/typescript/src/drivers/node-postgres/index.ts index 9828f1cbcc..22c548e151 100644 --- a/clients/typescript/src/drivers/node-postgres/index.ts +++ b/clients/typescript/src/drivers/node-postgres/index.ts @@ -1,13 +1,13 @@ import { DatabaseAdapter as DatabaseAdapterI } from '../../electric/adapter' import { DatabaseAdapter } from './adapter' -import { Database, ElectricDatabase } from './database' +import { Database, ElectricDatabase, createEmbeddedPostgres } from './database' import { ElectricConfig } from '../../config' import { electrify as baseElectrify, ElectrifyOptions } from '../../electric' -import { WebSocketWeb } from '../../sockets/web' +import { WebSocketNode } from '../../sockets/node' import { ElectricClient, DbSchema } from '../../client/model' import { PgBundleMigrator } from '../../migrators/bundle' -export { DatabaseAdapter, ElectricDatabase } +export { DatabaseAdapter, ElectricDatabase, createEmbeddedPostgres } export type { Database } /** @@ -25,15 +25,20 @@ export const electrify = async >( const adapter = opts?.adapter || new DatabaseAdapter(db) const migrator = opts?.migrator || new PgBundleMigrator(adapter, dbDescription.pgMigrations) - const socketFactory = opts?.socketFactory || WebSocketWeb + const socketFactory = opts?.socketFactory || WebSocketNode const prepare = async (_connection: DatabaseAdapterI) => undefined + const configWithDialect = { + ...config, + dialect: 'Postgres', + } as const + const client = await baseElectrify( dbName, dbDescription, adapter, socketFactory, - config, + configWithDialect, { migrator, prepare, diff --git a/clients/typescript/src/drivers/tauri-postgres/index.ts b/clients/typescript/src/drivers/tauri-postgres/index.ts index 02cd9b4bd4..1d40ba0f69 100644 --- a/clients/typescript/src/drivers/tauri-postgres/index.ts +++ b/clients/typescript/src/drivers/tauri-postgres/index.ts @@ -27,12 +27,17 @@ export const electrify = async >( const socketFactory = opts?.socketFactory || WebSocketWeb const prepare = async (_connection: DatabaseAdapterI) => undefined + const configWithDialect = { + ...config, + dialect: 'Postgres', + } as const + const client = await baseElectrify( dbName, dbDescription, adapter, socketFactory, - config, + configWithDialect, { migrator, prepare, diff --git a/clients/typescript/src/electric/index.ts b/clients/typescript/src/electric/index.ts index 57e7da1567..b36b1edc5f 100644 --- a/clients/typescript/src/electric/index.ts +++ b/clients/typescript/src/electric/index.ts @@ -75,7 +75,7 @@ export const electrify = async >( configWithDefaults ) - const dialect = migrator.electricQueryBuilder.dialect + const dialect = configWithDefaults.replication.dialect const electric = ElectricClient.create( dbName, dbDescription, diff --git a/clients/typescript/src/migrators/builder.ts b/clients/typescript/src/migrators/builder.ts index dc30b83dae..11ef578abc 100644 --- a/clients/typescript/src/migrators/builder.ts +++ b/clients/typescript/src/migrators/builder.ts @@ -3,7 +3,9 @@ import { SatOpMigrate } from '../_generated/protocol/satellite' import { base64, getProtocolVersion } from '../util' import { Migration } from './index' import { generateTriggersForTable } from '../satellite/process' -import { QueryBuilder } from './query-builder' +import { sqliteBuilder, pgBuilder, QueryBuilder } from './query-builder' + +export { sqliteBuilder, pgBuilder, QueryBuilder } const metaDataSchema = z .object({ diff --git a/clients/typescript/src/satellite/oplog.ts b/clients/typescript/src/satellite/oplog.ts index 8a66e15e58..f6f2a61a82 100644 --- a/clients/typescript/src/satellite/oplog.ts +++ b/clients/typescript/src/satellite/oplog.ts @@ -350,7 +350,7 @@ function deserialiseRow(str: string, rel: Pick): Rec { export const fromTransaction = ( transaction: DataTransaction, - relations: RelationsCache + relations: RelationsCache, ): OplogEntry[] => { return transaction.changes.map((t) => { const columnValues = t.record ? t.record : t.oldRecord! diff --git a/clients/typescript/src/satellite/process.ts b/clients/typescript/src/satellite/process.ts index 54cf6744eb..e4a88aa22e 100644 --- a/clients/typescript/src/satellite/process.ts +++ b/clients/typescript/src/satellite/process.ts @@ -1249,6 +1249,7 @@ export class SatelliteProcess implements Satellite { } async _applyTransaction(transaction: Transaction) { + console.log("APPLY TX: " + JSON.stringify(transaction)) const origin = transaction.origin! const commitTimestamp = new Date(transaction.commit_timestamp.toNumber()) @@ -1296,6 +1297,7 @@ export class SatelliteProcess implements Satellite { const { statements, tablenames } = await this._apply(entries, origin) entries.forEach((e) => opLogEntries.push(e)) statements.forEach((s) => { + console.log("DML stmt: " + JSON.stringify(s)) stmts.push(s) }) tablenames.forEach((n) => tablenamesSet.add(n)) @@ -1305,6 +1307,7 @@ export class SatelliteProcess implements Satellite { const affectedTables: Map = new Map() changes.forEach((change) => { const changeStmt = { sql: change.sql } + console.log("DDL stmt: " + JSON.stringify(changeStmt)) stmts.push(changeStmt) if ( @@ -1372,11 +1375,13 @@ export class SatelliteProcess implements Satellite { if (transaction.migrationVersion) { // If a migration version is specified // then the transaction is a migration + console.log("APPLYING MIGRATION") await this.migrator.applyIfNotAlready({ statements: allStatements, version: transaction.migrationVersion, }) } else { + console.log("APPLYING TRANSACTION") await this.adapter.runInTransaction(...allStatements) } diff --git a/clients/typescript/test/support/node-postgres.ts b/clients/typescript/test/support/node-postgres.ts index 73f28a42d2..303df73ca4 100644 --- a/clients/typescript/test/support/node-postgres.ts +++ b/clients/typescript/test/support/node-postgres.ts @@ -1,11 +1,12 @@ import fs from 'fs/promises' import { ElectricDatabase } from '../../src/drivers/node-postgres' +import { createEmbeddedPostgres } from '../../src/drivers/node-postgres/database'; export async function makePgDatabase( name: string, port: number ): Promise<{ db: ElectricDatabase; stop: () => Promise }> { - const db = await ElectricDatabase.init({ + const { db, stop: stopPg } = await createEmbeddedPostgres({ name, databaseDir: `./tmp-${name}`, persistent: false, @@ -13,7 +14,7 @@ export async function makePgDatabase( }) const stop = async () => { - await db.stop() + await stopPg() await fs.rm(`./tmp-${name}`, { recursive: true, force: true }) } return { db, stop } diff --git a/e2e/Makefile b/e2e/Makefile index 6e42d075b8..ae4fd5820f 100644 --- a/e2e/Makefile +++ b/e2e/Makefile @@ -10,6 +10,12 @@ test_only: test: deps pull test_only +test_pg: + DIALECT=Postgres make test + +test_only_pg: + DIALECT=Postgres make test_only + pull: docker compose -f services_templates.yaml pull \ postgresql diff --git a/e2e/common.mk b/e2e/common.mk index 71536f14ac..2757494a6a 100644 --- a/e2e/common.mk +++ b/e2e/common.mk @@ -99,6 +99,7 @@ start_satellite_client_%: docker compose -f ${DOCKER_COMPOSE_FILE} run \ --rm \ -e TERM=dumb \ + -e DIALECT=${DIALECT} \ satellite_client_$* @@ -134,3 +135,6 @@ single_test: single_test_debug: ${LUX} --debug ${TEST} + +single_test_pg: + DIALECT=Postgres ${LUX} --progress doc ${TEST} \ No newline at end of file diff --git a/e2e/init.sql b/e2e/init.sql index 6641664e73..a0b86e59d9 100755 --- a/e2e/init.sql +++ b/e2e/init.sql @@ -1,3 +1,6 @@ +CREATE DATABASE e2e_client_1_db; +CREATE DATABASE e2e_client_2_db; + CREATE TABLE entries ( id UUID PRIMARY KEY, content VARCHAR NOT NULL, diff --git a/e2e/satellite_client/package.json b/e2e/satellite_client/package.json index 49f1950abd..7fdb2ce50b 100644 --- a/e2e/satellite_client/package.json +++ b/e2e/satellite_client/package.json @@ -20,6 +20,7 @@ "better-sqlite3": "^8.4.0", "electric-sql": "workspace:*", "jsonwebtoken": "^9.0.0", + "pg": "^8.11.3", "uuid": "^9.0.0", "zod": "^3.21.4" }, diff --git a/e2e/satellite_client/src/client.ts b/e2e/satellite_client/src/client.ts index 43c28d9857..e7edfb8b6d 100644 --- a/e2e/satellite_client/src/client.ts +++ b/e2e/satellite_client/src/client.ts @@ -1,24 +1,53 @@ -import Database from 'better-sqlite3' +import fs from 'fs/promises' +import pg from 'pg' +import SQLiteDatabase from 'better-sqlite3' import { ElectricConfig } from 'electric-sql' import { mockSecureAuthToken } from 'electric-sql/auth/secure' +import { ElectricDatabase } from 'electric-sql/node-postgres' import { setLogLevel } from 'electric-sql/debug' -import { electrify } from 'electric-sql/node' +import { electrify as electrifySqlite } from 'electric-sql/node' +import { electrify as electrifyPg } from 'electric-sql/node-postgres' import { v4 as uuidv4 } from 'uuid' import { schema, Electric, ColorType as Color } from './generated/client' export { JsonNull } from './generated/client' import { globalRegistry } from 'electric-sql/satellite' import { SatelliteErrorCode } from 'electric-sql/util' -import { DbSchema, ElectricClient } from 'electric-sql/client/model' -import { AuthStatus } from 'electric-sql/auth' + +import { pgBuilder, sqliteBuilder, QueryBuilder } from 'electric-sql/migrators/builder' setLogLevel('DEBUG') let dbName: string +let electrify = electrifySqlite +let builder: QueryBuilder = sqliteBuilder + +async function makePgDatabase(): Promise { + const client = new pg.Client({ + host: 'pg_1', + port: 5432, + database: dbName, + user: 'postgres', + password: 'password', + }) -export const make_db = (name: string): any => { + await client.connect() + + //const stop = () => client.end() + const db = new ElectricDatabase(dbName, client) + return db //{ db, stop } +} + +export const make_db = async (name: string): Promise => { dbName = name - return new Database(name) + console.log("DIALECT: " + process.env.DIALECT) + if (process.env.DIALECT === 'Postgres') { + electrify = electrifyPg + builder = pgBuilder + return makePgDatabase() + } + + return new SQLiteDatabase(name) } export const electrify_db = async ( @@ -95,11 +124,11 @@ export const syncTable = async (electric: Electric, table: string) => { } export const get_tables = (electric: Electric) => { - return electric.db.rawQuery({ sql: `SELECT name FROM sqlite_master WHERE type='table';` }) + return electric.db.rawQuery(builder.getLocalTableNames()) } export const get_columns = (electric: Electric, table: string) => { - return electric.db.rawQuery({ sql: `SELECT * FROM pragma_table_info(?);`, args: [table] }) + return electric.db.rawQuery(builder.getTableInfo(table)) } export const get_rows = (electric: Electric, table: string) => { @@ -261,7 +290,7 @@ export const get_json_raw = async (electric: Electric, id: string) => { export const get_jsonb_raw = async (electric: Electric, id: string) => { const res = await electric.db.rawQuery({ - sql: `SELECT jsb FROM jsons WHERE id = ?;`, + sql: `SELECT jsb FROM jsons WHERE id = ${builder.paramSign};`, args: [id] }) as unknown as Array<{ jsb: string }> return res[0]?.jsb diff --git a/e2e/tests/03.13_node_satellite_can_sync_timestamps.lux b/e2e/tests/03.13_node_satellite_can_sync_timestamps.lux index 98ab033e99..5721b3eee4 100644 --- a/e2e/tests/03.13_node_satellite_can_sync_timestamps.lux +++ b/e2e/tests/03.13_node_satellite_can_sync_timestamps.lux @@ -19,7 +19,7 @@ [invoke setup_client 1 electric_1 5133] [shell satellite_1] - [invoke node_await_table "name: 'timestamps'"] + [invoke node_await_table "timestamps"] [invoke node_sync_table "timestamps"] [shell pg_1] @@ -36,7 +36,7 @@ [invoke setup_client 2 electric_1 5133] [shell satellite_2] - [invoke node_await_table "name: 'timestamps'"] + [invoke node_await_table "timestamps"] [invoke node_sync_table "timestamps"] # check that 2nd satellite also reads the row [invoke node_await_assert_timestamp "00000000-0000-0000-0000-000000000001" "2023-09-21 14:39:53.000" "2023-09-21T14:39:53.001Z"] diff --git a/e2e/tests/03.14_node_satellite_can_sync_dates_and_times.lux b/e2e/tests/03.14_node_satellite_can_sync_dates_and_times.lux index c5c4ea742a..464d37a098 100644 --- a/e2e/tests/03.14_node_satellite_can_sync_dates_and_times.lux +++ b/e2e/tests/03.14_node_satellite_can_sync_dates_and_times.lux @@ -19,7 +19,7 @@ [invoke setup_client 1 electric_1 5133] [shell satellite_1] - [invoke node_await_table "name: 'datetimes'"] + [invoke node_await_table "datetimes"] [invoke node_sync_table "datetimes"] [shell pg_1] diff --git a/e2e/tests/03.20_node_satellite_is_informed_when_jwt_expires.lux.disabled b/e2e/tests/03.20_node_satellite_is_informed_when_jwt_expires.lux.disabled index 33fd06b837..cad8389b89 100644 --- a/e2e/tests/03.20_node_satellite_is_informed_when_jwt_expires.lux.disabled +++ b/e2e/tests/03.20_node_satellite_is_informed_when_jwt_expires.lux.disabled @@ -10,7 +10,7 @@ ??$node # Set expiration time for the JWT to 5 seconds from now !exp="5s" - [invoke connect_to_electric electric_1 5133 "[]" true] + [invoke connect_to_electric electric_1 5133 "[]" true 1] # Subscribe to auth status changes #!client.subscribe_to_auth_status(db) #?New auth status: EXPIRED diff --git a/e2e/tests/03.21_node_satellite_authentication.lux.disabled b/e2e/tests/03.21_node_satellite_authentication.lux.disabled index cadade877d..b9fec655c8 100644 --- a/e2e/tests/03.21_node_satellite_authentication.lux.disabled +++ b/e2e/tests/03.21_node_satellite_authentication.lux.disabled @@ -17,7 +17,7 @@ -JWT expired too early # Set expiration time for the JWT to 10 seconds from now !exp="10s" - [invoke connect_to_electric electric_1 5133 "[]"] + [invoke connect_to_electric electric_1 5133 "[]" 1] # Wait for the items table migration and sync the table ??[rpc] recv: #SatInStartReplicationResp ??Connectivity state changed: connected diff --git a/e2e/tests/Makefile b/e2e/tests/Makefile index cb45f2f21c..98f680c5f8 100644 --- a/e2e/tests/Makefile +++ b/e2e/tests/Makefile @@ -4,3 +4,6 @@ DOCKER_COMPOSE_FILE=compose.yaml test: ${LUX} *.lux + +test_pg: + DIALECT=Postgres ${LUX} 03.*.lux \ No newline at end of file diff --git a/e2e/tests/_satellite_macros.luxinc b/e2e/tests/_satellite_macros.luxinc index 5ff9cad588..2b1af92413 100644 --- a/e2e/tests/_satellite_macros.luxinc +++ b/e2e/tests/_satellite_macros.luxinc @@ -1,14 +1,20 @@ [global node=>] -[macro connect_to_electric host port migrations connectToElectric] +[macro connect_to_electric host port migrations connectToElectric satellite_number] !client = await import('./dist/client.js') ??$node # !migrations = await client.read_migrations(process.env.MIGRATION_DIRS + "/index.js") # ?$node !migrations = $migrations ??$node - !originalDb = client.make_db(process.env.SATELLITE_DB_PATH + "/$LUX_SHELLNAME") + # Temporarily disable the failure pattern + # because the printed value contains "_connectionError" + # which matches the failure pattern... + - + !originalDb = await client.make_db('e2e_client_${satellite_number}_db') ??$node + # Restore the failure pattern + -$fail_pattern [invoke electrify_db "originalDb" $host $port $migrations $connectToElectric] ??(in electrify_db) config: [endmacro] @@ -31,7 +37,7 @@ [invoke start_satellite $satellite_number] -$fail_pattern ??$node - [invoke connect_to_electric $electric $port $migrations $connectToElectric] + [invoke connect_to_electric $electric $port $migrations $connectToElectric $satellite_number] [endmacro] [macro setup_client satellite_number electric port] @@ -153,7 +159,7 @@ [endmacro] [macro node_await_table match] - [invoke wait-for "await client.get_tables(db)" "${match}" 10 $node] + [invoke wait-for "await client.get_tables(db)" "name: '${match}'" 10 $node] [endmacro] [macro node_await_column table column]