|
1 | | -import { ContextProxy } from "../../../core/config/ContextProxy" |
| 1 | +import { describe, it, expect, beforeEach, vi } from "vitest" |
2 | 2 | import { CodeIndexConfigManager } from "../config-manager" |
3 | 3 |
|
4 | 4 | describe("CodeIndexConfigManager", () => { |
5 | | - let mockContextProxy: jest.Mocked<ContextProxy> |
| 5 | + let mockContextProxy: any |
6 | 6 | let configManager: CodeIndexConfigManager |
7 | 7 |
|
8 | 8 | beforeEach(() => { |
9 | 9 | // Setup mock ContextProxy |
10 | 10 | mockContextProxy = { |
11 | | - getGlobalState: jest.fn(), |
12 | | - getSecret: jest.fn().mockReturnValue(undefined), |
13 | | - } as unknown as jest.Mocked<ContextProxy> |
| 11 | + getGlobalState: vi.fn(), |
| 12 | + getSecret: vi.fn().mockReturnValue(undefined), |
| 13 | + } as unknown as any |
14 | 14 |
|
15 | 15 | configManager = new CodeIndexConfigManager(mockContextProxy) |
16 | 16 | }) |
@@ -122,9 +122,17 @@ describe("CodeIndexConfigManager", () => { |
122 | 122 | modelId: "text-embedding-3-large", |
123 | 123 | openAiOptions: { openAiNativeApiKey: "" }, |
124 | 124 | ollamaOptions: { ollamaBaseUrl: "" }, |
| 125 | + geminiOptions: { |
| 126 | + apiModelId: "text-embedding-3-large", |
| 127 | + geminiApiKey: "", |
| 128 | + geminiEmbeddingDimension: undefined, |
| 129 | + geminiEmbeddingTaskType: "CODE_RETRIEVAL_QUERY", |
| 130 | + rateLimitSeconds: undefined, |
| 131 | + }, |
125 | 132 | openAiCompatibleOptions: { |
126 | 133 | baseUrl: "https://api.example.com/v1", |
127 | 134 | apiKey: "test-openai-compatible-key", |
| 135 | + modelDimension: undefined, |
128 | 136 | }, |
129 | 137 | qdrantUrl: "http://qdrant.local", |
130 | 138 | qdrantApiKey: "test-qdrant-key", |
@@ -161,6 +169,13 @@ describe("CodeIndexConfigManager", () => { |
161 | 169 | modelId: "custom-model", |
162 | 170 | openAiOptions: { openAiNativeApiKey: "" }, |
163 | 171 | ollamaOptions: { ollamaBaseUrl: "" }, |
| 172 | + geminiOptions: { |
| 173 | + apiModelId: "custom-model", |
| 174 | + geminiApiKey: "", |
| 175 | + geminiEmbeddingDimension: undefined, |
| 176 | + geminiEmbeddingTaskType: "CODE_RETRIEVAL_QUERY", |
| 177 | + rateLimitSeconds: undefined, |
| 178 | + }, |
164 | 179 | openAiCompatibleOptions: { |
165 | 180 | baseUrl: "https://api.example.com/v1", |
166 | 181 | apiKey: "test-openai-compatible-key", |
@@ -201,9 +216,17 @@ describe("CodeIndexConfigManager", () => { |
201 | 216 | modelId: "custom-model", |
202 | 217 | openAiOptions: { openAiNativeApiKey: "" }, |
203 | 218 | ollamaOptions: { ollamaBaseUrl: "" }, |
| 219 | + geminiOptions: { |
| 220 | + apiModelId: "custom-model", |
| 221 | + geminiApiKey: "", |
| 222 | + geminiEmbeddingDimension: undefined, |
| 223 | + geminiEmbeddingTaskType: "CODE_RETRIEVAL_QUERY", |
| 224 | + rateLimitSeconds: undefined, |
| 225 | + }, |
204 | 226 | openAiCompatibleOptions: { |
205 | 227 | baseUrl: "https://api.example.com/v1", |
206 | 228 | apiKey: "test-openai-compatible-key", |
| 229 | + modelDimension: undefined, |
207 | 230 | }, |
208 | 231 | qdrantUrl: "http://qdrant.local", |
209 | 232 | qdrantApiKey: "test-qdrant-key", |
@@ -240,6 +263,13 @@ describe("CodeIndexConfigManager", () => { |
240 | 263 | modelId: "custom-model", |
241 | 264 | openAiOptions: { openAiNativeApiKey: "" }, |
242 | 265 | ollamaOptions: { ollamaBaseUrl: "" }, |
| 266 | + geminiOptions: { |
| 267 | + apiModelId: "custom-model", |
| 268 | + geminiApiKey: "", |
| 269 | + geminiEmbeddingDimension: undefined, |
| 270 | + geminiEmbeddingTaskType: "CODE_RETRIEVAL_QUERY", |
| 271 | + rateLimitSeconds: undefined, |
| 272 | + }, |
243 | 273 | openAiCompatibleOptions: { |
244 | 274 | baseUrl: "https://api.example.com/v1", |
245 | 275 | apiKey: "test-openai-compatible-key", |
@@ -1001,69 +1031,70 @@ describe("CodeIndexConfigManager", () => { |
1001 | 1031 |
|
1002 | 1032 | describe("initialization and restart prevention", () => { |
1003 | 1033 | it("should not require restart when configuration hasn't changed between calls", async () => { |
1004 | | - // Setup initial configuration - start with enabled and configured to avoid initial transition restart |
1005 | | - mockContextProxy.getGlobalState.mockReturnValue({ |
| 1034 | + const config = { |
1006 | 1035 | codebaseIndexEnabled: true, |
1007 | 1036 | codebaseIndexQdrantUrl: "http://qdrant.local", |
1008 | 1037 | codebaseIndexEmbedderProvider: "openai", |
1009 | 1038 | codebaseIndexEmbedderModelId: "text-embedding-3-small", |
1010 | | - }) |
| 1039 | + } |
| 1040 | + mockContextProxy.getGlobalState.mockReturnValue(config) |
1011 | 1041 | mockContextProxy.getSecret.mockImplementation((key: string) => { |
1012 | 1042 | if (key === "codeIndexOpenAiKey") return "test-key" |
1013 | 1043 | return undefined |
1014 | 1044 | }) |
1015 | 1045 |
|
1016 | | - // First load - this will initialize the config manager with current state |
1017 | | - await configManager.loadConfiguration() |
| 1046 | + // First load |
| 1047 | + const result1 = await configManager.loadConfiguration() |
| 1048 | + expect(result1.requiresRestart).toBe(true) // Restarts on first valid config |
1018 | 1049 |
|
1019 | | - // Second load with same configuration - should not require restart |
1020 | | - const secondResult = await configManager.loadConfiguration() |
1021 | | - expect(secondResult.requiresRestart).toBe(false) |
| 1050 | + // Second load with same config |
| 1051 | + const result2 = await configManager.loadConfiguration() |
| 1052 | + expect(result2.requiresRestart).toBe(false) |
1022 | 1053 | }) |
1023 | 1054 |
|
1024 | 1055 | it("should properly initialize with current config to prevent false restarts", async () => { |
1025 | | - // Setup configuration |
1026 | | - mockContextProxy.getGlobalState.mockReturnValue({ |
1027 | | - codebaseIndexEnabled: false, // Start disabled to avoid transition restart |
| 1056 | + const config = { |
| 1057 | + codebaseIndexEnabled: true, |
1028 | 1058 | codebaseIndexQdrantUrl: "http://qdrant.local", |
1029 | 1059 | codebaseIndexEmbedderProvider: "openai", |
1030 | 1060 | codebaseIndexEmbedderModelId: "text-embedding-3-small", |
1031 | | - }) |
| 1061 | + } |
| 1062 | + mockContextProxy.getGlobalState.mockReturnValue(config) |
1032 | 1063 | mockContextProxy.getSecret.mockImplementation((key: string) => { |
1033 | 1064 | if (key === "codeIndexOpenAiKey") return "test-key" |
1034 | 1065 | return undefined |
1035 | 1066 | }) |
1036 | 1067 |
|
1037 | | - // Create a new config manager (simulating what happens in CodeIndexManager.initialize) |
1038 | | - const newConfigManager = new CodeIndexConfigManager(mockContextProxy) |
| 1068 | + // Initialize with the current config |
| 1069 | + await configManager.loadConfiguration() |
1039 | 1070 |
|
1040 | | - // Load configuration - should not require restart since the manager should be initialized with current config |
1041 | | - const result = await newConfigManager.loadConfiguration() |
| 1071 | + // First load should not require restart |
| 1072 | + const result = await configManager.loadConfiguration() |
1042 | 1073 | expect(result.requiresRestart).toBe(false) |
1043 | 1074 | }) |
1044 | 1075 |
|
1045 | 1076 | it("should not require restart when settings are saved but code indexing config unchanged", async () => { |
1046 | | - // This test simulates the original issue: handleExternalSettingsChange() being called |
1047 | | - // when other settings are saved, but code indexing settings haven't changed |
1048 | | - |
1049 | | - // Setup initial state - enabled and configured |
1050 | | - mockContextProxy.getGlobalState.mockReturnValue({ |
| 1077 | + // Initial config |
| 1078 | + const initialConfig = { |
1051 | 1079 | codebaseIndexEnabled: true, |
1052 | 1080 | codebaseIndexQdrantUrl: "http://qdrant.local", |
1053 | 1081 | codebaseIndexEmbedderProvider: "openai", |
1054 | 1082 | codebaseIndexEmbedderModelId: "text-embedding-3-small", |
1055 | | - }) |
| 1083 | + } |
| 1084 | + mockContextProxy.getGlobalState.mockReturnValue(initialConfig) |
1056 | 1085 | mockContextProxy.getSecret.mockImplementation((key: string) => { |
1057 | 1086 | if (key === "codeIndexOpenAiKey") return "test-key" |
1058 | 1087 | return undefined |
1059 | 1088 | }) |
1060 | 1089 |
|
1061 | | - // First load to establish baseline |
1062 | 1090 | await configManager.loadConfiguration() |
1063 | 1091 |
|
1064 | | - // Simulate external settings change where code indexing config hasn't changed |
1065 | | - // (this is what happens when other settings are saved) |
1066 | | - const result = await configManager.loadConfiguration() |
| 1092 | + // Simulate saving settings by creating a new manager and initializing |
| 1093 | + const newConfigManager = new CodeIndexConfigManager(mockContextProxy) |
| 1094 | + await newConfigManager.loadConfiguration() |
| 1095 | + |
| 1096 | + // Load config again with the same settings |
| 1097 | + const result = await newConfigManager.loadConfiguration() |
1067 | 1098 | expect(result.requiresRestart).toBe(false) |
1068 | 1099 | }) |
1069 | 1100 | }) |
|
0 commit comments