Skip to content
This repository was archived by the owner on Mar 10, 2020. It is now read-only.

Commit dc0132e

Browse files
committed
feat: refs endpoint
1 parent fa21abb commit dc0132e

File tree

5 files changed

+355
-1
lines changed

5 files changed

+355
-1
lines changed

src/files-regular/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ const tests = {
1717
getPullStream: require('./get-pull-stream'),
1818
ls: require('./ls'),
1919
lsReadableStream: require('./ls-readable-stream'),
20-
lsPullStream: require('./ls-pull-stream')
20+
lsPullStream: require('./ls-pull-stream'),
21+
refs: require('./refs'),
22+
refsReadableStream: require('./refs-readable-stream'),
23+
refsPullStream: require('./refs-pull-stream')
2124
}
2225

2326
module.exports = createSuite(tests)

src/files-regular/refs-pull-stream.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/* eslint-env mocha */
2+
'use strict'
3+
4+
const pull = require('pull-stream')
5+
6+
module.exports = (createCommon, options) => {
7+
const ipfsRefs = (ipfs) => {
8+
return (path, params, cb) => {
9+
const stream = ipfs.refsPullStream(path, params)
10+
pull(stream, pull.collect(cb))
11+
}
12+
}
13+
require('./refs-tests')(createCommon, '.refsPullStream', ipfsRefs, options)
14+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/* eslint-env mocha */
2+
'use strict'
3+
4+
const concat = require('concat-stream')
5+
6+
module.exports = (createCommon, options) => {
7+
const ipfsRefs = (ipfs) => {
8+
return (path, params, cb) => {
9+
const stream = ipfs.refsReadableStream(path, params)
10+
stream.on('error', cb)
11+
stream.pipe(concat((refs) => cb(null, refs)))
12+
}
13+
}
14+
require('./refs-tests')(createCommon, '.refsReadableStream', ipfsRefs, options)
15+
}

src/files-regular/refs-tests.js

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
/* eslint-env mocha */
2+
'use strict'
3+
4+
const async = require('async')
5+
const { getDescribe, getIt, expect } = require('../utils/mocha')
6+
7+
module.exports = (createCommon, suiteName, ipfsRefs, options) => {
8+
const describe = getDescribe(options)
9+
const it = getIt(options)
10+
const common = createCommon()
11+
12+
describe(suiteName, function () {
13+
this.timeout(40 * 1000)
14+
15+
let ipfs, rootCid
16+
17+
before(function (done) {
18+
// CI takes longer to instantiate the daemon, so we need to increase the
19+
// timeout for the before step
20+
this.timeout(60 * 1000)
21+
22+
common.setup((err, factory) => {
23+
expect(err).to.not.exist()
24+
factory.spawnNode((err, node) => {
25+
expect(err).to.not.exist()
26+
ipfs = node
27+
done()
28+
})
29+
})
30+
})
31+
32+
before(function (done) {
33+
loadContent(ipfs, getMockObjects(), (err, cid) => {
34+
expect(err).to.not.exist()
35+
rootCid = cid
36+
done()
37+
})
38+
})
39+
40+
after((done) => common.teardown(done))
41+
42+
for (const [name, options] of Object.entries(getRefsTests())) {
43+
const { path, params, expected, expectError, expectTimeout } = options
44+
// eslint-disable-next-line no-loop-func
45+
it(name, function (done) {
46+
this.timeout(20 * 1000)
47+
48+
// If we're expecting a timeout, call done when it expires
49+
let timeout
50+
if (expectTimeout) {
51+
timeout = setTimeout(() => {
52+
done()
53+
done = null
54+
}, expectTimeout)
55+
}
56+
57+
// Call out to IPFS
58+
const p = (path ? path(rootCid) : rootCid)
59+
ipfsRefs(ipfs)(p, params, (err, refs) => {
60+
if (!done) {
61+
// Already timed out
62+
return
63+
}
64+
65+
if (expectError) {
66+
// Expected an error
67+
expect(err).to.exist()
68+
return done()
69+
}
70+
71+
if (expectTimeout && !err) {
72+
// Expected a timeout but there wasn't one
73+
return expect.fail('Expected timeout error')
74+
}
75+
76+
// Check there was no error and the refs match what was expected
77+
expect(err).to.not.exist()
78+
expect(refs.map(r => r.Ref)).to.eql(expected)
79+
80+
// Clear any pending timeout
81+
clearTimeout(timeout)
82+
83+
done()
84+
})
85+
})
86+
}
87+
})
88+
}
89+
90+
function getMockObjects () {
91+
return {
92+
animals: {
93+
land: {
94+
'african.txt': ['elephant', 'rhinocerous'],
95+
'americas.txt': ['ñandu', 'tapir'],
96+
'australian.txt': ['emu', 'kangaroo']
97+
},
98+
sea: {
99+
'atlantic.txt': ['dolphin', 'whale'],
100+
'indian.txt': ['cuttlefish', 'octopus']
101+
}
102+
},
103+
fruits: {
104+
'tropical.txt': ['banana', 'pineapple']
105+
},
106+
'atlantic-animals': ['dolphin', 'whale'],
107+
'mushroom.txt': ['mushroom']
108+
}
109+
}
110+
111+
function getRefsTests () {
112+
return {
113+
'prints added files': {
114+
params: {},
115+
expected: [
116+
'QmYEJ7qQNZUvBnv4SZ3rEbksagaan3sGvnUq948vSG8Z34',
117+
'QmUXzZKa3xhTauLektUiK4GiogHskuz1c57CnnoP4TgYJD',
118+
'QmYLvZrFn8KE2bcJ9UFhthScBVbbcXEgkJnnCBeKWYkpuQ',
119+
'QmRfqT4uTUgFXhWbfBZm6eZxi2FQ8pqYK5tcWRyTZ7RcgY'
120+
]
121+
},
122+
123+
'prints files in edges format': {
124+
params: { e: true },
125+
expected: [
126+
'Qmd5MhNjx3NSZm3L2QKG1TFvqkTRbtZwGJinqEfqpfHH7s -> QmYEJ7qQNZUvBnv4SZ3rEbksagaan3sGvnUq948vSG8Z34',
127+
'Qmd5MhNjx3NSZm3L2QKG1TFvqkTRbtZwGJinqEfqpfHH7s -> QmUXzZKa3xhTauLektUiK4GiogHskuz1c57CnnoP4TgYJD',
128+
'Qmd5MhNjx3NSZm3L2QKG1TFvqkTRbtZwGJinqEfqpfHH7s -> QmYLvZrFn8KE2bcJ9UFhthScBVbbcXEgkJnnCBeKWYkpuQ',
129+
'Qmd5MhNjx3NSZm3L2QKG1TFvqkTRbtZwGJinqEfqpfHH7s -> QmRfqT4uTUgFXhWbfBZm6eZxi2FQ8pqYK5tcWRyTZ7RcgY'
130+
]
131+
},
132+
133+
'prints files in custom format': {
134+
params: { format: '<linkname>: <src> => <dst>' },
135+
expected: [
136+
'animals: Qmd5MhNjx3NSZm3L2QKG1TFvqkTRbtZwGJinqEfqpfHH7s => QmYEJ7qQNZUvBnv4SZ3rEbksagaan3sGvnUq948vSG8Z34',
137+
'atlantic-animals: Qmd5MhNjx3NSZm3L2QKG1TFvqkTRbtZwGJinqEfqpfHH7s => QmUXzZKa3xhTauLektUiK4GiogHskuz1c57CnnoP4TgYJD',
138+
'fruits: Qmd5MhNjx3NSZm3L2QKG1TFvqkTRbtZwGJinqEfqpfHH7s => QmYLvZrFn8KE2bcJ9UFhthScBVbbcXEgkJnnCBeKWYkpuQ',
139+
'mushroom.txt: Qmd5MhNjx3NSZm3L2QKG1TFvqkTRbtZwGJinqEfqpfHH7s => QmRfqT4uTUgFXhWbfBZm6eZxi2FQ8pqYK5tcWRyTZ7RcgY'
140+
]
141+
},
142+
143+
'follows a path, <hash>/<subdir>': {
144+
path: (cid) => `/ipfs/${cid}/animals`,
145+
params: { format: '<linkname>' },
146+
expected: [
147+
'land',
148+
'sea'
149+
]
150+
},
151+
152+
'follows a path, <hash>/<subdir>/<subdir>': {
153+
path: (cid) => `/ipfs/${cid}/animals/land`,
154+
params: { format: '<linkname>' },
155+
expected: [
156+
'african.txt',
157+
'americas.txt',
158+
'australian.txt'
159+
]
160+
},
161+
162+
'follows a path with recursion, <hash>/<subdir>': {
163+
path: (cid) => `/ipfs/${cid}/animals`,
164+
params: { format: '<linkname>', r: true },
165+
expected: [
166+
'land',
167+
'african.txt',
168+
'americas.txt',
169+
'australian.txt',
170+
'sea',
171+
'atlantic.txt',
172+
'indian.txt'
173+
]
174+
},
175+
176+
'recursively follows folders, -r': {
177+
params: { format: '<linkname>', r: true },
178+
expected: [
179+
'animals',
180+
'land',
181+
'african.txt',
182+
'americas.txt',
183+
'australian.txt',
184+
'sea',
185+
'atlantic.txt',
186+
'indian.txt',
187+
'atlantic-animals',
188+
'fruits',
189+
'tropical.txt',
190+
'mushroom.txt'
191+
]
192+
},
193+
194+
'recursive with unique option': {
195+
params: { format: '<linkname>', r: true, u: true },
196+
expected: [
197+
'animals',
198+
'land',
199+
'african.txt',
200+
'americas.txt',
201+
'australian.txt',
202+
'sea',
203+
'atlantic.txt',
204+
'indian.txt',
205+
'fruits',
206+
'tropical.txt',
207+
'mushroom.txt'
208+
]
209+
},
210+
211+
'max depth of 1': {
212+
params: { format: '<linkname>', r: true, 'max-depth': 1 },
213+
expected: [
214+
'animals',
215+
'atlantic-animals',
216+
'fruits',
217+
'mushroom.txt'
218+
]
219+
},
220+
221+
'max depth of 2': {
222+
params: { format: '<linkname>', r: true, 'max-depth': 2 },
223+
expected: [
224+
'animals',
225+
'land',
226+
'sea',
227+
'atlantic-animals',
228+
'fruits',
229+
'tropical.txt',
230+
'mushroom.txt'
231+
]
232+
},
233+
234+
'max depth of 3': {
235+
params: { format: '<linkname>', r: true, 'max-depth': 3 },
236+
expected: [
237+
'animals',
238+
'land',
239+
'african.txt',
240+
'americas.txt',
241+
'australian.txt',
242+
'sea',
243+
'atlantic.txt',
244+
'indian.txt',
245+
'atlantic-animals',
246+
'fruits',
247+
'tropical.txt',
248+
'mushroom.txt'
249+
]
250+
},
251+
252+
'max depth of 0': {
253+
params: { r: true, 'max-depth': 0 },
254+
expected: []
255+
},
256+
257+
'follows a path with max depth 1, <hash>/<subdir>': {
258+
path: (cid) => `/ipfs/${cid}/animals`,
259+
params: { format: '<linkname>', r: true, 'max-depth': 1 },
260+
expected: [
261+
'land',
262+
'sea'
263+
]
264+
},
265+
266+
'follows a path with max depth 2, <hash>/<subdir>': {
267+
path: (cid) => `/ipfs/${cid}/animals`,
268+
params: { format: '<linkname>', r: true, 'max-depth': 2 },
269+
expected: [
270+
'land',
271+
'african.txt',
272+
'americas.txt',
273+
'australian.txt',
274+
'sea',
275+
'atlantic.txt',
276+
'indian.txt'
277+
]
278+
},
279+
280+
'cannot specify edges and format': {
281+
params: { format: '<linkname>', e: true },
282+
expectError: true
283+
},
284+
285+
'prints nothing for non-existent hashes': {
286+
path: () => 'QmYmW4HiZhotsoSqnv2o1oSssvkRM8b9RweBoH7ao5nki2',
287+
expectTimeout: 4000
288+
}
289+
}
290+
}
291+
292+
function loadContent (ipfs, node, callback) {
293+
if (Array.isArray(node)) {
294+
ipfs.object.put({ Data: node.join('\n'), Links: [] }, callback)
295+
}
296+
297+
if (typeof node === 'object') {
298+
const entries = Object.entries(node)
299+
const sorted = entries.sort((a, b) => a[0] > b[0] ? 1 : a[0] < b[0] ? -1 : 0)
300+
async.map(sorted, ([name, child], cb) => {
301+
loadContent(ipfs, child, (err, cid) => {
302+
cb(err, { name, cid: cid && cid.toString() })
303+
})
304+
}, (err, res) => {
305+
if (err) {
306+
return callback(err)
307+
}
308+
309+
ipfs.object.put({
310+
Data: '',
311+
Links: res.map(({ name, cid }) => ({ Name: name, Hash: cid, Size: 8 }))
312+
}, callback)
313+
})
314+
}
315+
}

src/files-regular/refs.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/* eslint-env mocha */
2+
'use strict'
3+
4+
module.exports = (createCommon, options) => {
5+
const ipfsRefs = (ipfs) => ipfs.refs.bind(ipfs)
6+
require('./refs-tests')(createCommon, '.refs', ipfsRefs, options)
7+
}

0 commit comments

Comments
 (0)