diff --git a/api_tests/package.json b/api_tests/package.json index 1d96f06e4e..0e5d573e9b 100644 --- a/api_tests/package.json +++ b/api_tests/package.json @@ -22,6 +22,7 @@ "@types/find-cache-dir": "^3.2.0", "@types/glob": "^7.1.3", "@types/jest": "^26.0.10", + "@types/lodash": "^4.14.159", "@types/node": "^14.6", "@types/proper-lockfile": "^4.1.1", "@types/rimraf": "^3.0.0", @@ -40,6 +41,7 @@ "glob": "^7.1.6", "jasmine": "^3.6.1", "jest": "^26.4.1", + "lodash": "^4.17.20", "log4js": "^6.3.0", "p-timeout": "^3.2.0", "prettier": "^2.0.5", diff --git a/api_tests/src/actors/actor.ts b/api_tests/src/actors/actor.ts index 2d8d819082..4c3cfbf8d6 100644 --- a/api_tests/src/actors/actor.ts +++ b/api_tests/src/actors/actor.ts @@ -16,7 +16,7 @@ import { SwapStatus, } from "../payload"; import { Logger } from "log4js"; -import { E2ETestActorConfig } from "../config"; +import { CndConfigFile, E2ETestActorConfig } from "../config"; import { Asset, assetAsKey, @@ -34,6 +34,7 @@ import { defaultLedgerDescriptionForLedger, getIdentities } from "./defaults"; import pTimeout from "p-timeout"; import { Entity, Link } from "comit-sdk/dist/src/cnd/siren"; import { BtcDaiOrder } from "./order_factory"; +import { merge } from "lodash"; export type ActorName = "alice" | "bob" | "carol"; @@ -48,23 +49,25 @@ export class Actor { ledgerConfig: LedgerConfig, cargoTargetDirectory: string, cndLogFile: string, - logger: Logger + logger: Logger, + configOverrides: Partial ) { const actorConfig = await E2ETestActorConfig.for(name, logger); - const cndConfigFile = actorConfig.generateCndConfigFile(ledgerConfig); + const generatedConfig = actorConfig.generateCndConfigFile(ledgerConfig); + const finalConfig = merge(generatedConfig, configOverrides); const cndInstance = new CndInstance( cargoTargetDirectory, cndLogFile, logger, - cndConfigFile + finalConfig ); await cndInstance.start(); logger.info( "Created new actor with config %s", - JSON.stringify(cndConfigFile) + JSON.stringify(finalConfig) ); return new Actor(logger, cndInstance, name); diff --git a/api_tests/src/config.ts b/api_tests/src/config.ts index 1344f2393e..8d8c342881 100644 --- a/api_tests/src/config.ts +++ b/api_tests/src/config.ts @@ -14,6 +14,9 @@ export interface CndConfigFile { data?: { dir: string }; network: { listen: string[] }; logging: { level: string }; + bitcoin?: BitcoinConfig; + ethereum?: EthereumConfig; + lightning?: LightningConfig; } export interface HttpApi { diff --git a/api_tests/src/create_actors.ts b/api_tests/src/create_actors.ts index 8e23504dfb..03c3a0bd45 100644 --- a/api_tests/src/create_actors.ts +++ b/api_tests/src/create_actors.ts @@ -21,7 +21,8 @@ export async function createActors( global.ledgerConfigs, global.cargoTargetDir, cndLogFile, - actorLogger + actorLogger, + global.cndConfigOverrides ) ); } diff --git a/api_tests/src/test_environment.ts b/api_tests/src/test_environment.ts index 3314db4372..ad108f5ee7 100644 --- a/api_tests/src/test_environment.ts +++ b/api_tests/src/test_environment.ts @@ -17,6 +17,8 @@ import { LedgerInstance, LightningNodeConfig } from "./ledgers"; import { GethInstance } from "./ledgers/geth_instance"; import { LndInstance } from "./ledgers/lnd_instance"; import BitcoinRpcClient from "bitcoin-core"; +import { CndConfigFile } from "./config"; +import { set } from "lodash"; export default class TestEnvironment extends NodeEnvironment { private readonly testSuite: string; @@ -25,6 +27,7 @@ export default class TestEnvironment extends NodeEnvironment { private readonly locksDir: string; private readonly nodeModulesBinDir: string; private readonly srcDir: string; + private readonly cndConfigOverrides: Partial; public global: HarnessGlobal; @@ -33,9 +36,12 @@ export default class TestEnvironment extends NodeEnvironment { constructor(config: Config.ProjectConfig, context: EnvironmentContext) { super(config); - this.ledgers = TestEnvironment.extractLedgersToBeStarted( + this.ledgers = extractLedgersToBeStarted(context.docblockPragmas); + this.cndConfigOverrides = extractCndConfigOverrides( context.docblockPragmas ); + assertNoUnhandledPargmas(context.docblockPragmas); + this.logDir = path.resolve(config.rootDir, "log"); this.locksDir = path.resolve(config.rootDir, "locks"); this.nodeModulesBinDir = path.resolve( @@ -60,6 +66,7 @@ export default class TestEnvironment extends NodeEnvironment { this.global.ledgerConfigs = {}; this.global.lndWallets = {}; this.global.cargoTargetDir = cargoTargetDir; + this.global.cndConfigOverrides = this.cndConfigOverrides; const log4js = configure({ appenders: { @@ -389,20 +396,54 @@ export default class TestEnvironment extends NodeEnvironment { return dir; } +} - private static extractLedgersToBeStarted( - docblockPragmas: Record - ): string[] { - const ledgersToStart = docblockPragmas.ledger; +function extractLedgersToBeStarted( + docblockPragmas: Record +): string[] { + const ledgersToStart = docblockPragmas.ledger; + delete docblockPragmas.ledger; - if (!ledgersToStart) { - return []; - } + if (!ledgersToStart) { + return []; + } - if (typeof ledgersToStart === "string") { - return [ledgersToStart]; - } + if (typeof ledgersToStart === "string") { + return [ledgersToStart]; + } + + return ledgersToStart; +} + +export function extractCndConfigOverrides( + docblockPragmas: Record +): Partial { + let configOverrides = docblockPragmas.cndConfigOverride; + delete docblockPragmas.cndConfigOverride; + + if (!configOverrides) { + return {}; + } + + // generalize single override to list of overrides + if (typeof configOverrides === "string") { + configOverrides = [configOverrides]; + } + + return configOverrides + .map((override) => override.split(" = ")) + .filter(([key, _]) => key !== "") + .reduce((config, [key, value]) => { + set(config, key, value); + + return config; + }, {}); +} - return ledgersToStart; +export function assertNoUnhandledPargmas( + docblockPragmas: Record +) { + for (const [pragma] of Object.entries(docblockPragmas)) { + throw new Error(`Unhandled pragma '${pragma}'! Typo?`); } } diff --git a/api_tests/src/utils.ts b/api_tests/src/utils.ts index 263cee03fc..b2e47b7079 100644 --- a/api_tests/src/utils.ts +++ b/api_tests/src/utils.ts @@ -11,6 +11,7 @@ import { EthereumNodeConfig, LightningNodeConfig, } from "./ledgers"; +import { CndConfigFile } from "./config"; export interface HarnessGlobal extends Global.Global { ledgerConfigs: LedgerConfig; @@ -21,6 +22,7 @@ export interface HarnessGlobal extends Global.Global { tokenContract: string; gethLockDir: string; cargoTargetDir: string; + cndConfigOverrides: Partial; getDataDir: (program: string) => Promise; getLogFile: (pathElements: string[]) => string; diff --git a/api_tests/tests/sanity.ts b/api_tests/tests/sanity.ts index b106da94e5..f83e01d575 100644 --- a/api_tests/tests/sanity.ts +++ b/api_tests/tests/sanity.ts @@ -1,3 +1,8 @@ +/** + * @cndConfigOverride ethereum.chain_id = 1337 + * @cndConfigOverride ethereum.tokens.dai = 0x0000000000000000000000000000000000000000 + */ + import { oneActorTest, twoActorTest } from "../src/actor_test"; import SwapFactory from "../src/actors/swap_factory"; diff --git a/api_tests/tests/test_environment.spec.ts b/api_tests/tests/test_environment.spec.ts new file mode 100644 index 0000000000..70e2917fb0 --- /dev/null +++ b/api_tests/tests/test_environment.spec.ts @@ -0,0 +1,61 @@ +import { extractCndConfigOverrides } from "../src/test_environment"; + +describe("extractCndConfigOverrides", () => { + test("given no overrides, returns empty object", () => { + expect(extractCndConfigOverrides({})).toStrictEqual({}); + expect( + extractCndConfigOverrides({ + cndConfigOverride: null, + }) + ).toStrictEqual({}); + expect( + extractCndConfigOverrides({ + cndConfigOverride: "", + }) + ).toStrictEqual({}); + expect( + extractCndConfigOverrides({ + cndConfigOverride: ["", "", ""], + }) + ).toStrictEqual({}); + }); + + test("given overrides, sets nested key", () => { + const overrides = { + cndConfigOverride: + "ethereum.tokens.dai = 0x0000000000000000000000000000000000000000", + }; + + const config = extractCndConfigOverrides(overrides); + + expect(config).toStrictEqual({ + ethereum: { + tokens: { + dai: "0x0000000000000000000000000000000000000000", + }, + }, + }); + }); + + test("given two overrides, sets them both", () => { + const overrides = { + cndConfigOverride: [ + "ethereum.tokens.dai = 0x0000000000000000000000000000000000000000", + "bitcoin.network = regtest", + ], + }; + + const config = extractCndConfigOverrides(overrides); + + expect(config).toStrictEqual({ + ethereum: { + tokens: { + dai: "0x0000000000000000000000000000000000000000", + }, + }, + bitcoin: { + network: "regtest", + }, + }); + }); +}); diff --git a/api_tests/yarn.lock b/api_tests/yarn.lock index 90eefa142f..d8f25ec602 100644 --- a/api_tests/yarn.lock +++ b/api_tests/yarn.lock @@ -1073,6 +1073,11 @@ jest-diff "^25.2.1" pretty-format "^25.2.1" +"@types/lodash@^4.14.159": + version "4.14.159" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.159.tgz#61089719dc6fdd9c5cb46efc827f2571d1517065" + integrity sha512-gF7A72f7WQN33DpqOWw9geApQPh4M3PxluMtaHxWHXEGSN12/WbcEk/eNSqWNQcQhF66VSZ06vCF94CrHwXJDg== + "@types/long@*", "@types/long@^4.0.0": version "4.0.1" resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9" @@ -4211,6 +4216,11 @@ lodash@^4.0.0, lodash@^4.17.13, lodash@^4.17.15: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== +lodash@^4.17.20: + version "4.17.20" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" + integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== + log4js@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.3.0.tgz#10dfafbb434351a3e30277a00b9879446f715bcb"