From 439dbc54aeb0bedab615f2940163ae263ef13000 Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Thu, 7 Mar 2024 10:22:25 -0800 Subject: [PATCH] fix(ipfs): Increased adapter to 100% unit test coverage --- src/adapters/ipfs/ipfs.js | 38 ++++++++---- test/unit/adapters/ipfs.adapter.unit.js | 79 +++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 11 deletions(-) diff --git a/src/adapters/ipfs/ipfs.js b/src/adapters/ipfs/ipfs.js index 9ec6d04..6b7839f 100644 --- a/src/adapters/ipfs/ipfs.js +++ b/src/adapters/ipfs/ipfs.js @@ -52,6 +52,8 @@ class IpfsAdapter { this.publicIp = publicIpv4 this.multiaddr = multiaddr this.jsonFiles = new JsonFiles() + this.keychain = keychain + this.createHelia = createHelia // Properties of this class instance. this.isReady = false @@ -62,6 +64,7 @@ class IpfsAdapter { this.stop = this.stop.bind(this) this.ensureBlocksDir = this.ensureBlocksDir.bind(this) this.getSeed = this.getSeed.bind(this) + this.getKeychain = this.getKeychain.bind(this) } // Start an IPFS node. @@ -107,6 +110,19 @@ class IpfsAdapter { } } + async getKeychain (datastore) { + const keychainInit = { + pass: await this.getSeed() + } + + const chain = this.keychain(keychainInit)({ + datastore, + logger: defaultLogger() + }) + + return chain + } + // This function creates an IPFS node using Helia. // It returns the node as an object. async createNode () { @@ -115,18 +131,18 @@ class IpfsAdapter { const blockstore = new FsBlockstore(`${IPFS_DIR}/blockstore`) const datastore = new FsDatastore(`${IPFS_DIR}/datastore`) - // TODO: Replace this with a random string generator. - // const keychainInit = await this.getSeed() - const keychainInit = { - pass: await this.getSeed() - } + // const keychainInit = { + // pass: await this.getSeed() + // } // Create an identity let peerId - const chain = keychain(keychainInit)({ - datastore, - logger: defaultLogger() - }) + // console.log('this.keychain: ', this.keychain) + // const chain = this.keychain(keychainInit)({ + // datastore, + // logger: defaultLogger() + // }) + const chain = await this.getKeychain(datastore) try { peerId = await chain.exportPeerId('myKey') } catch (err) { @@ -201,7 +217,7 @@ class IpfsAdapter { }) // create a Helia node - const helia = await createHelia({ + const helia = await this.createHelia({ blockstore, datastore, libp2p @@ -263,7 +279,7 @@ class IpfsAdapter { return seed } catch (err) { - console.error('Error in getSeed()') + console.error('Error in adapters/ipfs/ipfs.js/getSeed()') throw err } } diff --git a/test/unit/adapters/ipfs.adapter.unit.js b/test/unit/adapters/ipfs.adapter.unit.js index 6097beb..5930abb 100644 --- a/test/unit/adapters/ipfs.adapter.unit.js +++ b/test/unit/adapters/ipfs.adapter.unit.js @@ -6,6 +6,7 @@ import { assert } from 'chai' import sinon from 'sinon' import cloneDeep from 'lodash.clonedeep' +import { peerIdFromString } from '@libp2p/peer-id' // Local libraries import IPFSLib from '../../../src/adapters/ipfs/ipfs.js' @@ -159,5 +160,83 @@ describe('#IPFS-adapter', () => { // Stop the IPFS node await result.stop() }) + + it('should create a new private key on first run', async () => { + uut.config.isCircuitRelay = false + + // Mock dependencies and force desired code path. + let beenCalled = false + sandbox.stub(uut, 'getKeychain').resolves({ + exportPeerId: async () => { + if (!beenCalled) { + beenCalled = true + throw new Error('test error') + } + return peerIdFromString('12D3KooWSXF1PnEfiA8bCG8SJduCvzdwHtvhVPK4WC6zzDoto2XP') + }, + createKey: async () => {} + }) + sandbox.stub(uut, 'createLibp2p').resolves() + sandbox.stub(uut, 'createHelia').resolves(true) + + const result = await uut.createNode() + // console.log('result: ', result) + + assert.equal(result, true) + }) + + it('should not use circuit relay when CONNECT_PREF is set to direct', async () => { + process.env.CONNECT_PREF = 'direct' + + uut.config.isCircuitRelay = false + const result = await uut.createNode() + // console.log('result: ', result) + + delete process.env.CONNECT_PREF + + // Assert the returned IPFS node has expected properties + assert.property(result, 'libp2p') + assert.property(result, 'blockstore') + + // Stop the IPFS node + await result.stop() + }) + }) + + describe('#getSeed', () => { + it('should read the seed from the JSON file', async () => { + // Mock dependencies and force desired code path + sandbox.stub(uut.jsonFiles, 'readJSON').resolves('12345678') + + const result = await uut.getSeed() + // console.log('result: ', result) + + assert.isString(result) + }) + + it('should generate a new seed if the JSON file is not found', async () => { + // Mock dependencies and force desired code path + sandbox.stub(uut.jsonFiles, 'readJSON').rejects(new Error('test error')) + sandbox.stub(uut.jsonFiles, 'writeJSON').resolves() + + const result = await uut.getSeed() + // console.log('result: ', result) + + assert.isString(result) + }) + + it('should catch, report, and throw errors', async () => { + try { + // Force an error + sandbox.stub(uut.jsonFiles, 'readJSON').rejects(new Error('test error')) + sandbox.stub(uut.jsonFiles, 'writeJSON').rejects(new Error('test error')) + + await uut.getSeed() + + assert.fail('Unexpected code path') + } catch (err) { + assert.include(err.message, 'test error') + } + }) }) })