UNPKG

filecoin-pin

Version:

Bridge IPFS content to Filecoin Onchain Cloud using familiar tools

269 lines (227 loc) 7.84 kB
/** * Unit tests for calculateActualStorage * * Tests abort handling, timeout behavior, and basic calculation correctness. */ import { beforeEach, describe, expect, it, vi } from 'vitest' import { calculateActualStorage } from '../../core/data-set/calculate-actual-storage.js' import type { DataSetSummary } from '../../core/data-set/types.js' // Mock the dependencies const { mockSynapse, mockCreateStorageContext, mockGetDataSetPieces, defaultCreateStorageContext, defaultGetDataSetPieces, state, } = vi.hoisted(() => { const state = { pieces: [] as Array<{ pieceId: number; pieceCid: string; size?: number }>, } const mockGetAddress = vi.fn(async () => '0xtest-address') const defaultGetDataSetPieces = async (_synapse: any, _context: any, _options?: any) => { if (_options?.signal?.aborted) { const error = new Error('This operation was aborted') error.name = 'AbortError' throw error } const pieces = state.pieces.map((p) => ({ pieceId: p.pieceId, pieceCid: p.pieceCid, size: p.size ?? undefined, })) const totalSizeBytes = pieces.reduce((sum, p) => sum + BigInt(p.size ?? 0), 0n) return { pieces, dataSetId: _context?.dataSetId ?? 1, totalSizeBytes, warnings: [], } } const mockGetDataSetPieces = vi.fn(defaultGetDataSetPieces) const defaultCreateStorageContext = async (_synapse: any, dataSetId: number) => ({ storage: { dataSetId }, providerInfo: { id: 1 }, }) const mockCreateStorageContext = vi.fn(defaultCreateStorageContext) const mockSynapse = { getClient: () => ({ getAddress: mockGetAddress }), } return { mockSynapse, mockCreateStorageContext, mockGetDataSetPieces, defaultCreateStorageContext, defaultGetDataSetPieces, state, } }) // Mock the imports vi.mock('../../core/synapse/storage-context-helper.js', () => ({ createStorageContextFromDataSetId: mockCreateStorageContext, })) vi.mock('../../core/data-set/get-data-set-pieces.js', () => ({ getDataSetPieces: mockGetDataSetPieces, })) describe('calculateActualStorage', () => { beforeEach(() => { vi.resetAllMocks() state.pieces = [] mockCreateStorageContext.mockImplementation(defaultCreateStorageContext) mockGetDataSetPieces.mockImplementation(defaultGetDataSetPieces) }) describe('basic calculation', () => { it('should calculate total storage from multiple data sets', async () => { // Setup: 2 data sets with different piece sizes const dataSets: DataSetSummary[] = [ { dataSetId: 1, providerId: 1, serviceProvider: '0xprovider1', isLive: true, } as DataSetSummary, { dataSetId: 2, providerId: 1, serviceProvider: '0xprovider1', isLive: true, } as DataSetSummary, ] const oneGiB = 1024n * 1024n * 1024n // pieces apply to both data sets state.pieces = [ { pieceId: 1, pieceCid: 'bafy1', size: Number(oneGiB) }, { pieceId: 2, pieceCid: 'bafy2', size: Number(oneGiB) }, ] const result = await calculateActualStorage(mockSynapse as any, dataSets) expect(result.dataSetCount).toBe(2) expect(result.dataSetsProcessed).toBe(2) expect(result.totalBytes).toBe(oneGiB * 2n * 2n) // 2 pieces × 2 datasets expect(result.pieceCount).toBe(4) expect(result.timedOut).toBeFalsy() expect(result.warnings).toHaveLength(0) }) it('should handle empty data sets', async () => { const result = await calculateActualStorage(mockSynapse as any, []) expect(result.dataSetCount).toBe(0) expect(result.dataSetsProcessed).toBe(0) expect(result.totalBytes).toBe(0n) expect(result.pieceCount).toBe(0) expect(result.timedOut).toBeFalsy() }) it('should handle data sets with no pieces', async () => { const dataSets: DataSetSummary[] = [ { dataSetId: 1, providerId: 1, serviceProvider: '0xprovider1', isLive: true, } as DataSetSummary, ] state.pieces = [] const result = await calculateActualStorage(mockSynapse as any, dataSets) expect(result.dataSetCount).toBe(1) expect(result.dataSetsProcessed).toBe(1) expect(result.totalBytes).toBe(0n) expect(result.pieceCount).toBe(0) }) }) describe('abort handling', () => { it('should handle immediate abort', async () => { const dataSets: DataSetSummary[] = [ { dataSetId: 1, providerId: 1, serviceProvider: '0xprovider1', isLive: true, } as DataSetSummary, ] // Create already-aborted signal const controller = new AbortController() controller.abort() const result = await calculateActualStorage(mockSynapse as any, dataSets, { signal: controller.signal, }) expect(result.timedOut).toBe(true) expect(result.dataSetsProcessed).toBe(0) expect(result.warnings.some((w) => w.code === 'CALCULATION_ABORTED')).toBe(true) }) it('should return partial results on abort', async () => { const dataSets: DataSetSummary[] = [ { dataSetId: 1, providerId: 1, serviceProvider: '0xprovider1', isLive: true, } as DataSetSummary, { dataSetId: 2, providerId: 2, serviceProvider: '0xprovider2', isLive: true, } as DataSetSummary, ] const controller = new AbortController() // Allow first dataset to complete let callCount = 0 mockGetDataSetPieces.mockImplementation(async (_synapse: any, _context: any, _options?: any) => { callCount++ if (callCount === 1) { return { pieces: [{ pieceId: 1, pieceCid: 'bafy1', size: 1024 }], dataSetId: 1, totalSizeBytes: 1024n, warnings: [], } } controller.abort() const error = new Error('This operation was aborted') error.name = 'AbortError' throw error }) const result = await calculateActualStorage(mockSynapse as any, dataSets, { signal: controller.signal, }) expect(result.timedOut).toBe(true) expect(result.totalBytes).toBe(1024n) // Partial result from first dataset expect(result.dataSetsProcessed).toBe(1) expect(result.pieceCount).toBe(1) expect(result.warnings.some((w) => w.code === 'CALCULATION_ABORTED')).toBe(true) }) }) describe('error handling', () => { it('should continue processing other datasets when one fails', async () => { const dataSets: DataSetSummary[] = [ { dataSetId: 1, providerId: 1, serviceProvider: '0xprovider1', isLive: true, } as DataSetSummary, { dataSetId: 2, providerId: 2, serviceProvider: '0xprovider2', isLive: true, } as DataSetSummary, ] let callCount = 0 mockGetDataSetPieces.mockImplementation(async (_synapse: any, _context: any, _options?: any) => { callCount++ if (callCount === 1) { throw new Error('Dataset query failed') } return { pieces: [{ pieceId: 1, pieceCid: 'bafy1', size: 1024 }], dataSetId: 2, totalSizeBytes: 1024n, warnings: [], } }) const result = await calculateActualStorage(mockSynapse as any, dataSets) expect(result.dataSetsProcessed).toBe(1) // Only second dataset succeeded expect(result.totalBytes).toBe(1024n) expect(result.warnings.some((w) => w.code === 'DATA_SET_QUERY_FAILED')).toBe(true) }) }) })