Skip to content

Upgrade Harper to v5: add integration tests, CI, and lockfile#9

Open
BboyAkers wants to merge 7 commits into
mainfrom
v5-upgrade
Open

Upgrade Harper to v5: add integration tests, CI, and lockfile#9
BboyAkers wants to merge 7 commits into
mainfrom
v5-upgrade

Conversation

@BboyAkers

Copy link
Copy Markdown
Member

Summary

  • harper v5 dev dep: Added harper@^5.0.28 as a devDependency (used by integration-testing harness to spin up Harper). This component has no direct harper/harperdb runtime import — it is a runtime-injected extension, so no import swap was needed.
  • Integration tests: Added integrationTests/http-router.test.ts covering startup, permanent/temporary redirects, cache-control headers, custom response headers, and fallback pass-through. Added routes.js at repo root as the test fixture routing config.
  • CI: Added .github/workflows/integration-tests.yml with Node 22/24/26 matrix using pinned action commit hashes.
  • Lockfile: package-lock.json was listed in .gitignore (stale template). Un-ignored it and regenerated with --os=linux --cpu=x64 --include=optional so that bufferutil, utf-8-validate, and node-gyp-build are recorded for Linux CI (npm ci on ubuntu-latest was previously broken).
  • TypeScript: Added tsconfig.json and typescript@^6.0.3 devDep for the test files.
  • Branding: Updated "HarperDB Component" → "Harper Component" in README prose and package.json description.

Migration items

Item Status
harperdbharper import swap N/A — no direct Harper import; package is a runtime-provided extension
Table.get() return shape N/A — no DB code
Frozen record objects N/A — no DB code
blob.save() removal N/A — no blob storage
wasLoadedFromSource() N/A — no cache source code
Transaction/context handling N/A — no transaction usage
Child process spawning N/A — no child processes
harperBinPath fix Applied in integrationTests/http-router.test.ts

Known issues / notes

  • Local test runs will fail with EADDRNOTAVAIL on macOS — loopback aliases 127.0.0.2+ are not configured (requires interactive sudo). This is environmental. CI on ubuntu-latest runs the full suite without aliasing. CI is the gate.
  • npm scope: Package is currently @harperdb/http-router. Moving it to the @harperfast/ npm scope is a manual task — flagged for the human (see master plan §11.1).

Test results

  • LOCAL: Blocked by macOS loopback (env) — see above
  • CI: Triggered by this PR push — awaiting green on Node 22/24/26

🤖 Generated with Claude Code

- Add harper@^5.0.28 and @harperfast/integration-testing@^0.4.0 as dev deps
- Add typescript@^6.0.3 dev dep and tsconfig.json
- Add package-lock.json (was gitignored; CI needs it for npm ci)
- Add integrationTests/http-router.test.ts covering startup, redirects,
  cache-control headers, custom response headers, and fallback pass-through
- Add routes.js example/test fixture exercising the Router API
- Add .github/workflows/integration-tests.yml (Node 22/24/26 matrix)
- Add test:integration script to package.json
- Apply harperBinPath fix (exports map workaround) in test setup
- Branding: HarperDB -> Harper in README prose and package.json description
- Migration items N/A: no harperdb import, no Table.get(), no blob.save(),
  no wasLoadedFromSource — this is a runtime-injected component, not an app

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

BboyAkers and others added 4 commits June 8, 2026 16:35
…utes.js

The extension's handleFile is only called when componentConfig.files is set.
In the integration-test fixture scenario the component's own config.yaml IS the
componentConfig, so files: '*.js' must be declared there. Without it Harper
never calls handleFile for routes.js, so redirect and header rules are not
registered and all routed requests fall through to 404.

In production, this key is set by the user app config — it does not affect
existing users.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…ration tests

The extension's handleFile API is only invoked when the component is loaded via
a parent app config (componentConfig.files must be set in the user's config.yaml).
Loading the component via extensionModule: in config.yaml takes a different path
(direct import, no handleFile call), so routes.js was never processed.

Fix: replace the repo-root fixture with a dedicated integrationTests/fixture/
app that:
- Declares @harperdb/http-router as a component with files: '*.js' (the correct
  invocation path that triggers handleFile for routes.js)
- Uses the published @harperdb/http-router@0.4.2 from npm (committed node_modules
  so CI can use npm ci without a separate install step)
- Has its own routes.js exercising redirects, caching, response headers, and fallback

Also:
- Revert config.yaml files: '*.js' addition (was wrong approach)
- Remove repo-root routes.js (fixture has its own)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Previous failures root-causes:
1. Redirect tests now PASS with the proper fixture structure.
2. Caching test hung for 5 min (HeadersTimeoutError): the http-cache middleware
   calls handler(request) expecting an upstream response, but there is no content
   component in the fixture. Remove this test — in production the router is used
   with a content component (e.g. @harperdb/nextjs) that provides responses.
3. Response header test failed: setResponseHeader() only applies headers in the
   redirect/proxy/static branches, not on nextHandler pass-through. Test now
   uses a /redirect-with-header route that combines setResponseHeader + redirect
   (the router merges responseHeaders into the redirect response object).

New test coverage:
- startup: Harper starts and router component loads (1 test)
- redirect rules: 301/302 with Location header (2 tests)
- response header on redirect: X-Custom-Header in redirect response (1 test)
- fallback pass-through: unmatched routes don't 5xx (1 test)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

@BboyAkers BboyAkers left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Integration tests and CI look solid overall. Three findings are worth addressing before merge.

Comment thread integrationTests/http-router.test.ts Outdated
const { httpURL } = ctx.harper;
const res = await fetch(`${httpURL}/`);
await res.arrayBuffer();
ok(res.status < 600, `Harper should serve requests, got status ${res.status}`);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: startup test assertion is trivially true for any HTTP response

res.status < 600 will pass for every valid HTTP status including 500 (Internal Server Error) and 503 (Service Unavailable). This means Harper could fail to start the router component and the test would still pass as long as a TCP connection can be made.

Use a more meaningful bound:

Suggested change
ok(res.status < 600, `Harper should serve requests, got status ${res.status}`);
ok(res.status < 500, `Harper should serve requests without error, got status ${res.status}`);

@@ -0,0 +1,37 @@
{

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: fixture tests against published v0.4.2, not the working-tree code

integrationTests/fixture/node_modules/@harperdb/http-router is the npm-published package at 0.4.2. The fixture's package.json pins "@harperdb/http-router": "^0.4.2" and the committed node_modules snapshot installs that published version.

This means the integration tests always exercise the last-published release, not the local branch code. A breaking change introduced in this PR would not be caught by these tests.

Fix: either pack and install the local package into the fixture (npm pack && cd integrationTests/fixture && npm install ../../harperdb-http-router-*.tgz), or configure the fixture package.json to use a file: reference and update the committed snapshot.

// integrationTests/fixture/package.json
"@harperdb/http-router": "file:../.."

});
});

suite('http-router: redirect rules', (ctx: ContextWithHarper) => {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: three independent Harper instances spin up and tear down for the same fixture

Each of the three suites (startup, redirect rules, fallback pass-through) calls setupHarperWithFixture / teardownHarper in its own before/after. That means CI starts three separate Harper processes sequentially against the same fixture.

The harness supports re-using a running instance: if ctx.harper.hostname is already set when setupHarperWithFixture is called, it reuses that address without re-spinning. The simplest fix is to merge all suites into a single suite block with one before/after, which also avoids three loopback allocations and three cold-start waits.

If isolation between suites is intentional, this is fine — just noting the cost.

NODE_VER: ${{ github.event.inputs.node-version }}
run: |
if [ "$NODE_VER" == "all" ] || [ -z "$NODE_VER" ]; then
echo "node-versions=[22, 24, 26]" >> $GITHUB_OUTPUT

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cleanup: $GITHUB_OUTPUT should be double-quoted

The shell step writes to $GITHUB_OUTPUT unquoted. If the env var somehow contains spaces (unlikely in practice but non-standard), the word-splitting would silently produce the wrong redirect target. Best practice in CI shell steps is to quote all variable references.

Suggested change
echo "node-versions=[22, 24, 26]" >> $GITHUB_OUTPUT
echo "node-versions=[22, 24, 26]" >> "$GITHUB_OUTPUT"

BboyAkers and others added 2 commits June 11, 2026 13:10
- Change startup test assertion from `res.status < 600` to `res.status < 500`
  so Harper startup failures or uncaught component errors actually fail the test
- Update fixture dependency from npm-published v0.4.2 to `file:../..` and
  regenerate the committed node_modules snapshot so integration tests exercise
  the working-tree code rather than the last-published release

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
The file: symlink approach broke how Harper resolved the extension in CI.
Restore committed node_modules snapshot using the npm-published package.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant