|
1 | 1 | import fs from "node:fs/promises"; |
2 | 2 | import os from "node:os"; |
3 | 3 | import path from "node:path"; |
4 | | -import { afterAll, beforeAll, describe, expect, it } from "vitest"; |
| 4 | +import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; |
5 | 5 | import { compileMemoryWikiVault } from "./compile.js"; |
6 | 6 | import { renderWikiMarkdown } from "./markdown.js"; |
7 | 7 | import { createMemoryWikiTestHarness } from "./test-helpers.js"; |
@@ -110,6 +110,61 @@ describe("compileMemoryWikiVault", () => {
|
110 | 110 | ).resolves.toContain('"text":"Alpha is the canonical source page."'); |
111 | 111 | }); |
112 | 112 | |
| 113 | +it("bounds concurrent page reads while compiling", async () => { |
| 114 | +const { rootDir, config } = await createVault({ |
| 115 | +rootDir: nextCaseRoot(), |
| 116 | +initialize: true, |
| 117 | +}); |
| 118 | + |
| 119 | +for (let index = 0; index < 24; index += 1) { |
| 120 | +await fs.writeFile( |
| 121 | +path.join(rootDir, "sources", `page-${index}.md`), |
| 122 | +renderWikiMarkdown({ |
| 123 | +frontmatter: { |
| 124 | +pageType: "source", |
| 125 | +id: `source.page-${index}`, |
| 126 | +title: `Page ${index}`, |
| 127 | +}, |
| 128 | +body: `# Page ${index}\n`, |
| 129 | +}), |
| 130 | +"utf8", |
| 131 | +); |
| 132 | +} |
| 133 | + |
| 134 | +const originalReadFile = fs.readFile.bind(fs); |
| 135 | +let activePageReads = 0; |
| 136 | +let maxActivePageReads = 0; |
| 137 | +const readFileSpy = vi |
| 138 | +.spyOn(fs, "readFile") |
| 139 | +.mockImplementation(async (...args: Parameters<typeof fs.readFile>) => { |
| 140 | +const targetPath = args[0]; |
| 141 | +const isTestPageRead = |
| 142 | +typeof targetPath === "string" && |
| 143 | +targetPath.startsWith(path.join(rootDir, "sources", "page-")); |
| 144 | +if (!isTestPageRead) { |
| 145 | +return await originalReadFile(...args); |
| 146 | +} |
| 147 | + |
| 148 | +activePageReads += 1; |
| 149 | +maxActivePageReads = Math.max(maxActivePageReads, activePageReads); |
| 150 | +try { |
| 151 | +await new Promise((resolve) => setTimeout(resolve, 5)); |
| 152 | +return await originalReadFile(...args); |
| 153 | +} finally { |
| 154 | +activePageReads -= 1; |
| 155 | +} |
| 156 | +}); |
| 157 | + |
| 158 | +try { |
| 159 | +await compileMemoryWikiVault(config); |
| 160 | +} finally { |
| 161 | +readFileSpy.mockRestore(); |
| 162 | +} |
| 163 | + |
| 164 | +expect(maxActivePageReads).toBeGreaterThan(0); |
| 165 | +expect(maxActivePageReads).toBeLessThanOrEqual(16); |
| 166 | +}); |
| 167 | + |
113 | 168 | it("renders obsidian-friendly links when configured", async () => { |
114 | 169 | const { rootDir, config } = await createVault({ |
115 | 170 | rootDir: nextCaseRoot(), |
|