Skip to content

Commit b3acaf9

Browse files
committed
fix: pr notes
1 parent b404847 commit b3acaf9

File tree

4 files changed

+77
-12
lines changed

4 files changed

+77
-12
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 NameHash
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# @ensnode/integration-test-env
2+
3+
Integration test environment orchestration for ENSNode. Spins up the full ENSNode stack against the [ens-test-env](https://github.com/ensdomains/contracts-v2) devnet, runs monorepo-level integration tests, then tears everything down.
4+
5+
## Devnet Image
6+
7+
The current devnet image is pinned to:
8+
9+
```
10+
ghcr.io/ensdomains/contracts-v2:main-f476641
11+
```
12+
13+
Update the `DEVNET_IMAGE` constant in the orchestrator source to change the devnet version.
14+
15+
## How It Works
16+
17+
The orchestrator runs a 6-phase pipeline:
18+
19+
1. **Postgres + Devnet** — started in parallel via testcontainers
20+
2. **ENSRainbow database** — downloads pre-built LevelDB, extracts, starts ENSRainbow from source
21+
3. **ENSIndexer** — starts from source, waits for health
22+
4. **Indexing** — polls until omnichain status reaches "Following" or "Completed"
23+
5. **ENSApi** — starts from source, waits for health
24+
6. **Integration tests** — runs `pnpm test:integration` at monorepo root
25+
26+
## Usage
27+
28+
```sh
29+
pnpm start
30+
```
31+
32+
Works both in CI and locally — just make sure the required ports are available (8545, 8000, 3223, 42069, 4334).
33+
34+
## License
35+
36+
Licensed under the MIT License. See [LICENSE](./LICENSE).

packages/integration-test-env/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"type": "module",
66
"description": "Integration test environment orchestration for ENSNode",
77
"scripts": {
8-
"start": "CI=1 tsx src/ci.ts"
8+
"start": "CI=1 tsx src/orchestrator.ts"
99
},
1010
"dependencies": {
1111
"@ensnode/datasources": "workspace:*",

packages/integration-test-env/src/ci.ts renamed to packages/integration-test-env/src/orchestrator.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
/**
22
* Integration Test Environment Orchestrator
33
*
4-
* Co-authored by Claude (Opus 4.6).
5-
*
64
* Spins up the full ENSNode stack against the ens-test-env devnet, runs
75
* monorepo-level integration tests, then tears everything down.
86
*
@@ -17,7 +15,7 @@
1715
* - testcontainers for Postgres (dynamic port, built-in health check) and devnet
1816
* (fixed ports required — ensTestEnvChain hardcodes localhost:8545).
1917
* - execa for child process management — automatic cleanup on parent exit,
20-
* forceKillAfterDelay (10s SIGKILL fallback), env inheritance via extendEnv.
18+
* forceKillAfterDelay (10s SIGKILL fallback), env inherited from parent.
2119
* - Services run from source (pnpm start/serve) rather than Docker so that
2220
* CI tests the actual code in the PR.
2321
* - ENSRainbow database is downloaded via the existing shell script and
@@ -131,29 +129,29 @@ function logError(msg: string) {
131129
console.error(`[ci] ERROR: ${msg}`);
132130
}
133131

134-
async function waitForHealth(url: string, timeoutMs: number, label: string): Promise<void> {
132+
async function waitForHealth(url: string, timeoutMs: number, serviceName: string): Promise<void> {
135133
const start = Date.now();
136134
while (Date.now() - start < timeoutMs) {
137135
checkAborted();
138136
try {
139137
const res = await fetch(url, { signal: AbortSignal.timeout(5_000) });
140138
if (res.ok) {
141-
log(`${label} is healthy`);
139+
log(`${serviceName} is healthy`);
142140
return;
143141
}
144-
log(`${label} health check returned ${res.status}, retrying...`);
142+
log(`${serviceName} health check returned ${res.status}, retrying...`);
145143
} catch {}
146144
await new Promise((r) => setTimeout(r, 1000));
147145
}
148-
throw new Error(`${label} did not become healthy within ${timeoutMs / 1000}s`);
146+
throw new Error(`${serviceName} did not become healthy within ${timeoutMs / 1000}s`);
149147
}
150148

151149
function spawnService(
152150
command: string,
153151
args: string[],
154152
cwd: string,
155153
env: Record<string, string>,
156-
label: string,
154+
serviceName: string,
157155
): ResultPromise {
158156
const subprocess = spawn(command, args, {
159157
cwd,
@@ -167,19 +165,19 @@ function spawnService(
167165

168166
subprocess.stdout?.on("data", (data: Buffer) => {
169167
for (const line of data.toString().split("\n").filter(Boolean)) {
170-
console.log(`[${label}] ${line}`);
168+
console.log(`[${serviceName}] ${line}`);
171169
}
172170
});
173171

174172
subprocess.stderr?.on("data", (data: Buffer) => {
175173
for (const line of data.toString().split("\n").filter(Boolean)) {
176-
console.error(`[${label}] ${line}`);
174+
console.error(`[${serviceName}] ${line}`);
177175
}
178176
});
179177

180178
subprocess.then((result) => {
181179
if (result.failed && !result.isTerminated) {
182-
setAborted(`${label} exited with code ${result.exitCode}`);
180+
setAborted(`${serviceName} exited with code ${result.exitCode}`);
183181
}
184182
});
185183

@@ -219,8 +217,18 @@ async function pollIndexingStatus(timeoutMs: number): Promise<void> {
219217
throw new Error(`Indexing did not complete within ${timeoutMs / 1000}s`);
220218
}
221219

220+
function logVersions() {
221+
log("Software versions:");
222+
log(` Node.js: ${process.version}`);
223+
log(` pnpm: ${execaSync("pnpm", ["--version"]).stdout.trim()}`);
224+
log(` Docker: ${execaSync("docker", ["--version"]).stdout.trim()}`);
225+
log(` Postgres image: ${POSTGRES_IMAGE}`);
226+
log(` Devnet image: ${DEVNET_IMAGE}`);
227+
}
228+
222229
async function main() {
223230
log("Starting integration test environment...");
231+
logVersions();
224232

225233
// Phase 1: Start Postgres + Devnet in parallel
226234
log("Starting Postgres and devnet...");

0 commit comments

Comments
 (0)