Daniel Holmgren 4db923ca1c
Rewrite CAR implementation (#3672)
* use hand-written car writer

* tidy

* initial impl

* fix bug & compiler errors

* remove dependency

* refactor & tidy

* del old util test

* simple test fixtures

* changesets

* propagate termination

* pr feedback

* support async & sync iterables

* add dump methohd to iterator

* build branch

* fix import

* dont build branch
2025-04-02 16:57:32 -05:00

59 lines
2.0 KiB
TypeScript

import { CID } from 'multiformats/cid'
import * as ui8 from 'uint8arrays'
import { dataToCborBlock, streamToBytes, wait } from '@atproto/common'
import { CarBlock, readCarStream, writeCarStream } from '../src'
import fixtures from './car-file-fixtures.json'
describe('car', () => {
for (const fixture of fixtures) {
it('correctly writes car files', async () => {
const root = CID.parse(fixture.root)
async function* blockIter() {
for (const block of fixture.blocks) {
const cid = CID.parse(block.cid)
const bytes = ui8.fromString(block.bytes, 'base64')
yield { cid, bytes }
}
}
const carStream = writeCarStream(root, blockIter())
const car = await streamToBytes(carStream)
const carB64 = ui8.toString(car, 'base64')
expect(carB64).toEqual(fixture.car)
})
it('correctly reads carfiles', async () => {
const carStream = [ui8.fromString(fixture.car, 'base64')]
const { roots, blocks } = await readCarStream(carStream)
expect(roots.length).toBe(1)
expect(roots[0].toString()).toEqual(fixture.root)
const carBlocks: CarBlock[] = []
for await (const block of blocks) {
carBlocks.push(block)
}
expect(carBlocks.length).toEqual(fixture.blocks.length)
for (let i = 0; i < carBlocks.length; i++) {
expect(carBlocks[i].cid.toString()).toEqual(fixture.blocks[i].cid)
expect(ui8.toString(carBlocks[i].bytes, 'base64')).toEqual(
fixture.blocks[i].bytes,
)
}
})
}
it('writeCar propagates errors', async () => {
const iterate = async () => {
async function* blockIterator() {
await wait(1)
const block = await dataToCborBlock({ test: 1 })
yield block
throw new Error('Oops!')
}
const iter = writeCarStream(null, blockIterator())
for await (const _bytes of iter) {
// no-op
}
}
await expect(iterate).rejects.toThrow('Oops!')
})
})