@@ -4,13 +4,18 @@ import (
44 "context"
55 "fmt"
66 "math"
7+ "sort"
8+ "strings"
79 "testing"
810
11+ cid "github.com/ipfs/go-cid"
912 ipld "github.com/ipfs/go-ipld-format"
1013 mdag "github.com/ipfs/go-merkledag"
1114 mdtest "github.com/ipfs/go-merkledag/test"
1215
1316 ft "github.com/ipfs/go-unixfs"
17+
18+ "github.com/stretchr/testify/assert"
1419)
1520
1621func TestEmptyNode (t * testing.T ) {
@@ -164,6 +169,14 @@ func TestBasicDirectory_estimatedSize(t *testing.T) {
164169 basicDir .estimatedSize , restoredBasicDir .estimatedSize )
165170 }
166171}
172+ // FIXME: Add a similar one for HAMT directory, stressing particularly the
173+ // deleted/overwritten entries and their computation in the size variation.
174+
175+ func mockLinkSizeFunc (fixedSize int ) func (linkName string , linkCid cid.Cid ) int {
176+ return func (_ string , _ cid.Cid ) int {
177+ return fixedSize
178+ }
179+ }
167180
168181// Basic test on extreme threshold to trigger switch. More fine-grained sizes
169182// are checked in TestBasicDirectory_estimatedSize (without the swtich itself
@@ -172,8 +185,12 @@ func TestBasicDirectory_estimatedSize(t *testing.T) {
172185// upgrade on another a better structured test should test both dimensions
173186// simultaneously.
174187func TestUpgradeableDirectory (t * testing.T ) {
188+ // FIXME: Modifying these static configuraitons is probably not
189+ // concurrent-friendly.
175190 oldHamtOption := HAMTShardingSize
176191 defer func () { HAMTShardingSize = oldHamtOption }()
192+ estimatedLinkSize = mockLinkSizeFunc (1 )
193+ defer func () { estimatedLinkSize = productionLinkSize }()
177194
178195 ds := mdtest .Mock ()
179196 dir := NewDirectory (ds )
@@ -212,23 +229,79 @@ func TestUpgradeableDirectory(t *testing.T) {
212229 if _ , ok := dir .(* UpgradeableDirectory ).Directory .(* HAMTDirectory ); ! ok {
213230 t .Fatal ("UpgradeableDirectory wasn't upgraded to HAMTDirectory for a low threshold" )
214231 }
232+ upgradedDir := copyDir (t , dir )
215233
216234 // Remove the single entry triggering the switch back to BasicDirectory
217235 err = dir .RemoveChild (ctx , "test" )
218236 if err != nil {
219237 t .Fatal (err )
220238 }
221- // For performance reasons we only switch when serializing the data
222- // in the node format and not on any entry removal.
223- _ , err = dir .GetNode ()
224- if err != nil {
225- t .Fatal (err )
226- }
227239 if _ , ok := dir .(* UpgradeableDirectory ).Directory .(* BasicDirectory ); ! ok {
228240 t .Fatal ("UpgradeableDirectory wasn't downgraded to BasicDirectory after removal of the single entry" )
229241 }
230242
231- // FIXME: Test integrity of entries in-between switches.
243+ // Check integrity between switches.
244+ // We need to account for the removed entry that triggered the switch
245+ // back.
246+ // FIXME: Abstract this for arbitrary entries.
247+ missingLink , err := ipld .MakeLink (child )
248+ assert .NoError (t , err )
249+ missingLink .Name = "test"
250+ compareDirectoryEntries (t , upgradedDir , dir , []* ipld.Link {missingLink })
251+ }
252+
253+ // Compare entries in the leftDir against the rightDir and possibly
254+ // missingEntries in the second.
255+ func compareDirectoryEntries (t * testing.T , leftDir Directory , rightDir Directory , missingEntries []* ipld.Link ) {
256+ leftLinks , err := getAllLinksSortedByName (leftDir )
257+ assert .NoError (t , err )
258+ rightLinks , err := getAllLinksSortedByName (rightDir )
259+ assert .NoError (t , err )
260+ rightLinks = append (rightLinks , missingEntries ... )
261+ sortLinksByName (rightLinks )
262+
263+ assert .Equal (t , len (leftLinks ), len (rightLinks ))
264+
265+ for i , leftLink := range leftLinks {
266+ assert .Equal (t , leftLink , rightLinks [i ]) // FIXME: Can we just compare the entire struct?
267+ }
268+ }
269+
270+ func getAllLinksSortedByName (d Directory ) ([]* ipld.Link , error ) {
271+ entries , err := d .Links (context .Background ())
272+ if err != nil {
273+ return nil , err
274+ }
275+ sortLinksByName (entries )
276+ return entries , nil
277+ }
278+
279+ func sortLinksByName (l []* ipld.Link ) {
280+ sort .SliceStable (l , func (i , j int ) bool {
281+ return strings .Compare (l [i ].Name , l [j ].Name ) == - 1 // FIXME: Is this correct?
282+ })
283+ }
284+
285+ func copyDir (t * testing.T , d Directory ) Directory {
286+ dirNode , err := d .GetNode ()
287+ assert .NoError (t , err )
288+ // Extract the DAG service from the directory (i.e., its link entries saved
289+ // in it). This is not exposed in the interface and we won't change that now.
290+ // FIXME: Still, this isn't nice.
291+ var ds ipld.DAGService
292+ switch v := d .(type ) {
293+ case * BasicDirectory :
294+ ds = v .dserv
295+ case * HAMTDirectory :
296+ ds = v .dserv
297+ case * UpgradeableDirectory :
298+ ds = v .getDagService ()
299+ default :
300+ panic ("unknown directory type" )
301+ }
302+ copiedDir , err := NewDirectoryFromNode (ds , dirNode )
303+ assert .NoError (t , err )
304+ return copiedDir
232305}
233306
234307func TestDirBuilder (t * testing.T ) {
0 commit comments