test: move all tests to flat test/ directory

No more src/models/ and src/integration/ subfolders to forget about.
All 9 test files live in test/, one command runs everything:

  npx vitest run test/
  bun test test/
This commit is contained in:
Tobi Lutke 2026-02-15 21:37:47 -04:00
parent dcedfb5268
commit 870d3aed3b
No known key found for this signature in database
13 changed files with 37 additions and 77 deletions

View File

@ -33,16 +33,8 @@ jobs:
- run: npm install - run: npm install
- name: Unit tests - name: Tests
run: npx vitest run --reporter=verbose src/*.test.ts run: npx vitest run --reporter=verbose test/
- name: Model tests
run: npx vitest run --reporter=verbose src/models/*.test.ts
env:
CI: true
- name: Integration tests
run: npx vitest run --reporter=verbose src/integration/*.test.ts
env: env:
CI: true CI: true
@ -71,21 +63,8 @@ jobs:
- run: bun install - run: bun install
- name: Unit tests - name: Tests
run: bun test --preload ./src/test-preload.ts src/*.test.ts run: bun test --preload ./src/test-preload.ts test/
env:
DYLD_LIBRARY_PATH: /opt/homebrew/opt/sqlite/lib
LD_LIBRARY_PATH: /usr/lib/x86_64-linux-gnu
- name: Model tests
run: bun test --preload ./src/test-preload.ts src/models/*.test.ts
env:
CI: true
DYLD_LIBRARY_PATH: /opt/homebrew/opt/sqlite/lib
LD_LIBRARY_PATH: /usr/lib/x86_64-linux-gnu
- name: Integration tests
run: bun test --preload ./src/test-preload.ts src/integration/*.test.ts
env: env:
CI: true CI: true
DYLD_LIBRARY_PATH: /opt/homebrew/opt/sqlite/lib DYLD_LIBRARY_PATH: /opt/homebrew/opt/sqlite/lib

View File

@ -122,23 +122,15 @@ bun src/qmd.ts <command> # Run from source
bun link # Install globally as 'qmd' bun link # Install globally as 'qmd'
``` ```
## Test Layout ## Tests
- `src/*.test.ts` = unit tests All tests live in `test/`. Run everything:
- `src/models/*.test.ts` = tests that require model/runtime setup
- `src/integration/*.test.ts` = integration tests (CLI subprocesses, daemon/server behavior)
### Run Order
```sh ```sh
npx vitest run --reporter=verbose src/*.test.ts npx vitest run --reporter=verbose test/
npx vitest run --reporter=verbose src/models/*.test.ts bun test --preload ./src/test-preload.ts test/
npx vitest run --reporter=verbose src/integration/*.test.ts
``` ```
Use this order for faster feedback:
`unit -> models -> integration`.
## Architecture ## Architecture
- SQLite FTS5 for full-text search (BM25) - SQLite FTS5 for full-text search (BM25)

View File

@ -15,19 +15,7 @@
"CHANGELOG.md" "CHANGELOG.md"
], ],
"scripts": { "scripts": {
"test": "vitest run", "test": "vitest run --reporter=verbose test/",
"test:unit": "vitest run --reporter=verbose src/*.test.ts",
"test:models": "vitest run --reporter=verbose src/models/*.test.ts",
"test:integration": "vitest run --reporter=verbose src/integration/*.test.ts",
"test:unit:bun": "bun run vitest run --reporter=verbose --testTimeout=120000 src/*.test.ts",
"test:models:bun": "bun run vitest run --reporter=verbose --testTimeout=120000 src/models/*.test.ts",
"test:integration:bun": "bun run vitest run --reporter=verbose --testTimeout=120000 src/integration/*.test.ts",
"test:unit:node": "npx vitest run --reporter=verbose --testTimeout=120000 src/*.test.ts",
"test:models:node": "npx vitest run --reporter=verbose --testTimeout=120000 src/models/*.test.ts",
"test:integration:node": "npx vitest run --reporter=verbose --testTimeout=120000 src/integration/*.test.ts",
"test:ci:bun": "npm run test:unit:bun && npm run test:models:bun && npm run test:integration:bun",
"test:ci:node": "npm run test:unit:node && npm run test:models:node && npm run test:integration:node",
"test:ci": "npm run test:unit && npm run test:models && npm run test:integration",
"qmd": "tsx src/qmd.ts", "qmd": "tsx src/qmd.ts",
"index": "tsx src/qmd.ts index", "index": "tsx src/qmd.ts index",
"vector": "tsx src/qmd.ts vector", "vector": "tsx src/qmd.ts vector",

View File

@ -8,7 +8,7 @@ import { describe, test, expect, beforeAll, afterAll } from "vitest";
import { mkdtempSync, rmSync, readFileSync, readdirSync } from "fs"; import { mkdtempSync, rmSync, readFileSync, readdirSync } from "fs";
import { join, dirname } from "path"; import { join, dirname } from "path";
import { tmpdir } from "os"; import { tmpdir } from "os";
import type { Database } from "./db.js"; import type { Database } from "../src/db.js";
import { createHash } from "crypto"; import { createHash } from "crypto";
import { fileURLToPath } from "url"; import { fileURLToPath } from "url";
@ -17,7 +17,7 @@ import {
searchFTS, searchFTS,
insertDocument, insertDocument,
insertContent, insertContent,
} from "./store"; } from "../src/store";
// Set INDEX_PATH before importing store to prevent using global index // Set INDEX_PATH before importing store to prevent using global index
const tempDir = mkdtempSync(join(tmpdir(), "qmd-eval-unit-")); const tempDir = mkdtempSync(join(tmpdir(), "qmd-eval-unit-"));
@ -92,7 +92,7 @@ describe("BM25 Search (FTS)", () => {
db = store.db; db = store.db;
// Load and index eval documents // Load and index eval documents
const evalDocsDir = join(dirname(fileURLToPath(import.meta.url)), "../test/eval-docs"); const evalDocsDir = join(dirname(fileURLToPath(import.meta.url)), "eval-docs");
const files = readdirSync(evalDocsDir).filter(f => f.endsWith(".md")); const files = readdirSync(evalDocsDir).filter(f => f.endsWith(".md"));
for (const file of files) { for (const file of files) {

View File

@ -14,8 +14,8 @@ import { describe, test, expect, beforeAll, afterAll } from "vitest";
import { mkdtempSync, rmSync, readFileSync, readdirSync } from "fs"; import { mkdtempSync, rmSync, readFileSync, readdirSync } from "fs";
import { join } from "path"; import { join } from "path";
import { tmpdir } from "os"; import { tmpdir } from "os";
import { openDatabase } from "../db.js"; import { openDatabase } from "../src/db.js";
import type { Database } from "../db.js"; import type { Database } from "../src/db.js";
import { createHash } from "crypto"; import { createHash } from "crypto";
import { fileURLToPath } from "url"; import { fileURLToPath } from "url";
import { dirname } from "path"; import { dirname } from "path";
@ -35,8 +35,8 @@ import {
reciprocalRankFusion, reciprocalRankFusion,
DEFAULT_EMBED_MODEL, DEFAULT_EMBED_MODEL,
type RankedResult, type RankedResult,
} from "../store"; } from "../src/store";
import { getDefaultLlamaCpp, formatDocForEmbedding, disposeDefaultLlamaCpp } from "../llm"; import { getDefaultLlamaCpp, formatDocForEmbedding, disposeDefaultLlamaCpp } from "../src/llm";
// Eval queries with expected documents // Eval queries with expected documents
const evalQueries: { const evalQueries: {
@ -110,7 +110,7 @@ describe("BM25 Search (FTS)", () => {
db = store.db; db = store.db;
// Load and index eval documents // Load and index eval documents
const evalDocsDir = join(dirname(fileURLToPath(import.meta.url)), "../../test/eval-docs"); const evalDocsDir = join(dirname(fileURLToPath(import.meta.url)), "eval-docs");
const files = readdirSync(evalDocsDir).filter(f => f.endsWith(".md")); const files = readdirSync(evalDocsDir).filter(f => f.endsWith(".md"));
for (const file of files) { for (const file of files) {
@ -182,7 +182,7 @@ describe.skipIf(!!process.env.CI)("Vector Search", () => {
const llm = getDefaultLlamaCpp(); const llm = getDefaultLlamaCpp();
store.ensureVecTable(768); // embeddinggemma uses 768 dimensions store.ensureVecTable(768); // embeddinggemma uses 768 dimensions
const evalDocsDir = join(dirname(fileURLToPath(import.meta.url)), "../../test/eval-docs"); const evalDocsDir = join(dirname(fileURLToPath(import.meta.url)), "eval-docs");
const files = readdirSync(evalDocsDir).filter(f => f.endsWith(".md")); const files = readdirSync(evalDocsDir).filter(f => f.endsWith(".md"));
for (const file of files) { for (const file of files) {

View File

@ -27,8 +27,8 @@ import {
documentToXml, documentToXml,
formatDocument, formatDocument,
type MultiGetFile, type MultiGetFile,
} from "./formatter.js"; } from "../src/formatter.js";
import type { SearchResult, DocumentResult } from "./store.js"; import type { SearchResult, DocumentResult } from "../src/store.js";
// ============================================================================= // =============================================================================
// Test Fixtures // Test Fixtures

View File

@ -17,7 +17,7 @@ import {
SessionReleasedError, SessionReleasedError,
type RerankDocument, type RerankDocument,
type ILLMSession, type ILLMSession,
} from "../llm.js"; } from "../src/llm.js";
// ============================================================================= // =============================================================================
// Singleton Tests (no model loading required) // Singleton Tests (no model loading required)

View File

@ -6,16 +6,16 @@
*/ */
import { describe, test, expect, beforeAll, afterAll, beforeEach, afterEach } from "vitest"; import { describe, test, expect, beforeAll, afterAll, beforeEach, afterEach } from "vitest";
import { openDatabase, loadSqliteVec } from "../db.js"; import { openDatabase, loadSqliteVec } from "../src/db.js";
import type { Database } from "../db.js"; import type { Database } from "../src/db.js";
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js"; import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod"; import { z } from "zod";
import { getDefaultLlamaCpp, disposeDefaultLlamaCpp } from "../llm"; import { getDefaultLlamaCpp, disposeDefaultLlamaCpp } from "../src/llm";
import { mkdtemp, writeFile, readdir, unlink, rmdir } from "node:fs/promises"; import { mkdtemp, writeFile, readdir, unlink, rmdir } from "node:fs/promises";
import { join } from "node:path"; import { join } from "node:path";
import { tmpdir } from "node:os"; import { tmpdir } from "node:os";
import YAML from "yaml"; import YAML from "yaml";
import type { CollectionConfig } from "../collections"; import type { CollectionConfig } from "../src/collections";
// ============================================================================= // =============================================================================
// Test Database Setup // Test Database Setup
@ -192,8 +192,8 @@ import {
DEFAULT_RERANK_MODEL, DEFAULT_RERANK_MODEL,
DEFAULT_MULTI_GET_MAX_BYTES, DEFAULT_MULTI_GET_MAX_BYTES,
createStore, createStore,
} from "../store"; } from "../src/store";
import type { RankedResult } from "../store"; import type { RankedResult } from "../src/store";
// Note: searchResultsToMcpCsv no longer used in MCP - using structuredContent instead // Note: searchResultsToMcpCsv no longer used in MCP - using structuredContent instead
// ============================================================================= // =============================================================================
@ -865,8 +865,8 @@ describe("MCP Server", () => {
// HTTP Transport Tests // HTTP Transport Tests
// ============================================================================= // =============================================================================
import { startMcpHttpServer, type HttpServerHandle } from "../mcp"; import { startMcpHttpServer, type HttpServerHandle } from "../src/mcp";
import { enableProductionMode } from "../store"; import { enableProductionMode } from "../src/store";
describe("MCP HTTP Transport", () => { describe("MCP HTTP Transport", () => {
let handle: HttpServerHandle; let handle: HttpServerHandle;

View File

@ -16,7 +16,7 @@ import {
normalizePathSeparators, normalizePathSeparators,
getRelativePathFromPrefix, getRelativePathFromPrefix,
resolve, resolve,
} from "./store.js"; } from "../src/store.js";
// ============================================================================= // =============================================================================
// Test Utilities // Test Utilities

View File

@ -15,7 +15,7 @@ import {
normalizeDocid, normalizeDocid,
isDocid, isDocid,
handelize, handelize,
} from "./store"; } from "../src/store";
// ============================================================================= // =============================================================================
// Path Utilities // Path Utilities

View File

@ -7,13 +7,13 @@
*/ */
import { describe, test, expect, beforeAll, afterAll, beforeEach, afterEach, vi } from "vitest"; import { describe, test, expect, beforeAll, afterAll, beforeEach, afterEach, vi } from "vitest";
import { openDatabase, loadSqliteVec } from "../db.js"; import { openDatabase, loadSqliteVec } from "../src/db.js";
import type { Database } from "../db.js"; import type { Database } from "../src/db.js";
import { unlink, mkdtemp, rmdir, writeFile } from "node:fs/promises"; import { unlink, mkdtemp, rmdir, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os"; import { tmpdir } from "node:os";
import { join } from "node:path"; import { join } from "node:path";
import YAML from "yaml"; import YAML from "yaml";
import { disposeDefaultLlamaCpp } from "../llm.js"; import { disposeDefaultLlamaCpp } from "../src/llm.js";
import { import {
createStore, createStore,
verifySqliteVecLoaded, verifySqliteVecLoaded,
@ -49,8 +49,8 @@ import {
type DocumentResult, type DocumentResult,
type SearchResult, type SearchResult,
type RankedResult, type RankedResult,
} from "../store.js"; } from "../src/store.js";
import type { CollectionConfig } from "../collections.js"; import type { CollectionConfig } from "../src/collections.js";
// ============================================================================= // =============================================================================
// LlamaCpp Setup // LlamaCpp Setup

View File

@ -3,5 +3,6 @@ import { defineConfig } from "vitest/config";
export default defineConfig({ export default defineConfig({
test: { test: {
testTimeout: 30000, testTimeout: 30000,
include: ["test/**/*.test.ts"],
}, },
}); });