from allmydata.interfaces import IImmutableFileNode, IMutableFileNode, \
ExistingChildError, NoSuchChildError, MustNotBeUnknownRWError, \
MustBeDeepImmutableError, MustBeReadonlyError, \
- IDeepCheckResults, IDeepCheckAndRepairResults
+ IDeepCheckResults, IDeepCheckAndRepairResults, \
+ MDMF_VERSION, SDMF_VERSION
from allmydata.mutable.filenode import MutableFileNode
from allmydata.mutable.common import UncoordinatedWriteError
from allmydata.util import hashutil, base32
testutil.ReallyEqualMixin, testutil.ShouldFailMixin, testutil.StallMixin, ErrorMixin):
timeout = 480 # It occasionally takes longer than 240 seconds on Francois's arm box.
- def test_basic(self):
- self.basedir = "dirnode/Dirnode/test_basic"
- self.set_up_grid()
+ def _do_create_test(self, mdmf=False):
c = self.g.clients[0]
- d = c.create_dirnode()
- def _done(res):
- self.failUnless(isinstance(res, dirnode.DirectoryNode))
- self.failUnless(res.is_mutable())
- self.failIf(res.is_readonly())
- self.failIf(res.is_unknown())
- self.failIf(res.is_allowed_in_immutable_directory())
- res.raise_error()
- rep = str(res)
- self.failUnless("RW-MUT" in rep)
- d.addCallback(_done)
- return d
- def test_initial_children(self):
- self.basedir = "dirnode/Dirnode/test_initial_children"
- self.set_up_grid()
- c = self.g.clients[0]
- nm = c.nodemaker
+ self.expected_manifest = []
+ self.expected_verifycaps = set()
+ self.expected_storage_indexes = set()
- kids = {one_nfd: (nm.create_from_cap(one_uri), {}),
- u"two": (nm.create_from_cap(setup_py_uri),
- {"metakey": "metavalue"}),
- u"mut": (nm.create_from_cap(mut_write_uri, mut_read_uri), {}),
- u"fut": (nm.create_from_cap(future_write_uri, future_read_uri), {}),
- u"fro": (nm.create_from_cap(None, future_read_uri), {}),
- u"fut-unic": (nm.create_from_cap(future_nonascii_write_uri, future_nonascii_read_uri), {}),
- u"fro-unic": (nm.create_from_cap(None, future_nonascii_read_uri), {}),
- u"empty_litdir": (nm.create_from_cap(empty_litdir_uri), {}),
- u"tiny_litdir": (nm.create_from_cap(tiny_litdir_uri), {}),
- }
- d = c.create_dirnode(kids)
+ d = None
+ if mdmf:
+ d = c.create_dirnode(version=MDMF_VERSION)
+ else:
+ d = c.create_dirnode()
+ def _then(n):
+ # /
+ self.rootnode = n
+ backing_node = n._node
+ if mdmf:
+ self.failUnlessEqual(backing_node.get_version(),
+ MDMF_VERSION)
+ else:
+ self.failUnlessEqual(backing_node.get_version(),
+ SDMF_VERSION)
+ self.failUnless(n.is_mutable())
+ u = n.get_uri()
+ self.failUnless(u)
+ cap_formats = []
+ if mdmf:
+ cap_formats = ["URI:DIR2-MDMF:",
+ "URI:DIR2-MDMF-RO:",
+ "URI:DIR2-MDMF-Verifier:"]
+ else:
+ cap_formats = ["URI:DIR2:",
+ "URI:DIR2-RO",
+ "URI:DIR2-Verifier:"]
+ rw, ro, v = cap_formats
+ self.failUnless(u.startswith(rw), u)
+ u_ro = n.get_readonly_uri()
+ self.failUnless(u_ro.startswith(ro), u_ro)
+ u_v = n.get_verify_cap().to_string()
+ self.failUnless(u_v.startswith(v), u_v)
+ u_r = n.get_repair_cap().to_string()
+ self.failUnlessReallyEqual(u_r, u)
+ self.expected_manifest.append( ((), u) )
+ self.expected_verifycaps.add(u_v)
+ si = n.get_storage_index()
+ self.expected_storage_indexes.add(base32.b2a(si))
+ expected_si = n._uri.get_storage_index()
+ self.failUnlessReallyEqual(si, expected_si)
- def _created(dn):
- self.failUnless(isinstance(dn, dirnode.DirectoryNode))
- self.failUnless(dn.is_mutable())
- self.failIf(dn.is_readonly())
- self.failIf(dn.is_unknown())
- self.failIf(dn.is_allowed_in_immutable_directory())
- dn.raise_error()
- rep = str(dn)
- self.failUnless("RW-MUT" in rep)
- return dn.list()
- d.addCallback(_created)
+ d = n.list()
+ d.addCallback(lambda res: self.failUnlessEqual(res, {}))
+ d.addCallback(lambda res: n.has_child(u"missing"))
+ d.addCallback(lambda res: self.failIf(res))
- def _check_kids(children):
- self.failUnlessReallyEqual(set(children.keys()),
- set([one_nfc, u"two", u"mut", u"fut", u"fro",
- u"fut-unic", u"fro-unic", u"empty_litdir", u"tiny_litdir"]))
- one_node, one_metadata = children[one_nfc]
- two_node, two_metadata = children[u"two"]
- mut_node, mut_metadata = children[u"mut"]
- fut_node, fut_metadata = children[u"fut"]
- fro_node, fro_metadata = children[u"fro"]
- futna_node, futna_metadata = children[u"fut-unic"]
- frona_node, frona_metadata = children[u"fro-unic"]
- emptylit_node, emptylit_metadata = children[u"empty_litdir"]
- tinylit_node, tinylit_metadata = children[u"tiny_litdir"]
+ fake_file_uri = make_mutable_file_uri()
+ other_file_uri = make_mutable_file_uri()
+ m = c.nodemaker.create_from_cap(fake_file_uri)
+ ffu_v = m.get_verify_cap().to_string()
+ self.expected_manifest.append( ((u"child",) , m.get_uri()) )
+ self.expected_verifycaps.add(ffu_v)
+ self.expected_storage_indexes.add(base32.b2a(m.get_storage_index()))
+ d.addCallback(lambda res: n.set_uri(u"child",
+ fake_file_uri, fake_file_uri))
+ d.addCallback(lambda res:
+ self.shouldFail(ExistingChildError, "set_uri-no",
+ "child 'child' already exists",
+ n.set_uri, u"child",
+ other_file_uri, other_file_uri,
+ overwrite=False))
+ # /
+ # /child = mutable
- self.failUnlessReallyEqual(one_node.get_size(), 3)
- self.failUnlessReallyEqual(one_node.get_uri(), one_uri)
- self.failUnlessReallyEqual(one_node.get_readonly_uri(), one_uri)
- self.failUnless(isinstance(one_metadata, dict), one_metadata)
+ d.addCallback(lambda res: n.create_subdirectory(u"subdir"))
- self.failUnlessReallyEqual(two_node.get_size(), 14861)
- self.failUnlessReallyEqual(two_node.get_uri(), setup_py_uri)
- self.failUnlessReallyEqual(two_node.get_readonly_uri(), setup_py_uri)
- self.failUnlessEqual(two_metadata["metakey"], "metavalue")
+ # /
+ # /child = mutable
+ # /subdir = directory
+ def _created(subdir):
+ self.failUnless(isinstance(subdir, dirnode.DirectoryNode))
+ self.subdir = subdir
+ new_v = subdir.get_verify_cap().to_string()
+ assert isinstance(new_v, str)
+ self.expected_manifest.append( ((u"subdir",), subdir.get_uri()) )
+ self.expected_verifycaps.add(new_v)
+ si = subdir.get_storage_index()
+ self.expected_storage_indexes.add(base32.b2a(si))
+ d.addCallback(_created)
- self.failUnlessReallyEqual(mut_node.get_uri(), mut_write_uri)
- self.failUnlessReallyEqual(mut_node.get_readonly_uri(), mut_read_uri)
- self.failUnless(isinstance(mut_metadata, dict), mut_metadata)
+ d.addCallback(lambda res:
+ self.shouldFail(ExistingChildError, "mkdir-no",
+ "child 'subdir' already exists",
+ n.create_subdirectory, u"subdir",
+ overwrite=False))
- self.failUnless(fut_node.is_unknown())
- self.failUnlessReallyEqual(fut_node.get_uri(), future_write_uri)
- self.failUnlessReallyEqual(fut_node.get_readonly_uri(), "ro." + future_read_uri)
- self.failUnless(isinstance(fut_metadata, dict), fut_metadata)
+ d.addCallback(lambda res: n.list())
+ d.addCallback(lambda children:
+ self.failUnlessReallyEqual(set(children.keys()),
+ set([u"child", u"subdir"])))
- self.failUnless(futna_node.is_unknown())
- self.failUnlessReallyEqual(futna_node.get_uri(), future_nonascii_write_uri)
- self.failUnlessReallyEqual(futna_node.get_readonly_uri(), "ro." + future_nonascii_read_uri)
- self.failUnless(isinstance(futna_metadata, dict), futna_metadata)
+ d.addCallback(lambda res: n.start_deep_stats().when_done())
+ def _check_deepstats(stats):
+ self.failUnless(isinstance(stats, dict))
+ expected = {"count-immutable-files": 0,
+ "count-mutable-files": 1,
+ "count-literal-files": 0,
+ "count-files": 1,
+ "count-directories": 2,
+ "size-immutable-files": 0,
+ "size-literal-files": 0,
+ #"size-directories": 616, # varies
+ #"largest-directory": 616,
+ "largest-directory-children": 2,
+ "largest-immutable-file": 0,
+ }
+ for k,v in expected.iteritems():
+ self.failUnlessReallyEqual(stats[k], v,
+ "stats[%s] was %s, not %s" %
+ (k, stats[k], v))
+ self.failUnless(stats["size-directories"] > 500,
+ stats["size-directories"])
+ self.failUnless(stats["largest-directory"] > 500,
+ stats["largest-directory"])
+ self.failUnlessReallyEqual(stats["size-files-histogram"], [])
+ d.addCallback(_check_deepstats)
- self.failUnless(fro_node.is_unknown())
- self.failUnlessReallyEqual(fro_node.get_uri(), "ro." + future_read_uri)
- self.failUnlessReallyEqual(fut_node.get_readonly_uri(), "ro." + future_read_uri)
- self.failUnless(isinstance(fro_metadata, dict), fro_metadata)
+ d.addCallback(lambda res: n.build_manifest().when_done())
+ def _check_manifest(res):
+ manifest = res["manifest"]
+ self.failUnlessReallyEqual(sorted(manifest),
+ sorted(self.expected_manifest))
+ stats = res["stats"]
+ _check_deepstats(stats)
+ self.failUnlessReallyEqual(self.expected_verifycaps,
+ res["verifycaps"])
+ self.failUnlessReallyEqual(self.expected_storage_indexes,
+ res["storage-index"])
+ d.addCallback(_check_manifest)
- self.failUnless(frona_node.is_unknown())
- self.failUnlessReallyEqual(frona_node.get_uri(), "ro." + future_nonascii_read_uri)
- self.failUnlessReallyEqual(futna_node.get_readonly_uri(), "ro." + future_nonascii_read_uri)
- self.failUnless(isinstance(frona_metadata, dict), frona_metadata)
+ def _add_subsubdir(res):
+ return self.subdir.create_subdirectory(u"subsubdir")
+ d.addCallback(_add_subsubdir)
+ # /
+ # /child = mutable
+ # /subdir = directory
+ # /subdir/subsubdir = directory
+ d.addCallback(lambda res: n.get_child_at_path(u"subdir/subsubdir"))
+ d.addCallback(lambda subsubdir:
+ self.failUnless(isinstance(subsubdir,
+ dirnode.DirectoryNode)))
+ d.addCallback(lambda res: n.get_child_at_path(u""))
+ d.addCallback(lambda res: self.failUnlessReallyEqual(res.get_uri(),
+ n.get_uri()))
- self.failIf(emptylit_node.is_unknown())
- self.failUnlessReallyEqual(emptylit_node.get_storage_index(), None)
- self.failIf(tinylit_node.is_unknown())
- self.failUnlessReallyEqual(tinylit_node.get_storage_index(), None)
+ d.addCallback(lambda res: n.get_metadata_for(u"child"))
+ d.addCallback(lambda metadata:
+ self.failUnlessEqual(set(metadata.keys()),
+ set(["tahoe"])))
- d2 = defer.succeed(None)
- d2.addCallback(lambda ignored: emptylit_node.list())
- d2.addCallback(lambda children: self.failUnlessEqual(children, {}))
- d2.addCallback(lambda ignored: tinylit_node.list())
- d2.addCallback(lambda children: self.failUnlessReallyEqual(set(children.keys()),
- set([u"short"])))
- d2.addCallback(lambda ignored: tinylit_node.list())
- d2.addCallback(lambda children: children[u"short"][0].read(MemAccum()))
- d2.addCallback(lambda accum: self.failUnlessReallyEqual(accum.data, "The end."))
- return d2
+ d.addCallback(lambda res:
+ self.shouldFail(NoSuchChildError, "gcamap-no",
+ "nope",
+ n.get_child_and_metadata_at_path,
+ u"subdir/nope"))
+ d.addCallback(lambda res:
+ n.get_child_and_metadata_at_path(u""))
+ def _check_child_and_metadata1(res):
+ child, metadata = res
+ self.failUnless(isinstance(child, dirnode.DirectoryNode))
+ # edge-metadata needs at least one path segment
+ self.failUnlessEqual(set(metadata.keys()), set([]))
+ d.addCallback(_check_child_and_metadata1)
+ d.addCallback(lambda res:
+ n.get_child_and_metadata_at_path(u"child"))
- d.addCallback(_check_kids)
+ def _check_child_and_metadata2(res):
+ child, metadata = res
+ self.failUnlessReallyEqual(child.get_uri(),
+ fake_file_uri)
+ self.failUnlessEqual(set(metadata.keys()), set(["tahoe"]))
+ d.addCallback(_check_child_and_metadata2)
- d.addCallback(lambda ign: nm.create_new_mutable_directory(kids))
- d.addCallback(lambda dn: dn.list())
- d.addCallback(_check_kids)
+ d.addCallback(lambda res:
+ n.get_child_and_metadata_at_path(u"subdir/subsubdir"))
+ def _check_child_and_metadata3(res):
+ child, metadata = res
+ self.failUnless(isinstance(child, dirnode.DirectoryNode))
+ self.failUnlessEqual(set(metadata.keys()), set(["tahoe"]))
+ d.addCallback(_check_child_and_metadata3)
- bad_future_node = UnknownNode(future_write_uri, None)
- bad_kids1 = {one_nfd: (bad_future_node, {})}
- # This should fail because we don't know how to diminish the future_write_uri
- # cap (given in a write slot and not prefixed with "ro." or "imm.") to a readcap.
- d.addCallback(lambda ign:
- self.shouldFail(MustNotBeUnknownRWError, "bad_kids1",
- "cannot attach unknown",
- nm.create_new_mutable_directory,
- bad_kids1))
- bad_kids2 = {one_nfd: (nm.create_from_cap(one_uri), None)}
- d.addCallback(lambda ign:
- self.shouldFail(AssertionError, "bad_kids2",
- "requires metadata to be a dict",
- nm.create_new_mutable_directory,
- bad_kids2))
- return d
+ # set_uri + metadata
+ # it should be possible to add a child without any metadata
+ d.addCallback(lambda res: n.set_uri(u"c2",
+ fake_file_uri, fake_file_uri,
+ {}))
+ d.addCallback(lambda res: n.get_metadata_for(u"c2"))
+ d.addCallback(lambda metadata:
+ self.failUnlessEqual(set(metadata.keys()), set(["tahoe"])))
- def test_immutable(self):
- self.basedir = "dirnode/Dirnode/test_immutable"
- self.set_up_grid()
- c = self.g.clients[0]
- nm = c.nodemaker
+ # You can't override the link timestamps.
+ d.addCallback(lambda res: n.set_uri(u"c2",
+ fake_file_uri, fake_file_uri,
+ { 'tahoe': {'linkcrtime': "bogus"}}))
+ d.addCallback(lambda res: n.get_metadata_for(u"c2"))
+ def _has_good_linkcrtime(metadata):
+ self.failUnless(metadata.has_key('tahoe'))
+ self.failUnless(metadata['tahoe'].has_key('linkcrtime'))
+ self.failIfEqual(metadata['tahoe']['linkcrtime'], 'bogus')
+ d.addCallback(_has_good_linkcrtime)
- kids = {one_nfd: (nm.create_from_cap(one_uri), {}),
- u"two": (nm.create_from_cap(setup_py_uri),
- {"metakey": "metavalue"}),
- u"fut": (nm.create_from_cap(None, future_read_uri), {}),
- u"futna": (nm.create_from_cap(None, future_nonascii_read_uri), {}),
- u"empty_litdir": (nm.create_from_cap(empty_litdir_uri), {}),
- u"tiny_litdir": (nm.create_from_cap(tiny_litdir_uri), {}),
- }
- d = c.create_immutable_dirnode(kids)
+ # if we don't set any defaults, the child should get timestamps
+ d.addCallback(lambda res: n.set_uri(u"c3",
+ fake_file_uri, fake_file_uri))
+ d.addCallback(lambda res: n.get_metadata_for(u"c3"))
+ d.addCallback(lambda metadata:
+ self.failUnlessEqual(set(metadata.keys()), set(["tahoe"])))
- def _created(dn):
- self.failUnless(isinstance(dn, dirnode.DirectoryNode))
- self.failIf(dn.is_mutable())
- self.failUnless(dn.is_readonly())
- self.failIf(dn.is_unknown())
- self.failUnless(dn.is_allowed_in_immutable_directory())
- dn.raise_error()
- rep = str(dn)
- self.failUnless("RO-IMM" in rep)
- cap = dn.get_cap()
- self.failUnlessIn("CHK", cap.to_string())
- self.cap = cap
- return dn.list()
- d.addCallback(_created)
+ # we can also add specific metadata at set_uri() time
+ d.addCallback(lambda res: n.set_uri(u"c4",
+ fake_file_uri, fake_file_uri,
+ {"key": "value"}))
+ d.addCallback(lambda res: n.get_metadata_for(u"c4"))
+ d.addCallback(lambda metadata:
+ self.failUnless((set(metadata.keys()) == set(["key", "tahoe"])) and
+ (metadata['key'] == "value"), metadata))
- def _check_kids(children):
- self.failUnlessReallyEqual(set(children.keys()),
- set([one_nfc, u"two", u"fut", u"futna", u"empty_litdir", u"tiny_litdir"]))
- one_node, one_metadata = children[one_nfc]
- two_node, two_metadata = children[u"two"]
- fut_node, fut_metadata = children[u"fut"]
- futna_node, futna_metadata = children[u"futna"]
- emptylit_node, emptylit_metadata = children[u"empty_litdir"]
- tinylit_node, tinylit_metadata = children[u"tiny_litdir"]
+ d.addCallback(lambda res: n.delete(u"c2"))
+ d.addCallback(lambda res: n.delete(u"c3"))
+ d.addCallback(lambda res: n.delete(u"c4"))
- self.failUnlessReallyEqual(one_node.get_size(), 3)
- self.failUnlessReallyEqual(one_node.get_uri(), one_uri)
- self.failUnlessReallyEqual(one_node.get_readonly_uri(), one_uri)
- self.failUnless(isinstance(one_metadata, dict), one_metadata)
+ # set_node + metadata
+ # it should be possible to add a child without any metadata except for timestamps
+ d.addCallback(lambda res: n.set_node(u"d2", n, {}))
+ d.addCallback(lambda res: c.create_dirnode())
+ d.addCallback(lambda n2:
+ self.shouldFail(ExistingChildError, "set_node-no",
+ "child 'd2' already exists",
+ n.set_node, u"d2", n2,
+ overwrite=False))
+ d.addCallback(lambda res: n.get_metadata_for(u"d2"))
+ d.addCallback(lambda metadata:
+ self.failUnlessEqual(set(metadata.keys()), set(["tahoe"])))
- self.failUnlessReallyEqual(two_node.get_size(), 14861)
- self.failUnlessReallyEqual(two_node.get_uri(), setup_py_uri)
- self.failUnlessReallyEqual(two_node.get_readonly_uri(), setup_py_uri)
- self.failUnlessEqual(two_metadata["metakey"], "metavalue")
+ # if we don't set any defaults, the child should get timestamps
+ d.addCallback(lambda res: n.set_node(u"d3", n))
+ d.addCallback(lambda res: n.get_metadata_for(u"d3"))
+ d.addCallback(lambda metadata:
+ self.failUnlessEqual(set(metadata.keys()), set(["tahoe"])))
- self.failUnless(fut_node.is_unknown())
- self.failUnlessReallyEqual(fut_node.get_uri(), "imm." + future_read_uri)
- self.failUnlessReallyEqual(fut_node.get_readonly_uri(), "imm." + future_read_uri)
- self.failUnless(isinstance(fut_metadata, dict), fut_metadata)
+ # we can also add specific metadata at set_node() time
+ d.addCallback(lambda res: n.set_node(u"d4", n,
+ {"key": "value"}))
+ d.addCallback(lambda res: n.get_metadata_for(u"d4"))
+ d.addCallback(lambda metadata:
+ self.failUnless((set(metadata.keys()) == set(["key", "tahoe"])) and
+ (metadata["key"] == "value"), metadata))
- self.failUnless(futna_node.is_unknown())
- self.failUnlessReallyEqual(futna_node.get_uri(), "imm." + future_nonascii_read_uri)
- self.failUnlessReallyEqual(futna_node.get_readonly_uri(), "imm." + future_nonascii_read_uri)
- self.failUnless(isinstance(futna_metadata, dict), futna_metadata)
+ d.addCallback(lambda res: n.delete(u"d2"))
+ d.addCallback(lambda res: n.delete(u"d3"))
+ d.addCallback(lambda res: n.delete(u"d4"))
- self.failIf(emptylit_node.is_unknown())
- self.failUnlessReallyEqual(emptylit_node.get_storage_index(), None)
- self.failIf(tinylit_node.is_unknown())
- self.failUnlessReallyEqual(tinylit_node.get_storage_index(), None)
+ # metadata through set_children()
+ d.addCallback(lambda res:
+ n.set_children({
+ u"e1": (fake_file_uri, fake_file_uri),
+ u"e2": (fake_file_uri, fake_file_uri, {}),
+ u"e3": (fake_file_uri, fake_file_uri,
+ {"key": "value"}),
+ }))
+ d.addCallback(lambda n2: self.failUnlessIdentical(n2, n))
+ d.addCallback(lambda res:
+ self.shouldFail(ExistingChildError, "set_children-no",
+ "child 'e1' already exists",
+ n.set_children,
+ { u"e1": (other_file_uri,
+ other_file_uri),
+ u"new": (other_file_uri,
+ other_file_uri),
+ },
+ overwrite=False))
+ # and 'new' should not have been created
+ d.addCallback(lambda res: n.list())
+ d.addCallback(lambda children: self.failIf(u"new" in children))
+ d.addCallback(lambda res: n.get_metadata_for(u"e1"))
+ d.addCallback(lambda metadata:
+ self.failUnlessEqual(set(metadata.keys()), set(["tahoe"])))
+ d.addCallback(lambda res: n.get_metadata_for(u"e2"))
+ d.addCallback(lambda metadata:
+ self.failUnlessEqual(set(metadata.keys()), set(["tahoe"])))
+ d.addCallback(lambda res: n.get_metadata_for(u"e3"))
+ d.addCallback(lambda metadata:
+ self.failUnless((set(metadata.keys()) == set(["key", "tahoe"])) and
+ (metadata["key"] == "value"), metadata))
- d2 = defer.succeed(None)
- d2.addCallback(lambda ignored: emptylit_node.list())
- d2.addCallback(lambda children: self.failUnlessEqual(children, {}))
- d2.addCallback(lambda ignored: tinylit_node.list())
- d2.addCallback(lambda children: self.failUnlessReallyEqual(set(children.keys()),
- set([u"short"])))
- d2.addCallback(lambda ignored: tinylit_node.list())
- d2.addCallback(lambda children: children[u"short"][0].read(MemAccum()))
- d2.addCallback(lambda accum: self.failUnlessReallyEqual(accum.data, "The end."))
- return d2
+ d.addCallback(lambda res: n.delete(u"e1"))
+ d.addCallback(lambda res: n.delete(u"e2"))
+ d.addCallback(lambda res: n.delete(u"e3"))
- d.addCallback(_check_kids)
+ # metadata through set_nodes()
+ d.addCallback(lambda res:
+ n.set_nodes({ u"f1": (n, None),
+ u"f2": (n, {}),
+ u"f3": (n, {"key": "value"}),
+ }))
+ d.addCallback(lambda n2: self.failUnlessIdentical(n2, n))
+ d.addCallback(lambda res:
+ self.shouldFail(ExistingChildError, "set_nodes-no",
+ "child 'f1' already exists",
+ n.set_nodes, { u"f1": (n, None),
+ u"new": (n, None), },
+ overwrite=False))
+ # and 'new' should not have been created
+ d.addCallback(lambda res: n.list())
+ d.addCallback(lambda children: self.failIf(u"new" in children))
+ d.addCallback(lambda res: n.get_metadata_for(u"f1"))
+ d.addCallback(lambda metadata:
+ self.failUnlessEqual(set(metadata.keys()), set(["tahoe"])))
+ d.addCallback(lambda res: n.get_metadata_for(u"f2"))
+ d.addCallback(lambda metadata:
+ self.failUnlessEqual(set(metadata.keys()), set(["tahoe"])))
+ d.addCallback(lambda res: n.get_metadata_for(u"f3"))
+ d.addCallback(lambda metadata:
+ self.failUnless((set(metadata.keys()) == set(["key", "tahoe"])) and
+ (metadata["key"] == "value"), metadata))
- d.addCallback(lambda ign: nm.create_from_cap(self.cap.to_string()))
- d.addCallback(lambda dn: dn.list())
- d.addCallback(_check_kids)
+ d.addCallback(lambda res: n.delete(u"f1"))
+ d.addCallback(lambda res: n.delete(u"f2"))
+ d.addCallback(lambda res: n.delete(u"f3"))
- bad_future_node1 = UnknownNode(future_write_uri, None)
- bad_kids1 = {one_nfd: (bad_future_node1, {})}
- d.addCallback(lambda ign:
- self.shouldFail(MustNotBeUnknownRWError, "bad_kids1",
- "cannot attach unknown",
- c.create_immutable_dirnode,
- bad_kids1))
- bad_future_node2 = UnknownNode(future_write_uri, future_read_uri)
- bad_kids2 = {one_nfd: (bad_future_node2, {})}
- d.addCallback(lambda ign:
- self.shouldFail(MustBeDeepImmutableError, "bad_kids2",
- "is not allowed in an immutable directory",
- c.create_immutable_dirnode,
- bad_kids2))
- bad_kids3 = {one_nfd: (nm.create_from_cap(one_uri), None)}
- d.addCallback(lambda ign:
- self.shouldFail(AssertionError, "bad_kids3",
- "requires metadata to be a dict",
- c.create_immutable_dirnode,
- bad_kids3))
- bad_kids4 = {one_nfd: (nm.create_from_cap(mut_write_uri), {})}
- d.addCallback(lambda ign:
- self.shouldFail(MustBeDeepImmutableError, "bad_kids4",
- "is not allowed in an immutable directory",
- c.create_immutable_dirnode,
- bad_kids4))
- bad_kids5 = {one_nfd: (nm.create_from_cap(mut_read_uri), {})}
- d.addCallback(lambda ign:
- self.shouldFail(MustBeDeepImmutableError, "bad_kids5",
- "is not allowed in an immutable directory",
- c.create_immutable_dirnode,
- bad_kids5))
- d.addCallback(lambda ign: c.create_immutable_dirnode({}))
- def _created_empty(dn):
- self.failUnless(isinstance(dn, dirnode.DirectoryNode))
- self.failIf(dn.is_mutable())
- self.failUnless(dn.is_readonly())
- self.failIf(dn.is_unknown())
- self.failUnless(dn.is_allowed_in_immutable_directory())
- dn.raise_error()
- rep = str(dn)
- self.failUnless("RO-IMM" in rep)
- cap = dn.get_cap()
- self.failUnlessIn("LIT", cap.to_string())
- self.failUnlessReallyEqual(cap.to_string(), "URI:DIR2-LIT:")
- self.cap = cap
- return dn.list()
- d.addCallback(_created_empty)
- d.addCallback(lambda kids: self.failUnlessEqual(kids, {}))
- smallkids = {u"o": (nm.create_from_cap(one_uri), {})}
- d.addCallback(lambda ign: c.create_immutable_dirnode(smallkids))
- def _created_small(dn):
- self.failUnless(isinstance(dn, dirnode.DirectoryNode))
- self.failIf(dn.is_mutable())
- self.failUnless(dn.is_readonly())
- self.failIf(dn.is_unknown())
- self.failUnless(dn.is_allowed_in_immutable_directory())
- dn.raise_error()
- rep = str(dn)
- self.failUnless("RO-IMM" in rep)
- cap = dn.get_cap()
- self.failUnlessIn("LIT", cap.to_string())
- self.failUnlessReallyEqual(cap.to_string(),
- "URI:DIR2-LIT:gi4tumj2n4wdcmz2kvjesosmjfkdu3rvpbtwwlbqhiwdeot3puwcy")
- self.cap = cap
- return dn.list()
- d.addCallback(_created_small)
- d.addCallback(lambda kids: self.failUnlessReallyEqual(kids.keys(), [u"o"]))
-
- # now test n.create_subdirectory(mutable=False)
- d.addCallback(lambda ign: c.create_dirnode())
- def _made_parent(n):
- d = n.create_subdirectory(u"subdir", kids, mutable=False)
- d.addCallback(lambda sd: sd.list())
- d.addCallback(_check_kids)
- d.addCallback(lambda ign: n.list())
- d.addCallback(lambda children:
- self.failUnlessReallyEqual(children.keys(), [u"subdir"]))
- d.addCallback(lambda ign: n.get(u"subdir"))
- d.addCallback(lambda sd: sd.list())
- d.addCallback(_check_kids)
- d.addCallback(lambda ign: n.get(u"subdir"))
- d.addCallback(lambda sd: self.failIf(sd.is_mutable()))
- bad_kids = {one_nfd: (nm.create_from_cap(mut_write_uri), {})}
- d.addCallback(lambda ign:
- self.shouldFail(MustBeDeepImmutableError, "YZ",
- "is not allowed in an immutable directory",
- n.create_subdirectory,
- u"sub2", bad_kids, mutable=False))
- return d
- d.addCallback(_made_parent)
- return d
- def test_directory_representation(self):
- self.basedir = "dirnode/Dirnode/test_directory_representation"
- self.set_up_grid()
- c = self.g.clients[0]
- nm = c.nodemaker
+ d.addCallback(lambda res:
+ n.set_metadata_for(u"child",
+ {"tags": ["web2.0-compatible"], "tahoe": {"bad": "mojo"}}))
+ d.addCallback(lambda n1: n1.get_metadata_for(u"child"))
+ d.addCallback(lambda metadata:
+ self.failUnless((set(metadata.keys()) == set(["tags", "tahoe"])) and
+ metadata["tags"] == ["web2.0-compatible"] and
+ "bad" not in metadata["tahoe"], metadata))
- # This test checks that any trailing spaces in URIs are retained in the
- # encoded directory, but stripped when we get them out of the directory.
- # See ticket #925 for why we want that.
- # It also tests that we store child names as UTF-8 NFC, and normalize
- # them again when retrieving them.
+ d.addCallback(lambda res:
+ self.shouldFail(NoSuchChildError, "set_metadata_for-nosuch", "",
+ n.set_metadata_for, u"nosuch", {}))
- stripped_write_uri = "lafs://from_the_future\t"
- stripped_read_uri = "lafs://readonly_from_the_future\t"
- spacedout_write_uri = stripped_write_uri + " "
- spacedout_read_uri = stripped_read_uri + " "
- child = nm.create_from_cap(spacedout_write_uri, spacedout_read_uri)
- self.failUnlessReallyEqual(child.get_write_uri(), spacedout_write_uri)
- self.failUnlessReallyEqual(child.get_readonly_uri(), "ro." + spacedout_read_uri)
+ def _start(res):
+ self._start_timestamp = time.time()
+ d.addCallback(_start)
+ # simplejson-1.7.1 (as shipped on Ubuntu 'gutsy') rounds all
+ # floats to hundredeths (it uses str(num) instead of repr(num)).
+ # simplejson-1.7.3 does not have this bug. To prevent this bug
+ # from causing the test to fail, stall for more than a few
+ # hundrededths of a second.
+ d.addCallback(self.stall, 0.1)
+ d.addCallback(lambda res: n.add_file(u"timestamps",
+ upload.Data("stamp me", convergence="some convergence string")))
+ d.addCallback(self.stall, 0.1)
+ def _stop(res):
+ self._stop_timestamp = time.time()
+ d.addCallback(_stop)
- child_dottedi = u"ch\u0131\u0307ld"
+ d.addCallback(lambda res: n.get_metadata_for(u"timestamps"))
+ def _check_timestamp1(metadata):
+ self.failUnlessEqual(set(metadata.keys()), set(["tahoe"]))
+ tahoe_md = metadata["tahoe"]
+ self.failUnlessEqual(set(tahoe_md.keys()), set(["linkcrtime", "linkmotime"]))
- kids_in = {child_dottedi: (child, {}), one_nfd: (child, {})}
- kids_out = {child_dottedi: (child, {}), one_nfc: (child, {})}
- kids_norm = {u"child": (child, {}), one_nfc: (child, {})}
- d = c.create_dirnode(kids_in)
+ self.failUnlessGreaterOrEqualThan(tahoe_md["linkcrtime"],
+ self._start_timestamp)
+ self.failUnlessGreaterOrEqualThan(self._stop_timestamp,
+ tahoe_md["linkcrtime"])
+ self.failUnlessGreaterOrEqualThan(tahoe_md["linkmotime"],
+ self._start_timestamp)
+ self.failUnlessGreaterOrEqualThan(self._stop_timestamp,
+ tahoe_md["linkmotime"])
+ # Our current timestamp rules say that replacing an existing
+ # child should preserve the 'linkcrtime' but update the
+ # 'linkmotime'
+ self._old_linkcrtime = tahoe_md["linkcrtime"]
+ self._old_linkmotime = tahoe_md["linkmotime"]
+ d.addCallback(_check_timestamp1)
+ d.addCallback(self.stall, 2.0) # accomodate low-res timestamps
+ d.addCallback(lambda res: n.set_node(u"timestamps", n))
+ d.addCallback(lambda res: n.get_metadata_for(u"timestamps"))
+ def _check_timestamp2(metadata):
+ self.failUnlessIn("tahoe", metadata)
+ tahoe_md = metadata["tahoe"]
+ self.failUnlessEqual(set(tahoe_md.keys()), set(["linkcrtime", "linkmotime"]))
- def _created(dn):
- self.failUnless(isinstance(dn, dirnode.DirectoryNode))
- self.failUnless(dn.is_mutable())
- self.failIf(dn.is_readonly())
- dn.raise_error()
- self.cap = dn.get_cap()
- self.rootnode = dn
- return dn._node.download_best_version()
- d.addCallback(_created)
+ self.failUnlessReallyEqual(tahoe_md["linkcrtime"], self._old_linkcrtime)
+ self.failUnlessGreaterThan(tahoe_md["linkmotime"], self._old_linkmotime)
+ return n.delete(u"timestamps")
+ d.addCallback(_check_timestamp2)
- def _check_data(data):
- # Decode the netstring representation of the directory to check that the
- # spaces are retained when the URIs are stored, and that the names are stored
- # as NFC.
- position = 0
- numkids = 0
- while position < len(data):
- entries, position = split_netstring(data, 1, position)
- entry = entries[0]
- (name_utf8, ro_uri, rwcapdata, metadata_s), subpos = split_netstring(entry, 4)
- name = name_utf8.decode("utf-8")
- rw_uri = self.rootnode._decrypt_rwcapdata(rwcapdata)
- self.failUnlessIn(name, kids_out)
- (expected_child, ign) = kids_out[name]
- self.failUnlessReallyEqual(rw_uri, expected_child.get_write_uri())
- self.failUnlessReallyEqual("ro." + ro_uri, expected_child.get_readonly_uri())
- numkids += 1
+ d.addCallback(lambda res: n.delete(u"subdir"))
+ d.addCallback(lambda old_child:
+ self.failUnlessReallyEqual(old_child.get_uri(),
+ self.subdir.get_uri()))
- self.failUnlessReallyEqual(numkids, len(kids_out))
- return self.rootnode
- d.addCallback(_check_data)
+ d.addCallback(lambda res: n.list())
+ d.addCallback(lambda children:
+ self.failUnlessReallyEqual(set(children.keys()),
+ set([u"child"])))
- # Mock up a hypothetical future version of Unicode that adds a canonical equivalence
- # between dotless-i + dot-above, and 'i'. That would actually be prohibited by the
- # stability rules, but similar additions involving currently-unassigned characters
- # would not be.
- old_normalize = unicodedata.normalize
- def future_normalize(form, s):
- assert form == 'NFC', form
- return old_normalize(form, s).replace(u"\u0131\u0307", u"i")
+ uploadable1 = upload.Data("some data", convergence="converge")
+ d.addCallback(lambda res: n.add_file(u"newfile", uploadable1))
+ d.addCallback(lambda newnode:
+ self.failUnless(IImmutableFileNode.providedBy(newnode)))
+ uploadable2 = upload.Data("some data", convergence="stuff")
+ d.addCallback(lambda res:
+ self.shouldFail(ExistingChildError, "add_file-no",
+ "child 'newfile' already exists",
+ n.add_file, u"newfile",
+ uploadable2,
+ overwrite=False))
+ d.addCallback(lambda res: n.list())
+ d.addCallback(lambda children:
+ self.failUnlessReallyEqual(set(children.keys()),
+ set([u"child", u"newfile"])))
+ d.addCallback(lambda res: n.get_metadata_for(u"newfile"))
+ d.addCallback(lambda metadata:
+ self.failUnlessEqual(set(metadata.keys()), set(["tahoe"])))
- def _list(node):
- unicodedata.normalize = future_normalize
- d2 = node.list()
- def _undo_mock(res):
- unicodedata.normalize = old_normalize
- return res
- d2.addBoth(_undo_mock)
- return d2
- d.addCallback(_list)
+ uploadable3 = upload.Data("some data", convergence="converge")
+ d.addCallback(lambda res: n.add_file(u"newfile-metadata",
+ uploadable3,
+ {"key": "value"}))
+ d.addCallback(lambda newnode:
+ self.failUnless(IImmutableFileNode.providedBy(newnode)))
+ d.addCallback(lambda res: n.get_metadata_for(u"newfile-metadata"))
+ d.addCallback(lambda metadata:
+ self.failUnless((set(metadata.keys()) == set(["key", "tahoe"])) and
+ (metadata['key'] == "value"), metadata))
+ d.addCallback(lambda res: n.delete(u"newfile-metadata"))
- def _check_kids(children):
- # Now when we use the real directory listing code, the trailing spaces
- # should have been stripped (and "ro." should have been prepended to the
- # ro_uri, since it's unknown). Also the dotless-i + dot-above should have been
- # normalized to 'i'.
+ d.addCallback(lambda res: n.create_subdirectory(u"subdir2"))
+ def _created2(subdir2):
+ self.subdir2 = subdir2
+ # put something in the way, to make sure it gets overwritten
+ return subdir2.add_file(u"child", upload.Data("overwrite me",
+ "converge"))
+ d.addCallback(_created2)
- self.failUnlessReallyEqual(set(children.keys()), set(kids_norm.keys()))
- child_node, child_metadata = children[u"child"]
+ d.addCallback(lambda res:
+ n.move_child_to(u"child", self.subdir2))
+ d.addCallback(lambda res: n.list())
+ d.addCallback(lambda children:
+ self.failUnlessReallyEqual(set(children.keys()),
+ set([u"newfile", u"subdir2"])))
+ d.addCallback(lambda res: self.subdir2.list())
+ d.addCallback(lambda children:
+ self.failUnlessReallyEqual(set(children.keys()),
+ set([u"child"])))
+ d.addCallback(lambda res: self.subdir2.get(u"child"))
+ d.addCallback(lambda child:
+ self.failUnlessReallyEqual(child.get_uri(),
+ fake_file_uri))
- self.failUnlessReallyEqual(child_node.get_write_uri(), stripped_write_uri)
- self.failUnlessReallyEqual(child_node.get_readonly_uri(), "ro." + stripped_read_uri)
- d.addCallback(_check_kids)
+ # move it back, using new_child_name=
+ d.addCallback(lambda res:
+ self.subdir2.move_child_to(u"child", n, u"newchild"))
+ d.addCallback(lambda res: n.list())
+ d.addCallback(lambda children:
+ self.failUnlessReallyEqual(set(children.keys()),
+ set([u"newchild", u"newfile",
+ u"subdir2"])))
+ d.addCallback(lambda res: self.subdir2.list())
+ d.addCallback(lambda children:
+ self.failUnlessReallyEqual(set(children.keys()), set([])))
- d.addCallback(lambda ign: nm.create_from_cap(self.cap.to_string()))
- d.addCallback(_list)
- d.addCallback(_check_kids) # again with dirnode recreated from cap
- return d
+ # now make sure that we honor overwrite=False
+ d.addCallback(lambda res:
+ self.subdir2.set_uri(u"newchild",
+ other_file_uri, other_file_uri))
- def test_check(self):
- self.basedir = "dirnode/Dirnode/test_check"
- self.set_up_grid()
- c = self.g.clients[0]
- d = c.create_dirnode()
- d.addCallback(lambda dn: dn.check(Monitor()))
- def _done(res):
- self.failUnless(res.is_healthy())
- d.addCallback(_done)
- return d
+ d.addCallback(lambda res:
+ self.shouldFail(ExistingChildError, "move_child_to-no",
+ "child 'newchild' already exists",
+ n.move_child_to, u"newchild",
+ self.subdir2,
+ overwrite=False))
+ d.addCallback(lambda res: self.subdir2.get(u"newchild"))
+ d.addCallback(lambda child:
+ self.failUnlessReallyEqual(child.get_uri(),
+ other_file_uri))
- def _test_deepcheck_create(self):
- # create a small tree with a loop, and some non-directories
- # root/
- # root/subdir/
- # root/subdir/file1
- # root/subdir/link -> root
- # root/rodir
- c = self.g.clients[0]
- d = c.create_dirnode()
- def _created_root(rootnode):
- self._rootnode = rootnode
- return rootnode.create_subdirectory(u"subdir")
- d.addCallback(_created_root)
- def _created_subdir(subdir):
- self._subdir = subdir
- d = subdir.add_file(u"file1", upload.Data("data"*100, None))
- d.addCallback(lambda res: subdir.set_node(u"link", self._rootnode))
- d.addCallback(lambda res: c.create_dirnode())
- d.addCallback(lambda dn:
- self._rootnode.set_uri(u"rodir",
- dn.get_uri(),
- dn.get_readonly_uri()))
- return d
- d.addCallback(_created_subdir)
- def _done(res):
- return self._rootnode
- d.addCallback(_done)
- return d
- def test_deepcheck(self):
- self.basedir = "dirnode/Dirnode/test_deepcheck"
- self.set_up_grid()
- d = self._test_deepcheck_create()
- d.addCallback(lambda rootnode: rootnode.start_deep_check().when_done())
- def _check_results(r):
- self.failUnless(IDeepCheckResults.providedBy(r))
- c = r.get_counters()
- self.failUnlessReallyEqual(c,
- {"count-objects-checked": 4,
- "count-objects-healthy": 4,
- "count-objects-unhealthy": 0,
- "count-objects-unrecoverable": 0,
- "count-corrupt-shares": 0,
- })
- self.failIf(r.get_corrupt_shares())
- self.failUnlessReallyEqual(len(r.get_all_results()), 4)
- d.addCallback(_check_results)
- return d
+ # Setting the no-write field should diminish a mutable cap to read-only
+ # (for both files and directories).
- def test_deepcheck_and_repair(self):
- self.basedir = "dirnode/Dirnode/test_deepcheck_and_repair"
- self.set_up_grid()
- d = self._test_deepcheck_create()
- d.addCallback(lambda rootnode:
- rootnode.start_deep_check_and_repair().when_done())
- def _check_results(r):
- self.failUnless(IDeepCheckAndRepairResults.providedBy(r))
- c = r.get_counters()
- self.failUnlessReallyEqual(c,
- {"count-objects-checked": 4,
- "count-objects-healthy-pre-repair": 4,
- "count-objects-unhealthy-pre-repair": 0,
- "count-objects-unrecoverable-pre-repair": 0,
- "count-corrupt-shares-pre-repair": 0,
- "count-objects-healthy-post-repair": 4,
- "count-objects-unhealthy-post-repair": 0,
- "count-objects-unrecoverable-post-repair": 0,
- "count-corrupt-shares-post-repair": 0,
- "count-repairs-attempted": 0,
- "count-repairs-successful": 0,
- "count-repairs-unsuccessful": 0,
- })
- self.failIf(r.get_corrupt_shares())
- self.failIf(r.get_remaining_corrupt_shares())
- self.failUnlessReallyEqual(len(r.get_all_results()), 4)
- d.addCallback(_check_results)
- return d
+ d.addCallback(lambda ign: n.set_uri(u"mutable", other_file_uri, other_file_uri))
+ d.addCallback(lambda ign: n.get(u"mutable"))
+ d.addCallback(lambda mutable: self.failIf(mutable.is_readonly(), mutable))
+ d.addCallback(lambda ign: n.set_metadata_for(u"mutable", {"no-write": True}))
+ d.addCallback(lambda ign: n.get(u"mutable"))
+ d.addCallback(lambda mutable: self.failUnless(mutable.is_readonly(), mutable))
+ d.addCallback(lambda ign: n.set_metadata_for(u"mutable", {"no-write": True}))
+ d.addCallback(lambda ign: n.get(u"mutable"))
+ d.addCallback(lambda mutable: self.failUnless(mutable.is_readonly(), mutable))
- def _mark_file_bad(self, rootnode):
- self.delete_shares_numbered(rootnode.get_uri(), [0])
- return rootnode
+ d.addCallback(lambda ign: n.get(u"subdir2"))
+ d.addCallback(lambda subdir2: self.failIf(subdir2.is_readonly()))
+ d.addCallback(lambda ign: n.set_metadata_for(u"subdir2", {"no-write": True}))
+ d.addCallback(lambda ign: n.get(u"subdir2"))
+ d.addCallback(lambda subdir2: self.failUnless(subdir2.is_readonly(), subdir2))
- def test_deepcheck_problems(self):
- self.basedir = "dirnode/Dirnode/test_deepcheck_problems"
- self.set_up_grid()
- d = self._test_deepcheck_create()
- d.addCallback(lambda rootnode: self._mark_file_bad(rootnode))
- d.addCallback(lambda rootnode: rootnode.start_deep_check().when_done())
- def _check_results(r):
- c = r.get_counters()
- self.failUnlessReallyEqual(c,
- {"count-objects-checked": 4,
- "count-objects-healthy": 3,
- "count-objects-unhealthy": 1,
- "count-objects-unrecoverable": 0,
- "count-corrupt-shares": 0,
- })
- #self.failUnlessReallyEqual(len(r.get_problems()), 1) # TODO
- d.addCallback(_check_results)
+ d.addCallback(lambda ign: n.set_uri(u"mutable_ro", other_file_uri, other_file_uri,
+ metadata={"no-write": True}))
+ d.addCallback(lambda ign: n.get(u"mutable_ro"))
+ d.addCallback(lambda mutable_ro: self.failUnless(mutable_ro.is_readonly(), mutable_ro))
+
+ d.addCallback(lambda ign: n.create_subdirectory(u"subdir_ro", metadata={"no-write": True}))
+ d.addCallback(lambda ign: n.get(u"subdir_ro"))
+ d.addCallback(lambda subdir_ro: self.failUnless(subdir_ro.is_readonly(), subdir_ro))
+
+ return d
+
+ d.addCallback(_then)
+
+ d.addErrback(self.explain_error)
return d
- def test_readonly(self):
- self.basedir = "dirnode/Dirnode/test_readonly"
- self.set_up_grid()
+
+ def _do_initial_children_test(self, mdmf=False):
c = self.g.clients[0]
nm = c.nodemaker
- filecap = make_chk_file_uri(1234)
- filenode = nm.create_from_cap(filecap)
- uploadable = upload.Data("some data", convergence="some convergence string")
- d = c.create_dirnode()
- def _created(rw_dn):
- d2 = rw_dn.set_uri(u"child", filecap, filecap)
- d2.addCallback(lambda res: rw_dn)
- return d2
+ kids = {one_nfd: (nm.create_from_cap(one_uri), {}),
+ u"two": (nm.create_from_cap(setup_py_uri),
+ {"metakey": "metavalue"}),
+ u"mut": (nm.create_from_cap(mut_write_uri, mut_read_uri), {}),
+ u"fut": (nm.create_from_cap(future_write_uri, future_read_uri), {}),
+ u"fro": (nm.create_from_cap(None, future_read_uri), {}),
+ u"fut-unic": (nm.create_from_cap(future_nonascii_write_uri, future_nonascii_read_uri), {}),
+ u"fro-unic": (nm.create_from_cap(None, future_nonascii_read_uri), {}),
+ u"empty_litdir": (nm.create_from_cap(empty_litdir_uri), {}),
+ u"tiny_litdir": (nm.create_from_cap(tiny_litdir_uri), {}),
+ }
+ d = c.create_dirnode(kids)
+
+ def _created(dn):
+ self.failUnless(isinstance(dn, dirnode.DirectoryNode))
+ backing_node = dn._node
+ if mdmf:
+ self.failUnlessEqual(backing_node.get_version(),
+ MDMF_VERSION)
+ else:
+ self.failUnlessEqual(backing_node.get_version(),
+ SDMF_VERSION)
+ self.failUnless(dn.is_mutable())
+ self.failIf(dn.is_readonly())
+ self.failIf(dn.is_unknown())
+ self.failIf(dn.is_allowed_in_immutable_directory())
+ dn.raise_error()
+ rep = str(dn)
+ self.failUnless("RW-MUT" in rep)
+ return dn.list()
d.addCallback(_created)
+
+ def _check_kids(children):
+ self.failUnlessReallyEqual(set(children.keys()),
+ set([one_nfc, u"two", u"mut", u"fut", u"fro",
+ u"fut-unic", u"fro-unic", u"empty_litdir", u"tiny_litdir"]))
+ one_node, one_metadata = children[one_nfc]
+ two_node, two_metadata = children[u"two"]
+ mut_node, mut_metadata = children[u"mut"]
+ fut_node, fut_metadata = children[u"fut"]
+ fro_node, fro_metadata = children[u"fro"]
+ futna_node, futna_metadata = children[u"fut-unic"]
+ frona_node, frona_metadata = children[u"fro-unic"]
+ emptylit_node, emptylit_metadata = children[u"empty_litdir"]
+ tinylit_node, tinylit_metadata = children[u"tiny_litdir"]
- def _ready(rw_dn):
- ro_uri = rw_dn.get_readonly_uri()
- ro_dn = c.create_node_from_uri(ro_uri)
- self.failUnless(ro_dn.is_readonly())
- self.failUnless(ro_dn.is_mutable())
- self.failIf(ro_dn.is_unknown())
- self.failIf(ro_dn.is_allowed_in_immutable_directory())
- ro_dn.raise_error()
+ self.failUnlessReallyEqual(one_node.get_size(), 3)
+ self.failUnlessReallyEqual(one_node.get_uri(), one_uri)
+ self.failUnlessReallyEqual(one_node.get_readonly_uri(), one_uri)
+ self.failUnless(isinstance(one_metadata, dict), one_metadata)
- self.shouldFail(dirnode.NotWriteableError, "set_uri ro", None,
- ro_dn.set_uri, u"newchild", filecap, filecap)
- self.shouldFail(dirnode.NotWriteableError, "set_uri ro", None,
- ro_dn.set_node, u"newchild", filenode)
- self.shouldFail(dirnode.NotWriteableError, "set_nodes ro", None,
- ro_dn.set_nodes, { u"newchild": (filenode, None) })
- self.shouldFail(dirnode.NotWriteableError, "set_uri ro", None,
- ro_dn.add_file, u"newchild", uploadable)
- self.shouldFail(dirnode.NotWriteableError, "set_uri ro", None,
- ro_dn.delete, u"child")
- self.shouldFail(dirnode.NotWriteableError, "set_uri ro", None,
- ro_dn.create_subdirectory, u"newchild")
- self.shouldFail(dirnode.NotWriteableError, "set_metadata_for ro", None,
- ro_dn.set_metadata_for, u"child", {})
- self.shouldFail(dirnode.NotWriteableError, "set_uri ro", None,
- ro_dn.move_child_to, u"child", rw_dn)
- self.shouldFail(dirnode.NotWriteableError, "set_uri ro", None,
- rw_dn.move_child_to, u"child", ro_dn)
- return ro_dn.list()
- d.addCallback(_ready)
- def _listed(children):
- self.failUnless(u"child" in children)
- d.addCallback(_listed)
- return d
+ self.failUnlessReallyEqual(two_node.get_size(), 14861)
+ self.failUnlessReallyEqual(two_node.get_uri(), setup_py_uri)
+ self.failUnlessReallyEqual(two_node.get_readonly_uri(), setup_py_uri)
+ self.failUnlessEqual(two_metadata["metakey"], "metavalue")
- def failUnlessGreaterThan(self, a, b):
- self.failUnless(a > b, "%r should be > %r" % (a, b))
+ self.failUnlessReallyEqual(mut_node.get_uri(), mut_write_uri)
+ self.failUnlessReallyEqual(mut_node.get_readonly_uri(), mut_read_uri)
+ self.failUnless(isinstance(mut_metadata, dict), mut_metadata)
- def failUnlessGreaterOrEqualThan(self, a, b):
- self.failUnless(a >= b, "%r should be >= %r" % (a, b))
+ self.failUnless(fut_node.is_unknown())
+ self.failUnlessReallyEqual(fut_node.get_uri(), future_write_uri)
+ self.failUnlessReallyEqual(fut_node.get_readonly_uri(), "ro." + future_read_uri)
+ self.failUnless(isinstance(fut_metadata, dict), fut_metadata)
- def test_create(self):
- self.basedir = "dirnode/Dirnode/test_create"
- self.set_up_grid()
- c = self.g.clients[0]
+ self.failUnless(futna_node.is_unknown())
+ self.failUnlessReallyEqual(futna_node.get_uri(), future_nonascii_write_uri)
+ self.failUnlessReallyEqual(futna_node.get_readonly_uri(), "ro." + future_nonascii_read_uri)
+ self.failUnless(isinstance(futna_metadata, dict), futna_metadata)
- self.expected_manifest = []
- self.expected_verifycaps = set()
- self.expected_storage_indexes = set()
+ self.failUnless(fro_node.is_unknown())
+ self.failUnlessReallyEqual(fro_node.get_uri(), "ro." + future_read_uri)
+ self.failUnlessReallyEqual(fut_node.get_readonly_uri(), "ro." + future_read_uri)
+ self.failUnless(isinstance(fro_metadata, dict), fro_metadata)
- d = c.create_dirnode()
- def _then(n):
- # /
- self.rootnode = n
- self.failUnless(n.is_mutable())
- u = n.get_uri()
- self.failUnless(u)
- self.failUnless(u.startswith("URI:DIR2:"), u)
- u_ro = n.get_readonly_uri()
- self.failUnless(u_ro.startswith("URI:DIR2-RO:"), u_ro)
- u_v = n.get_verify_cap().to_string()
- self.failUnless(u_v.startswith("URI:DIR2-Verifier:"), u_v)
- u_r = n.get_repair_cap().to_string()
- self.failUnlessReallyEqual(u_r, u)
- self.expected_manifest.append( ((), u) )
- self.expected_verifycaps.add(u_v)
- si = n.get_storage_index()
- self.expected_storage_indexes.add(base32.b2a(si))
- expected_si = n._uri.get_storage_index()
- self.failUnlessReallyEqual(si, expected_si)
+ self.failUnless(frona_node.is_unknown())
+ self.failUnlessReallyEqual(frona_node.get_uri(), "ro." + future_nonascii_read_uri)
+ self.failUnlessReallyEqual(futna_node.get_readonly_uri(), "ro." + future_nonascii_read_uri)
+ self.failUnless(isinstance(frona_metadata, dict), frona_metadata)
- d = n.list()
- d.addCallback(lambda res: self.failUnlessEqual(res, {}))
- d.addCallback(lambda res: n.has_child(u"missing"))
- d.addCallback(lambda res: self.failIf(res))
+ self.failIf(emptylit_node.is_unknown())
+ self.failUnlessReallyEqual(emptylit_node.get_storage_index(), None)
+ self.failIf(tinylit_node.is_unknown())
+ self.failUnlessReallyEqual(tinylit_node.get_storage_index(), None)
- fake_file_uri = make_mutable_file_uri()
- other_file_uri = make_mutable_file_uri()
- m = c.nodemaker.create_from_cap(fake_file_uri)
- ffu_v = m.get_verify_cap().to_string()
- self.expected_manifest.append( ((u"child",) , m.get_uri()) )
- self.expected_verifycaps.add(ffu_v)
- self.expected_storage_indexes.add(base32.b2a(m.get_storage_index()))
- d.addCallback(lambda res: n.set_uri(u"child",
- fake_file_uri, fake_file_uri))
- d.addCallback(lambda res:
- self.shouldFail(ExistingChildError, "set_uri-no",
- "child 'child' already exists",
- n.set_uri, u"child",
- other_file_uri, other_file_uri,
- overwrite=False))
- # /
- # /child = mutable
+ d2 = defer.succeed(None)
+ d2.addCallback(lambda ignored: emptylit_node.list())
+ d2.addCallback(lambda children: self.failUnlessEqual(children, {}))
+ d2.addCallback(lambda ignored: tinylit_node.list())
+ d2.addCallback(lambda children: self.failUnlessReallyEqual(set(children.keys()),
+ set([u"short"])))
+ d2.addCallback(lambda ignored: tinylit_node.list())
+ d2.addCallback(lambda children: children[u"short"][0].read(MemAccum()))
+ d2.addCallback(lambda accum: self.failUnlessReallyEqual(accum.data, "The end."))
+ return d2
+ d.addCallback(_created)
+ d.addCallback(_check_kids)
- d.addCallback(lambda res: n.create_subdirectory(u"subdir"))
+ d.addCallback(lambda ign: nm.create_new_mutable_directory(kids))
+ d.addCallback(lambda dn: dn.list())
+ d.addCallback(_check_kids)
- # /
- # /child = mutable
- # /subdir = directory
- def _created(subdir):
- self.failUnless(isinstance(subdir, dirnode.DirectoryNode))
- self.subdir = subdir
- new_v = subdir.get_verify_cap().to_string()
- assert isinstance(new_v, str)
- self.expected_manifest.append( ((u"subdir",), subdir.get_uri()) )
- self.expected_verifycaps.add(new_v)
- si = subdir.get_storage_index()
- self.expected_storage_indexes.add(base32.b2a(si))
- d.addCallback(_created)
+ bad_future_node = UnknownNode(future_write_uri, None)
+ bad_kids1 = {one_nfd: (bad_future_node, {})}
+ # This should fail because we don't know how to diminish the future_write_uri
+ # cap (given in a write slot and not prefixed with "ro." or "imm.") to a readcap.
+ d.addCallback(lambda ign:
+ self.shouldFail(MustNotBeUnknownRWError, "bad_kids1",
+ "cannot attach unknown",
+ nm.create_new_mutable_directory,
+ bad_kids1))
+ bad_kids2 = {one_nfd: (nm.create_from_cap(one_uri), None)}
+ d.addCallback(lambda ign:
+ self.shouldFail(AssertionError, "bad_kids2",
+ "requires metadata to be a dict",
+ nm.create_new_mutable_directory,
+ bad_kids2))
+ return d
- d.addCallback(lambda res:
- self.shouldFail(ExistingChildError, "mkdir-no",
- "child 'subdir' already exists",
- n.create_subdirectory, u"subdir",
- overwrite=False))
+ def _do_basic_test(self, mdmf=False):
+ c = self.g.clients[0]
+ d = None
+ if mdmf:
+ d = c.create_dirnode(version=MDMF_VERSION)
+ else:
+ d = c.create_dirnode()
+ def _done(res):
+ self.failUnless(isinstance(res, dirnode.DirectoryNode))
+ self.failUnless(res.is_mutable())
+ self.failIf(res.is_readonly())
+ self.failIf(res.is_unknown())
+ self.failIf(res.is_allowed_in_immutable_directory())
+ res.raise_error()
+ rep = str(res)
+ self.failUnless("RW-MUT" in rep)
+ d.addCallback(_done)
+ return d
- d.addCallback(lambda res: n.list())
- d.addCallback(lambda children:
- self.failUnlessReallyEqual(set(children.keys()),
- set([u"child", u"subdir"])))
+ def test_basic(self):
+ self.basedir = "dirnode/Dirnode/test_basic"
+ self.set_up_grid()
+ return self._do_basic_test()
- d.addCallback(lambda res: n.start_deep_stats().when_done())
- def _check_deepstats(stats):
- self.failUnless(isinstance(stats, dict))
- expected = {"count-immutable-files": 0,
- "count-mutable-files": 1,
- "count-literal-files": 0,
- "count-files": 1,
- "count-directories": 2,
- "size-immutable-files": 0,
- "size-literal-files": 0,
- #"size-directories": 616, # varies
- #"largest-directory": 616,
- "largest-directory-children": 2,
- "largest-immutable-file": 0,
- }
- for k,v in expected.iteritems():
- self.failUnlessReallyEqual(stats[k], v,
- "stats[%s] was %s, not %s" %
- (k, stats[k], v))
- self.failUnless(stats["size-directories"] > 500,
- stats["size-directories"])
- self.failUnless(stats["largest-directory"] > 500,
- stats["largest-directory"])
- self.failUnlessReallyEqual(stats["size-files-histogram"], [])
- d.addCallback(_check_deepstats)
+ def test_basic_mdmf(self):
+ self.basedir = "dirnode/Dirnode/test_basic_mdmf"
+ self.set_up_grid()
+ return self._do_basic_test(mdmf=True)
- d.addCallback(lambda res: n.build_manifest().when_done())
- def _check_manifest(res):
- manifest = res["manifest"]
- self.failUnlessReallyEqual(sorted(manifest),
- sorted(self.expected_manifest))
- stats = res["stats"]
- _check_deepstats(stats)
- self.failUnlessReallyEqual(self.expected_verifycaps,
- res["verifycaps"])
- self.failUnlessReallyEqual(self.expected_storage_indexes,
- res["storage-index"])
- d.addCallback(_check_manifest)
+ def test_initial_children(self):
+ self.basedir = "dirnode/Dirnode/test_initial_children"
+ self.set_up_grid()
+ return self._do_initial_children_test()
- def _add_subsubdir(res):
- return self.subdir.create_subdirectory(u"subsubdir")
- d.addCallback(_add_subsubdir)
- # /
- # /child = mutable
- # /subdir = directory
- # /subdir/subsubdir = directory
- d.addCallback(lambda res: n.get_child_at_path(u"subdir/subsubdir"))
- d.addCallback(lambda subsubdir:
- self.failUnless(isinstance(subsubdir,
- dirnode.DirectoryNode)))
- d.addCallback(lambda res: n.get_child_at_path(u""))
- d.addCallback(lambda res: self.failUnlessReallyEqual(res.get_uri(),
- n.get_uri()))
+ def test_immutable(self):
+ self.basedir = "dirnode/Dirnode/test_immutable"
+ self.set_up_grid()
+ c = self.g.clients[0]
+ nm = c.nodemaker
- d.addCallback(lambda res: n.get_metadata_for(u"child"))
- d.addCallback(lambda metadata:
- self.failUnlessEqual(set(metadata.keys()),
- set(["tahoe"])))
+ kids = {one_nfd: (nm.create_from_cap(one_uri), {}),
+ u"two": (nm.create_from_cap(setup_py_uri),
+ {"metakey": "metavalue"}),
+ u"fut": (nm.create_from_cap(None, future_read_uri), {}),
+ u"futna": (nm.create_from_cap(None, future_nonascii_read_uri), {}),
+ u"empty_litdir": (nm.create_from_cap(empty_litdir_uri), {}),
+ u"tiny_litdir": (nm.create_from_cap(tiny_litdir_uri), {}),
+ }
+ d = c.create_immutable_dirnode(kids)
- d.addCallback(lambda res:
- self.shouldFail(NoSuchChildError, "gcamap-no",
- "nope",
- n.get_child_and_metadata_at_path,
- u"subdir/nope"))
- d.addCallback(lambda res:
- n.get_child_and_metadata_at_path(u""))
- def _check_child_and_metadata1(res):
- child, metadata = res
- self.failUnless(isinstance(child, dirnode.DirectoryNode))
- # edge-metadata needs at least one path segment
- self.failUnlessEqual(set(metadata.keys()), set([]))
- d.addCallback(_check_child_and_metadata1)
- d.addCallback(lambda res:
- n.get_child_and_metadata_at_path(u"child"))
+ def _created(dn):
+ self.failUnless(isinstance(dn, dirnode.DirectoryNode))
+ self.failIf(dn.is_mutable())
+ self.failUnless(dn.is_readonly())
+ self.failIf(dn.is_unknown())
+ self.failUnless(dn.is_allowed_in_immutable_directory())
+ dn.raise_error()
+ rep = str(dn)
+ self.failUnless("RO-IMM" in rep)
+ cap = dn.get_cap()
+ self.failUnlessIn("CHK", cap.to_string())
+ self.cap = cap
+ return dn.list()
+ d.addCallback(_created)
- def _check_child_and_metadata2(res):
- child, metadata = res
- self.failUnlessReallyEqual(child.get_uri(),
- fake_file_uri)
- self.failUnlessEqual(set(metadata.keys()), set(["tahoe"]))
- d.addCallback(_check_child_and_metadata2)
+ def _check_kids(children):
+ self.failUnlessReallyEqual(set(children.keys()),
+ set([one_nfc, u"two", u"fut", u"futna", u"empty_litdir", u"tiny_litdir"]))
+ one_node, one_metadata = children[one_nfc]
+ two_node, two_metadata = children[u"two"]
+ fut_node, fut_metadata = children[u"fut"]
+ futna_node, futna_metadata = children[u"futna"]
+ emptylit_node, emptylit_metadata = children[u"empty_litdir"]
+ tinylit_node, tinylit_metadata = children[u"tiny_litdir"]
- d.addCallback(lambda res:
- n.get_child_and_metadata_at_path(u"subdir/subsubdir"))
- def _check_child_and_metadata3(res):
- child, metadata = res
- self.failUnless(isinstance(child, dirnode.DirectoryNode))
- self.failUnlessEqual(set(metadata.keys()), set(["tahoe"]))
- d.addCallback(_check_child_and_metadata3)
+ self.failUnlessReallyEqual(one_node.get_size(), 3)
+ self.failUnlessReallyEqual(one_node.get_uri(), one_uri)
+ self.failUnlessReallyEqual(one_node.get_readonly_uri(), one_uri)
+ self.failUnless(isinstance(one_metadata, dict), one_metadata)
- # set_uri + metadata
- # it should be possible to add a child without any metadata
- d.addCallback(lambda res: n.set_uri(u"c2",
- fake_file_uri, fake_file_uri,
- {}))
- d.addCallback(lambda res: n.get_metadata_for(u"c2"))
- d.addCallback(lambda metadata:
- self.failUnlessEqual(set(metadata.keys()), set(["tahoe"])))
+ self.failUnlessReallyEqual(two_node.get_size(), 14861)
+ self.failUnlessReallyEqual(two_node.get_uri(), setup_py_uri)
+ self.failUnlessReallyEqual(two_node.get_readonly_uri(), setup_py_uri)
+ self.failUnlessEqual(two_metadata["metakey"], "metavalue")
- # You can't override the link timestamps.
- d.addCallback(lambda res: n.set_uri(u"c2",
- fake_file_uri, fake_file_uri,
- { 'tahoe': {'linkcrtime': "bogus"}}))
- d.addCallback(lambda res: n.get_metadata_for(u"c2"))
- def _has_good_linkcrtime(metadata):
- self.failUnless(metadata.has_key('tahoe'))
- self.failUnless(metadata['tahoe'].has_key('linkcrtime'))
- self.failIfEqual(metadata['tahoe']['linkcrtime'], 'bogus')
- d.addCallback(_has_good_linkcrtime)
+ self.failUnless(fut_node.is_unknown())
+ self.failUnlessReallyEqual(fut_node.get_uri(), "imm." + future_read_uri)
+ self.failUnlessReallyEqual(fut_node.get_readonly_uri(), "imm." + future_read_uri)
+ self.failUnless(isinstance(fut_metadata, dict), fut_metadata)
- # if we don't set any defaults, the child should get timestamps
- d.addCallback(lambda res: n.set_uri(u"c3",
- fake_file_uri, fake_file_uri))
- d.addCallback(lambda res: n.get_metadata_for(u"c3"))
- d.addCallback(lambda metadata:
- self.failUnlessEqual(set(metadata.keys()), set(["tahoe"])))
+ self.failUnless(futna_node.is_unknown())
+ self.failUnlessReallyEqual(futna_node.get_uri(), "imm." + future_nonascii_read_uri)
+ self.failUnlessReallyEqual(futna_node.get_readonly_uri(), "imm." + future_nonascii_read_uri)
+ self.failUnless(isinstance(futna_metadata, dict), futna_metadata)
- # we can also add specific metadata at set_uri() time
- d.addCallback(lambda res: n.set_uri(u"c4",
- fake_file_uri, fake_file_uri,
- {"key": "value"}))
- d.addCallback(lambda res: n.get_metadata_for(u"c4"))
- d.addCallback(lambda metadata:
- self.failUnless((set(metadata.keys()) == set(["key", "tahoe"])) and
- (metadata['key'] == "value"), metadata))
+ self.failIf(emptylit_node.is_unknown())
+ self.failUnlessReallyEqual(emptylit_node.get_storage_index(), None)
+ self.failIf(tinylit_node.is_unknown())
+ self.failUnlessReallyEqual(tinylit_node.get_storage_index(), None)
- d.addCallback(lambda res: n.delete(u"c2"))
- d.addCallback(lambda res: n.delete(u"c3"))
- d.addCallback(lambda res: n.delete(u"c4"))
+ d2 = defer.succeed(None)
+ d2.addCallback(lambda ignored: emptylit_node.list())
+ d2.addCallback(lambda children: self.failUnlessEqual(children, {}))
+ d2.addCallback(lambda ignored: tinylit_node.list())
+ d2.addCallback(lambda children: self.failUnlessReallyEqual(set(children.keys()),
+ set([u"short"])))
+ d2.addCallback(lambda ignored: tinylit_node.list())
+ d2.addCallback(lambda children: children[u"short"][0].read(MemAccum()))
+ d2.addCallback(lambda accum: self.failUnlessReallyEqual(accum.data, "The end."))
+ return d2
- # set_node + metadata
- # it should be possible to add a child without any metadata except for timestamps
- d.addCallback(lambda res: n.set_node(u"d2", n, {}))
- d.addCallback(lambda res: c.create_dirnode())
- d.addCallback(lambda n2:
- self.shouldFail(ExistingChildError, "set_node-no",
- "child 'd2' already exists",
- n.set_node, u"d2", n2,
- overwrite=False))
- d.addCallback(lambda res: n.get_metadata_for(u"d2"))
- d.addCallback(lambda metadata:
- self.failUnlessEqual(set(metadata.keys()), set(["tahoe"])))
+ d.addCallback(_check_kids)
- # if we don't set any defaults, the child should get timestamps
- d.addCallback(lambda res: n.set_node(u"d3", n))
- d.addCallback(lambda res: n.get_metadata_for(u"d3"))
- d.addCallback(lambda metadata:
- self.failUnlessEqual(set(metadata.keys()), set(["tahoe"])))
+ d.addCallback(lambda ign: nm.create_from_cap(self.cap.to_string()))
+ d.addCallback(lambda dn: dn.list())
+ d.addCallback(_check_kids)
- # we can also add specific metadata at set_node() time
- d.addCallback(lambda res: n.set_node(u"d4", n,
- {"key": "value"}))
- d.addCallback(lambda res: n.get_metadata_for(u"d4"))
- d.addCallback(lambda metadata:
- self.failUnless((set(metadata.keys()) == set(["key", "tahoe"])) and
- (metadata["key"] == "value"), metadata))
+ bad_future_node1 = UnknownNode(future_write_uri, None)
+ bad_kids1 = {one_nfd: (bad_future_node1, {})}
+ d.addCallback(lambda ign:
+ self.shouldFail(MustNotBeUnknownRWError, "bad_kids1",
+ "cannot attach unknown",
+ c.create_immutable_dirnode,
+ bad_kids1))
+ bad_future_node2 = UnknownNode(future_write_uri, future_read_uri)
+ bad_kids2 = {one_nfd: (bad_future_node2, {})}
+ d.addCallback(lambda ign:
+ self.shouldFail(MustBeDeepImmutableError, "bad_kids2",
+ "is not allowed in an immutable directory",
+ c.create_immutable_dirnode,
+ bad_kids2))
+ bad_kids3 = {one_nfd: (nm.create_from_cap(one_uri), None)}
+ d.addCallback(lambda ign:
+ self.shouldFail(AssertionError, "bad_kids3",
+ "requires metadata to be a dict",
+ c.create_immutable_dirnode,
+ bad_kids3))
+ bad_kids4 = {one_nfd: (nm.create_from_cap(mut_write_uri), {})}
+ d.addCallback(lambda ign:
+ self.shouldFail(MustBeDeepImmutableError, "bad_kids4",
+ "is not allowed in an immutable directory",
+ c.create_immutable_dirnode,
+ bad_kids4))
+ bad_kids5 = {one_nfd: (nm.create_from_cap(mut_read_uri), {})}
+ d.addCallback(lambda ign:
+ self.shouldFail(MustBeDeepImmutableError, "bad_kids5",
+ "is not allowed in an immutable directory",
+ c.create_immutable_dirnode,
+ bad_kids5))
+ d.addCallback(lambda ign: c.create_immutable_dirnode({}))
+ def _created_empty(dn):
+ self.failUnless(isinstance(dn, dirnode.DirectoryNode))
+ self.failIf(dn.is_mutable())
+ self.failUnless(dn.is_readonly())
+ self.failIf(dn.is_unknown())
+ self.failUnless(dn.is_allowed_in_immutable_directory())
+ dn.raise_error()
+ rep = str(dn)
+ self.failUnless("RO-IMM" in rep)
+ cap = dn.get_cap()
+ self.failUnlessIn("LIT", cap.to_string())
+ self.failUnlessReallyEqual(cap.to_string(), "URI:DIR2-LIT:")
+ self.cap = cap
+ return dn.list()
+ d.addCallback(_created_empty)
+ d.addCallback(lambda kids: self.failUnlessEqual(kids, {}))
+ smallkids = {u"o": (nm.create_from_cap(one_uri), {})}
+ d.addCallback(lambda ign: c.create_immutable_dirnode(smallkids))
+ def _created_small(dn):
+ self.failUnless(isinstance(dn, dirnode.DirectoryNode))
+ self.failIf(dn.is_mutable())
+ self.failUnless(dn.is_readonly())
+ self.failIf(dn.is_unknown())
+ self.failUnless(dn.is_allowed_in_immutable_directory())
+ dn.raise_error()
+ rep = str(dn)
+ self.failUnless("RO-IMM" in rep)
+ cap = dn.get_cap()
+ self.failUnlessIn("LIT", cap.to_string())
+ self.failUnlessReallyEqual(cap.to_string(),
+ "URI:DIR2-LIT:gi4tumj2n4wdcmz2kvjesosmjfkdu3rvpbtwwlbqhiwdeot3puwcy")
+ self.cap = cap
+ return dn.list()
+ d.addCallback(_created_small)
+ d.addCallback(lambda kids: self.failUnlessReallyEqual(kids.keys(), [u"o"]))
- d.addCallback(lambda res: n.delete(u"d2"))
- d.addCallback(lambda res: n.delete(u"d3"))
- d.addCallback(lambda res: n.delete(u"d4"))
+ # now test n.create_subdirectory(mutable=False)
+ d.addCallback(lambda ign: c.create_dirnode())
+ def _made_parent(n):
+ d = n.create_subdirectory(u"subdir", kids, mutable=False)
+ d.addCallback(lambda sd: sd.list())
+ d.addCallback(_check_kids)
+ d.addCallback(lambda ign: n.list())
+ d.addCallback(lambda children:
+ self.failUnlessReallyEqual(children.keys(), [u"subdir"]))
+ d.addCallback(lambda ign: n.get(u"subdir"))
+ d.addCallback(lambda sd: sd.list())
+ d.addCallback(_check_kids)
+ d.addCallback(lambda ign: n.get(u"subdir"))
+ d.addCallback(lambda sd: self.failIf(sd.is_mutable()))
+ bad_kids = {one_nfd: (nm.create_from_cap(mut_write_uri), {})}
+ d.addCallback(lambda ign:
+ self.shouldFail(MustBeDeepImmutableError, "YZ",
+ "is not allowed in an immutable directory",
+ n.create_subdirectory,
+ u"sub2", bad_kids, mutable=False))
+ return d
+ d.addCallback(_made_parent)
+ return d
- # metadata through set_children()
- d.addCallback(lambda res:
- n.set_children({
- u"e1": (fake_file_uri, fake_file_uri),
- u"e2": (fake_file_uri, fake_file_uri, {}),
- u"e3": (fake_file_uri, fake_file_uri,
- {"key": "value"}),
- }))
- d.addCallback(lambda n2: self.failUnlessIdentical(n2, n))
- d.addCallback(lambda res:
- self.shouldFail(ExistingChildError, "set_children-no",
- "child 'e1' already exists",
- n.set_children,
- { u"e1": (other_file_uri,
- other_file_uri),
- u"new": (other_file_uri,
- other_file_uri),
- },
- overwrite=False))
- # and 'new' should not have been created
- d.addCallback(lambda res: n.list())
- d.addCallback(lambda children: self.failIf(u"new" in children))
- d.addCallback(lambda res: n.get_metadata_for(u"e1"))
- d.addCallback(lambda metadata:
- self.failUnlessEqual(set(metadata.keys()), set(["tahoe"])))
- d.addCallback(lambda res: n.get_metadata_for(u"e2"))
- d.addCallback(lambda metadata:
- self.failUnlessEqual(set(metadata.keys()), set(["tahoe"])))
- d.addCallback(lambda res: n.get_metadata_for(u"e3"))
- d.addCallback(lambda metadata:
- self.failUnless((set(metadata.keys()) == set(["key", "tahoe"])) and
- (metadata["key"] == "value"), metadata))
+ def test_directory_representation(self):
+ self.basedir = "dirnode/Dirnode/test_directory_representation"
+ self.set_up_grid()
+ c = self.g.clients[0]
+ nm = c.nodemaker
- d.addCallback(lambda res: n.delete(u"e1"))
- d.addCallback(lambda res: n.delete(u"e2"))
- d.addCallback(lambda res: n.delete(u"e3"))
+ # This test checks that any trailing spaces in URIs are retained in the
+ # encoded directory, but stripped when we get them out of the directory.
+ # See ticket #925 for why we want that.
+ # It also tests that we store child names as UTF-8 NFC, and normalize
+ # them again when retrieving them.
- # metadata through set_nodes()
- d.addCallback(lambda res:
- n.set_nodes({ u"f1": (n, None),
- u"f2": (n, {}),
- u"f3": (n, {"key": "value"}),
- }))
- d.addCallback(lambda n2: self.failUnlessIdentical(n2, n))
- d.addCallback(lambda res:
- self.shouldFail(ExistingChildError, "set_nodes-no",
- "child 'f1' already exists",
- n.set_nodes, { u"f1": (n, None),
- u"new": (n, None), },
- overwrite=False))
- # and 'new' should not have been created
- d.addCallback(lambda res: n.list())
- d.addCallback(lambda children: self.failIf(u"new" in children))
- d.addCallback(lambda res: n.get_metadata_for(u"f1"))
- d.addCallback(lambda metadata:
- self.failUnlessEqual(set(metadata.keys()), set(["tahoe"])))
- d.addCallback(lambda res: n.get_metadata_for(u"f2"))
- d.addCallback(lambda metadata:
- self.failUnlessEqual(set(metadata.keys()), set(["tahoe"])))
- d.addCallback(lambda res: n.get_metadata_for(u"f3"))
- d.addCallback(lambda metadata:
- self.failUnless((set(metadata.keys()) == set(["key", "tahoe"])) and
- (metadata["key"] == "value"), metadata))
+ stripped_write_uri = "lafs://from_the_future\t"
+ stripped_read_uri = "lafs://readonly_from_the_future\t"
+ spacedout_write_uri = stripped_write_uri + " "
+ spacedout_read_uri = stripped_read_uri + " "
- d.addCallback(lambda res: n.delete(u"f1"))
- d.addCallback(lambda res: n.delete(u"f2"))
- d.addCallback(lambda res: n.delete(u"f3"))
+ child = nm.create_from_cap(spacedout_write_uri, spacedout_read_uri)
+ self.failUnlessReallyEqual(child.get_write_uri(), spacedout_write_uri)
+ self.failUnlessReallyEqual(child.get_readonly_uri(), "ro." + spacedout_read_uri)
+ child_dottedi = u"ch\u0131\u0307ld"
- d.addCallback(lambda res:
- n.set_metadata_for(u"child",
- {"tags": ["web2.0-compatible"], "tahoe": {"bad": "mojo"}}))
- d.addCallback(lambda n1: n1.get_metadata_for(u"child"))
- d.addCallback(lambda metadata:
- self.failUnless((set(metadata.keys()) == set(["tags", "tahoe"])) and
- metadata["tags"] == ["web2.0-compatible"] and
- "bad" not in metadata["tahoe"], metadata))
+ kids_in = {child_dottedi: (child, {}), one_nfd: (child, {})}
+ kids_out = {child_dottedi: (child, {}), one_nfc: (child, {})}
+ kids_norm = {u"child": (child, {}), one_nfc: (child, {})}
+ d = c.create_dirnode(kids_in)
- d.addCallback(lambda res:
- self.shouldFail(NoSuchChildError, "set_metadata_for-nosuch", "",
- n.set_metadata_for, u"nosuch", {}))
+ def _created(dn):
+ self.failUnless(isinstance(dn, dirnode.DirectoryNode))
+ self.failUnless(dn.is_mutable())
+ self.failIf(dn.is_readonly())
+ dn.raise_error()
+ self.cap = dn.get_cap()
+ self.rootnode = dn
+ return dn._node.download_best_version()
+ d.addCallback(_created)
+ def _check_data(data):
+ # Decode the netstring representation of the directory to check that the
+ # spaces are retained when the URIs are stored, and that the names are stored
+ # as NFC.
+ position = 0
+ numkids = 0
+ while position < len(data):
+ entries, position = split_netstring(data, 1, position)
+ entry = entries[0]
+ (name_utf8, ro_uri, rwcapdata, metadata_s), subpos = split_netstring(entry, 4)
+ name = name_utf8.decode("utf-8")
+ rw_uri = self.rootnode._decrypt_rwcapdata(rwcapdata)
+ self.failUnlessIn(name, kids_out)
+ (expected_child, ign) = kids_out[name]
+ self.failUnlessReallyEqual(rw_uri, expected_child.get_write_uri())
+ self.failUnlessReallyEqual("ro." + ro_uri, expected_child.get_readonly_uri())
+ numkids += 1
- def _start(res):
- self._start_timestamp = time.time()
- d.addCallback(_start)
- # simplejson-1.7.1 (as shipped on Ubuntu 'gutsy') rounds all
- # floats to hundredeths (it uses str(num) instead of repr(num)).
- # simplejson-1.7.3 does not have this bug. To prevent this bug
- # from causing the test to fail, stall for more than a few
- # hundrededths of a second.
- d.addCallback(self.stall, 0.1)
- d.addCallback(lambda res: n.add_file(u"timestamps",
- upload.Data("stamp me", convergence="some convergence string")))
- d.addCallback(self.stall, 0.1)
- def _stop(res):
- self._stop_timestamp = time.time()
- d.addCallback(_stop)
+ self.failUnlessReallyEqual(numkids, len(kids_out))
+ return self.rootnode
+ d.addCallback(_check_data)
- d.addCallback(lambda res: n.get_metadata_for(u"timestamps"))
- def _check_timestamp1(metadata):
- self.failUnlessEqual(set(metadata.keys()), set(["tahoe"]))
- tahoe_md = metadata["tahoe"]
- self.failUnlessEqual(set(tahoe_md.keys()), set(["linkcrtime", "linkmotime"]))
+ # Mock up a hypothetical future version of Unicode that adds a canonical equivalence
+ # between dotless-i + dot-above, and 'i'. That would actually be prohibited by the
+ # stability rules, but similar additions involving currently-unassigned characters
+ # would not be.
+ old_normalize = unicodedata.normalize
+ def future_normalize(form, s):
+ assert form == 'NFC', form
+ return old_normalize(form, s).replace(u"\u0131\u0307", u"i")
- self.failUnlessGreaterOrEqualThan(tahoe_md["linkcrtime"],
- self._start_timestamp)
- self.failUnlessGreaterOrEqualThan(self._stop_timestamp,
- tahoe_md["linkcrtime"])
- self.failUnlessGreaterOrEqualThan(tahoe_md["linkmotime"],
- self._start_timestamp)
- self.failUnlessGreaterOrEqualThan(self._stop_timestamp,
- tahoe_md["linkmotime"])
- # Our current timestamp rules say that replacing an existing
- # child should preserve the 'linkcrtime' but update the
- # 'linkmotime'
- self._old_linkcrtime = tahoe_md["linkcrtime"]
- self._old_linkmotime = tahoe_md["linkmotime"]
- d.addCallback(_check_timestamp1)
- d.addCallback(self.stall, 2.0) # accomodate low-res timestamps
- d.addCallback(lambda res: n.set_node(u"timestamps", n))
- d.addCallback(lambda res: n.get_metadata_for(u"timestamps"))
- def _check_timestamp2(metadata):
- self.failUnlessIn("tahoe", metadata)
- tahoe_md = metadata["tahoe"]
- self.failUnlessEqual(set(tahoe_md.keys()), set(["linkcrtime", "linkmotime"]))
+ def _list(node):
+ unicodedata.normalize = future_normalize
+ d2 = node.list()
+ def _undo_mock(res):
+ unicodedata.normalize = old_normalize
+ return res
+ d2.addBoth(_undo_mock)
+ return d2
+ d.addCallback(_list)
- self.failUnlessReallyEqual(tahoe_md["linkcrtime"], self._old_linkcrtime)
- self.failUnlessGreaterThan(tahoe_md["linkmotime"], self._old_linkmotime)
- return n.delete(u"timestamps")
- d.addCallback(_check_timestamp2)
+ def _check_kids(children):
+ # Now when we use the real directory listing code, the trailing spaces
+ # should have been stripped (and "ro." should have been prepended to the
+ # ro_uri, since it's unknown). Also the dotless-i + dot-above should have been
+ # normalized to 'i'.
- d.addCallback(lambda res: n.delete(u"subdir"))
- d.addCallback(lambda old_child:
- self.failUnlessReallyEqual(old_child.get_uri(),
- self.subdir.get_uri()))
+ self.failUnlessReallyEqual(set(children.keys()), set(kids_norm.keys()))
+ child_node, child_metadata = children[u"child"]
- d.addCallback(lambda res: n.list())
- d.addCallback(lambda children:
- self.failUnlessReallyEqual(set(children.keys()),
- set([u"child"])))
+ self.failUnlessReallyEqual(child_node.get_write_uri(), stripped_write_uri)
+ self.failUnlessReallyEqual(child_node.get_readonly_uri(), "ro." + stripped_read_uri)
+ d.addCallback(_check_kids)
- uploadable1 = upload.Data("some data", convergence="converge")
- d.addCallback(lambda res: n.add_file(u"newfile", uploadable1))
- d.addCallback(lambda newnode:
- self.failUnless(IImmutableFileNode.providedBy(newnode)))
- uploadable2 = upload.Data("some data", convergence="stuff")
- d.addCallback(lambda res:
- self.shouldFail(ExistingChildError, "add_file-no",
- "child 'newfile' already exists",
- n.add_file, u"newfile",
- uploadable2,
- overwrite=False))
- d.addCallback(lambda res: n.list())
- d.addCallback(lambda children:
- self.failUnlessReallyEqual(set(children.keys()),
- set([u"child", u"newfile"])))
- d.addCallback(lambda res: n.get_metadata_for(u"newfile"))
- d.addCallback(lambda metadata:
- self.failUnlessEqual(set(metadata.keys()), set(["tahoe"])))
+ d.addCallback(lambda ign: nm.create_from_cap(self.cap.to_string()))
+ d.addCallback(_list)
+ d.addCallback(_check_kids) # again with dirnode recreated from cap
+ return d
- uploadable3 = upload.Data("some data", convergence="converge")
- d.addCallback(lambda res: n.add_file(u"newfile-metadata",
- uploadable3,
- {"key": "value"}))
- d.addCallback(lambda newnode:
- self.failUnless(IImmutableFileNode.providedBy(newnode)))
- d.addCallback(lambda res: n.get_metadata_for(u"newfile-metadata"))
- d.addCallback(lambda metadata:
- self.failUnless((set(metadata.keys()) == set(["key", "tahoe"])) and
- (metadata['key'] == "value"), metadata))
- d.addCallback(lambda res: n.delete(u"newfile-metadata"))
+ def test_check(self):
+ self.basedir = "dirnode/Dirnode/test_check"
+ self.set_up_grid()
+ c = self.g.clients[0]
+ d = c.create_dirnode()
+ d.addCallback(lambda dn: dn.check(Monitor()))
+ def _done(res):
+ self.failUnless(res.is_healthy())
+ d.addCallback(_done)
+ return d
+
+ def _test_deepcheck_create(self, version=SDMF_VERSION):
+ # create a small tree with a loop, and some non-directories
+ # root/
+ # root/subdir/
+ # root/subdir/file1
+ # root/subdir/link -> root
+ # root/rodir
+ c = self.g.clients[0]
+ d = c.create_dirnode(version=version)
+ def _created_root(rootnode):
+ self._rootnode = rootnode
+ self.failUnlessEqual(rootnode._node.get_version(), version)
+ return rootnode.create_subdirectory(u"subdir")
+ d.addCallback(_created_root)
+ def _created_subdir(subdir):
+ self._subdir = subdir
+ d = subdir.add_file(u"file1", upload.Data("data"*100, None))
+ d.addCallback(lambda res: subdir.set_node(u"link", self._rootnode))
+ d.addCallback(lambda res: c.create_dirnode())
+ d.addCallback(lambda dn:
+ self._rootnode.set_uri(u"rodir",
+ dn.get_uri(),
+ dn.get_readonly_uri()))
+ return d
+ d.addCallback(_created_subdir)
+ def _done(res):
+ return self._rootnode
+ d.addCallback(_done)
+ return d
+
+ def test_deepcheck(self):
+ self.basedir = "dirnode/Dirnode/test_deepcheck"
+ self.set_up_grid()
+ d = self._test_deepcheck_create()
+ d.addCallback(lambda rootnode: rootnode.start_deep_check().when_done())
+ def _check_results(r):
+ self.failUnless(IDeepCheckResults.providedBy(r))
+ c = r.get_counters()
+ self.failUnlessReallyEqual(c,
+ {"count-objects-checked": 4,
+ "count-objects-healthy": 4,
+ "count-objects-unhealthy": 0,
+ "count-objects-unrecoverable": 0,
+ "count-corrupt-shares": 0,
+ })
+ self.failIf(r.get_corrupt_shares())
+ self.failUnlessReallyEqual(len(r.get_all_results()), 4)
+ d.addCallback(_check_results)
+ return d
- d.addCallback(lambda res: n.create_subdirectory(u"subdir2"))
- def _created2(subdir2):
- self.subdir2 = subdir2
- # put something in the way, to make sure it gets overwritten
- return subdir2.add_file(u"child", upload.Data("overwrite me",
- "converge"))
- d.addCallback(_created2)
+ def test_deepcheck_mdmf(self):
+ self.basedir = "dirnode/Dirnode/test_deepcheck_mdmf"
+ self.set_up_grid()
+ d = self._test_deepcheck_create(MDMF_VERSION)
+ d.addCallback(lambda rootnode: rootnode.start_deep_check().when_done())
+ def _check_results(r):
+ self.failUnless(IDeepCheckResults.providedBy(r))
+ c = r.get_counters()
+ self.failUnlessReallyEqual(c,
+ {"count-objects-checked": 4,
+ "count-objects-healthy": 4,
+ "count-objects-unhealthy": 0,
+ "count-objects-unrecoverable": 0,
+ "count-corrupt-shares": 0,
+ })
+ self.failIf(r.get_corrupt_shares())
+ self.failUnlessReallyEqual(len(r.get_all_results()), 4)
+ d.addCallback(_check_results)
+ return d
- d.addCallback(lambda res:
- n.move_child_to(u"child", self.subdir2))
- d.addCallback(lambda res: n.list())
- d.addCallback(lambda children:
- self.failUnlessReallyEqual(set(children.keys()),
- set([u"newfile", u"subdir2"])))
- d.addCallback(lambda res: self.subdir2.list())
- d.addCallback(lambda children:
- self.failUnlessReallyEqual(set(children.keys()),
- set([u"child"])))
- d.addCallback(lambda res: self.subdir2.get(u"child"))
- d.addCallback(lambda child:
- self.failUnlessReallyEqual(child.get_uri(),
- fake_file_uri))
+ def test_deepcheck_and_repair(self):
+ self.basedir = "dirnode/Dirnode/test_deepcheck_and_repair"
+ self.set_up_grid()
+ d = self._test_deepcheck_create()
+ d.addCallback(lambda rootnode:
+ rootnode.start_deep_check_and_repair().when_done())
+ def _check_results(r):
+ self.failUnless(IDeepCheckAndRepairResults.providedBy(r))
+ c = r.get_counters()
+ self.failUnlessReallyEqual(c,
+ {"count-objects-checked": 4,
+ "count-objects-healthy-pre-repair": 4,
+ "count-objects-unhealthy-pre-repair": 0,
+ "count-objects-unrecoverable-pre-repair": 0,
+ "count-corrupt-shares-pre-repair": 0,
+ "count-objects-healthy-post-repair": 4,
+ "count-objects-unhealthy-post-repair": 0,
+ "count-objects-unrecoverable-post-repair": 0,
+ "count-corrupt-shares-post-repair": 0,
+ "count-repairs-attempted": 0,
+ "count-repairs-successful": 0,
+ "count-repairs-unsuccessful": 0,
+ })
+ self.failIf(r.get_corrupt_shares())
+ self.failIf(r.get_remaining_corrupt_shares())
+ self.failUnlessReallyEqual(len(r.get_all_results()), 4)
+ d.addCallback(_check_results)
+ return d
- # move it back, using new_child_name=
- d.addCallback(lambda res:
- self.subdir2.move_child_to(u"child", n, u"newchild"))
- d.addCallback(lambda res: n.list())
- d.addCallback(lambda children:
- self.failUnlessReallyEqual(set(children.keys()),
- set([u"newchild", u"newfile",
- u"subdir2"])))
- d.addCallback(lambda res: self.subdir2.list())
- d.addCallback(lambda children:
- self.failUnlessReallyEqual(set(children.keys()), set([])))
+ def test_deepcheck_and_repair_mdmf(self):
+ self.basedir = "dirnode/Dirnode/test_deepcheck_and_repair_mdmf"
+ self.set_up_grid()
+ d = self._test_deepcheck_create(version=MDMF_VERSION)
+ d.addCallback(lambda rootnode:
+ rootnode.start_deep_check_and_repair().when_done())
+ def _check_results(r):
+ self.failUnless(IDeepCheckAndRepairResults.providedBy(r))
+ c = r.get_counters()
+ self.failUnlessReallyEqual(c,
+ {"count-objects-checked": 4,
+ "count-objects-healthy-pre-repair": 4,
+ "count-objects-unhealthy-pre-repair": 0,
+ "count-objects-unrecoverable-pre-repair": 0,
+ "count-corrupt-shares-pre-repair": 0,
+ "count-objects-healthy-post-repair": 4,
+ "count-objects-unhealthy-post-repair": 0,
+ "count-objects-unrecoverable-post-repair": 0,
+ "count-corrupt-shares-post-repair": 0,
+ "count-repairs-attempted": 0,
+ "count-repairs-successful": 0,
+ "count-repairs-unsuccessful": 0,
+ })
+ self.failIf(r.get_corrupt_shares())
+ self.failIf(r.get_remaining_corrupt_shares())
+ self.failUnlessReallyEqual(len(r.get_all_results()), 4)
+ d.addCallback(_check_results)
+ return d
- # now make sure that we honor overwrite=False
- d.addCallback(lambda res:
- self.subdir2.set_uri(u"newchild",
- other_file_uri, other_file_uri))
+ def _mark_file_bad(self, rootnode):
+ self.delete_shares_numbered(rootnode.get_uri(), [0])
+ return rootnode
- d.addCallback(lambda res:
- self.shouldFail(ExistingChildError, "move_child_to-no",
- "child 'newchild' already exists",
- n.move_child_to, u"newchild",
- self.subdir2,
- overwrite=False))
- d.addCallback(lambda res: self.subdir2.get(u"newchild"))
- d.addCallback(lambda child:
- self.failUnlessReallyEqual(child.get_uri(),
- other_file_uri))
+ def test_deepcheck_problems(self):
+ self.basedir = "dirnode/Dirnode/test_deepcheck_problems"
+ self.set_up_grid()
+ d = self._test_deepcheck_create()
+ d.addCallback(lambda rootnode: self._mark_file_bad(rootnode))
+ d.addCallback(lambda rootnode: rootnode.start_deep_check().when_done())
+ def _check_results(r):
+ c = r.get_counters()
+ self.failUnlessReallyEqual(c,
+ {"count-objects-checked": 4,
+ "count-objects-healthy": 3,
+ "count-objects-unhealthy": 1,
+ "count-objects-unrecoverable": 0,
+ "count-corrupt-shares": 0,
+ })
+ #self.failUnlessReallyEqual(len(r.get_problems()), 1) # TODO
+ d.addCallback(_check_results)
+ return d
+ def test_deepcheck_problems_mdmf(self):
+ self.basedir = "dirnode/Dirnode/test_deepcheck_problems_mdmf"
+ self.set_up_grid()
+ d = self._test_deepcheck_create(version=MDMF_VERSION)
+ d.addCallback(lambda rootnode: self._mark_file_bad(rootnode))
+ d.addCallback(lambda rootnode: rootnode.start_deep_check().when_done())
+ def _check_results(r):
+ c = r.get_counters()
+ self.failUnlessReallyEqual(c,
+ {"count-objects-checked": 4,
+ "count-objects-healthy": 3,
+ "count-objects-unhealthy": 1,
+ "count-objects-unrecoverable": 0,
+ "count-corrupt-shares": 0,
+ })
+ #self.failUnlessReallyEqual(len(r.get_problems()), 1) # TODO
+ d.addCallback(_check_results)
+ return d
- # Setting the no-write field should diminish a mutable cap to read-only
- # (for both files and directories).
+ def _do_readonly_test(self, version=SDMF_VERSION):
+ c = self.g.clients[0]
+ nm = c.nodemaker
+ filecap = make_chk_file_uri(1234)
+ filenode = nm.create_from_cap(filecap)
+ uploadable = upload.Data("some data", convergence="some convergence string")
- d.addCallback(lambda ign: n.set_uri(u"mutable", other_file_uri, other_file_uri))
- d.addCallback(lambda ign: n.get(u"mutable"))
- d.addCallback(lambda mutable: self.failIf(mutable.is_readonly(), mutable))
- d.addCallback(lambda ign: n.set_metadata_for(u"mutable", {"no-write": True}))
- d.addCallback(lambda ign: n.get(u"mutable"))
- d.addCallback(lambda mutable: self.failUnless(mutable.is_readonly(), mutable))
- d.addCallback(lambda ign: n.set_metadata_for(u"mutable", {"no-write": True}))
- d.addCallback(lambda ign: n.get(u"mutable"))
- d.addCallback(lambda mutable: self.failUnless(mutable.is_readonly(), mutable))
+ d = c.create_dirnode(version=version)
+ def _created(rw_dn):
+ backing_node = rw_dn._node
+ self.failUnlessEqual(backing_node.get_version(), version)
+ d2 = rw_dn.set_uri(u"child", filecap, filecap)
+ d2.addCallback(lambda res: rw_dn)
+ return d2
+ d.addCallback(_created)
- d.addCallback(lambda ign: n.get(u"subdir2"))
- d.addCallback(lambda subdir2: self.failIf(subdir2.is_readonly()))
- d.addCallback(lambda ign: n.set_metadata_for(u"subdir2", {"no-write": True}))
- d.addCallback(lambda ign: n.get(u"subdir2"))
- d.addCallback(lambda subdir2: self.failUnless(subdir2.is_readonly(), subdir2))
+ def _ready(rw_dn):
+ ro_uri = rw_dn.get_readonly_uri()
+ ro_dn = c.create_node_from_uri(ro_uri)
+ self.failUnless(ro_dn.is_readonly())
+ self.failUnless(ro_dn.is_mutable())
+ self.failIf(ro_dn.is_unknown())
+ self.failIf(ro_dn.is_allowed_in_immutable_directory())
+ ro_dn.raise_error()
- d.addCallback(lambda ign: n.set_uri(u"mutable_ro", other_file_uri, other_file_uri,
- metadata={"no-write": True}))
- d.addCallback(lambda ign: n.get(u"mutable_ro"))
- d.addCallback(lambda mutable_ro: self.failUnless(mutable_ro.is_readonly(), mutable_ro))
+ self.shouldFail(dirnode.NotWriteableError, "set_uri ro", None,
+ ro_dn.set_uri, u"newchild", filecap, filecap)
+ self.shouldFail(dirnode.NotWriteableError, "set_uri ro", None,
+ ro_dn.set_node, u"newchild", filenode)
+ self.shouldFail(dirnode.NotWriteableError, "set_nodes ro", None,
+ ro_dn.set_nodes, { u"newchild": (filenode, None) })
+ self.shouldFail(dirnode.NotWriteableError, "set_uri ro", None,
+ ro_dn.add_file, u"newchild", uploadable)
+ self.shouldFail(dirnode.NotWriteableError, "set_uri ro", None,
+ ro_dn.delete, u"child")
+ self.shouldFail(dirnode.NotWriteableError, "set_uri ro", None,
+ ro_dn.create_subdirectory, u"newchild")
+ self.shouldFail(dirnode.NotWriteableError, "set_metadata_for ro", None,
+ ro_dn.set_metadata_for, u"child", {})
+ self.shouldFail(dirnode.NotWriteableError, "set_uri ro", None,
+ ro_dn.move_child_to, u"child", rw_dn)
+ self.shouldFail(dirnode.NotWriteableError, "set_uri ro", None,
+ rw_dn.move_child_to, u"child", ro_dn)
+ return ro_dn.list()
+ d.addCallback(_ready)
+ def _listed(children):
+ self.failUnless(u"child" in children)
+ d.addCallback(_listed)
+ return d
- d.addCallback(lambda ign: n.create_subdirectory(u"subdir_ro", metadata={"no-write": True}))
- d.addCallback(lambda ign: n.get(u"subdir_ro"))
- d.addCallback(lambda subdir_ro: self.failUnless(subdir_ro.is_readonly(), subdir_ro))
+ def test_readonly(self):
+ self.basedir = "dirnode/Dirnode/test_readonly"
+ self.set_up_grid()
+ return self._do_readonly_test()
- return d
+ def test_readonly_mdmf(self):
+ self.basedir = "dirnode/Dirnode/test_readonly_mdmf"
+ self.set_up_grid()
+ return self._do_readonly_test(version=MDMF_VERSION)
- d.addCallback(_then)
+ def failUnlessGreaterThan(self, a, b):
+ self.failUnless(a > b, "%r should be > %r" % (a, b))
- d.addErrback(self.explain_error)
- return d
+ def failUnlessGreaterOrEqualThan(self, a, b):
+ self.failUnless(a >= b, "%r should be >= %r" % (a, b))
+
+ def test_create(self):
+ self.basedir = "dirnode/Dirnode/test_create"
+ self.set_up_grid()
+ return self._do_create_test()
def test_update_metadata(self):
(t1, t2, t3) = (626644800.0, 634745640.0, 892226160.0)
self.failUnlessEqual(md4, {"bool": True, "number": 42,
"tahoe":{"linkcrtime": t1, "linkmotime": t1}})
- def test_create_subdirectory(self):
- self.basedir = "dirnode/Dirnode/test_create_subdirectory"
- self.set_up_grid()
+ def _do_create_subdirectory_test(self, version=SDMF_VERSION):
c = self.g.clients[0]
nm = c.nodemaker
- d = c.create_dirnode()
+ d = c.create_dirnode(version=version)
def _then(n):
# /
self.rootnode = n
kids = {u"kid1": (nm.create_from_cap(fake_file_uri), {}),
u"kid2": (nm.create_from_cap(other_file_uri), md),
}
- d = n.create_subdirectory(u"subdir", kids)
+ d = n.create_subdirectory(u"subdir", kids,
+ mutable_version=version)
def _check(sub):
d = n.get_child_at_path(u"subdir")
d.addCallback(lambda sub2: self.failUnlessReallyEqual(sub2.get_uri(),
d.addCallback(_then)
return d
+ def test_create_subdirectory(self):
+ self.basedir = "dirnode/Dirnode/test_create_subdirectory"
+ self.set_up_grid()
+ return self._do_create_subdirectory_test()
+
+ def test_create_subdirectory_mdmf(self):
+ self.basedir = "dirnode/Dirnode/test_create_subdirectory_mdmf"
+ self.set_up_grid()
+ return self._do_create_subdirectory_test(version=MDMF_VERSION)
+
+ def test_create_mdmf(self):
+ self.basedir = "dirnode/Dirnode/test_mdmf"
+ self.set_up_grid()
+ return self._do_create_test(mdmf=True)
+
+ def test_mdmf_initial_children(self):
+ self.basedir = "dirnode/Dirnode/test_mdmf"
+ self.set_up_grid()
+ return self._do_initial_children_test(mdmf=True)
+
class MinimalFakeMutableFile:
def get_writekey(self):
return "writekey"
implements(IMutableFileNode)
counter = 0
def __init__(self, initial_contents=""):
- self.data = self._get_initial_contents(initial_contents)
+ data = self._get_initial_contents(initial_contents)
+ self.data = data.read(data.get_size())
+ self.data = "".join(self.data)
+
counter = FakeMutableFile.counter
FakeMutableFile.counter += 1
writekey = hashutil.ssk_writekey_hash(str(counter))
pass
def modify(self, modifier):
- self.data = modifier(self.data, None, True)
+ data = modifier(self.data, None, True)
+ self.data = data
return defer.succeed(None)
class FakeNodeMaker(NodeMaker):
- def create_mutable_file(self, contents="", keysize=None):
+ def create_mutable_file(self, contents="", keysize=None, version=None):
return defer.succeed(FakeMutableFile(contents))
class FakeClient2(Client):
self.failUnless(n.get_readonly_uri().startswith("imm."), i)
+
class DeepStats(testutil.ReallyEqualMixin, unittest.TestCase):
timeout = 240 # It takes longer than 120 seconds on Francois's arm box.
def test_stats(self):