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

Commit f64f836

Browse files
committed
feat: tests for GC
1 parent ba4f788 commit f64f836

File tree

1 file changed

+197
-0
lines changed

1 file changed

+197
-0
lines changed

src/repo/gc.js

+197
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,21 @@
11
/* eslint-env mocha */
22
'use strict'
33

4+
const { promisify } = require('es6-promisify')
45
const { getDescribe, getIt, expect } = require('../utils/mocha')
6+
const { DAGNode, DAGLink } = require('ipld-dag-pb')
7+
8+
const createDAGNode = promisify((data, links, cb) => {
9+
DAGNode.create(data, links, cb)
10+
})
11+
12+
const createDAGLink = promisify((name, size, cid, cb) => {
13+
DAGLink.create(name, size, cid, cb)
14+
})
15+
16+
const addDAGLink = promisify((node, link, cb) => {
17+
DAGNode.addLink(node, link, cb)
18+
})
519

620
module.exports = (createCommon, options) => {
721
const describe = getDescribe(options)
@@ -41,5 +55,188 @@ module.exports = (createCommon, options) => {
4155
expect(res).to.exist()
4256
})
4357
})
58+
59+
it('should clean up unpinned data', async () => {
60+
// Get initial list of local blocks
61+
const refsBeforeAdd = await ipfs.refs.local()
62+
63+
// Add some data. Note: this will implicitly pin the data, which causes
64+
// some blocks to be added for the data itself and for the pinning
65+
// information that refers to the blocks
66+
const addRes = await ipfs.add(Buffer.from('apples'))
67+
const hash = addRes[0].hash
68+
69+
// Get the list of local blocks after the add, should be bigger than
70+
// the initial list and contain hash
71+
const refsAfterAdd = await ipfs.refs.local()
72+
expect(refsAfterAdd.length).to.be.gt(refsBeforeAdd.length)
73+
expect(refsAfterAdd.map(r => r.ref)).includes(hash)
74+
75+
// Run garbage collection
76+
await ipfs.repo.gc()
77+
78+
// Get the list of local blocks after GC, should still contain the hash,
79+
// because the file is still pinned
80+
const refsAfterGc = await ipfs.refs.local()
81+
expect(refsAfterGc.map(r => r.ref)).includes(hash)
82+
83+
// Unpin the data
84+
await ipfs.pin.rm(hash)
85+
86+
// Run garbage collection
87+
await ipfs.repo.gc()
88+
89+
// The list of local blocks should now be the same as at the start
90+
const refsAfterUnpinAndGc = await ipfs.refs.local()
91+
expect(refsAfterUnpinAndGc).to.eql(refsBeforeAdd)
92+
})
93+
94+
it('should clean up removed MFS files', async () => {
95+
// Get initial list of local blocks
96+
const refsBeforeAdd = await ipfs.refs.local()
97+
98+
// Add a file to MFS
99+
await ipfs.files.write('/test', Buffer.from('oranges'), { create: true })
100+
const stats = await ipfs.files.stat('/test')
101+
expect(stats.type).to.equal('file')
102+
const hash = stats.hash
103+
104+
// Get the list of local blocks after the add, should be bigger than
105+
// the initial list and contain hash
106+
const refsAfterAdd = await ipfs.refs.local()
107+
expect(refsAfterAdd.length).to.be.gt(refsBeforeAdd.length)
108+
expect(refsAfterAdd.map(r => r.ref)).includes(hash)
109+
110+
// Run garbage collection
111+
await ipfs.repo.gc()
112+
113+
// Get the list of local blocks after GC, should still contain the hash,
114+
// because the file is in MFS
115+
const refsAfterGc = await ipfs.refs.local()
116+
expect(refsAfterGc.map(r => r.ref)).includes(hash)
117+
118+
// Remove the file
119+
await ipfs.files.rm('/test')
120+
121+
// Run garbage collection
122+
await ipfs.repo.gc()
123+
124+
// The list of local blocks should now be the same as at the start
125+
const refsAfterUnpinAndGc = await ipfs.refs.local()
126+
expect(refsAfterUnpinAndGc).to.eql(refsBeforeAdd)
127+
})
128+
129+
it('should clean up block only after unpinned and removed from MFS', async () => {
130+
// Get initial list of local blocks
131+
const refsBeforeAdd = await ipfs.refs.local()
132+
133+
// Add a file to MFS
134+
await ipfs.files.write('/test', Buffer.from('peaches'), { create: true })
135+
const stats = await ipfs.files.stat('/test')
136+
expect(stats.type).to.equal('file')
137+
const mfsFileHash = stats.hash
138+
139+
// Get the CID of the data in the file
140+
const block = await ipfs.block.get(mfsFileHash)
141+
142+
// Add the data to IPFS (which implicitly pins the data)
143+
const addRes = await ipfs.add(block.data)
144+
const dataHash = addRes[0].hash
145+
146+
// Get the list of local blocks after the add, should be bigger than
147+
// the initial list and contain the data hash
148+
const refsAfterAdd = await ipfs.refs.local()
149+
expect(refsAfterAdd.length).to.be.gt(refsBeforeAdd.length)
150+
const hashesAfterAdd = refsAfterAdd.map(r => r.ref)
151+
expect(hashesAfterAdd).includes(dataHash)
152+
153+
// Run garbage collection
154+
await ipfs.repo.gc()
155+
156+
// Get the list of local blocks after GC, should still contain the hash,
157+
// because the file is pinned and in MFS
158+
const refsAfterGc = await ipfs.refs.local()
159+
const hashesAfterGc = refsAfterGc.map(r => r.ref)
160+
expect(hashesAfterGc).includes(dataHash)
161+
162+
// Remove the file
163+
await ipfs.files.rm('/test')
164+
165+
// Run garbage collection
166+
await ipfs.repo.gc()
167+
168+
// Get the list of local blocks after GC, should still contain the hash,
169+
// because the file is still pinned
170+
const refsAfterRmAndGc = await ipfs.refs.local()
171+
const hashesAfterRmAndGc = refsAfterRmAndGc.map(r => r.ref)
172+
expect(hashesAfterRmAndGc).not.includes(mfsFileHash)
173+
expect(hashesAfterRmAndGc).includes(dataHash)
174+
175+
// Unpin the data
176+
await ipfs.pin.rm(dataHash)
177+
178+
// Run garbage collection
179+
await ipfs.repo.gc()
180+
181+
// The list of local blocks should now be the same as at the start
182+
const refsAfterUnpinAndGc = await ipfs.refs.local()
183+
expect(refsAfterUnpinAndGc).to.eql(refsBeforeAdd)
184+
})
185+
186+
it('should clean up indirectly pinned data after recursive pin removal', async () => {
187+
// Get initial list of local blocks
188+
const refsBeforeAdd = await ipfs.refs.local()
189+
190+
// Add some data
191+
const addRes = await ipfs.add(Buffer.from('pears'))
192+
const dataHash = addRes[0].hash
193+
194+
// Unpin the data
195+
await ipfs.pin.rm(dataHash)
196+
197+
// Create a link to the data from an object
198+
const link = await createDAGLink('p', addRes[0].size, dataHash)
199+
const node = await createDAGNode(Buffer.from('fruit'))
200+
const obj = await addDAGLink(node, link)
201+
202+
// Put the object into IPFS
203+
const objHash = (await ipfs.object.put(obj)).toString()
204+
205+
// Putting an object doesn't pin it
206+
expect((await ipfs.pin.ls()).map(p => p.hash)).not.includes(objHash)
207+
208+
// Get the list of local blocks after the add, should be bigger than
209+
// the initial list and contain data and object hash
210+
const refsAfterAdd = await ipfs.refs.local()
211+
expect(refsAfterAdd.length).to.be.gt(refsBeforeAdd.length)
212+
const hashesAfterAdd = refsAfterAdd.map(r => r.ref)
213+
expect(hashesAfterAdd).includes(objHash)
214+
expect(hashesAfterAdd).includes(dataHash)
215+
216+
// Recursively pin the object
217+
await ipfs.pin.add(objHash, { recursive: true })
218+
219+
// The data should now be indirectly pinned
220+
const pins = await ipfs.pin.ls()
221+
expect(pins.find(p => p.hash === dataHash).type).to.eql('indirect')
222+
223+
// Run garbage collection
224+
await ipfs.repo.gc()
225+
226+
// Get the list of local blocks after GC, should still contain the data
227+
// hash, because the data is still (indirectly) pinned
228+
const refsAfterGc = await ipfs.refs.local()
229+
expect(refsAfterGc.map(r => r.ref)).includes(dataHash)
230+
231+
// Recursively unpin the object
232+
await ipfs.pin.rm(objHash)
233+
234+
// Run garbage collection
235+
await ipfs.repo.gc()
236+
237+
// The list of local blocks should now be the same as at the start
238+
const refsAfterUnpinAndGc = await ipfs.refs.local()
239+
expect(refsAfterUnpinAndGc).to.eql(refsBeforeAdd)
240+
})
44241
})
45242
}

0 commit comments

Comments
 (0)