|
| 1 | +/* eslint-env mocha */ |
| 2 | +'use strict' |
| 3 | + |
| 4 | +const fs = require('fs') |
| 5 | +const chai = require('chai') |
| 6 | +const dirtyChai = require('dirty-chai') |
| 7 | +const expect = chai.expect |
| 8 | +chai.use(dirtyChai) |
| 9 | + |
| 10 | +const DaemonFactory = require('ipfsd-ctl') |
| 11 | + |
| 12 | +const utils = require('./utils/pin-utils') |
| 13 | + |
| 14 | +describe('pin', function () { |
| 15 | + this.timeout(5 * 1000) |
| 16 | + |
| 17 | + const filePath = 'test/fixtures/planets/jupiter-from-cassini.jpg' |
| 18 | + const jupiter = [{ |
| 19 | + path: filePath, |
| 20 | + content: fs.readFileSync(filePath) |
| 21 | + }] |
| 22 | + |
| 23 | + let daemons = [] |
| 24 | + function spawnAndStart (type, repoPath = utils.tmpPath()) { |
| 25 | + return new Promise((resolve, reject) => { |
| 26 | + DaemonFactory.create({ type }) |
| 27 | + .spawn({ |
| 28 | + repoPath, |
| 29 | + disposable: false |
| 30 | + }, (err, daemon) => { |
| 31 | + if (err) return reject(err) |
| 32 | + daemons.push(daemon) |
| 33 | + |
| 34 | + if (daemon.initialized) { |
| 35 | + // repo already exists, no need to init |
| 36 | + daemon.start(err => err ? reject(err) : resolve(daemon)) |
| 37 | + } else { |
| 38 | + daemon.init((err, initRes) => { |
| 39 | + if (err) return reject(err) |
| 40 | + daemon.start(err => err ? reject(err) : resolve(daemon)) |
| 41 | + }) |
| 42 | + } |
| 43 | + }) |
| 44 | + }) |
| 45 | + } |
| 46 | + |
| 47 | + function withDaemons (pipeline) { |
| 48 | + return Promise.all([ |
| 49 | + spawnAndStart('go').then(utils.removeAllPins).then(pipeline), |
| 50 | + spawnAndStart('js').then(utils.removeAllPins).then(pipeline) |
| 51 | + ]) |
| 52 | + } |
| 53 | + |
| 54 | + afterEach(function () { |
| 55 | + this.timeout(25 * 1000) |
| 56 | + return utils.stopDaemons(daemons) |
| 57 | + .then(() => { daemons = [] }) |
| 58 | + }) |
| 59 | + |
| 60 | + describe('pin add', function () { |
| 61 | + // Pinning a large file recursively results in the same pins |
| 62 | + it('pin recursively', function () { |
| 63 | + this.timeout(30 * 1000) |
| 64 | + this.slow(30 * 1000) |
| 65 | + |
| 66 | + function pipeline (daemon) { |
| 67 | + return daemon.api.add(jupiter, { pin: false }) |
| 68 | + .then(chunks => daemon.api.pin.add(chunks[0].hash)) |
| 69 | + .then(() => daemon.api.pin.ls()) |
| 70 | + } |
| 71 | + |
| 72 | + return withDaemons(pipeline) |
| 73 | + .then(([goPins, jsPins]) => { |
| 74 | + expect(goPins.length).to.be.gt(0) |
| 75 | + expect(jsPins).to.deep.include.members(goPins) |
| 76 | + expect(goPins).to.deep.include.members(jsPins) |
| 77 | + }) |
| 78 | + }) |
| 79 | + |
| 80 | + // Pinning a large file with recursive=false results in the same direct pin |
| 81 | + it('pin directly', function () { |
| 82 | + this.timeout(30 * 1000) |
| 83 | + this.slow(20 * 1000) |
| 84 | + |
| 85 | + function pipeline (daemon) { |
| 86 | + return daemon.api.add(jupiter, { pin: false }) |
| 87 | + .then(chunks => daemon.api.pin.add(chunks[0].hash, { recursive: false })) |
| 88 | + .then(() => daemon.api.pin.ls()) |
| 89 | + } |
| 90 | + |
| 91 | + return withDaemons(pipeline) |
| 92 | + .then(([goPins, jsPins]) => { |
| 93 | + expect(goPins.length).to.be.gt(0) |
| 94 | + expect(jsPins).to.deep.include.members(goPins) |
| 95 | + expect(goPins).to.deep.include.members(jsPins) |
| 96 | + }) |
| 97 | + }) |
| 98 | + }) |
| 99 | + |
| 100 | + describe('pin rm', function () { |
| 101 | + // removing a root pin removes children as long as they're |
| 102 | + // not part of another pin's dag |
| 103 | + it('pin recursively, remove the root pin', function () { |
| 104 | + this.timeout(20 * 1000) |
| 105 | + this.slow(20 * 1000) |
| 106 | + |
| 107 | + function pipeline (daemon) { |
| 108 | + return daemon.api.add(jupiter) |
| 109 | + .then(chunks => { |
| 110 | + const testFolder = chunks.find(chunk => chunk.path === 'test') |
| 111 | + return daemon.api.pin.rm(testFolder.hash) |
| 112 | + }) |
| 113 | + .then(() => daemon.api.pin.ls()) |
| 114 | + } |
| 115 | + |
| 116 | + return withDaemons(pipeline) |
| 117 | + .then(([goPins, jsPins]) => { |
| 118 | + expect(goPins.length).to.eql(0) |
| 119 | + expect(jsPins.length).to.eql(0) |
| 120 | + }) |
| 121 | + }) |
| 122 | + |
| 123 | + // When a pin contains the root of another pin and we remove it, it is |
| 124 | + // instead kept but its type is changed to 'indirect' |
| 125 | + it('remove a child shared by multiple pins', function () { |
| 126 | + this.timeout(20 * 1000) |
| 127 | + this.slow(20 * 1000) |
| 128 | + |
| 129 | + let jupiterDir |
| 130 | + function pipeline (daemon) { |
| 131 | + return daemon.api.add(jupiter, { pin: false }) |
| 132 | + .then(chunks => { |
| 133 | + jupiterDir = jupiterDir || |
| 134 | + chunks.find(chunk => chunk.path === 'test/fixtures/planets') |
| 135 | + |
| 136 | + // by separately pinning all the DAG nodes created when adding, |
| 137 | + // dirs are pinned as type=recursive and |
| 138 | + // nested pins reference each other |
| 139 | + return daemon.api.pin.add(chunks.map(chunk => chunk.hash)) |
| 140 | + }) |
| 141 | + .then(() => daemon.api.pin.rm(jupiterDir.hash)) |
| 142 | + .then(() => daemon.api.pin.ls()) |
| 143 | + } |
| 144 | + |
| 145 | + return withDaemons(pipeline) |
| 146 | + .then(([goPins, jsPins]) => { |
| 147 | + expect(goPins.length).to.be.gt(0) |
| 148 | + expect(goPins).to.deep.include.members(jsPins) |
| 149 | + expect(jsPins).to.deep.include.members(goPins) |
| 150 | + |
| 151 | + const dirPin = goPins.find(pin => pin.hash === jupiterDir.hash) |
| 152 | + expect(dirPin.type).to.eql('indirect') |
| 153 | + }) |
| 154 | + }) |
| 155 | + }) |
| 156 | + |
| 157 | + describe('ls', function () { |
| 158 | + it('print same pins', function () { |
| 159 | + this.timeout(30 * 1000) |
| 160 | + |
| 161 | + function pipeline (daemon) { |
| 162 | + return daemon.api.add(jupiter) |
| 163 | + .then(() => daemon.api.pin.ls()) |
| 164 | + } |
| 165 | + |
| 166 | + return withDaemons(pipeline) |
| 167 | + .then(([goPins, jsPins]) => { |
| 168 | + expect(goPins.length).to.be.gt(0) |
| 169 | + expect(goPins).to.deep.include.members(jsPins) |
| 170 | + expect(jsPins).to.deep.include.members(goPins) |
| 171 | + }) |
| 172 | + }) |
| 173 | + }) |
| 174 | + |
| 175 | + describe(`go and js pinset storage are compatible`, function () { |
| 176 | + function pipeline (options) { |
| 177 | + // by starting each daemon with the same repoPath, they |
| 178 | + // will read/write pins from the same datastore. |
| 179 | + const repoPath = utils.tmpPath() |
| 180 | + const content = Buffer.from(String(Math.random())) |
| 181 | + const pins = [] |
| 182 | + |
| 183 | + return spawnAndStart(options.first, repoPath) |
| 184 | + .then(daemon => { |
| 185 | + return daemon.api.add(content) |
| 186 | + .then(() => daemon.api.pin.ls()) |
| 187 | + }) |
| 188 | + .then(ls => pins.push(ls)) |
| 189 | + .then(() => utils.stopDaemons(daemons)) |
| 190 | + .then(() => spawnAndStart(options.second, repoPath)) |
| 191 | + .then(daemon => daemon.api.pin.ls()) |
| 192 | + .then(ls => pins.push(ls)) |
| 193 | + .then(() => pins) |
| 194 | + } |
| 195 | + |
| 196 | + // js-ipfs can read pins stored by go-ipfs |
| 197 | + // tests that go's pin.flush and js' pin.load are compatible |
| 198 | + it('go -> js', function () { |
| 199 | + this.timeout(20 * 1000) |
| 200 | + this.slow(15000) |
| 201 | + |
| 202 | + return pipeline({ first: 'go', second: 'js' }) |
| 203 | + .then(([goPins, jsPins]) => { |
| 204 | + expect(goPins.length).to.be.gt(0) |
| 205 | + expect(jsPins).to.deep.include.members(goPins) |
| 206 | + expect(goPins).to.deep.include.members(jsPins) |
| 207 | + }) |
| 208 | + }) |
| 209 | + |
| 210 | + // go-ipfs can read pins stored by js-ipfs |
| 211 | + // tests that js' pin.flush and go's pin.load are compatible |
| 212 | + it.skip('js -> go', function () { |
| 213 | + // skipped because go can not be spawned on a js repo due to changes in |
| 214 | + // the DataStore config [link] |
| 215 | + this.timeout(20 * 1000) |
| 216 | + this.slow(15000) |
| 217 | + |
| 218 | + return pipeline({ first: 'js', second: 'go' }) |
| 219 | + .then(([jsPins, goPins]) => { |
| 220 | + expect(jsPins.length).to.be.gt(0) |
| 221 | + expect(goPins).to.deep.include.members(jsPins) |
| 222 | + expect(jsPins).to.deep.include.members(goPins) |
| 223 | + }) |
| 224 | + }) |
| 225 | + }) |
| 226 | +}) |
0 commit comments