|
1 | 1 | /** |
2 | | - * Tests for createSourceFromState |
| 2 | + * Tests for MultiIndexRunner |
3 | 3 | * |
4 | | - * These tests verify that createSourceFromState correctly uses resolvedRef |
| 4 | + * Tests for createSourceFromState verify that it correctly uses resolvedRef |
5 | 5 | * from state metadata when creating source instances. |
6 | 6 | * |
7 | | - * We mock GitHub and Website sources to capture what config gets passed |
8 | | - * to the constructors, without needing API credentials. |
9 | | - * |
10 | | - * Since all VCS sources (GitHub, GitLab, BitBucket) use the same getRef() logic, |
11 | | - * we only test GitHub as the representative case. |
| 7 | + * Tests for MultiIndexRunner.refreshIndexList verify that it respects |
| 8 | + * the fixed mode allowlist when refreshing the index list. |
12 | 9 | */ |
13 | 10 |
|
14 | 11 | import { describe, it, expect, vi, beforeEach } from "vitest"; |
15 | | -import type { IndexStateSearchOnly, SourceMetadata } from "../core/types.js"; |
| 12 | +import type { IndexStateSearchOnly, SourceMetadata, IndexState } from "../core/types.js"; |
| 13 | +import type { IndexStoreReader } from "../stores/types.js"; |
| 14 | +import { MultiIndexRunner } from "./multi-index-runner.js"; |
16 | 15 |
|
17 | 16 | // Mock only the sources we actually test |
18 | 17 | vi.mock("../sources/github.js", () => ({ |
@@ -113,3 +112,128 @@ describe("createSourceFromState", () => { |
113 | 112 | ); |
114 | 113 | }); |
115 | 114 | }); |
| 115 | + |
| 116 | +describe("MultiIndexRunner.refreshIndexList", () => { |
| 117 | + // Helper to create a mock store with multiple indexes |
| 118 | + const createMockStoreWithIndexes = (indexNames: string[]): IndexStoreReader => { |
| 119 | + const mockState = (name: string): IndexState => ({ |
| 120 | + version: 1, |
| 121 | + contextState: { version: 1 } as any, |
| 122 | + source: { |
| 123 | + type: "github", |
| 124 | + config: { owner: "test", repo: name }, |
| 125 | + syncedAt: new Date().toISOString(), |
| 126 | + }, |
| 127 | + }); |
| 128 | + |
| 129 | + return { |
| 130 | + loadState: vi.fn(), |
| 131 | + loadSearch: vi.fn().mockImplementation((name: string) => { |
| 132 | + if (indexNames.includes(name)) { |
| 133 | + return Promise.resolve(mockState(name)); |
| 134 | + } |
| 135 | + return Promise.resolve(null); |
| 136 | + }), |
| 137 | + list: vi.fn().mockResolvedValue(indexNames), |
| 138 | + }; |
| 139 | + }; |
| 140 | + |
| 141 | + it("in discovery mode, refreshIndexList includes all indexes from store", async () => { |
| 142 | + const store = createMockStoreWithIndexes(["pytorch", "react", "docs"]); |
| 143 | + |
| 144 | + const runner = await MultiIndexRunner.create({ |
| 145 | + store, |
| 146 | + // No indexNames = discovery mode |
| 147 | + }); |
| 148 | + |
| 149 | + expect(runner.indexNames).toEqual(["pytorch", "react", "docs"]); |
| 150 | + |
| 151 | + // Simulate store gaining a new index |
| 152 | + (store.list as any).mockResolvedValue(["pytorch", "react", "docs", "vue"]); |
| 153 | + (store.loadSearch as any).mockImplementation((name: string) => { |
| 154 | + if (["pytorch", "react", "docs", "vue"].includes(name)) { |
| 155 | + return Promise.resolve({ |
| 156 | + version: 1, |
| 157 | + contextState: { version: 1 } as any, |
| 158 | + source: { |
| 159 | + type: "github", |
| 160 | + config: { owner: "test", repo: name }, |
| 161 | + syncedAt: new Date().toISOString(), |
| 162 | + }, |
| 163 | + }); |
| 164 | + } |
| 165 | + return Promise.resolve(null); |
| 166 | + }); |
| 167 | + |
| 168 | + await runner.refreshIndexList(); |
| 169 | + expect(runner.indexNames).toEqual(["pytorch", "react", "docs", "vue"]); |
| 170 | + }); |
| 171 | + |
| 172 | + it("in fixed mode, refreshIndexList respects the original allowlist", async () => { |
| 173 | + const store = createMockStoreWithIndexes(["pytorch", "react", "docs"]); |
| 174 | + |
| 175 | + // Create runner in fixed mode with only pytorch and react |
| 176 | + const runner = await MultiIndexRunner.create({ |
| 177 | + store, |
| 178 | + indexNames: ["pytorch", "react"], |
| 179 | + }); |
| 180 | + |
| 181 | + expect(runner.indexNames).toEqual(["pytorch", "react"]); |
| 182 | + |
| 183 | + // Simulate store gaining a new index (docs is already there, vue is new) |
| 184 | + (store.list as any).mockResolvedValue(["pytorch", "react", "docs", "vue"]); |
| 185 | + (store.loadSearch as any).mockImplementation((name: string) => { |
| 186 | + if (["pytorch", "react", "docs", "vue"].includes(name)) { |
| 187 | + return Promise.resolve({ |
| 188 | + version: 1, |
| 189 | + contextState: { version: 1 } as any, |
| 190 | + source: { |
| 191 | + type: "github", |
| 192 | + config: { owner: "test", repo: name }, |
| 193 | + syncedAt: new Date().toISOString(), |
| 194 | + }, |
| 195 | + }); |
| 196 | + } |
| 197 | + return Promise.resolve(null); |
| 198 | + }); |
| 199 | + |
| 200 | + await runner.refreshIndexList(); |
| 201 | + |
| 202 | + // Should still only include pytorch and react, not docs or vue |
| 203 | + expect(runner.indexNames).toEqual(["pytorch", "react"]); |
| 204 | + }); |
| 205 | + |
| 206 | + it("in fixed mode, refreshIndexList handles missing indexes gracefully", async () => { |
| 207 | + const store = createMockStoreWithIndexes(["pytorch", "react"]); |
| 208 | + |
| 209 | + // Create runner in fixed mode with pytorch, react, and a missing index |
| 210 | + const runner = await MultiIndexRunner.create({ |
| 211 | + store, |
| 212 | + indexNames: ["pytorch", "react"], |
| 213 | + }); |
| 214 | + |
| 215 | + expect(runner.indexNames).toEqual(["pytorch", "react"]); |
| 216 | + |
| 217 | + // Simulate pytorch being deleted from store |
| 218 | + (store.list as any).mockResolvedValue(["react"]); |
| 219 | + (store.loadSearch as any).mockImplementation((name: string) => { |
| 220 | + if (name === "react") { |
| 221 | + return Promise.resolve({ |
| 222 | + version: 1, |
| 223 | + contextState: { version: 1 } as any, |
| 224 | + source: { |
| 225 | + type: "github", |
| 226 | + config: { owner: "test", repo: name }, |
| 227 | + syncedAt: new Date().toISOString(), |
| 228 | + }, |
| 229 | + }); |
| 230 | + } |
| 231 | + return Promise.resolve(null); |
| 232 | + }); |
| 233 | + |
| 234 | + await runner.refreshIndexList(); |
| 235 | + |
| 236 | + // Should only include react (pytorch is gone from store) |
| 237 | + expect(runner.indexNames).toEqual(["react"]); |
| 238 | + }); |
| 239 | +}); |
0 commit comments