Skip to content

Commit

Permalink
lots of progress. but why do the tests fail in concurrency mode?
Browse files Browse the repository at this point in the history
  • Loading branch information
Ethan-Arrowood committed Dec 2, 2024
1 parent f84b972 commit ce61a75
Show file tree
Hide file tree
Showing 23 changed files with 154 additions and 208 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ jobs:

- name: Install dependencies
run: npm ci

- name: Run tests
run: npm run test
1 change: 0 additions & 1 deletion extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,6 @@ function executeCommand(commandInput, componentPath) {
* @returns
*/
export function startOnMainThread(options = {}) {

const config = resolveConfig(options);

logger.debug('Next.js Extension Configuration:', JSON.stringify(config, undefined, 2));
Expand Down
4 changes: 1 addition & 3 deletions fixtures/next-13/app/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ export const metadata = {
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
</body>
<body>{children}</body>
</html>
);
}
2 changes: 1 addition & 1 deletion fixtures/next-13/next.config.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
module.exports = {};
module.exports = {};
5 changes: 2 additions & 3 deletions fixtures/next-13/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
"lint": "next lint"
},
"dependencies": {
"@harperdb/nextjs": "file:/harperdb-nextjs",
"@harperdb/nextjs": "file:/@harperdb/nextjs",
"next": "13.5.7"
}
}

}
4 changes: 1 addition & 3 deletions fixtures/next-14/app/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ export const metadata = {
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
</body>
<body>{children}</body>
</html>
);
}
2 changes: 1 addition & 1 deletion fixtures/next-14/next.config.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
module.exports = {};
module.exports = {};
2 changes: 1 addition & 1 deletion fixtures/next-14/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"lint": "next lint"
},
"dependencies": {
"@harperdb/nextjs": "file:/harperdb-nextjs",
"@harperdb/nextjs": "file:/@harperdb/nextjs",
"react": "^18",
"react-dom": "^18",
"next": "14.2.18"
Expand Down
4 changes: 1 addition & 3 deletions fixtures/next-15/app/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ export const metadata = {
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
</body>
<body>{children}</body>
</html>
);
}
2 changes: 1 addition & 1 deletion fixtures/next-15/next.config.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
module.exports = {};
module.exports = {};
5 changes: 2 additions & 3 deletions fixtures/next-15/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@
"lint": "next lint"
},
"dependencies": {
"@harperdb/nextjs": "file:/harperdb-nextjs",
"@harperdb/nextjs": "file:/@harperdb/nextjs",
"react": "19.0.0-rc-66855b96-20241106",
"react-dom": "19.0.0-rc-66855b96-20241106",
"next": "15.0.3"
}
}

}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@
"scripts": {
"format": "prettier .",
"format:check": "npm run format -- --check",
"format:write": "npm run format -- --write",
"pretest": "node scripts/pretest.js",
"format:fix": "npm run format -- --write",
"pretest": "node util/pretest.js",
"test": "node --test"
},
"dependencies": {
Expand Down
11 changes: 9 additions & 2 deletions test/next-15-node-18.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,17 @@ suite('Next.js v15 - Node.js v18', async () => {
before(async () => {
ctx.fixture = new Fixture({ nextMajor: '15', nodeMajor: '18' });
await ctx.fixture.ready;
ctx.rest = new URL(`http://${ctx.fixture.portMap.get('9926')}`);

const restPort = ctx.fixture.portMap.get('9926');

if (!restPort) {
throw new Error('Rest port not found');
}

ctx.rest = new URL(`http://${restPort}`);
});

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

after(async () => {
await ctx.fixture.clear();
Expand Down
26 changes: 3 additions & 23 deletions test/next-15-node-20.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { suite, test, before, after } from 'node:test';
import { base, next15 } from '../util/tests.js';
import { Fixture } from '../util/fixture.js';

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

await test('should run base component', async (t) => {
const response = await fetch(`${ctx.rest}/Dog/0`, {
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic aGRiX2FkbWluOnBhc3N3b3Jk',
},
});
const json = await response.json();

t.assert.deepStrictEqual(json, { id: '0', name: 'Lincoln', breed: 'Shepherd' });
});

await test('should reach home page', async (t) => {
const response = await fetch(`${ctx.rest}/`, {
headers: {
'Content-Type': 'text/html',
}
});

const text = await response.text();
t.assert.match(text, /Next\.js v15/);
});
await Promise.all(base.concat(next15).map(async ({ name, testFunction }) => test(name, (t) => testFunction(t, ctx))));

after(async () => {
await ctx.fixture.clear();
Expand Down
26 changes: 3 additions & 23 deletions test/next-15-node-22.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { suite, test, before, after } from 'node:test';
import { base, next15 } from '../util/tests.js';
import { Fixture } from '../util/fixture.js';

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

await test('should run base component', async (t) => {
const response = await fetch(`${ctx.rest}/Dog/0`, {
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic aGRiX2FkbWluOnBhc3N3b3Jk',
},
});
const json = await response.json();

t.assert.deepStrictEqual(json, { id: '0', name: 'Lincoln', breed: 'Shepherd' });
});

await test('should reach home page', async (t) => {
const response = await fetch(`${ctx.rest}/`, {
headers: {
'Content-Type': 'text/html',
}
});

const text = await response.text();
t.assert.match(text, /Next\.js v15/);
});
await Promise.all(base.concat(next15).map(async ({ name, testFunction }) => test(name, (t) => testFunction(t, ctx))));

after(async () => {
await ctx.fixture.clear();
Expand Down
3 changes: 3 additions & 0 deletions util/base.dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Base Dockerfile for HarperDB Next.js Integration Tests fixtures
# Must be run from the root of the repository

ARG NODE_MAJOR

FROM node:${NODE_MAJOR}
Expand Down
14 changes: 14 additions & 0 deletions util/collected-transform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Transform } from 'node:stream';

export class CollectedTransform extends Transform {
#chunks = [];

_transform(chunk, _, callback) {
this.#chunks.push(chunk);
callback(null, chunk);
}

get output() {
return Buffer.concat(this.#chunks).toString();
}
}
87 changes: 20 additions & 67 deletions util/fixture.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,21 @@
import child_process from 'node:child_process';
import path from 'node:path';
import { Transform } from 'node:stream';
import { fileURLToPath } from 'node:url';
import { getNextImageName } from './get-next-image-name.js';
import { containerEngine } from './get-container-engine.js';

export class Fixture {
static CONTAINER_ENGINE_LIST = ['podman', 'docker'];
static FIXTURE_PATH = fileURLToPath(new URL('../fixtures/', import.meta.url));

/** @type {string} */
#containerEngine;

constructor({ autoSetup = true, debug = false, nextMajor, nodeMajor }) {
this.nextMajor = nextMajor;
this.nodeMajor = nodeMajor;

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

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

if (autoSetup) {
this.ready = this.clear()
.then(() => this.build())
.then(() => this.run());
}
}

get containerEngine() {
if (this.#containerEngine) {
return this.#containerEngine;
this.ready = this.clear().then(() => this.run());
}

for (const containerEngine of Fixture.CONTAINER_ENGINE_LIST) {
const { status } = child_process.spawnSync(containerEngine, ['--version'], { stdio: 'ignore' });
if (status === 0) {
return (this.#containerEngine = containerEngine);
}
}

throw new Error(`No container engine found in ${CONTAINER_ENGINE_LIST.join(', ')}`);
}

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

#runCommand(args = [], options = {}) {
return new Promise((resolve, reject) => {
const childProcess = child_process.spawn(this.containerEngine, args, {
const childProcess = child_process.spawn(containerEngine, args, {
stdio: this.#stdio,
...options,
});

childProcess.on('error', (error) => {
reject(error);
});

childProcess.on('exit', (code) => {
resolve(code);
});
childProcess.on('error', reject);
childProcess.on('exit', resolve);
});
}

build() {
return this.#runCommand([
'build',
'--build-arg',
`NEXT_MAJOR=${this.nextMajor}`,
'--build-arg',
`NODE_MAJOR=${this.nodeMajor}`,
'-t',
this.imageName,
'-f',
path.join(Fixture.FIXTURE_PATH, 'Dockerfile'),
path.join(Fixture.FIXTURE_PATH, '..'),
]);
}

stop() {
return this.#runCommand(['stop', this.containerName]);
}
Expand All @@ -87,15 +44,15 @@ export class Fixture {

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

psProcess.on('error', reject);

const collectedStdout = psProcess.stdout.pipe(
new Transform({
construct(cb) {
construct(callback) {
this.chunks = [];
cb(null);
callback(null);
},
transform(chunk, encoding, callback) {
this.chunks.push(chunk);
Expand All @@ -110,28 +67,27 @@ export class Fixture {
}

psProcess.on('exit', (code) => {
if (code === 0) {
if (collectedStdout.chunks.length !== 0) {
this.stop()
.then(() => this.rm())
.then(resolve, reject);
}
resolve();
} else {
reject(new Error(`\`${this.containerEngine} ps\` exited with code ${code}`));
if (code === 0 && collectedStdout.chunks.length !== 0) {
return this.stop()
.then(() => this.rm())
.then(resolve, reject);
}
return resolve(code);
});
});
}

run() {
return new Promise((resolve, reject) => {
const runProcess = child_process.spawn(
this.containerEngine,
containerEngine,
['run', '-P', '--name', this.containerName, this.imageName],
{ stdio: ['ignore', 'pipe', this.debug ? 'inherit' : 'ignore'] }
);

runProcess.on('error', reject);
runProcess.on('exit', resolve);

const stdout = runProcess.stdout.pipe(
new Transform({
transform(chunk, encoding, callback) {
Expand All @@ -146,16 +102,13 @@ export class Fixture {
if (this.debug) {
stdout.pipe(process.stdout);
}

runProcess.on('error', reject);
runProcess.on('exit', resolve);
});
}

get portMap() {
const portMap = new Map();
for (const port of ['9925', '9926']) {
const { stdout } = child_process.spawnSync(this.containerEngine, ['port', this.containerName, port]);
const { stdout } = child_process.spawnSync(containerEngine, ['port', this.containerName, port]);
portMap.set(port, stdout.toString().trim());
}
return portMap;
Expand Down
Loading

0 comments on commit ce61a75

Please sign in to comment.