Skip to content

Commit 5f7ae01

Browse files
author
mdatelle
committed
test: update and fix the rest of the failing api key tests
1 parent 0be3fb0 commit 5f7ae01

File tree

2 files changed

+61
-40
lines changed

2 files changed

+61
-40
lines changed

api/src/unraid-api/auth/api-key.service.spec.ts

Lines changed: 48 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,15 @@ describe('ApiKeyService', () => {
164164

165165
describe('findAll', () => {
166166
it('should return all API keys', async () => {
167-
vi.mocked(readdir).mockResolvedValue(['key1.json', 'key2.json'] as any);
168-
vi.mocked(readFile).mockResolvedValue(JSON.stringify(mockApiKey));
167+
vi.spyOn(apiKeyService, 'loadAllFromDisk').mockResolvedValue([
168+
mockApiKeyWithSecret,
169+
{ ...mockApiKeyWithSecret, id: 'second-id' },
170+
]);
171+
await apiKeyService.onModuleInit();
172+
173+
vi.mocked(ApiKeySchema).mockReturnValue({
174+
parse: vi.fn().mockReturnValue(mockApiKey),
175+
} as any);
169176

170177
const result = await apiKeyService.findAll();
171178

@@ -175,50 +182,61 @@ describe('ApiKeyService', () => {
175182
});
176183

177184
it('should handle file read errors gracefully', async () => {
178-
vi.mocked(readdir).mockResolvedValue(['key1.json', 'key2.json'] as any);
179-
vi.mocked(readFile).mockRejectedValue(new Error('Read error'));
180-
181-
const result = await apiKeyService.findAll();
182-
183-
expect(result).toHaveLength(0);
185+
vi.spyOn(apiKeyService, 'loadAllFromDisk').mockRejectedValue(new Error('Read error'));
186+
await expect(apiKeyService.onModuleInit()).rejects.toThrow('Read error');
184187
});
185188
});
186189

187190
describe('findById', () => {
188-
it('should return API key by id', async () => {
189-
vi.mocked(readFile).mockResolvedValue(JSON.stringify(mockApiKey));
191+
it('should return API key by id when found', async () => {
192+
vi.spyOn(apiKeyService, 'loadAllFromDisk').mockResolvedValue([mockApiKeyWithSecret]);
193+
await apiKeyService.onModuleInit();
194+
190195
vi.mocked(ApiKeySchema).mockReturnValue({
191196
parse: vi.fn().mockReturnValue(mockApiKey),
192197
} as any);
193198

194-
const result = await apiKeyService.findById(mockApiKey.id);
199+
const result = await apiKeyService.findById(mockApiKeyWithSecret.id);
195200

196201
expect(result).toEqual(mockApiKey);
197202
});
198203

199-
it('should return null if API key not found (ENOENT error)', async () => {
200-
const error = new Error('ENOENT') as NodeJS.ErrnoException;
201-
202-
error.code = 'ENOENT';
203-
vi.mocked(readFile).mockRejectedValue(error);
204+
it('should return null if API key not found', async () => {
205+
vi.spyOn(apiKeyService, 'loadAllFromDisk').mockResolvedValue([
206+
{ ...mockApiKeyWithSecret, id: 'different-id' },
207+
]);
208+
await apiKeyService.onModuleInit();
204209

205210
const result = await apiKeyService.findById('non-existent-id');
206211

207212
expect(result).toBeNull();
208213
});
209214

210-
it('should throw GraphQLError if JSON parsing fails', async () => {
211-
vi.mocked(readFile).mockResolvedValue('invalid json');
215+
it('should throw error if schema validation fails', async () => {
216+
vi.spyOn(apiKeyService, 'loadAllFromDisk').mockResolvedValue([mockApiKeyWithSecret]);
217+
await apiKeyService.onModuleInit();
212218

213-
await expect(apiKeyService.findById(mockApiKey.id)).rejects.toThrow(
214-
'Failed to read API key'
219+
vi.mocked(ApiKeySchema).mockReturnValue({
220+
parse: vi.fn().mockImplementation(() => {
221+
throw new ZodError([
222+
{
223+
code: 'custom',
224+
path: ['roles'],
225+
message: 'Invalid role',
226+
},
227+
]);
228+
}),
229+
} as any);
230+
231+
expect(() => apiKeyService.findById(mockApiKeyWithSecret.id)).toThrow(
232+
'Invalid API key structure'
215233
);
216234
});
217235
});
218236

219237
describe('findByIdWithSecret', () => {
220238
it('should return API key with secret when found', async () => {
221-
vi.spyOn(apiKeyService as any, 'loadAllFromDisk').mockResolvedValue([mockApiKeyWithSecret]);
239+
vi.spyOn(apiKeyService, 'loadAllFromDisk').mockResolvedValue([mockApiKeyWithSecret]);
222240
await apiKeyService.onModuleInit();
223241

224242
const result = await apiKeyService.findByIdWithSecret(mockApiKeyWithSecret.id);
@@ -227,7 +245,7 @@ describe('ApiKeyService', () => {
227245
});
228246

229247
it('should return null when API key not found', async () => {
230-
vi.spyOn(apiKeyService as any, 'loadAllFromDisk').mockResolvedValue([]);
248+
vi.spyOn(apiKeyService, 'loadAllFromDisk').mockResolvedValue([]);
231249
await apiKeyService.onModuleInit();
232250

233251
const result = await apiKeyService.findByIdWithSecret('non-existent-id');
@@ -236,28 +254,23 @@ describe('ApiKeyService', () => {
236254
});
237255

238256
it('should throw GraphQLError on invalid data structure', async () => {
239-
vi.mocked(ApiKeyWithSecretSchema).mockReturnValue({
240-
parse: vi.fn().mockImplementation(() => {
241-
throw new ZodError([]);
242-
}),
243-
} as any);
257+
vi.spyOn(apiKeyService, 'loadAllFromDisk').mockImplementation(async () => {
258+
throw new Error('Invalid API key structure');
259+
});
244260

245-
vi.spyOn(apiKeyService as any, 'loadAllFromDisk').mockResolvedValue([mockApiKeyWithSecret]);
246-
await expect(apiKeyService.onModuleInit()).rejects.toThrow('Invalid API key data structure');
261+
await expect(apiKeyService.onModuleInit()).rejects.toThrow('Invalid API key structure');
247262
});
248263

249264
it('should throw error on file read error', async () => {
250-
vi.spyOn(apiKeyService as any, 'loadAllFromDisk').mockRejectedValue(
251-
new Error('Read failed')
252-
);
265+
vi.spyOn(apiKeyService, 'loadAllFromDisk').mockRejectedValue(new Error('Read failed'));
253266
await expect(apiKeyService.onModuleInit()).rejects.toThrow('Read failed');
254267
});
255268
});
256269

257270
describe('findByKey', () => {
258271
it('should return API key by key value when multiple keys exist', async () => {
259272
const differentKey = { ...mockApiKeyWithSecret, key: 'different-key' };
260-
vi.spyOn(apiKeyService as any, 'loadAllFromDisk').mockResolvedValue([
273+
vi.spyOn(apiKeyService, 'loadAllFromDisk').mockResolvedValue([
261274
differentKey,
262275
mockApiKeyWithSecret,
263276
]);
@@ -273,7 +286,7 @@ describe('ApiKeyService', () => {
273286
});
274287

275288
it('should return null if key not found in any file', async () => {
276-
vi.spyOn(apiKeyService as any, 'loadAllFromDisk').mockResolvedValue([
289+
vi.spyOn(apiKeyService, 'loadAllFromDisk').mockResolvedValue([
277290
{ ...mockApiKeyWithSecret, key: 'different-key-1' },
278291
{ ...mockApiKeyWithSecret, key: 'different-key-2' },
279292
]);
@@ -289,7 +302,7 @@ describe('ApiKeyService', () => {
289302
});
290303

291304
it('Should throw error when API key is corrupted', async () => {
292-
vi.spyOn(apiKeyService as any, 'loadAllFromDisk').mockRejectedValue(
305+
vi.spyOn(apiKeyService, 'loadAllFromDisk').mockRejectedValue(
293306
new Error('Authentication system error: Corrupted key file')
294307
);
295308

api/src/unraid-api/auth/api-key.service.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ export class ApiKeyService implements OnModuleInit {
118118
}
119119
if (error instanceof ZodError) {
120120
this.logger.error(`Invalid API key structure in file ${file}`, error.errors);
121-
continue;
121+
throw new Error('Invalid API key structure');
122122
}
123123
this.logger.warn(`Error reading API key file ${file}: ${error}`);
124124
}
@@ -135,12 +135,20 @@ export class ApiKeyService implements OnModuleInit {
135135
}
136136

137137
findById(id: string): ApiKey | null {
138-
const key = this.findByField('id', id);
138+
try {
139+
const key = this.findByField('id', id);
139140

140-
if (key) {
141-
return ApiKeySchema().parse(key);
141+
if (key) {
142+
return ApiKeySchema().parse(key);
143+
}
144+
return null;
145+
} catch (error) {
146+
if (error instanceof ZodError) {
147+
this.logger.error('Invalid API key structure', error.errors);
148+
throw new Error('Invalid API key structure');
149+
}
150+
throw error;
142151
}
143-
return null;
144152
}
145153

146154
public findByIdWithSecret(id: string): ApiKeyWithSecret | null {

0 commit comments

Comments
 (0)