]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/test/test_filetree_new.py
79114ce57d7351e8435b516edf8564787b9351ea
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / test / test_filetree_new.py
1
2 from zope.interface import implements
3 from twisted.trial import unittest
4 from twisted.internet import defer
5 from allmydata.interfaces import IDownloader, IUploader
6 #from allmydata.filetree.directory import (ImmutableDirectorySubTree,
7 #                                          SubTreeNode,
8 #                                          CHKDirectorySubTree)
9 #from allmydata.filetree.specification import (CHKFileSpecification,
10 #                                              CHKDirectorySpecification)
11 from allmydata import workqueue
12 from cStringIO import StringIO
13
14 class FakeMesh(object):
15     implements(IDownloader, IUploader)
16
17 """
18 class FakeOpener(object):
19     implements(IOpener)
20     def __init__(self, objects={}):
21         self.objects = objects
22     def open(self, subtree_specification, parent_is_mutable):
23         #print "open", subtree_specification, subtree_specification.serialize(), parent_is_mutable
24         return defer.succeed(self.objects[subtree_specification.serialize()])
25
26
27 class FakeWorkQueue(object):
28     implements(workqueue.IWorkQueue)
29     def __init__(self):
30         self.first_commands = []
31         self.last_commands = []
32         self.tempfile_number = 0
33         self.boxname_number = 0
34     def dump_commands(self):
35         return self.first_commands + self.last_commands
36     def clear_commands(self):
37         self.first_commands = []
38         self.last_commands = []
39
40     def create_tempfile(self, suffix=""):
41         self.tempfile_number += 1
42         self.first_commands.append("create_tempfile-%d" % self.tempfile_number)
43         return (StringIO(), "dummy_filename-%d" % self.tempfile_number)
44     def create_boxname(self):
45         self.boxname_number += 1
46         self.first_commands.append("create_boxname-%d" % self.boxname_number)
47         return "dummy_boxname-%d" % self.boxname_number
48     def add_upload_chk(self, source_filename, stash_uri_in_boxname):
49         self.first_commands.append(("upload_chk", source_filename,
50                                     stash_uri_in_boxname))
51     def add_upload_ssk(self, source_filename, write_capability,
52                        previous_version):
53         self.first_commands.append(("upload_ssk", source_filename,
54                                     write_capability, previous_version))
55     def add_retain_ssk(self, read_capability):
56         self.last_commands.append(("retain_ssk", read_capability))
57     def add_unlink_ssk(self, write_capability):
58         self.last_commands.append(("unlink_ssk", write_capability))
59     def add_retain_uri_from_box(self, boxname):
60         self.last_commands.append(("retain_uri_from_box", boxname))
61     def add_addpath(self, boxname, path):
62         self.first_commands.append(("addpath", boxname, path))
63     def add_unlink_uri(self, uri):
64         self.last_commands.append(("unlink_uri", uri))
65     def add_delete_tempfile(self, filename):
66         self.first_commands.append(("delete_tempfile", filename))
67     def add_delete_box(self, boxname):
68         self.last_commands.append(("delete_box", boxname))
69
70
71
72 class OneSubTree(unittest.TestCase):
73     def test_create_empty_immutable(self):
74         st = ImmutableDirectorySubTree()
75         st.new()
76         self.failIf(st.is_mutable())
77         d = st.get([], FakeOpener())
78         def _got_root(root):
79             self.failUnless(IDirectoryNode.providedBy(root))
80             self.failUnlessEqual(root.list(), [])
81         d.addCallback(_got_root)
82         return d
83
84     def test_immutable_1(self):
85         st = ImmutableDirectorySubTree()
86         st.new()
87         # now populate it (by modifying the internal data structures) with
88         # some internal directories
89         one = SubTreeNode(st)
90         two = SubTreeNode(st)
91         three = SubTreeNode(st)
92         st.root.node_children["one"] = one
93         st.root.node_children["two"] = two
94         two.node_children["three"] = three
95
96         # now examine it
97         self.failIf(st.is_mutable())
98         o = FakeOpener()
99         d = st.get([], o)
100         def _got_root(root):
101             self.failUnless(IDirectoryNode.providedBy(root))
102             self.failUnlessEqual(root.list(), ["one", "two"])
103         d.addCallback(_got_root)
104         d.addCallback(lambda res: st.get(["one"], o))
105         def _got_one(_one):
106             self.failUnlessIdentical(one, _one)
107             self.failUnless(IDirectoryNode.providedBy(_one))
108             self.failUnlessEqual(_one.list(), [])
109         d.addCallback(_got_one)
110         d.addCallback(lambda res: st.get(["two"], o))
111         def _got_two(_two):
112             self.failUnlessIdentical(two, _two)
113             self.failUnless(IDirectoryNode.providedBy(_two))
114             self.failUnlessEqual(_two.list(), ["three"])
115         d.addCallback(_got_two)
116         d.addCallback(lambda res: st.get(["two", "three"], o))
117         def _got_three(_three):
118             self.failUnlessIdentical(three, _three)
119             self.failUnless(IDirectoryNode.providedBy(_three))
120             self.failUnlessEqual(_three.list(), [])
121         d.addCallback(_got_three)
122         d.addCallback(lambda res: st.get(["missing"], o))
123         d.addCallback(self.failUnlessEqual, None)
124         return d
125
126     def test_mutable_1(self):
127         o = FakeOpener()
128         wq = FakeWorkQueue()
129         st = MutableCHKDirectorySubTree()
130         st.new()
131         st.set_uri(None)
132         self.failUnless(st.is_mutable())
133         d = st.get([], o)
134         def _got_root(root):
135             self.failUnless(IDirectoryNode.providedBy(root))
136             self.failUnlessEqual(root.list(), [])
137         d.addCallback(_got_root)
138         file_three = CHKFileSpecification()
139         file_three.set_uri("file_three_uri")
140         d.addCallback(lambda res: st.add(["one", "two", "three"], file_three,
141                                          o, wq))
142         d.addCallback(lambda res: st.get(["one"], o))
143         def _got_one(one):
144             self.failUnless(IDirectoryNode.providedBy(one))
145             self.failUnlessEqual(one.list(), ["two"])
146         d.addCallback(_got_one)
147         d.addCallback(lambda res: st.get(["one", "two"], o))
148         def _got_two(two):
149             self.failUnless(IDirectoryNode.providedBy(two))
150             self.failUnlessEqual(two.list(), ["three"])
151             self.failUnlessIdentical(two.child_specifications["three"],
152                                      file_three)
153         d.addCallback(_got_two)
154         return d
155
156     def test_addpath(self):
157         o = FakeOpener()
158         wq = FakeWorkQueue()
159         st = MutableCHKDirectorySubTree()
160         st.new()
161         st.set_uri(None)
162         file_three = CHKFileSpecification()
163         file_three.set_uri("file_three_uri")
164         d = st.add(["one", "two", "three"], file_three, o, wq)
165         def _done(res):
166             expected = [
167                 "create_tempfile-1",
168                 "create_boxname-1",
169                 ('upload_chk', 'dummy_filename-1', 'dummy_boxname-1'),
170                 ('delete_tempfile', 'dummy_filename-1'),
171                 ('addpath', 'dummy_boxname-1', []),
172                 ('retain_uri_from_box', 'dummy_boxname-1'),
173                 ('delete_box', 'dummy_boxname-1'),
174                 ('unlink_uri', None),
175                 ]
176             self.failUnlessEqual(wq.dump_commands(), expected)
177             #print
178             #for c in wq.dump_commands():
179             #    print c
180         d.addCallback(_done)
181         return d
182
183     def test_serialize(self):
184         st = ImmutableDirectorySubTree()
185         st.new()
186         one = SubTreeNode(st)
187         two = SubTreeNode(st)
188         three = SubTreeNode(st)
189         st.root.node_children["one"] = one
190         st.root.node_children["two"] = two
191         two.node_children["three"] = three
192         file_four = CHKFileSpecification()
193         file_four.set_uri("file_four_uri")
194         two.child_specifications["four"] = file_four
195         data = st.serialize()
196         st_new = ImmutableDirectorySubTree()
197         st_new.unserialize(data)
198
199         st_four = ImmutableDirectorySubTree()
200         st_four.new()
201         st_four.root.node_children["five"] = SubTreeNode(st_four)
202
203         o = FakeOpener({("CHK-File", "file_four_uri"): st_four})
204         d = st.get([], o)
205         def _got_root(root):
206             self.failUnless(IDirectoryNode.providedBy(root))
207             self.failUnlessEqual(root.list(), ["one", "two"])
208         d.addCallback(_got_root)
209         d.addCallback(lambda res: st.get(["two"], o))
210         def _got_two(_two):
211             self.failUnless(IDirectoryNode.providedBy(_two))
212             self.failUnlessEqual(_two.list(), ["four", "three"])
213         d.addCallback(_got_two)
214
215         d.addCallback(lambda res: st.get(["two", "four"], o))
216         def _got_four(_four):
217             self.failUnless(IDirectoryNode.providedBy(_four))
218             self.failUnlessEqual(_four.list(), ["five"])
219         d.addCallback(_got_four)
220
221 class MultipleSubTrees(unittest.TestCase):
222
223     def test_open(self):
224         st = ImmutableDirectorySubTree()
225         st.new()
226         # populate it with some internal directories and child links and see
227         # if we can follow them
228         one = SubTreeNode(st)
229         two = SubTreeNode(st)
230         three = SubTreeNode(st)
231         st.root.node_children["one"] = one
232         st.root.node_children["two"] = two
233         two.node_children["three"] = three
234
235     def test_addpath(self):
236         wq = FakeWorkQueue()
237         st1 = MutableCHKDirectorySubTree()
238         st1.new()
239         st1.set_uri(None)
240         one = SubTreeNode(st1)
241         two = SubTreeNode(st1)
242         st1.root.node_children["one"] = one
243         one.node_children["two"] = two
244         three = CHKDirectorySpecification()
245         three.set_uri("dir_three_uri")
246         two.child_specifications["three"] = three
247
248         st2 = MutableCHKDirectorySubTree()
249         st2.new()
250         st2.set_uri(None)
251         four = SubTreeNode(st2)
252         five = SubTreeNode(st2)
253         st2.root.node_children["four"] = four
254         four.node_children["five"] = five
255
256         file_six = CHKFileSpecification()
257         file_six.set_uri("file_six_uri")
258
259         o = FakeOpener({("CHK-Directory", "dir_three_uri"): st2})
260
261         d = defer.succeed(None)
262         d.addCallback(lambda res:
263                       st1.get(["one", "two", "three", "four", "five"], o))
264         def _got_five(res):
265             self.failUnless(IDirectoryNode.providedBy(res))
266             self.failUnlessIdentical(res, five)
267         d.addCallback(_got_five)
268
269         d.addCallback(lambda res:
270                       st1.add(["one", "two", "six"],
271                               file_six, o, wq))
272         def _done(res):
273             expected = [
274                 "create_tempfile-1",
275                 "create_boxname-1",
276                 ('upload_chk', 'dummy_filename-1', 'dummy_boxname-1'),
277                 ('delete_tempfile', 'dummy_filename-1'),
278                 # one/two/six only modifies the top-most CHKDirectory, so
279                 # the addpath that gets scheduled is targeted at the root
280                 ('addpath', 'dummy_boxname-1', []),
281                 ('retain_uri_from_box', 'dummy_boxname-1'),
282                 ('delete_box', 'dummy_boxname-1'),
283                 ('unlink_uri', None),
284                 ]
285             self.failUnlessEqual(wq.dump_commands(), expected)
286             wq.clear_commands()
287         d.addCallback(_done)
288
289         d.addCallback(lambda res:
290                       st1.add(["one", "two", "three", "four", "six"],
291                               file_six, o, wq))
292         def _done2(res):
293             expected = [
294                 "create_tempfile-2",
295                 "create_boxname-2",
296                 ('upload_chk', 'dummy_filename-2', 'dummy_boxname-2'),
297                 ('delete_tempfile', 'dummy_filename-2'),
298                 # one/two/three/four/six modifies the lower CHKDirectory, so
299                 # we schedule an addpath of the link that points from the
300                 # upper CHKDirectory to the lower one (at one/two/three).
301                 ('addpath', 'dummy_boxname-2', ["one", "two", "three"]),
302                 ('retain_uri_from_box', 'dummy_boxname-2'),
303                 ('delete_box', 'dummy_boxname-2'),
304                 ('unlink_uri', None),
305                 ]
306             self.failUnlessEqual(wq.dump_commands(), expected)
307         d.addCallback(_done2)
308
309
310         return d
311
312 del OneSubTree
313 del MultipleSubTrees
314
315 class Redirect(unittest.TestCase):
316     pass
317 """
318
319 import os.path
320 from twisted.python.failure import Failure
321 from allmydata.filetree import directory, redirect, vdrive
322 from allmydata.filetree.interfaces import (ISubTree, INode, IDirectoryNode,
323                                            IFileNode, NoSuchDirectoryError,
324                                            NoSuchChildError)
325 from allmydata.filetree.file import CHKFileNode
326 from allmydata import upload
327 from allmydata.interfaces import IDownloader
328 from allmydata.util import bencode
329
330 class Utils(unittest.TestCase):
331     def test_in_pairs(self):
332         l = range(8)
333         pairs = list(directory.in_pairs(l))
334         self.failUnlessEqual(pairs, [(0,1), (2,3), (4,5), (6,7)])
335
336 class FakeMesh(object):
337     implements(IDownloader, IUploader)
338     debug = False
339
340     def __init__(self):
341         self.files = {}
342
343     def upload(self, uploadable):
344         uri = "stub-uri-%d" % len(self.files)
345         if self.debug:
346             print "FakeMesh.upload -> %s" % uri
347         assert upload.IUploadable.providedBy(uploadable)
348         f = uploadable.get_filehandle()
349         data = f.read()
350         uploadable.close_filehandle(f)
351         self.files[uri] = data
352         return defer.succeed(uri)
353
354     def upload_filename(self, filename):
355         if self.debug:
356             print "FakeMesh.upload_filename(%s)" % filename
357         return self.upload(upload.FileName(filename))
358
359     def upload_data(self, data):
360         if self.debug:
361             print "FakeMesh.upload_data(%s)" % data
362         return self.upload(upload.Data(data))
363
364     def download(self, uri, target):
365         if self.debug:
366             print "FakeMesh.download(%s)" % uri
367         target.open()
368         target.write(self.files[uri])
369         target.close()
370         return defer.maybeDeferred(target.finish)
371
372
373 class VDrive(unittest.TestCase):
374
375     def makeVirtualDrive(self, basedir, root_node=None, mesh=None):
376         wq = workqueue.WorkQueue(os.path.join("test_filetree",
377                                               "VDrive",
378                                               basedir, "1.workqueue"))
379         if mesh:
380             assert IUploader.providedBy(mesh)
381             assert IDownloader.providedBy(mesh)
382             dl = ul = mesh
383         else:
384             dl = ul = FakeMesh()
385         if not root_node:
386             root_node = directory.LocalFileSubTreeNode()
387             root_node.new("rootdirtree.save")
388         v = vdrive.VirtualDrive(wq, dl, ul, root_node)
389         return v
390
391     def makeLocalTree(self, basename):
392         # create a LocalFileRedirection pointing at a LocalFileSubTree.
393         # Returns a VirtualDrive instance.
394         topdir = directory.LocalFileSubTree().new("%s-dirtree.save" % basename)
395         topdir.update_now(None)
396         root = redirect.LocalFileRedirection().new("%s-root" % basename,
397                                                    topdir.create_node_now())
398         root.update_now(None)
399         v = self.makeVirtualDrive("%s-vdrive" % basename,
400                                   root.create_node_now())
401         return v
402
403     def makeCHKTree(self, basename):
404         # create a LocalFileRedirection pointing at a CHKDirectorySubTree.
405         # Returns a VirtualDrive instance.
406         mesh = FakeMesh()
407         topdir = directory.CHKDirectorySubTree().new()
408         d = topdir.update_now(mesh)
409         def _updated(topnode):
410             root = redirect.LocalFileRedirection()
411             root.new("%s-root" % basename, topnode)
412             return root.update_now(mesh)
413         d.addCallback(_updated)
414         d.addCallback(lambda rootnode:
415                       self.makeVirtualDrive("%s-vdrive" % basename,
416                                             rootnode, mesh))
417         return d
418
419     def failUnlessListsAreEqual(self, list1, list2):
420         self.failUnlessEqual(sorted(list1), sorted(list2))
421
422     def failUnlessContentsAreEqual(self, c1, c2):
423         c1a = dict([(k,v.serialize_node()) for k,v in c1.items()])
424         c2a = dict([(k,v.serialize_node()) for k,v in c2.items()])
425         self.failUnlessEqual(c1a, c2a)
426
427     def testDirectory(self):
428         stm = vdrive.SubTreeMaker(FakeMesh())
429
430         # create an empty directory (stored locally)
431         subtree = directory.LocalFileSubTree()
432         subtree.new("dirtree.save")
433         self.failUnless(ISubTree.providedBy(subtree))
434
435         # get the root IDirectoryNode (which is still empty) and examine it
436         (found_path, root, remaining_path) = subtree.get_node_for_path([])
437         self.failUnlessEqual(found_path, [])
438         self.failUnlessEqual(remaining_path, [])
439         self.failUnless(INode.providedBy(root))
440         self.failUnless(IDirectoryNode.providedBy(root))
441         self.failUnlessListsAreEqual(root.list().keys(), [])
442         self.failUnlessIdentical(root.get_subtree(), subtree)
443
444         # now add some children to it
445         subdir1 = root.add_subdir("subdir1")
446         file1 = CHKFileNode()
447         file1.new("uri1")
448         root.add("foo.txt", file1)
449         self.failUnlessListsAreEqual(root.list().keys(),
450                                      ["foo.txt", "subdir1"])
451         self.failUnlessIdentical(root.get("foo.txt"), file1)
452         subdir1a = root.get("subdir1")
453         self.failUnlessIdentical(subdir1, subdir1a)
454         del subdir1a
455         self.failUnless(IDirectoryNode.providedBy(subdir1))
456         self.failUnlessListsAreEqual(subdir1.list().keys(), [])
457         self.failUnlessIdentical(subdir1.get_subtree(), subtree)
458
459         subdir2 = subdir1.add_subdir("subdir2")
460         subdir3 = subdir2.add_subdir("subdir3")
461         subdir4 = subdir2.add_subdir("subdir4")
462
463         subdir2.delete("subdir4")
464         self.failUnlessListsAreEqual(subdir2.list().keys(), ["subdir3"])
465
466         del root, subdir1, subdir2, subdir3, subdir4
467         # leaving file1 for later use
468
469         # now serialize it and examine the results
470         f = StringIO()
471         subtree.serialize_subtree_to_file(f)
472         data = f.getvalue()
473         #print data
474         unpacked = bencode.bdecode(data)
475         #print unpacked
476         del f, data, unpacked
477
478         node = subtree.create_node_now()
479         self.failUnless(isinstance(node, directory.LocalFileSubTreeNode))
480         node_s = node.serialize_node()
481         self.failUnless(isinstance(node_s, str))
482         self.failUnless(node_s.startswith("LocalFileDirectory:"))
483         self.failUnless("dirtree.save" in node_s)
484         del node, node_s
485
486         d = defer.maybeDeferred(subtree.update_now, None)
487         def _updated(node):
488             # now reconstruct it
489             return stm.make_subtree_from_node(node, False)
490         d.addCallback(_updated)
491
492         def _opened(new_subtree):
493             res = new_subtree.get_node_for_path([])
494             (found_path, root, remaining_path) = res
495             self.failUnlessEqual(found_path, [])
496             self.failUnlessEqual(remaining_path, [])
497             self.failUnless(INode.providedBy(root))
498             self.failUnless(IDirectoryNode.providedBy(root))
499             self.failUnlessListsAreEqual(root.list().keys(),
500                                          ["foo.txt", "subdir1"])
501             file1a = root.get("foo.txt")
502             self.failUnless(INode(file1a))
503             self.failUnless(isinstance(file1a, CHKFileNode))
504             self.failUnless(IFileNode(file1a))
505             self.failUnlessEqual(file1a.get_uri(), "uri1")
506             subdir1 = root.get("subdir1")
507             subdir2 = subdir1.get("subdir2")
508             self.failUnlessListsAreEqual(subdir2.list().keys(), ["subdir3"])
509             subdir2.delete("subdir3")
510             self.failUnlessListsAreEqual(subdir2.list().keys(), [])
511         d.addCallback(_opened)
512         return d
513
514     def shouldFail(self, res, expected_failure, which):
515         if isinstance(res, Failure):
516             res.trap(expected_failure)
517         else:
518             self.fail("%s was supposed to raise %s, not get '%s'" %
519                       (which, expected_failure, res))
520
521     def testVdrive(self):
522         v = self.makeLocalTree("vdrive")
523
524         d = v.list([])
525         def _listed(contents):
526             self.failUnlessEqual(contents, {})
527         d.addCallback(_listed)
528
529         child1 = CHKFileNode().new("uri1")
530         d.addCallback(lambda res: v.add_node(["a"], child1))
531         d.addCallback(lambda res: v.workqueue.flush())
532         d.addCallback(lambda res: v.list([]))
533         def _listed2(contents):
534             self.failUnlessListsAreEqual(contents.keys(), ["a"])
535             self.failUnlessContentsAreEqual(contents, {"a": child1})
536         d.addCallback(_listed2)
537         child2 = CHKFileNode().new("uri2")
538         child3 = CHKFileNode().new("uri3")
539         d.addCallback(lambda res: v.add_node(["b","c"], child2))
540         d.addCallback(lambda res: v.add_node(["b","d"], child3))
541         d.addCallback(lambda res: v.workqueue.flush())
542         d.addCallback(lambda res: v.list([]))
543         def _listed3(contents):
544             self.failUnlessListsAreEqual(contents.keys(), ["a","b"])
545         d.addCallback(_listed3)
546         d.addCallback(lambda res: v.list(["b"]))
547         def _listed4(contents):
548             self.failUnlessListsAreEqual(contents.keys(), ["c","d"])
549             self.failUnlessContentsAreEqual(contents,
550                                             {"c": child2, "d": child3})
551         d.addCallback(_listed4)
552
553         d.addCallback(lambda res: v._get_file_uri(["b","c"]))
554         d.addCallback(self.failUnlessEqual, "uri2")
555
556         d.addCallback(lambda res: v.list(["bogus"]))
557         d.addBoth(self.shouldFail, NoSuchDirectoryError, "list(bogus)")
558
559         d.addCallback(lambda res: v._get_file_uri(["b", "bogus"]))
560         d.addBoth(self.shouldFail, NoSuchChildError, "_get_file_uri(b/bogus)")
561
562         return d
563
564     def testUpload(self):
565         v = self.makeLocalTree("upload")
566         filename = "upload1"
567         DATA = "here is some data\n"
568         f = open(filename, "wb")
569         f.write(DATA)
570         f.close()
571
572         rc = v.upload(["a","b","upload1"], filename)
573         self.failUnlessIdentical(rc, None)
574
575         d = v.workqueue.flush()
576
577         d.addCallback(lambda res: v.list([]))
578         d.addCallback(lambda contents:
579                       self.failUnlessListsAreEqual(contents.keys(), ["a"]))
580         d.addCallback(lambda res: v.list(["a"]))
581         d.addCallback(lambda contents:
582                       self.failUnlessListsAreEqual(contents.keys(), ["b"]))
583         d.addCallback(lambda res: v.list(["a","b"]))
584         d.addCallback(lambda contents:
585                       self.failUnlessListsAreEqual(contents.keys(),
586                                                    ["upload1"]))
587         d.addCallback(lambda res: v.download_as_data(["a","b","upload1"]))
588         d.addCallback(self.failUnlessEqual, DATA)
589
590         return d
591
592     def testCHKDirUpload(self):
593         DATA = "here is some data\n"
594         filename = "upload1"
595         f = open(filename, "wb")
596         f.write(DATA)
597         f.close()
598
599         d = defer.maybeDeferred(self.makeCHKTree, "chk-upload")
600         def _made(v):
601             self.v = v
602
603             rc = v.upload(["a","b","upload1"], filename)
604             self.failUnlessIdentical(rc, None)
605
606             return v.workqueue.flush()
607         d.addCallback(_made)
608
609         d.addCallback(lambda res: self.v.list([]))
610         d.addCallback(lambda contents:
611                       self.failUnlessListsAreEqual(contents.keys(), ["a"]))
612         d.addCallback(lambda res: self.v.list(["a"]))
613         d.addCallback(lambda contents:
614                       self.failUnlessListsAreEqual(contents.keys(), ["b"]))
615         d.addCallback(lambda res: self.v.list(["a","b"]))
616         d.addCallback(lambda contents:
617                       self.failUnlessListsAreEqual(contents.keys(),
618                                                    ["upload1"]))
619         d.addCallback(lambda res: self.v.download_as_data(["a","b","upload1"]))
620         d.addCallback(self.failUnlessEqual, DATA)
621
622         return d
623
624     def testCHKDirDelete(self):
625         DATA = "here is some data\n"
626         filename = "upload1"
627         f = open(filename, "wb")
628         f.write(DATA)
629         f.close()
630
631         d = defer.maybeDeferred(self.makeCHKTree, "chk-delete")
632         def _made(v):
633             self.v = v
634         d.addCallback(_made)
635
636         d.addCallback(lambda r:
637                       self.v.upload(["a","b","upload1"], filename))
638         d.addCallback(lambda r:
639                       self.v.upload_data(["a","b","upload2"], DATA))
640         d.addCallback(lambda r:
641                       self.v.upload(["a","c","upload3"], filename))
642         d.addCallback(lambda r:
643                       self.v.workqueue.flush())
644
645         d.addCallback(lambda r: self.v.list([]))
646         d.addCallback(lambda contents:
647                       self.failUnlessListsAreEqual(contents.keys(), ["a"]))
648         d.addCallback(lambda r: self.v.list(["a"]))
649         d.addCallback(lambda contents:
650                       self.failUnlessListsAreEqual(contents.keys(), ["b","c"]))
651         d.addCallback(lambda r: self.v.list(["a","b"]))
652         d.addCallback(lambda contents:
653                       self.failUnlessListsAreEqual(contents.keys(),
654                                                    ["upload1", "upload2"]))
655         #d.addCallback(lambda r: self.v.download_as_data(["a","b","upload1"]))
656         #d.addCallback(self.failUnlessEqual, DATA)
657
658         # now delete it
659         d.addCallback(lambda r: self.v.delete(["a","b","upload2"]))
660         d.addCallback(lambda r: self.v.workqueue.flush())
661         d.addCallback(lambda r: self.v.list(["a","b"]))
662         d.addCallback(lambda contents:
663                       self.failUnlessListsAreEqual(contents.keys(),
664                                                    ["upload1"]))
665
666
667         return d