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

Commit 8cbdf6c

Browse files
dirkmcAlan Shaw
authored and
Alan Shaw
committed
test: add tests for garbage collection (#462)
* test: add test for Object.links with CBOR * feat: tests for GC * test: update gc tests with new ipld api * chore: rebase onto master * fix: make gc tests work in browser
1 parent c644c83 commit 8cbdf6c

File tree

1 file changed

+190
-0
lines changed

1 file changed

+190
-0
lines changed

src/repo/gc.js

+190
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
'use strict'
33

44
const { getDescribe, getIt, expect } = require('../utils/mocha')
5+
const { DAGNode } = require('ipld-dag-pb')
56

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

0 commit comments

Comments
 (0)