Skip to content

Commit

Permalink
Draft of spinning up all services
Browse files Browse the repository at this point in the history
  • Loading branch information
jared committed Apr 18, 2024
1 parent 9bf9945 commit 8a12605
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 37 deletions.
5 changes: 5 additions & 0 deletions dens-testsuites/integration/bin/dens-integration-cli.js
@@ -0,0 +1,5 @@
#!/usr/bin/env node

import "../dist/lib/services.js";

await Services.spawn();
4 changes: 4 additions & 0 deletions dens-testsuites/integration/package.json
Expand Up @@ -2,6 +2,10 @@
"name": "dens-integration",
"version": "1.0.0",
"description": "Integration testsuite for DeNS",
"type": "module",
"bin": {
"dens-integration-cli": "./bin/dens-integration-cli.js"
},
"scripts": {
"build": "npx tsc -b src/",
"test": "npm run build && node --test"
Expand Down
169 changes: 147 additions & 22 deletions dens-testsuites/integration/src/lib/services.ts
Expand Up @@ -12,11 +12,16 @@ import * as fs from "node:fs/promises";
import * as os from "node:os";
import * as timers from "timers/promises";
import * as path from "node:path";
import { Config } from "lbf-dens-db/LambdaBuffers/Dens/Config.mjs";

import chalk from "chalk";

import * as utils from "./utils.js";
// import * as Pla from "plutus-ledger-api/V1.js";

import * as PlaV1 from "plutus-ledger-api/V1.js";
import * as P from "prelude";
import * as PJson from "prelude/Json.js";
import * as LbrPrelude from "lbr-prelude";

interface Cardano {
/** Path to UNIX domain socket that the cardano node is running on */
Expand Down Expand Up @@ -44,18 +49,32 @@ interface Ogmios {
childProcess: ChildProcess;
}

interface DensQuery {
/** Path to UNIX domain socket that dens query is listening on */
socketPath: string;

childProcess: ChildProcess;
}

/**
* {@link Services} a class to
*/
export class Services {
cardano: Cardano;
database: Database;
ogmios: Ogmios;

constructor(cardano: Cardano, database: Database, ogmios: Ogmios) {
densQuery: DensQuery;

constructor(
cardano: Cardano,
database: Database,
ogmios: Ogmios,
densQuery: DensQuery,
) {
this.cardano = cardano;
this.database = database;
this.ogmios = ogmios;
this.densQuery = densQuery;
}

/**
Expand All @@ -68,30 +87,20 @@ export class Services {
spawnDatabase(),
]);
const ogmios = await spawnOgmios(cardano);
return new Services(cardano, database, ogmios);
const densQuery = await spawnDensQuery(database, ogmios);
return new Services(cardano, database, ogmios, densQuery);
}

kill(): Promise<void> {
this.cardano.childProcess.kill("SIGINT");
this.database.childProcess.kill("SIGINT"); // See {@link https://www.postgresql.org/docs/current/server-shutdown.html}
this.ogmios.childProcess.kill("SIGINT");
this.densQuery.childProcess.kill("SIGINT");

return Promise.resolve();
}
}

// export class DensQueryService {
// static async spawn(
// protocolNft: [string],
// services: Services,
// ): Promise<DensQueryService> {
// const [cardano, database] = await Promise.all([
// spawnPlutip(numWallets),
// spawnDatabase(),
// ]);
// const ogmios = await spawnOgmios(cardano);
// return new Services(cardano, database, ogmios);
// }
// }

/**
* This is needed because of the awkwardness of knowing when plutip is
* initialized... Plutip will dump a bunch of files to the file system, and we
Expand Down Expand Up @@ -156,6 +165,108 @@ async function pollReadJsonFile(filePath: string): Promise<any | undefined> {
return result;
}

async function spawnDensQuery(
database: Database,
ogmios: Ogmios,
): Promise<DensQuery> {
// Create the database user / names
const densUserName = `dens`;
const createDensUserProcess = child_process.spawn(`createuser`, [
`-h`,
database.socketPath,
`-d`,
`-r`,
densUserName,
], { stdio: ["ignore", "ignore", "inherit"] });

const densDatabase = `dens`;

const createDensDbProcess = child_process.spawn(`createdb`, [
`-h`,
database.socketPath,
`-O`,
densUserName,
densDatabase,
], { stdio: ["ignore", "ignore", "inherit"] });

await new Promise<void>((resolve, reject) =>
createDensUserProcess.on("close", (code) => {
if (code !== 0) {
return reject(new Error(`createuser failed`));
}
resolve();
})
);
await new Promise<void>((resolve, reject) =>
createDensDbProcess.on("close", (code) => {
if (code !== 0) {
return reject(new Error(`createdb failed`));
}
resolve();
})
);

// Create a temporary directory to put dens-query's files
const densQueryDir = await fs.mkdtemp(path.join(os.tmpdir(), `dens-query-`));
console.error(chalk.blue(`dens-query working directory:\n\t${densQueryDir}`));

// Create the database user / names
const socketPath = path.join(densQueryDir, `.s.dens-query`);
const zeroCurrencySymbolBytes = [];
for (let i = 0; i < 28; ++i) {
zeroCurrencySymbolBytes.push(0);
}

const config: Config = {
ogmios: { url: `ws://${ogmios.host}:${ogmios.port}` },
database: {
socket: { name: `UnixDomain`, fields: { path: database.socketPath } },
user: densUserName,
password: ``,
database: densDatabase,
},
server: { name: `UnixDomain`, fields: { path: socketPath } },
protocolNft: [
P.fromJust(
PlaV1.currencySymbolFromBytes(Uint8Array.from(zeroCurrencySymbolBytes)),
),
PlaV1.adaToken,
],
};

const configFileName = path.join(densQueryDir, `config.json`);
await fs.appendFile(
configFileName,
PJson.stringify(LbrPrelude.Json[Config].toJson(config)),
);

// Start dens-query
const env = JSON.parse(JSON.stringify(process.env)); // silly way to copy the current environment
env["DENS_QUERY_CONFIG"] = configFileName;

const densQueryProcess = child_process.spawn(`dens-query-cli`, [], {
env,
stdio: [`inherit`, `inherit`, `inherit`],
cwd: densQueryDir,
});

densQueryProcess.on("close", (code, signal) => {
if (code === 0 || signal === "SIGINT") {
return;
}
throw new Error(`dens-query-cli failed with exit code ${code}`);
});

// FIXME(jaredponn): we wait 15 seconds to let initialize. Change this to poll
// dens-query until it replies
await timers.setTimeout(15000);

return { socketPath, childProcess: densQueryProcess };
}

/**
* Spawns an ogmios connection
*/
function spawnOgmios(cardano: Cardano): Promise<Ogmios> {
// See {@link https://www.rfc-editor.org/rfc/rfc6335.html}'s Dynamic ports
// for why we choose this range
Expand All @@ -173,9 +284,13 @@ function spawnOgmios(cardano: Cardano): Promise<Ogmios> {
host,
`--port`,
port.toString(),
]);
], { stdio: [`ignore`, `ignore`, `inherit`] });

return { host, port: port.toString(), childProcess: ogmiosProcess };
return Promise.resolve({
host,
port: port.toString(),
childProcess: ogmiosProcess,
});
}

/**
Expand All @@ -186,6 +301,16 @@ async function spawnDatabase(): Promise<Database> {
const postgresDir = await fs.mkdtemp(path.join(os.tmpdir(), `postgres-`));

console.error(chalk.blue(`Postgres working directory:\n\t${postgresDir}`));
console.error(
chalk.blue(
`To restart Postgres execute\n\tcd ${postgresDir} && postgres -h '' -k ${postgresDir} -D ${postgresDir}`,
),
);
console.error(
chalk.blue(
`To connect to Postgres via psql execute:\n\tpsql -h ${postgresDir}`,
),
);

{
// Use `initdb` to initialize the database
Expand Down Expand Up @@ -222,7 +347,7 @@ async function spawnDatabase(): Promise<Database> {
postgresDir,
`-r`,
path.join(postgresDir, `logs.output`),
], { stdio: [`ignore`, `ignore`, `inherit`] });
], { stdio: [`ignore`, `ignore`, `ignore`] });

// Somewhere in the postgres docs it says this is what the socket is
// named
Expand Down Expand Up @@ -280,7 +405,7 @@ async function spawnPlutip(numWallets: number): Promise<Cardano> {
numWallets.toString(),
`--wallets-dir`,
plutipWalletsDir,
], { stdio: [`ignore`, `ignore`, `inherit`] });
], { stdio: [`ignore`, `ignore`, `ignore`] });

result.childProcess = childProcess;

Expand Down
12 changes: 0 additions & 12 deletions dens-testsuites/integration/src/tests/more-valid-test.ts

This file was deleted.

7 changes: 4 additions & 3 deletions dens-testsuites/integration/src/tests/valid-test.ts
Expand Up @@ -2,11 +2,12 @@ import test from "node:test";
import { Services } from "../lib/services.js";

test.describe("Runtime services can be initialized", async () => {
let result: Services | undefined;
let services: Services | undefined;
await test.before(async () => {
result = await Services.spawn();
services = await Services.spawn();
});

await test.after(async () => {
await result!.kill();
await services!.kill();
});
});

0 comments on commit 8a12605

Please sign in to comment.