test: add a full automated test suite (and fix six defects it uncovered) - #117
Merged
Conversation
…and honor documented status codes - await the part counter update so sequential part requests are deterministic - invalidate the file-<id> cache in deleteFile, mirroring deleteNote, so a deleted upload is no longer served from a stale cache entry - POST /note/:id/decrypt now returns the documented 200 instead of Nest's default 201 - PUT /file/upload/:id now returns the documented 204 instead of 200 Adds file transfer e2e coverage for the full upload lifecycle.
…nce e2e tests
The stale-upload cleanup used where("upload_id", "!=", null), which knex
compiles to "upload_id != NULL" — never true in SQL — so abandoned
multipart uploads were never aborted before their expiry.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Establishes a complete automated test suite for everything the server currently does, and fixes the defects the tests uncovered.
62 tests across 9 suites, running fully offline (sqlite3
:memory:, S3 stubbed withaws-sdk-client-mock, no live valkey/redis).pnpm testis now part of PR CI.Test infrastructure
jest.config.js+pnpm test/pnpm test:covtest/app.ts—createTestApp()mirrorsmain.tsbootstrapping (rawBody, body-parser limits) and sandboxes env vars per suitetest/esm-fix-mock.ts— deterministic stand-in for the fix-esm loaded modules, whose runtime require hooks do not work under jesttest/jest.setup.ts— silences module-global Nest loggers so output stays readableCoverage
CryptoService,getIp(proxy trust, IPv6 stripping, per-request caching)/info,/stats, stats password, instance password guard; request rate limit, failed-request ban, 418 block, limits-disabled bypass; the full file upload lifecycle with every documented error code; both cleanup crons and migrations (up, idempotent, revert)Deliberately not covered: the swagger UI itself (
main.ts-only), fatal-exit startup paths, remote trusted-proxy URL fetching (network), and themaxTokensPerRequest/decryptionRequestMultiplierconfig options, which no controller references.Bugs fixed
Each was found by a failing test, not by inspection:
CryptoService.decrypthad its AES arguments swapped — it decrypted the user's key using the note content as the passphrase, so/note/:id/decryptcould never return the plaintext. It also now rejects empty/undecryptable results with 401 instead of returning an empty string.GET/POST /note/:id/decryptreturned 500 for an unknown id —getDecrypteddereferencednote.contentwithout a null check. Now 404.awaitonupdateFile(id, { part })made part counting racy.getUploadFilesLastUpdatedBeforeusedwhere("upload_id", "!=", null), which knex compiles toupload_id != NULL— never true in SQL. Abandoned uploads therefore survived until their expiry instead of being cleaned up afteruploadPartTimeInMinutes. NowwhereNotNull. (getStats's two-argwhere(col, null)forms compile correctly; only this query was affected.)deleteFilenever invalidated its cache entry.getFilecaches for 30s, so a deleted or aborted upload kept being served from a stale cache entry. Now mirrorsdeleteNote.POST /note/:id/decryptreturned Nest's default 201 where 200 is documented, andPUT /file/upload/:idreturned 200 where 204 is documented. Both now match the documented contract.Additional Notes
tsconfig.jsongains"types": ["node", "jest"]— TypeScript 6 no longer auto-includes@types/jestglobals, so the spec files would not compile without it.Note for local development: the prebuilt
sqlite3binary requires glibc 2.38. On older distros it fails to load and needsnpm_config_build_from_source=true pnpm rebuild sqlite3. CI'subuntu-latestrunner is unaffected.Checklist