@onlineapps/conn-base-storage 1.0.6 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/package.json +1 -1
  2. package/coverage/base.css +0 -224
  3. package/coverage/block-navigation.js +0 -87
  4. package/coverage/clover.xml +0 -297
  5. package/coverage/coverage-final.json +0 -6
  6. package/coverage/favicon.png +0 -0
  7. package/coverage/index.html +0 -131
  8. package/coverage/index.js.html +0 -1579
  9. package/coverage/internal-url-adapter.js.html +0 -604
  10. package/coverage/lcov-report/base.css +0 -224
  11. package/coverage/lcov-report/block-navigation.js +0 -87
  12. package/coverage/lcov-report/config.js.html +0 -244
  13. package/coverage/lcov-report/defaults.js.html +0 -214
  14. package/coverage/lcov-report/favicon.png +0 -0
  15. package/coverage/lcov-report/index.html +0 -176
  16. package/coverage/lcov-report/index.js.html +0 -2608
  17. package/coverage/lcov-report/internal-url-adapter.js.html +0 -559
  18. package/coverage/lcov-report/prettify.css +0 -1
  19. package/coverage/lcov-report/prettify.js +0 -2
  20. package/coverage/lcov-report/sharedUrlAdapter.js.html +0 -856
  21. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  22. package/coverage/lcov-report/sorter.js +0 -210
  23. package/coverage/lcov.info +0 -13
  24. package/coverage/prettify.css +0 -1
  25. package/coverage/prettify.js +0 -2
  26. package/coverage/sort-arrow-sprite.png +0 -0
  27. package/coverage/sorter.js +0 -210
  28. package/tests/component/storage.component.test.js +0 -363
  29. package/tests/integration/setup.js +0 -3
  30. package/tests/integration/storage.integration.test.js +0 -224
  31. package/tests/unit/internal-url-adapter.test.js +0 -210
  32. package/tests/unit/legacy.storage.test.js.bak +0 -614
  33. package/tests/unit/storage.extended.unit.test.js +0 -444
  34. package/tests/unit/storage.unit.test.js +0 -382
@@ -1,444 +0,0 @@
1
- /**
2
- * Extended Unit Tests for StorageConnector
3
- * Focus on increasing coverage with mocked MinIO client
4
- */
5
-
6
- const StorageConnector = require('../../src/index');
7
- const Minio = require('minio');
8
-
9
- // Minimal required MinIO config for tests (all external I/O is mocked)
10
- const MINIO_CONFIG = {
11
- endPoint: 'localhost',
12
- port: 9000,
13
- accessKey: 'test',
14
- secretKey: 'test',
15
- };
16
-
17
- // Mock MinIO client
18
- jest.mock('minio');
19
-
20
- describe('StorageConnector Extended Unit Tests @unit', () => {
21
- let storage;
22
- let mockMinioClient;
23
-
24
- beforeEach(() => {
25
- // Setup mock MinIO client
26
- mockMinioClient = {
27
- bucketExists: jest.fn(),
28
- makeBucket: jest.fn(),
29
- setBucketPolicy: jest.fn(),
30
- putObject: jest.fn(),
31
- getObject: jest.fn(),
32
- statObject: jest.fn(),
33
- listObjectsV2: jest.fn(),
34
- presignedGetUrl: jest.fn(),
35
- presignedUrl: jest.fn(), // Add missing mock method
36
- removeBucket: jest.fn()
37
- };
38
-
39
- Minio.Client.mockImplementation(() => mockMinioClient);
40
-
41
- storage = new StorageConnector({
42
- endPoint: 'localhost',
43
- port: 9000,
44
- accessKey: 'test',
45
- secretKey: 'test'
46
- });
47
- });
48
-
49
- describe('Initialization with Mocked MinIO', () => {
50
- test('should initialize and create bucket if not exists', async () => {
51
- mockMinioClient.bucketExists.mockResolvedValue(false);
52
- mockMinioClient.makeBucket.mockResolvedValue();
53
- mockMinioClient.setBucketPolicy.mockResolvedValue();
54
-
55
- await storage.initialize();
56
-
57
- expect(mockMinioClient.bucketExists).toHaveBeenCalledWith('api-storage');
58
- expect(mockMinioClient.makeBucket).toHaveBeenCalledWith('api-storage', 'us-east-1');
59
- expect(mockMinioClient.setBucketPolicy).toHaveBeenCalled();
60
- expect(storage.initialized).toBe(true);
61
- });
62
-
63
- test('should not create bucket if already exists', async () => {
64
- mockMinioClient.bucketExists.mockResolvedValue(true);
65
-
66
- await storage.initialize();
67
-
68
- expect(mockMinioClient.bucketExists).toHaveBeenCalled();
69
- expect(mockMinioClient.makeBucket).not.toHaveBeenCalled();
70
- expect(storage.initialized).toBe(true);
71
- });
72
-
73
- test('should handle initialization errors', async () => {
74
- mockMinioClient.bucketExists.mockRejectedValue(new Error('Connection failed'));
75
-
76
- await expect(storage.initialize()).rejects.toThrow('Connection failed');
77
- expect(storage.initialized).toBe(false);
78
- });
79
- });
80
-
81
- describe('Upload Operations', () => {
82
- beforeEach(async () => {
83
- mockMinioClient.bucketExists.mockResolvedValue(true);
84
- await storage.initialize();
85
- });
86
-
87
- test('should upload content with fingerprint', async () => {
88
- const content = 'Test content';
89
- mockMinioClient.statObject.mockRejectedValue({ code: 'NotFound' });
90
- mockMinioClient.putObject.mockResolvedValue({ etag: '123' });
91
-
92
- const result = await storage.uploadWithFingerprint('test-bucket', content, 'prefix');
93
-
94
- expect(result.fingerprint).toHaveLength(64);
95
- expect(result.bucket).toBe('test-bucket');
96
- expect(result.path).toContain('prefix');
97
- expect(result.existed).toBe(false);
98
- expect(mockMinioClient.putObject).toHaveBeenCalled();
99
- });
100
-
101
- test('should skip upload if object already exists', async () => {
102
- const content = 'Existing content';
103
- mockMinioClient.statObject.mockResolvedValue({ size: 100 });
104
-
105
- const result = await storage.uploadWithFingerprint('test-bucket', content);
106
-
107
- expect(result.existed).toBe(true);
108
- expect(mockMinioClient.putObject).not.toHaveBeenCalled();
109
- });
110
-
111
- test('should handle different content types', async () => {
112
- mockMinioClient.statObject.mockRejectedValue({ code: 'NotFound' });
113
- mockMinioClient.putObject.mockResolvedValue({ etag: '123' });
114
-
115
- // Test with object
116
- const objectContent = { key: 'value', nested: { data: 123 } };
117
- const result1 = await storage.uploadWithFingerprint('bucket', objectContent);
118
- expect(result1.fingerprint).toHaveLength(64);
119
-
120
- // Test with Buffer
121
- const bufferContent = Buffer.from('Buffer content');
122
- const result2 = await storage.uploadWithFingerprint('bucket', bufferContent);
123
- expect(result2.fingerprint).toHaveLength(64);
124
-
125
- // Test with string
126
- const stringContent = 'String content';
127
- const result3 = await storage.uploadWithFingerprint('bucket', stringContent);
128
- expect(result3.fingerprint).toHaveLength(64);
129
- });
130
-
131
- test('should use default bucket if not provided', async () => {
132
- mockMinioClient.statObject.mockRejectedValue({ code: 'NotFound' });
133
- mockMinioClient.putObject.mockResolvedValue({ etag: '123' });
134
-
135
- const result = await storage.uploadWithFingerprint(null, 'content');
136
-
137
- expect(result.bucket).toBe('api-storage');
138
- expect(mockMinioClient.putObject).toHaveBeenCalledWith(
139
- 'api-storage',
140
- expect.any(String),
141
- expect.any(Buffer),
142
- expect.any(Number),
143
- expect.any(Object)
144
- );
145
- });
146
-
147
- test('should handle upload errors', async () => {
148
- mockMinioClient.statObject.mockRejectedValue({ code: 'NotFound' });
149
- mockMinioClient.putObject.mockRejectedValue(new Error('Upload failed'));
150
-
151
- await expect(storage.uploadWithFingerprint('bucket', 'content'))
152
- .rejects.toThrow('Upload failed');
153
- });
154
- });
155
-
156
- describe('Download Operations', () => {
157
- beforeEach(async () => {
158
- mockMinioClient.bucketExists.mockResolvedValue(true);
159
- await storage.initialize();
160
- });
161
-
162
- test('should download and verify content', async () => {
163
- const content = 'Downloaded content';
164
- const expectedFingerprint = storage.generateFingerprint(content);
165
-
166
- // Mock async iterable stream for getObject
167
- const mockStream = {
168
- [Symbol.asyncIterator]: async function* () {
169
- yield Buffer.from(content);
170
- }
171
- };
172
-
173
- mockMinioClient.getObject.mockResolvedValue(mockStream);
174
-
175
- const result = await storage.downloadWithVerification(
176
- 'test-bucket',
177
- 'test-path',
178
- expectedFingerprint
179
- );
180
-
181
- expect(result).toBe(content);
182
- });
183
-
184
- test('should detect fingerprint mismatch', async () => {
185
- const content = 'Content';
186
- const wrongFingerprint = 'wrong'.repeat(16); // 64 chars
187
-
188
- const mockStream = {
189
- [Symbol.asyncIterator]: async function* () {
190
- yield Buffer.from(content);
191
- }
192
- };
193
-
194
- mockMinioClient.getObject.mockResolvedValue(mockStream);
195
-
196
- await expect(storage.downloadWithVerification(
197
- 'test-bucket',
198
- 'test-path',
199
- wrongFingerprint
200
- )).rejects.toThrow('Fingerprint mismatch');
201
- });
202
-
203
- test('should return cached content if available', async () => {
204
- const content = 'Cached content';
205
- const fingerprint = storage.generateFingerprint(content);
206
- const cacheKey = `test-bucket/test-path/${fingerprint}`;
207
-
208
- // Add to cache
209
- storage.contentCache.set(cacheKey, content);
210
-
211
- const result = await storage.downloadWithVerification(
212
- 'test-bucket',
213
- 'test-path',
214
- fingerprint
215
- );
216
-
217
- expect(result).toBe(content);
218
- expect(mockMinioClient.getObject).not.toHaveBeenCalled();
219
- });
220
-
221
- test('should handle download errors', async () => {
222
- mockMinioClient.getObject.mockRejectedValue(new Error('Download failed'));
223
-
224
- await expect(storage.downloadWithVerification('bucket', 'path', 'fingerprint'))
225
- .rejects.toThrow('Download failed');
226
- });
227
- });
228
-
229
- describe('List Operations', () => {
230
- beforeEach(async () => {
231
- mockMinioClient.bucketExists.mockResolvedValue(true);
232
- await storage.initialize();
233
- });
234
-
235
- test('should list objects with fingerprints', async () => {
236
- const mockObjects = [
237
- { name: 'file1-abc123.json', size: 100, lastModified: new Date() },
238
- { name: 'file2-def456.json', size: 200, lastModified: new Date() }
239
- ];
240
-
241
- const mockStream = {
242
- on: jest.fn((event, callback) => {
243
- if (event === 'data') {
244
- mockObjects.forEach(obj => callback(obj));
245
- } else if (event === 'end') {
246
- setTimeout(callback, 0);
247
- }
248
- return mockStream;
249
- })
250
- };
251
-
252
- mockMinioClient.listObjectsV2.mockReturnValue(mockStream);
253
-
254
- const result = await storage.listObjectsWithFingerprints('test-bucket', 'prefix');
255
-
256
- expect(result).toHaveLength(2);
257
- expect(result[0].name).toBe('file1-abc123.json');
258
- expect(result[0].fingerprint).toBeDefined();
259
- });
260
-
261
- test('should handle empty bucket', async () => {
262
- const mockStream = {
263
- on: jest.fn((event, callback) => {
264
- if (event === 'end') {
265
- setTimeout(callback, 0);
266
- }
267
- return mockStream;
268
- })
269
- };
270
-
271
- mockMinioClient.listObjectsV2.mockReturnValue(mockStream);
272
-
273
- const result = await storage.listObjectsWithFingerprints('test-bucket');
274
-
275
- expect(result).toEqual([]);
276
- });
277
-
278
- test('should handle list errors', async () => {
279
- const mockStream = {
280
- on: jest.fn((event, callback) => {
281
- if (event === 'error') {
282
- callback(new Error('List failed'));
283
- }
284
- return mockStream;
285
- })
286
- };
287
-
288
- mockMinioClient.listObjectsV2.mockReturnValue(mockStream);
289
-
290
- await expect(storage.listObjectsWithFingerprints('test-bucket'))
291
- .rejects.toThrow('List failed');
292
- });
293
- });
294
-
295
- describe('Presigned URLs', () => {
296
- beforeEach(async () => {
297
- mockMinioClient.bucketExists.mockResolvedValue(true);
298
- await storage.initialize();
299
- });
300
-
301
- test('should generate presigned URL', async () => {
302
- const mockUrl = 'https://minio.example.com/bucket/object?signature=xyz';
303
- mockMinioClient.presignedUrl.mockResolvedValue(mockUrl);
304
-
305
- const url = await storage.getPresignedUrl('test-bucket', 'test-object', 3600);
306
-
307
- expect(url).toBe(mockUrl);
308
- expect(mockMinioClient.presignedUrl).toHaveBeenCalledWith(
309
- 'GET',
310
- 'test-bucket',
311
- 'test-object',
312
- 3600
313
- );
314
- });
315
-
316
- test('should use default expiry', async () => {
317
- mockMinioClient.presignedUrl.mockResolvedValue('https://example.com');
318
-
319
- await storage.getPresignedUrl('bucket', 'object');
320
-
321
- expect(mockMinioClient.presignedUrl).toHaveBeenCalledWith(
322
- 'GET',
323
- 'bucket',
324
- 'object',
325
- 86400 // Default 24 hours
326
- );
327
- });
328
- });
329
-
330
- describe('Internal URL Generation', () => {
331
- test('should generate abstract internal URL', () => {
332
- storage = new StorageConnector(MINIO_CONFIG);
333
-
334
- const url = storage.getInternalUrl('bucket', 'path/to/object');
335
- expect(url).toBe('internal://storage/bucket/path/to/object');
336
- });
337
-
338
- test('should generate consistent internal URLs', () => {
339
- const storage1 = new StorageConnector(MINIO_CONFIG);
340
- const storage2 = new StorageConnector(MINIO_CONFIG);
341
-
342
- const url1 = storage1.getInternalUrl('bucket', 'object');
343
- const url2 = storage2.getInternalUrl('bucket', 'object');
344
-
345
- expect(url1).toBe(url2);
346
- expect(url1).toBe('internal://storage/bucket/object');
347
- });
348
- });
349
-
350
- describe('Bucket Operations', () => {
351
- beforeEach(() => {
352
- storage = new StorageConnector(MINIO_CONFIG);
353
- });
354
-
355
- test('should ensure bucket exists', async () => {
356
- mockMinioClient.bucketExists.mockResolvedValue(false);
357
- mockMinioClient.makeBucket.mockResolvedValue();
358
-
359
- const result = await storage.ensureBucket('new-bucket');
360
-
361
- expect(result).toBe(true);
362
- expect(mockMinioClient.makeBucket).toHaveBeenCalledWith('new-bucket', 'us-east-1');
363
- });
364
-
365
- test('should not create bucket if exists', async () => {
366
- mockMinioClient.bucketExists.mockResolvedValue(true);
367
-
368
- const result = await storage.ensureBucket('existing-bucket');
369
-
370
- expect(result).toBe(true);
371
- expect(mockMinioClient.makeBucket).not.toHaveBeenCalled();
372
- });
373
-
374
- test('should handle bucket creation errors', async () => {
375
- mockMinioClient.bucketExists.mockResolvedValue(false);
376
- mockMinioClient.makeBucket.mockRejectedValue(new Error('Permission denied'));
377
-
378
- await expect(storage.ensureBucket('bucket')).rejects.toThrow('Permission denied');
379
- });
380
- });
381
-
382
- describe('Cache Operations', () => {
383
- test('should clear all caches', () => {
384
- storage = new StorageConnector(MINIO_CONFIG);
385
-
386
- // Add items to caches
387
- storage.cache.set('key1', 'value1');
388
- storage.contentCache.set('key2', 'value2');
389
-
390
- expect(storage.cache.size).toBe(1);
391
- expect(storage.contentCache.size).toBe(1);
392
-
393
- storage.clearCache();
394
-
395
- expect(storage.cache.size).toBe(0);
396
- expect(storage.contentCache.size).toBe(0);
397
- });
398
-
399
- test('should handle cache size limits', () => {
400
- storage = new StorageConnector({ ...MINIO_CONFIG, cacheMaxSize: 2 });
401
-
402
- storage.addToCache('key1', 'value1');
403
- storage.addToCache('key2', 'value2');
404
- storage.addToCache('key3', 'value3');
405
-
406
- expect(storage.cache.size).toBe(2);
407
- expect(storage.getFromCache('key1')).toBeUndefined();
408
- expect(storage.getFromCache('key2')).toBe('value2');
409
- expect(storage.getFromCache('key3')).toBe('value3');
410
- });
411
- });
412
-
413
- describe('Error Scenarios', () => {
414
- test('should handle network errors', async () => {
415
- const networkError = new Error('ECONNREFUSED');
416
- networkError.code = 'ECONNREFUSED';
417
-
418
- mockMinioClient.bucketExists.mockRejectedValue(networkError);
419
-
420
- await expect(storage.initialize()).rejects.toThrow('ECONNREFUSED');
421
- });
422
-
423
- test('should handle invalid credentials', async () => {
424
- const authError = new Error('InvalidAccessKeyId');
425
- authError.code = 'InvalidAccessKeyId';
426
-
427
- mockMinioClient.bucketExists.mockRejectedValue(authError);
428
-
429
- await expect(storage.initialize()).rejects.toThrow('InvalidAccessKeyId');
430
- });
431
-
432
- test('should handle timeout errors', async () => {
433
- const timeoutError = new Error('RequestTimeout');
434
- timeoutError.code = 'RequestTimeout';
435
-
436
- mockMinioClient.putObject.mockRejectedValue(timeoutError);
437
- mockMinioClient.statObject.mockRejectedValue({ code: 'NotFound' });
438
-
439
- await storage.initialize();
440
- await expect(storage.uploadWithFingerprint('bucket', 'content'))
441
- .rejects.toThrow('RequestTimeout');
442
- });
443
- });
444
- });