UNPKG

@ahmedhegazee/nestjs-telescope

Version:

Advanced observability and monitoring solution for NestJS applications with ML-powered analytics, enterprise features, and production-ready scaling

356 lines 15.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const file_storage_driver_1 = require("./file-storage.driver"); const fs_1 = require("fs"); const path = require("path"); jest.mock('fs', () => ({ promises: { mkdir: jest.fn(), writeFile: jest.fn(), readFile: jest.fn(), unlink: jest.fn(), readdir: jest.fn(), stat: jest.fn(), }, })); describe('FileStorageDriver', () => { let driver; const mockFs = fs_1.promises; beforeEach(async () => { jest.clearAllMocks(); mockFs.mkdir.mockResolvedValue(undefined); mockFs.readFile.mockRejectedValue(new Error('ENOENT')); driver = new file_storage_driver_1.FileStorageDriver({ file: { directory: './test-storage', }, }); await new Promise(resolve => setTimeout(resolve, 10)); }); afterEach(() => { jest.clearAllMocks(); }); describe('store', () => { it('should store a single entry', async () => { const entry = { id: 'test-id', type: 'request', familyHash: 'hash123', content: { method: 'GET', url: '/test' }, tags: ['http'], timestamp: new Date(), sequence: 1, }; mockFs.writeFile.mockResolvedValue(undefined); await driver.store(entry); expect(mockFs.writeFile).toHaveBeenCalledWith(path.join('./test-storage', 'test-id.json'), JSON.stringify(entry, null, 2)); expect(mockFs.writeFile).toHaveBeenCalledWith(path.join('./test-storage', 'index.json'), expect.stringContaining('test-id')); }); }); describe('storeBatch', () => { it('should store multiple entries', async () => { const entries = [ { id: 'test-id-1', type: 'request', familyHash: 'hash123', content: { method: 'GET', url: '/test1' }, tags: ['http'], timestamp: new Date(), sequence: 1, }, { id: 'test-id-2', type: 'request', familyHash: 'hash456', content: { method: 'POST', url: '/test2' }, tags: ['http'], timestamp: new Date(), sequence: 2, }, ]; mockFs.writeFile.mockResolvedValue(undefined); await driver.storeBatch(entries); expect(mockFs.writeFile).toHaveBeenCalledWith(path.join('./test-storage', 'test-id-1.json'), expect.any(String)); expect(mockFs.writeFile).toHaveBeenCalledWith(path.join('./test-storage', 'test-id-2.json'), expect.any(String)); }); }); describe('find', () => { it('should find entries with type filter', async () => { const entry = { id: 'test-id', type: 'request', familyHash: 'hash123', content: { method: 'GET', url: '/test' }, tags: ['http'], timestamp: new Date().toISOString(), sequence: 1, }; const indexData = { 'test-id': { filename: 'test-id.json', type: 'request', timestamp: entry.timestamp, tags: entry.tags, familyHash: entry.familyHash, sequence: entry.sequence, }, }; mockFs.readFile .mockResolvedValueOnce(JSON.stringify(indexData)) .mockResolvedValueOnce(JSON.stringify(entry)); const result = await driver.find({ type: 'request', limit: 10 }); expect(result.entries).toHaveLength(1); expect(result.total).toBe(1); expect(result.hasMore).toBe(false); expect(result.entries[0].type).toBe('request'); }); it('should find entries with tag filter', async () => { const entry = { id: 'test-id', type: 'request', familyHash: 'hash123', content: { method: 'GET', url: '/test' }, tags: ['http', 'api'], timestamp: new Date().toISOString(), sequence: 1, }; const indexData = { 'test-id': { filename: 'test-id.json', type: 'request', timestamp: entry.timestamp, tags: entry.tags, familyHash: entry.familyHash, sequence: entry.sequence, }, }; mockFs.readFile .mockResolvedValueOnce(JSON.stringify(indexData)) .mockResolvedValueOnce(JSON.stringify(entry)); const result = await driver.find({ tags: ['http'], limit: 10 }); expect(result.entries).toHaveLength(1); expect(result.entries[0].tags).toContain('http'); }); it('should find entries with date range filter', async () => { const now = new Date(); const entry = { id: 'test-id', type: 'request', familyHash: 'hash123', content: { method: 'GET', url: '/test' }, tags: ['http'], timestamp: now.toISOString(), sequence: 1, }; const indexData = { 'test-id': { filename: 'test-id.json', type: 'request', timestamp: now.toISOString(), tags: entry.tags, familyHash: entry.familyHash, sequence: entry.sequence, }, }; mockFs.readFile .mockResolvedValueOnce(JSON.stringify(indexData)) .mockResolvedValueOnce(JSON.stringify(entry)); const dateFrom = new Date(now.getTime() - 60 * 60 * 1000); const dateTo = new Date(now.getTime() + 60 * 60 * 1000); const result = await driver.find({ dateFrom, dateTo, limit: 10 }); expect(result.entries).toHaveLength(1); }); it('should handle pagination', async () => { const entries = Array.from({ length: 15 }, (_, i) => ({ id: `test-id-${i}`, type: 'request', familyHash: `hash${i}`, content: { method: 'GET', url: `/test${i}` }, tags: ['http'], timestamp: new Date().toISOString(), sequence: i + 1, })); const indexData = entries.reduce((acc, entry) => { acc[entry.id] = { filename: `${entry.id}.json`, type: entry.type, timestamp: entry.timestamp, tags: entry.tags, familyHash: entry.familyHash, sequence: entry.sequence, }; return acc; }, {}); mockFs.readFile .mockResolvedValueOnce(JSON.stringify(indexData)) .mockImplementation((filepath) => { const filename = path.basename(filepath); const entryId = filename.replace('.json', ''); const entry = entries.find(e => e.id === entryId); return Promise.resolve(JSON.stringify(entry)); }); const result = await driver.find({ offset: 5, limit: 10 }); expect(result.entries).toHaveLength(10); expect(result.total).toBe(15); expect(result.hasMore).toBe(false); }); }); describe('findById', () => { it('should find entry by id', async () => { const entry = { id: 'test-id', type: 'request', familyHash: 'hash123', content: { method: 'GET', url: '/test' }, tags: ['http'], timestamp: new Date().toISOString(), sequence: 1, }; const indexData = { 'test-id': { filename: 'test-id.json', type: 'request', timestamp: entry.timestamp, tags: entry.tags, familyHash: entry.familyHash, sequence: entry.sequence, }, }; mockFs.readFile .mockResolvedValueOnce(JSON.stringify(indexData)) .mockResolvedValueOnce(JSON.stringify(entry)); const result = await driver.findById('test-id'); expect(result).toEqual(entry); }); it('should return null if entry not found', async () => { const indexData = {}; mockFs.readFile.mockResolvedValueOnce(JSON.stringify(indexData)); const result = await driver.findById('non-existent'); expect(result).toBeNull(); }); }); describe('delete', () => { it('should delete entry by id', async () => { const indexData = { 'test-id': { filename: 'test-id.json', type: 'request', timestamp: new Date().toISOString(), tags: ['http'], familyHash: 'hash123', sequence: 1, }, }; mockFs.readFile.mockResolvedValueOnce(JSON.stringify(indexData)); mockFs.unlink.mockResolvedValue(undefined); mockFs.writeFile.mockResolvedValue(undefined); const result = await driver.delete('test-id'); expect(result).toBe(true); expect(mockFs.unlink).toHaveBeenCalledWith(path.join('./test-storage', 'test-id.json')); }); it('should return false if entry not found', async () => { const indexData = {}; mockFs.readFile.mockResolvedValueOnce(JSON.stringify(indexData)); const result = await driver.delete('non-existent'); expect(result).toBe(false); }); }); describe('clear', () => { it('should clear all entries', async () => { const indexData = { 'test-id-1': { filename: 'test-id-1.json' }, 'test-id-2': { filename: 'test-id-2.json' }, }; mockFs.readFile.mockResolvedValueOnce(JSON.stringify(indexData)); mockFs.readdir.mockResolvedValue(['test-id-1.json', 'test-id-2.json', 'index.json']); mockFs.unlink.mockResolvedValue(undefined); mockFs.writeFile.mockResolvedValue(undefined); await driver.clear(); expect(mockFs.unlink).toHaveBeenCalledWith(path.join('./test-storage', 'test-id-1.json')); expect(mockFs.unlink).toHaveBeenCalledWith(path.join('./test-storage', 'test-id-2.json')); expect(mockFs.writeFile).toHaveBeenCalledWith(path.join('./test-storage', 'index.json'), '{}'); }); }); describe('prune', () => { it('should prune old entries', async () => { const now = new Date(); const oldDate = new Date(now.getTime() - 2 * 24 * 60 * 60 * 1000); const recentDate = new Date(now.getTime() - 1 * 60 * 60 * 1000); const indexData = { 'old-entry': { filename: 'old-entry.json', type: 'request', timestamp: oldDate.toISOString(), tags: ['http'], familyHash: 'hash1', sequence: 1, }, 'recent-entry': { filename: 'recent-entry.json', type: 'request', timestamp: recentDate.toISOString(), tags: ['http'], familyHash: 'hash2', sequence: 2, }, }; mockFs.readFile.mockResolvedValueOnce(JSON.stringify(indexData)); mockFs.unlink.mockResolvedValue(undefined); mockFs.writeFile.mockResolvedValue(undefined); const olderThan = new Date(now.getTime() - 24 * 60 * 60 * 1000); const result = await driver.prune(olderThan); expect(result).toBe(1); expect(mockFs.unlink).toHaveBeenCalledWith(path.join('./test-storage', 'old-entry.json')); expect(mockFs.unlink).not.toHaveBeenCalledWith(path.join('./test-storage', 'recent-entry.json')); }); }); describe('getStats', () => { it('should return storage statistics', async () => { const now = new Date(); const indexData = { 'entry-1': { filename: 'entry-1.json', type: 'request', timestamp: now.toISOString(), tags: ['http'], familyHash: 'hash1', sequence: 1, }, 'entry-2': { filename: 'entry-2.json', type: 'query', timestamp: new Date(now.getTime() - 60 * 60 * 1000).toISOString(), tags: ['db'], familyHash: 'hash2', sequence: 2, }, }; mockFs.readFile.mockResolvedValueOnce(JSON.stringify(indexData)); mockFs.readdir.mockResolvedValue(['entry-1.json', 'entry-2.json', 'index.json']); mockFs.stat.mockResolvedValue({ size: 1024 }); const result = await driver.getStats(); expect(result.totalEntries).toBe(2); expect(result.entriesByType).toEqual({ request: 1, query: 1 }); expect(result.oldestEntry).toBeInstanceOf(Date); expect(result.newestEntry).toBeInstanceOf(Date); expect(result.sizeInBytes).toBe(3072); }); }); describe('healthCheck', () => { it('should return true when file system is healthy', async () => { mockFs.writeFile.mockResolvedValue(undefined); mockFs.readFile.mockResolvedValue('{"test":true}'); mockFs.unlink.mockResolvedValue(undefined); const result = await driver.healthCheck(); expect(result).toBe(true); expect(mockFs.writeFile).toHaveBeenCalledWith(path.join('./test-storage', 'health-check.json'), '{"test":true}'); }); it('should return false when file system is unhealthy', async () => { mockFs.writeFile.mockRejectedValue(new Error('Permission denied')); const result = await driver.healthCheck(); expect(result).toBe(false); }); }); }); //# sourceMappingURL=file-storage.driver.spec.js.map