From 6eeb44dace9b17e8053a99c267650fd190b6ae74 Mon Sep 17 00:00:00 2001 From: achingbrain Date: Mon, 12 Feb 2024 11:29:29 +0000 Subject: [PATCH] fix: remove stubs from verified-fetch tests The extensive stubbing in the `@helia/verified-fetch` tests have some baked-in assumptions about how the codecs work which are not easy to unpick. It's quick to test using the actual codecs if the block data is already present so remove the stubs and use a network-less Helia node to make the tests more reliable. --- packages/verified-fetch/package.json | 4 + packages/verified-fetch/src/verified-fetch.ts | 48 ++- .../test/fixtures/create-offline-helia.ts | 20 + .../test/verified-fetch.spec.ts | 396 ++++++------------ 4 files changed, 188 insertions(+), 280 deletions(-) create mode 100644 packages/verified-fetch/test/fixtures/create-offline-helia.ts diff --git a/packages/verified-fetch/package.json b/packages/verified-fetch/package.json index 8945b8359..03bd4686e 100644 --- a/packages/verified-fetch/package.json +++ b/packages/verified-fetch/package.json @@ -161,12 +161,16 @@ "progress-events": "^1.0.0" }, "devDependencies": { + "@helia/utils": "^0.0.1", "@libp2p/logger": "^4.0.5", "@libp2p/peer-id-factory": "^4.0.5", "@sgtpooki/file-type": "^1.0.1", "@types/sinon": "^17.0.3", "aegir": "^42.2.2", + "blockstore-core": "^4.4.0", + "datastore-core": "^9.2.8", "helia": "^4.0.1", + "it-last": "^3.0.4", "magic-bytes.js": "^1.8.0", "sinon": "^17.0.1", "sinon-ts": "^2.0.0", diff --git a/packages/verified-fetch/src/verified-fetch.ts b/packages/verified-fetch/src/verified-fetch.ts index e513f46ad..0719a6e8d 100644 --- a/packages/verified-fetch/src/verified-fetch.ts +++ b/packages/verified-fetch/src/verified-fetch.ts @@ -9,6 +9,7 @@ import { code as dagJsonCode } from '@ipld/dag-json' import { code as dagPbCode } from '@ipld/dag-pb' import { code as jsonCode } from 'multiformats/codecs/json' import { decode, code as rawCode } from 'multiformats/codecs/raw' +import { identity } from 'multiformats/hashes/identity' import { CustomProgressEvent } from 'progress-events' import { getStreamFromAsyncIterable } from './utils/get-stream-from-async-iterable.js' import { parseResource } from './utils/parse-resource.js' @@ -62,6 +63,20 @@ function convertOptions (options?: VerifiedFetchOptions): (Omit { - const response = new Response('vnd.ipfs.ipns-record support is not implemented', { status: 501 }) + const response = notSupportedResponse('vnd.ipfs.ipns-record support is not implemented') response.headers.set('X-Content-Type-Options', 'nosniff') // see https://specs.ipfs.tech/http-gateways/path-gateway/#x-content-type-options-response-header return response } // handle vnd.ipld.car private async handleIPLDCar ({ cid, path, options }: FetchHandlerFunctionArg): Promise { - const response = new Response('vnd.ipld.car support is not implemented', { status: 501 }) + const response = notSupportedResponse('vnd.ipld.car support is not implemented') response.headers.set('X-Content-Type-Options', 'nosniff') // see https://specs.ipfs.tech/http-gateways/path-gateway/#x-content-type-options-response-header return response } @@ -113,7 +128,7 @@ export class VerifiedFetch { onProgress: options?.onProgress }) options?.onProgress?.(new CustomProgressEvent('verified-fetch:request:end', { cid, path })) - const response = new Response(JSON.stringify(result), { status: 200 }) + const response = okResponse(JSON.stringify(result)) response.headers.set('content-type', 'application/json') return response } @@ -126,7 +141,7 @@ export class VerifiedFetch { onProgress: options?.onProgress }) options?.onProgress?.(new CustomProgressEvent('verified-fetch:request:end', { cid, path })) - const response = new Response(JSON.stringify(result), { status: 200 }) + const response = okResponse(JSON.stringify(result)) response.headers.set('content-type', 'application/json') return response } @@ -139,7 +154,7 @@ export class VerifiedFetch { onProgress: options?.onProgress }) options?.onProgress?.(new CustomProgressEvent('verified-fetch:request:end', { cid, path })) - const response = new Response(result, { status: 200 }) + const response = okResponse(JSON.stringify(result)) await this.setContentType(result, path, response) return response } @@ -166,7 +181,7 @@ export class VerifiedFetch { // terminalElement = stat } catch (err: any) { this.log('error loading path %c/%s', dirCid, rootFilePath, err) - return new Response('Unable to find index.html for directory at given path. Support for directories with implicit root is not implemented', { status: 501 }) + return notSupportedResponse('Unable to find index.html for directory at given path. Support for directories with implicit root is not implemented') } finally { options?.onProgress?.(new CustomProgressEvent('verified-fetch:request:end', { cid: dirCid, path: rootFilePath })) } @@ -183,7 +198,7 @@ export class VerifiedFetch { const { stream, firstChunk } = await getStreamFromAsyncIterable(asyncIter, path ?? '', this.helia.logger, { onProgress: options?.onProgress }) - const response = new Response(stream, { status: 200 }) + const response = okResponse(stream) await this.setContentType(firstChunk, path, response) return response @@ -194,7 +209,7 @@ export class VerifiedFetch { options?.onProgress?.(new CustomProgressEvent('verified-fetch:request:start', { cid, path })) const result = await this.helia.blockstore.get(cid) options?.onProgress?.(new CustomProgressEvent('verified-fetch:request:end', { cid, path })) - const response = new Response(decode(result), { status: 200 }) + const response = okResponse(decode(result)) await this.setContentType(result, path, response) return response } @@ -261,14 +276,14 @@ export class VerifiedFetch { * These format handlers should adjust the response headers as specified in https://specs.ipfs.tech/http-gateways/path-gateway/#response-headers */ private readonly formatHandlers: Record = { - raw: async () => new Response('application/vnd.ipld.raw support is not implemented', { status: 501 }), + raw: async () => notSupportedResponse('application/vnd.ipld.raw support is not implemented'), car: this.handleIPLDCar, 'ipns-record': this.handleIPNSRecord, - tar: async () => new Response('application/x-tar support is not implemented', { status: 501 }), - 'dag-json': async () => new Response('application/vnd.ipld.dag-json support is not implemented', { status: 501 }), - 'dag-cbor': async () => new Response('application/vnd.ipld.dag-cbor support is not implemented', { status: 501 }), - json: async () => new Response('application/json support is not implemented', { status: 501 }), - cbor: async () => new Response('application/cbor support is not implemented', { status: 501 }) + tar: async () => notSupportedResponse('application/x-tar support is not implemented'), + 'dag-json': async () => notSupportedResponse('application/vnd.ipld.dag-json support is not implemented'), + 'dag-cbor': async () => notSupportedResponse('application/vnd.ipld.dag-cbor support is not implemented'), + json: async () => notSupportedResponse('application/json support is not implemented'), + cbor: async () => notSupportedResponse('application/cbor support is not implemented') } private readonly codecHandlers: Record = { @@ -276,7 +291,8 @@ export class VerifiedFetch { [dagPbCode]: this.handleDagPb, [jsonCode]: this.handleJson, [dagCborCode]: this.handleDagCbor, - [rawCode]: this.handleRaw + [rawCode]: this.handleRaw, + [identity.code]: this.handleRaw } async fetch (resource: Resource, opts?: VerifiedFetchOptions): Promise { @@ -318,7 +334,7 @@ export class VerifiedFetch { if (codecHandler != null) { response = await codecHandler.call(this, { cid, path, options, terminalElement }) } else { - return new Response(`Support for codec with code ${cid.code} is not yet implemented. Please open an issue at https://github.com/ipfs/helia/issues/new`, { status: 501 }) + return notSupportedResponse(`Support for codec with code ${cid.code} is not yet implemented. Please open an issue at https://github.com/ipfs/helia/issues/new`) } } diff --git a/packages/verified-fetch/test/fixtures/create-offline-helia.ts b/packages/verified-fetch/test/fixtures/create-offline-helia.ts new file mode 100644 index 000000000..2c6ab4afa --- /dev/null +++ b/packages/verified-fetch/test/fixtures/create-offline-helia.ts @@ -0,0 +1,20 @@ +import { Helia as HeliaClass } from '@helia/utils' +import { MemoryBlockstore } from 'blockstore-core' +import { MemoryDatastore } from 'datastore-core' +import type { Helia } from '@helia/interface' + +export async function createHelia (): Promise { + const datastore = new MemoryDatastore() + const blockstore = new MemoryBlockstore() + + const helia = new HeliaClass({ + datastore, + blockstore, + blockBrokers: [], + routers: [] + }) + + await helia.start() + + return helia +} diff --git a/packages/verified-fetch/test/verified-fetch.spec.ts b/packages/verified-fetch/test/verified-fetch.spec.ts index b36cfc488..77a4b256a 100644 --- a/packages/verified-fetch/test/verified-fetch.spec.ts +++ b/packages/verified-fetch/test/verified-fetch.spec.ts @@ -1,43 +1,56 @@ /* eslint-env mocha */ -import { type DAGCBOR } from '@helia/dag-cbor' -import { type DAGJSON } from '@helia/dag-json' +import { dagCbor } from '@helia/dag-cbor' +import { dagJson } from '@helia/dag-json' import { type IPNS } from '@helia/ipns' -import { type JSON as HeliaJSON } from '@helia/json' -import { type UnixFS } from '@helia/unixfs' +import { json } from '@helia/json' +import { unixfs, type UnixFS } from '@helia/unixfs' +import { stop } from '@libp2p/interface' import { defaultLogger } from '@libp2p/logger' import { expect } from 'aegir/chai' +import last from 'it-last' import { CID } from 'multiformats/cid' -import { encode } from 'multiformats/codecs/raw' -import sinon, { type SinonStub } from 'sinon' +import * as raw from 'multiformats/codecs/raw' +import { identity } from 'multiformats/hashes/identity' +import { sha256 } from 'multiformats/hashes/sha2' +import Sinon from 'sinon' import { stubInterface } from 'sinon-ts' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' import { VerifiedFetch } from '../src/verified-fetch.js' -import type { PathWalkerFn } from '../src/utils/walk-path' -import type { Blocks, Helia } from '@helia/interface' +import { createHelia } from './fixtures/create-offline-helia.js' +import type { Helia } from '@helia/interface' import type { Logger, ComponentLogger } from '@libp2p/interface' -import type { UnixFSDirectory, UnixFSEntry } from 'ipfs-unixfs-exporter' const testCID = CID.parse('QmQJ8fxavY54CUsxMSx9aE9Rdcmvhx8awJK2jzJp4iAqCr') -const anyOnProgressMatcher = sinon.match.any as unknown as () => void describe('@helia/verifed-fetch', () => { + let helia: Helia + + beforeEach(async () => { + helia = await createHelia() + }) + + afterEach(async () => { + await stop(helia) + }) + it('starts and stops the helia node', async () => { - const stopStub = sinon.stub() - const startStub = sinon.stub() + const helia = stubInterface({ + logger: defaultLogger() + }) const verifiedFetch = new VerifiedFetch({ - helia: stubInterface({ - start: startStub, - stop: stopStub, - logger: defaultLogger() - }) + helia }) - expect(stopStub.withArgs().callCount).to.equal(0) - expect(startStub.withArgs().callCount).to.equal(0) + + expect(helia.stop.callCount).to.equal(0) + expect(helia.start.callCount).to.equal(0) + await verifiedFetch.start() - expect(stopStub.withArgs().callCount).to.equal(0) - expect(startStub.withArgs().callCount).to.equal(1) + expect(helia.stop.callCount).to.equal(0) + expect(helia.start.callCount).to.equal(1) + await verifiedFetch.stop() - expect(stopStub.withArgs().callCount).to.equal(1) - expect(startStub.withArgs().callCount).to.equal(1) + expect(helia.stop.callCount).to.equal(1) + expect(helia.start.callCount).to.equal(1) }) describe('format not implemented', () => { @@ -97,43 +110,10 @@ describe('@helia/verifed-fetch', () => { describe('implicit format', () => { let verifiedFetch: VerifiedFetch - let unixfsStub: ReturnType> - let dagJsonStub: ReturnType> - let jsonStub: ReturnType> - let dagCborStub: ReturnType> - let pathWalkerStub: SinonStub, ReturnType> - let blockstoreStub: ReturnType> beforeEach(async () => { - blockstoreStub = stubInterface() - unixfsStub = stubInterface({ - cat: sinon.stub(), - stat: sinon.stub() - }) - dagJsonStub = stubInterface({ - // @ts-expect-error - stub errors - get: sinon.stub() - }) - jsonStub = stubInterface({ - // @ts-expect-error - stub errors - get: sinon.stub() - }) - dagCborStub = stubInterface({ - // @ts-expect-error - stub errors - get: sinon.stub() - }) - pathWalkerStub = sinon.stub, ReturnType>() verifiedFetch = new VerifiedFetch({ - helia: stubInterface({ - blockstore: blockstoreStub, - logger: defaultLogger() - }), - ipns: stubInterface(), - unixfs: unixfsStub, - dagJson: dagJsonStub, - json: jsonStub, - dagCbor: dagCborStub, - pathWalker: pathWalkerStub + helia }) }) @@ -143,256 +123,144 @@ describe('@helia/verifed-fetch', () => { it('should return raw data', async () => { const finalRootFileContent = new Uint8Array([0x01, 0x02, 0x03]) - pathWalkerStub.returns(Promise.resolve({ - ipfsRoots: [testCID], - terminalElement: { - cid: testCID, - size: BigInt(3), - depth: 1, - content: async function * () { yield finalRootFileContent }, - name: 'index.html', - path: '', - type: 'raw', - node: finalRootFileContent - } - })) - unixfsStub.cat.returns({ - [Symbol.asyncIterator]: async function * () { - yield finalRootFileContent - } - }) - const resp = await verifiedFetch.fetch(testCID) - expect(pathWalkerStub.callCount).to.equal(1) - expect(unixfsStub.cat.callCount).to.equal(1) + const cid = CID.createV1(raw.code, await sha256.digest(finalRootFileContent)) + await helia.blockstore.put(cid, finalRootFileContent) + + const resp = await verifiedFetch.fetch(`ipfs://${cid}`) expect(resp).to.be.ok() expect(resp.status).to.equal(200) + expect(resp.statusText).to.equal('OK') const data = await resp.arrayBuffer() - expect(new Uint8Array(data)).to.deep.equal(finalRootFileContent) + expect(new Uint8Array(data)).to.equalBytes(finalRootFileContent) }) - it('should look for root files when directory is returned', async () => { + it('should report progress during fetch', async () => { const finalRootFileContent = new Uint8Array([0x01, 0x02, 0x03]) - const signal = sinon.match.any as unknown as AbortSignal - const onProgress = sinon.spy() - // @ts-expect-error - stubbed type is incorrect - pathWalkerStub.onCall(0).returns(Promise.resolve({ - ipfsRoots: [testCID], - terminalElement: { - cid: testCID, - size: BigInt(3), - depth: 1, - // @ts-expect-error - stubbed type is incorrect - content: sinon.stub() as unknown as AsyncGenerator, - // @ts-expect-error - stubbed type is incorrect - unixfs: {} as unknown as UnixFS, - name: 'dirName', - path: '', - type: 'directory', - // @ts-expect-error - stubbed type is incorrect - node: {} - } satisfies UnixFSDirectory - })) - unixfsStub.stat.withArgs(testCID, { path: 'index.html', signal, onProgress: anyOnProgressMatcher }).onCall(0) - .returns(Promise.resolve({ - cid: CID.parse('Qmc3zqKcwzbbvw3MQm3hXdg8BQoFjGdZiGdAfXAyAGGdLi'), - size: 3, - type: 'raw', - fileSize: BigInt(3), - dagSize: BigInt(1), - localFileSize: BigInt(3), - localDagSize: BigInt(1), - blocks: 1 - })) - unixfsStub.cat.returns({ - [Symbol.asyncIterator]: async function * () { - yield finalRootFileContent - } - }) - unixfsStub.cat.returns({ - [Symbol.asyncIterator]: async function * () { - yield finalRootFileContent - } + const cid = CID.createV1(raw.code, await sha256.digest(finalRootFileContent)) + await helia.blockstore.put(cid, finalRootFileContent) + + const onProgress = Sinon.spy() + + await verifiedFetch.fetch(`ipfs://${cid}`, { + onProgress }) - const resp = await verifiedFetch.fetch(testCID, { onProgress }) - expect(unixfsStub.stat.callCount).to.equal(1) - expect(pathWalkerStub.callCount).to.equal(1) - expect(pathWalkerStub.getCall(0).args[1]).to.equal(`${testCID.toString()}/`) - expect(unixfsStub.cat.callCount).to.equal(1) - expect(unixfsStub.cat.withArgs(testCID).callCount).to.equal(0) - expect(unixfsStub.cat.withArgs(CID.parse('Qmc3zqKcwzbbvw3MQm3hXdg8BQoFjGdZiGdAfXAyAGGdLi'), sinon.match.any).callCount).to.equal(1) - expect(onProgress.callCount).to.equal(5) + expect(onProgress.callCount).to.equal(3) const onProgressEvents = onProgress.getCalls().map(call => call.args[0]) - expect(onProgressEvents[0]).to.include({ type: 'verified-fetch:request:start' }).and.to.have.property('detail').that.deep.equals({ - cid: testCID, - path: 'index.html' - }) - expect(onProgressEvents[1]).to.include({ type: 'verified-fetch:request:end' }).and.to.have.property('detail').that.deep.equals({ - cid: testCID, - path: 'index.html' + expect(onProgressEvents[0]).to.include({ type: 'blocks:get:blockstore:get' }).and.to.have.property('detail').that.deep.equals(cid) + expect(onProgressEvents[1]).to.include({ type: 'verified-fetch:request:start' }).and.to.have.property('detail').that.deep.equals({ + cid, + path: '' }) - expect(onProgressEvents[3]).to.include({ type: 'verified-fetch:request:end' }).and.to.have.property('detail').that.deep.equals({ - cid: CID.parse('Qmc3zqKcwzbbvw3MQm3hXdg8BQoFjGdZiGdAfXAyAGGdLi'), + expect(onProgressEvents[2]).to.include({ type: 'verified-fetch:request:end' }).and.to.have.property('detail').that.deep.equals({ + cid, path: '' }) - expect(onProgressEvents[4]).to.include({ type: 'verified-fetch:request:progress:chunk' }).and.to.have.property('detail').that.is.undefined() + }) + + it('should look for index files when directory is returned', async () => { + const finalRootFileContent = new Uint8Array([0x01, 0x02, 0x03]) + + const fs = unixfs(helia) + const res = await last(fs.addAll([{ + path: 'index.html', + content: finalRootFileContent + }], { + wrapWithDirectory: true + })) + + if (res == null) { + throw new Error('Import failed') + } + + const stat = await fs.stat(res.cid) + expect(stat.type).to.equal('directory') + + const resp = await verifiedFetch.fetch(res.cid) expect(resp).to.be.ok() expect(resp.status).to.equal(200) + expect(resp.statusText).to.equal('OK') const data = await resp.arrayBuffer() - expect(new Uint8Array(data)).to.deep.equal(finalRootFileContent) + expect(new Uint8Array(data)).to.equalBytes(finalRootFileContent) }) - it('should not call unixfs.cat if root file is not found', async () => { - const signal = sinon.match.any as unknown as AbortSignal - const onProgress = sinon.spy() - // @ts-expect-error - stubbed type is incorrect - pathWalkerStub.onCall(0).returns(Promise.resolve({ - ipfsRoots: [testCID], - terminalElement: { - cid: testCID, - size: BigInt(3), - depth: 1, - // @ts-expect-error - stubbed type is incorrect - content: sinon.stub() as unknown as AsyncGenerator, - // @ts-expect-error - stubbed type is incorrect - unixfs: {} as unknown as UnixFS, - name: 'dirName', - path: '', - type: 'directory', - // @ts-expect-error - stubbed type is incorrect - node: {} - } satisfies UnixFSDirectory + it('should return 501 if index file is not found', async () => { + const finalRootFileContent = new Uint8Array([0x01, 0x02, 0x03]) + + const fs = unixfs(helia) + const res = await last(fs.addAll([{ + path: 'not_an_index.html', + content: finalRootFileContent + }], { + wrapWithDirectory: true })) - unixfsStub.stat.withArgs(testCID, { path: 'index.html', signal, onProgress: anyOnProgressMatcher }).onCall(0).throws(new Error('not found')) - const resp = await verifiedFetch.fetch(testCID) + if (res == null) { + throw new Error('Import failed') + } - expect(unixfsStub.stat.withArgs(testCID, { path: 'index.html', signal, onProgress: anyOnProgressMatcher }).callCount).to.equal(1) - expect(unixfsStub.cat.withArgs(testCID).callCount).to.equal(0) - expect(onProgress.callCount).to.equal(0) + const stat = await fs.stat(res.cid) + expect(stat.type).to.equal('directory') + + const resp = await verifiedFetch.fetch(res.cid) expect(resp).to.be.ok() expect(resp.status).to.equal(501) + expect(resp.statusText).to.equal('Not Implemented') }) - it('should return dag-json encoded CID', async () => { - const abortSignal = new AbortController().signal - const onProgress = sinon.spy() - const cid = CID.parse('baguqeerasords4njcts6vs7qvdjfcvgnume4hqohf65zsfguprqphs3icwea') - dagJsonStub.get.withArgs(cid).returns(Promise.resolve({ + it('should handle dag-json block', async () => { + const obj = { hello: 'world' - })) - const resp = await verifiedFetch.fetch(cid, { - signal: abortSignal, - onProgress - }) - expect(unixfsStub.stat.withArgs(cid).callCount).to.equal(0) - expect(unixfsStub.cat.withArgs(cid).callCount).to.equal(0) - expect(dagJsonStub.get.withArgs(cid).callCount).to.equal(1) - expect(onProgress.callCount).to.equal(2) - const onProgressEvents = onProgress.getCalls().map(call => call.args[0]) - expect(onProgressEvents[0]).to.have.property('type', 'verified-fetch:request:start') - expect(onProgressEvents[0]).to.have.property('detail').that.deep.equals({ - cid, - path: '' - }) - expect(onProgressEvents[1]).to.have.property('type', 'verified-fetch:request:end') - expect(onProgressEvents[1]).to.have.property('detail').that.deep.equals({ - cid, - path: '' - }) + } + const j = dagJson(helia) + const cid = await j.add(obj) + + const resp = await verifiedFetch.fetch(cid) expect(resp).to.be.ok() expect(resp.status).to.equal(200) - const data = await resp.json() - expect(data).to.deep.equal({ - hello: 'world' - }) + expect(resp.statusText).to.equal('OK') + await expect(resp.json()).to.eventually.deep.equal(obj) }) - it('should return dag-cbor encoded CID', async () => { - const abortSignal = new AbortController().signal - const onProgress = sinon.spy() - const cid = CID.parse('bafyreidykglsfhoixmivffc5uwhcgshx4j465xwqntbmu43nb2dzqwfvae') - dagCborStub.get.withArgs(cid).returns(Promise.resolve(JSON.stringify({ + it('should handle dag-cbor block', async () => { + const obj = { hello: 'world' - }))) - const resp = await verifiedFetch.fetch(cid, { - signal: abortSignal, - onProgress - }) + } + const c = dagCbor(helia) + const cid = await c.add(obj) + + const resp = await verifiedFetch.fetch(cid) expect(resp).to.be.ok() expect(resp.status).to.equal(200) - expect(unixfsStub.stat.withArgs(cid).callCount).to.equal(0) - expect(unixfsStub.cat.withArgs(cid).callCount).to.equal(0) - expect(dagCborStub.get.withArgs(cid).callCount).to.equal(1) - expect(onProgress.callCount).to.equal(2) - const onProgressEvents = onProgress.getCalls().map(call => call.args[0]) - expect(onProgressEvents[0]).to.have.property('type', 'verified-fetch:request:start') - expect(onProgressEvents[0]).to.have.property('detail').that.deep.equals({ - cid, - path: '' - }) - expect(onProgressEvents[1]).to.have.property('type', 'verified-fetch:request:end') - expect(onProgressEvents[1]).to.have.property('detail').that.deep.equals({ - cid, - path: '' - }) - const data = await resp.json() - expect(data).to.deep.equal({ - hello: 'world' - }) + expect(resp.statusText).to.equal('OK') + await expect(resp.json()).to.eventually.deep.equal(obj) }) - it('should return json encoded CID', async () => { - const abortSignal = new AbortController().signal - const onProgress = sinon.spy() - const cid = CID.parse('bagaaifcavabu6fzheerrmtxbbwv7jjhc3kaldmm7lbnvfopyrthcvod4m6ygpj3unrcggkzhvcwv5wnhc5ufkgzlsji7agnmofovc2g4a3ui7ja') - jsonStub.get.withArgs(cid).returns(Promise.resolve({ + it('should handle json block', async () => { + const obj = { hello: 'world' - })) - const resp = await verifiedFetch.fetch(cid, { - signal: abortSignal, - onProgress - }) - expect(unixfsStub.stat.withArgs(cid).callCount).to.equal(0) - expect(unixfsStub.cat.withArgs(cid).callCount).to.equal(0) - expect(dagJsonStub.get.withArgs(cid).callCount).to.equal(0) - expect(jsonStub.get.withArgs(cid).callCount).to.equal(1) - const onProgressEvents = onProgress.getCalls().map(call => call.args[0]) - expect(onProgressEvents[0]).to.have.property('type', 'verified-fetch:request:start') - expect(onProgressEvents[0]).to.have.property('detail').that.deep.equals({ - cid, - path: '' - }) - expect(onProgressEvents[1]).to.have.property('type', 'verified-fetch:request:end') - expect(onProgressEvents[1]).to.have.property('detail').that.deep.equals({ - cid, - path: '' - }) + } + const j = json(helia) + const cid = await j.add(obj) + + const resp = await verifiedFetch.fetch(cid) expect(resp).to.be.ok() expect(resp.status).to.equal(200) - const data = await resp.json() - expect(data).to.deep.equal({ - hello: 'world' - }) + expect(resp.statusText).to.equal('OK') + await expect(resp.json()).to.eventually.deep.equal(obj) }) - it('should handle raw identity CID', async () => { - const abortSignal = new AbortController().signal - const onProgress = sinon.spy() - const cid = CID.parse('bafkqac3imvwgy3zao5xxe3de') - const textEncoder = new TextEncoder() - blockstoreStub.get.withArgs(cid).returns(Promise.resolve(encode(textEncoder.encode('hello world')))) - const resp = await verifiedFetch.fetch(cid, { - signal: abortSignal, - onProgress - }) + it('should handle identity CID', async () => { + const data = uint8ArrayFromString('hello world') + const cid = CID.createV1(identity.code, identity.digest(data)) + + const resp = await verifiedFetch.fetch(cid) expect(resp).to.be.ok() - // expect(resp.statusText).to.equal('OK') expect(resp.status).to.equal(200) - const data = await resp.text() - expect(data).to.equal('hello world') + expect(resp.statusText).to.equal('OK') + await expect(resp.text()).to.eventually.equal('hello world') }) }) })