Skip to content

Commit ce61a75

Browse files
lots of progress. but why do the tests fail in concurrency mode?
1 parent f84b972 commit ce61a75

23 files changed

+154
-208
lines changed

.github/workflows/test.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@ jobs:
2121

2222
- name: Install dependencies
2323
run: npm ci
24-
24+
2525
- name: Run tests
2626
run: npm run test

extension.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,6 @@ function executeCommand(commandInput, componentPath) {
208208
* @returns
209209
*/
210210
export function startOnMainThread(options = {}) {
211-
212211
const config = resolveConfig(options);
213212

214213
logger.debug('Next.js Extension Configuration:', JSON.stringify(config, undefined, 2));

fixtures/next-13/app/layout.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ export const metadata = {
55
export default function RootLayout({ children }) {
66
return (
77
<html>
8-
<body>
9-
{children}
10-
</body>
8+
<body>{children}</body>
119
</html>
1210
);
1311
}

fixtures/next-13/next.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
module.exports = {};
1+
module.exports = {};

fixtures/next-13/package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
"lint": "next lint"
99
},
1010
"dependencies": {
11-
"@harperdb/nextjs": "file:/harperdb-nextjs",
11+
"@harperdb/nextjs": "file:/@harperdb/nextjs",
1212
"next": "13.5.7"
1313
}
14-
}
15-
14+
}

fixtures/next-14/app/layout.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ export const metadata = {
55
export default function RootLayout({ children }) {
66
return (
77
<html>
8-
<body>
9-
{children}
10-
</body>
8+
<body>{children}</body>
119
</html>
1210
);
1311
}

fixtures/next-14/next.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
module.exports = {};
1+
module.exports = {};

fixtures/next-14/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"lint": "next lint"
99
},
1010
"dependencies": {
11-
"@harperdb/nextjs": "file:/harperdb-nextjs",
11+
"@harperdb/nextjs": "file:/@harperdb/nextjs",
1212
"react": "^18",
1313
"react-dom": "^18",
1414
"next": "14.2.18"

fixtures/next-15/app/layout.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ export const metadata = {
55
export default function RootLayout({ children }) {
66
return (
77
<html>
8-
<body>
9-
{children}
10-
</body>
8+
<body>{children}</body>
119
</html>
1210
);
1311
}

fixtures/next-15/next.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
module.exports = {};
1+
module.exports = {};

fixtures/next-15/package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,9 @@
88
"lint": "next lint"
99
},
1010
"dependencies": {
11-
"@harperdb/nextjs": "file:/harperdb-nextjs",
11+
"@harperdb/nextjs": "file:/@harperdb/nextjs",
1212
"react": "19.0.0-rc-66855b96-20241106",
1313
"react-dom": "19.0.0-rc-66855b96-20241106",
1414
"next": "15.0.3"
1515
}
16-
}
17-
16+
}

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@
3535
"scripts": {
3636
"format": "prettier .",
3737
"format:check": "npm run format -- --check",
38-
"format:write": "npm run format -- --write",
39-
"pretest": "node scripts/pretest.js",
38+
"format:fix": "npm run format -- --write",
39+
"pretest": "node util/pretest.js",
4040
"test": "node --test"
4141
},
4242
"dependencies": {

test/next-15-node-18.test.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,17 @@ suite('Next.js v15 - Node.js v18', async () => {
88
before(async () => {
99
ctx.fixture = new Fixture({ nextMajor: '15', nodeMajor: '18' });
1010
await ctx.fixture.ready;
11-
ctx.rest = new URL(`http://${ctx.fixture.portMap.get('9926')}`);
11+
12+
const restPort = ctx.fixture.portMap.get('9926');
13+
14+
if (!restPort) {
15+
throw new Error('Rest port not found');
16+
}
17+
18+
ctx.rest = new URL(`http://${restPort}`);
1219
});
1320

14-
await Promise.all(base.concat(next15).map(async ({ name, testFunction }) => test(name, t => testFunction(t, ctx))));
21+
await Promise.all(base.concat(next15).map(async ({ name, testFunction }) => test(name, (t) => testFunction(t, ctx))));
1522

1623
after(async () => {
1724
await ctx.fixture.clear();

test/next-15-node-20.test.js

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { suite, test, before, after } from 'node:test';
2+
import { base, next15 } from '../util/tests.js';
23
import { Fixture } from '../util/fixture.js';
34

45
suite('Next.js v15 - Node.js v20', async () => {
@@ -7,31 +8,10 @@ suite('Next.js v15 - Node.js v20', async () => {
78
before(async () => {
89
ctx.fixture = new Fixture({ nextMajor: '15', nodeMajor: '20' });
910
await ctx.fixture.ready;
10-
ctx.rest = `http://${ctx.fixture.portMap.get('9926')}`;
11+
ctx.rest = new URL(`http://${ctx.fixture.portMap.get('9926')}`);
1112
});
1213

13-
await test('should run base component', async (t) => {
14-
const response = await fetch(`${ctx.rest}/Dog/0`, {
15-
headers: {
16-
'Content-Type': 'application/json',
17-
'Authorization': 'Basic aGRiX2FkbWluOnBhc3N3b3Jk',
18-
},
19-
});
20-
const json = await response.json();
21-
22-
t.assert.deepStrictEqual(json, { id: '0', name: 'Lincoln', breed: 'Shepherd' });
23-
});
24-
25-
await test('should reach home page', async (t) => {
26-
const response = await fetch(`${ctx.rest}/`, {
27-
headers: {
28-
'Content-Type': 'text/html',
29-
}
30-
});
31-
32-
const text = await response.text();
33-
t.assert.match(text, /Next\.js v15/);
34-
});
14+
await Promise.all(base.concat(next15).map(async ({ name, testFunction }) => test(name, (t) => testFunction(t, ctx))));
3515

3616
after(async () => {
3717
await ctx.fixture.clear();

test/next-15-node-22.test.js

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { suite, test, before, after } from 'node:test';
2+
import { base, next15 } from '../util/tests.js';
23
import { Fixture } from '../util/fixture.js';
34

45
suite('Next.js v15 - Node.js v22', async () => {
@@ -7,31 +8,10 @@ suite('Next.js v15 - Node.js v22', async () => {
78
before(async () => {
89
ctx.fixture = new Fixture({ nextMajor: '15', nodeMajor: '22' });
910
await ctx.fixture.ready;
10-
ctx.rest = `http://${ctx.fixture.portMap.get('9926')}`;
11+
ctx.rest = new URL(`http://${ctx.fixture.portMap.get('9926')}`);
1112
});
1213

13-
await test('should run base component', async (t) => {
14-
const response = await fetch(`${ctx.rest}/Dog/0`, {
15-
headers: {
16-
'Content-Type': 'application/json',
17-
'Authorization': 'Basic aGRiX2FkbWluOnBhc3N3b3Jk',
18-
},
19-
});
20-
const json = await response.json();
21-
22-
t.assert.deepStrictEqual(json, { id: '0', name: 'Lincoln', breed: 'Shepherd' });
23-
});
24-
25-
await test('should reach home page', async (t) => {
26-
const response = await fetch(`${ctx.rest}/`, {
27-
headers: {
28-
'Content-Type': 'text/html',
29-
}
30-
});
31-
32-
const text = await response.text();
33-
t.assert.match(text, /Next\.js v15/);
34-
});
14+
await Promise.all(base.concat(next15).map(async ({ name, testFunction }) => test(name, (t) => testFunction(t, ctx))));
3515

3616
after(async () => {
3717
await ctx.fixture.clear();

util/base.dockerfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# Base Dockerfile for HarperDB Next.js Integration Tests fixtures
2+
# Must be run from the root of the repository
3+
14
ARG NODE_MAJOR
25

36
FROM node:${NODE_MAJOR}

util/collected-transform.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Transform } from 'node:stream';
2+
3+
export class CollectedTransform extends Transform {
4+
#chunks = [];
5+
6+
_transform(chunk, _, callback) {
7+
this.#chunks.push(chunk);
8+
callback(null, chunk);
9+
}
10+
11+
get output() {
12+
return Buffer.concat(this.#chunks).toString();
13+
}
14+
}

util/fixture.js

Lines changed: 20 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,21 @@
11
import child_process from 'node:child_process';
2-
import path from 'node:path';
32
import { Transform } from 'node:stream';
4-
import { fileURLToPath } from 'node:url';
3+
import { getNextImageName } from './get-next-image-name.js';
4+
import { containerEngine } from './get-container-engine.js';
55

66
export class Fixture {
7-
static CONTAINER_ENGINE_LIST = ['podman', 'docker'];
8-
static FIXTURE_PATH = fileURLToPath(new URL('../fixtures/', import.meta.url));
9-
10-
/** @type {string} */
11-
#containerEngine;
12-
137
constructor({ autoSetup = true, debug = false, nextMajor, nodeMajor }) {
148
this.nextMajor = nextMajor;
159
this.nodeMajor = nodeMajor;
1610

1711
this.debug = debug || process.env.DEBUG === '1';
1812

19-
this.imageName = `hdb-next-integration-test-image-next-${nextMajor}-node-${nodeMajor}`;
13+
this.imageName = getNextImageName(nextMajor, nodeMajor);
2014
this.containerName = `hdb-next-integration-test-container-next-${nextMajor}-node-${nodeMajor}`;
2115

2216
if (autoSetup) {
23-
this.ready = this.clear()
24-
.then(() => this.build())
25-
.then(() => this.run());
26-
}
27-
}
28-
29-
get containerEngine() {
30-
if (this.#containerEngine) {
31-
return this.#containerEngine;
17+
this.ready = this.clear().then(() => this.run());
3218
}
33-
34-
for (const containerEngine of Fixture.CONTAINER_ENGINE_LIST) {
35-
const { status } = child_process.spawnSync(containerEngine, ['--version'], { stdio: 'ignore' });
36-
if (status === 0) {
37-
return (this.#containerEngine = containerEngine);
38-
}
39-
}
40-
41-
throw new Error(`No container engine found in ${CONTAINER_ENGINE_LIST.join(', ')}`);
4219
}
4320

4421
get #stdio() {
@@ -47,36 +24,16 @@ export class Fixture {
4724

4825
#runCommand(args = [], options = {}) {
4926
return new Promise((resolve, reject) => {
50-
const childProcess = child_process.spawn(this.containerEngine, args, {
27+
const childProcess = child_process.spawn(containerEngine, args, {
5128
stdio: this.#stdio,
5229
...options,
5330
});
5431

55-
childProcess.on('error', (error) => {
56-
reject(error);
57-
});
58-
59-
childProcess.on('exit', (code) => {
60-
resolve(code);
61-
});
32+
childProcess.on('error', reject);
33+
childProcess.on('exit', resolve);
6234
});
6335
}
6436

65-
build() {
66-
return this.#runCommand([
67-
'build',
68-
'--build-arg',
69-
`NEXT_MAJOR=${this.nextMajor}`,
70-
'--build-arg',
71-
`NODE_MAJOR=${this.nodeMajor}`,
72-
'-t',
73-
this.imageName,
74-
'-f',
75-
path.join(Fixture.FIXTURE_PATH, 'Dockerfile'),
76-
path.join(Fixture.FIXTURE_PATH, '..'),
77-
]);
78-
}
79-
8037
stop() {
8138
return this.#runCommand(['stop', this.containerName]);
8239
}
@@ -87,15 +44,15 @@ export class Fixture {
8744

8845
clear() {
8946
return new Promise((resolve, reject) => {
90-
const psProcess = child_process.spawn(this.containerEngine, ['ps', '-aq', '-f', `name=${this.containerName}`]);
47+
const psProcess = child_process.spawn(containerEngine, ['ps', '-aq', '-f', `name=${this.containerName}`]);
9148

9249
psProcess.on('error', reject);
9350

9451
const collectedStdout = psProcess.stdout.pipe(
9552
new Transform({
96-
construct(cb) {
53+
construct(callback) {
9754
this.chunks = [];
98-
cb(null);
55+
callback(null);
9956
},
10057
transform(chunk, encoding, callback) {
10158
this.chunks.push(chunk);
@@ -110,28 +67,27 @@ export class Fixture {
11067
}
11168

11269
psProcess.on('exit', (code) => {
113-
if (code === 0) {
114-
if (collectedStdout.chunks.length !== 0) {
115-
this.stop()
116-
.then(() => this.rm())
117-
.then(resolve, reject);
118-
}
119-
resolve();
120-
} else {
121-
reject(new Error(`\`${this.containerEngine} ps\` exited with code ${code}`));
70+
if (code === 0 && collectedStdout.chunks.length !== 0) {
71+
return this.stop()
72+
.then(() => this.rm())
73+
.then(resolve, reject);
12274
}
75+
return resolve(code);
12376
});
12477
});
12578
}
12679

12780
run() {
12881
return new Promise((resolve, reject) => {
12982
const runProcess = child_process.spawn(
130-
this.containerEngine,
83+
containerEngine,
13184
['run', '-P', '--name', this.containerName, this.imageName],
13285
{ stdio: ['ignore', 'pipe', this.debug ? 'inherit' : 'ignore'] }
13386
);
13487

88+
runProcess.on('error', reject);
89+
runProcess.on('exit', resolve);
90+
13591
const stdout = runProcess.stdout.pipe(
13692
new Transform({
13793
transform(chunk, encoding, callback) {
@@ -146,16 +102,13 @@ export class Fixture {
146102
if (this.debug) {
147103
stdout.pipe(process.stdout);
148104
}
149-
150-
runProcess.on('error', reject);
151-
runProcess.on('exit', resolve);
152105
});
153106
}
154107

155108
get portMap() {
156109
const portMap = new Map();
157110
for (const port of ['9925', '9926']) {
158-
const { stdout } = child_process.spawnSync(this.containerEngine, ['port', this.containerName, port]);
111+
const { stdout } = child_process.spawnSync(containerEngine, ['port', this.containerName, port]);
159112
portMap.set(port, stdout.toString().trim());
160113
}
161114
return portMap;

0 commit comments

Comments
 (0)