filecoin-pin
Version:
Bridge IPFS content to Filecoin Onchain Cloud using familiar tools
184 lines (155 loc) • 5.67 kB
text/typescript
import { CID } from 'multiformats/cid'
import * as raw from 'multiformats/codecs/raw'
import { sha256 } from 'multiformats/hashes/sha2'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { createConfig } from '../../config.js'
import { FilecoinPinStore } from '../../filecoin-pin-store.js'
import { createLogger } from '../../logger.js'
// Mock Synapse service - minimal mock since unit tests don't test background processing
const mockSynapseService = {
synapse: {} as any,
storage: {} as any,
providerInfo: {
id: 1,
name: 'Mock Provider',
serviceProvider: '0x1234567890123456789012345678901234567890',
} as any,
}
// Mock the heavy dependencies
vi.mock('../../create-pinning-helia.js', () => ({
createPinningHeliaNode: vi.fn().mockResolvedValue({
helia: {
blockstore: {
get: vi.fn(),
},
pins: {
add: vi.fn(),
},
stop: vi.fn(),
},
blockstore: {
on: vi.fn(),
getStats: vi.fn().mockReturnValue({
blocksWritten: 1,
missingBlocks: new Set(),
totalSize: 100,
startTime: Date.now(),
finalized: false,
}),
finalize: vi.fn().mockResolvedValue({
blocksWritten: 1,
missingBlocks: new Set(),
totalSize: 100,
startTime: Date.now(),
finalized: true,
}),
cleanup: vi.fn(),
},
}),
}))
describe('FilecoinPinStore (Unit)', () => {
let pinStore: FilecoinPinStore
let testCID: CID
let testUser: any
beforeEach(async () => {
// Create test data
const testBlock = new TextEncoder().encode('Test block')
const hash = await sha256.digest(testBlock)
testCID = CID.create(1, raw.code, hash)
testUser = { id: 'test-user', name: 'Test User' }
// Create test config
const config = {
...createConfig(),
carStoragePath: './test-output',
privateKey: '0x0000000000000000000000000000000000000000000000000000000000000001', // Fake test key
}
const logger = createLogger(config)
// Create pin store
pinStore = new FilecoinPinStore({
config,
logger,
synapseService: mockSynapseService,
})
await pinStore.start()
})
describe('Pin Operations', () => {
it('should create a pin with queued status immediately', async () => {
const pinResult = await pinStore.pin(testUser, testCID, {
name: 'Test Pin',
meta: { test: 'metadata' },
})
expect(pinResult).toBeDefined()
expect(pinResult.id).toBeDefined()
expect(pinResult.status).toBe('queued')
expect(pinResult.pin.cid).toBe(testCID.toString())
expect(pinResult.pin.name).toBe('Test Pin')
expect(pinResult.filecoin).toBeDefined()
expect(pinResult.filecoin?.carFilePath).toContain(testCID.toString())
})
it('should handle pin updates synchronously', async () => {
const pinResult = await pinStore.pin(testUser, testCID, { name: 'Original' })
const updated = await pinStore.update(testUser, pinResult.id, {
name: 'Updated Name',
meta: { updated: 'true' },
})
expect(updated).toBeDefined()
expect(updated?.pin.name).toBe('Updated Name')
expect(updated?.pin.meta?.updated).toBe('true')
})
it('should retrieve pin by ID', async () => {
const pinResult = await pinStore.pin(testUser, testCID, { name: 'Test' })
const retrieved = await pinStore.get(testUser, pinResult.id)
expect(retrieved).toBeDefined()
expect(retrieved?.id).toBe(pinResult.id)
expect(retrieved?.pin.cid).toBe(testCID.toString())
})
it('should cancel pins', async () => {
const pinResult = await pinStore.pin(testUser, testCID, { name: 'Cancel Test' })
await pinStore.cancel(testUser, pinResult.id)
const retrieved = await pinStore.get(testUser, pinResult.id)
expect(retrieved).toBeUndefined()
})
it('should list pins with filters', async () => {
const pin1 = await pinStore.pin(testUser, testCID, { name: 'Pin 1' })
const hash2 = await sha256.digest(new TextEncoder().encode('second'))
const cid2 = CID.create(1, raw.code, hash2)
const pin2 = await pinStore.pin(testUser, cid2, { name: 'Pin 2' })
// List all
const listAll = await pinStore.list(testUser)
expect(listAll.count).toBe(2)
expect(listAll.results).toHaveLength(2)
// List by CID
const listByCid = await pinStore.list(testUser, { cid: testCID.toString() })
expect(listByCid.count).toBe(1)
expect(listByCid.results[0]?.id).toBe(pin1.id)
// List by name
const listByName = await pinStore.list(testUser, { name: 'Pin 2' })
expect(listByName.count).toBe(1)
expect(listByName.results[0]?.id).toBe(pin2.id)
// List with limit
const listWithLimit = await pinStore.list(testUser, { limit: 1 })
expect(listWithLimit.results).toHaveLength(1)
})
})
describe('Statistics', () => {
it('should start with empty active pins', () => {
const stats = pinStore.getActivePinStats()
expect(stats).toHaveLength(0)
})
})
describe('Lifecycle', () => {
it('should handle start/stop', async () => {
const config = {
...createConfig(),
privateKey: '0x0000000000000000000000000000000000000000000000000000000000000001', // Fake test key
}
const newPinStore = new FilecoinPinStore({
config,
logger: createLogger(config),
synapseService: mockSynapseService,
})
await expect(newPinStore.start()).resolves.not.toThrow()
await expect(newPinStore.stop()).resolves.not.toThrow()
})
})
})