2006-12-04 04:11:26 +00:00
|
|
|
|
2007-06-26 22:36:46 +00:00
|
|
|
from cStringIO import StringIO
|
2006-12-04 04:11:26 +00:00
|
|
|
from twisted.trial import unittest
|
|
|
|
from twisted.internet import defer
|
2007-06-25 20:23:51 +00:00
|
|
|
from twisted.python import failure
|
|
|
|
from allmydata import vdrive, filetable, uri
|
|
|
|
from allmydata.interfaces import IDirectoryNode
|
2007-06-26 22:36:46 +00:00
|
|
|
from allmydata.scripts import runner
|
2007-06-25 20:23:51 +00:00
|
|
|
from foolscap import eventual
|
2006-12-04 04:11:26 +00:00
|
|
|
|
2007-06-25 20:23:51 +00:00
|
|
|
class LocalReference:
|
|
|
|
def __init__(self, target):
|
|
|
|
self.target = target
|
2006-12-04 04:11:26 +00:00
|
|
|
def callRemote(self, methname, *args, **kwargs):
|
2007-06-25 20:23:51 +00:00
|
|
|
def _call(ignored):
|
|
|
|
meth = getattr(self.target, methname)
|
2006-12-04 04:11:26 +00:00
|
|
|
return meth(*args, **kwargs)
|
2007-06-25 20:23:51 +00:00
|
|
|
d = eventual.fireEventually(None)
|
|
|
|
d.addCallback(_call)
|
|
|
|
return d
|
|
|
|
|
|
|
|
class MyTub:
|
|
|
|
def __init__(self, vds, myfurl):
|
|
|
|
self.vds = vds
|
|
|
|
self.myfurl = myfurl
|
|
|
|
def getReference(self, furl):
|
|
|
|
assert furl == self.myfurl
|
|
|
|
return eventual.fireEventually(LocalReference(self.vds))
|
|
|
|
|
|
|
|
class MyClient:
|
|
|
|
def __init__(self, vds, myfurl):
|
|
|
|
self.tub = MyTub(vds, myfurl)
|
|
|
|
|
|
|
|
class Test(unittest.TestCase):
|
|
|
|
def test_create_directory(self):
|
2007-06-26 22:36:46 +00:00
|
|
|
basedir = "vdrive/test_create_directory/vdrive"
|
2007-06-25 20:23:51 +00:00
|
|
|
vds = filetable.VirtualDriveServer(basedir)
|
|
|
|
vds.set_furl("myFURL")
|
|
|
|
self.client = client = MyClient(vds, "myFURL")
|
|
|
|
d = vdrive.create_directory(client, "myFURL")
|
|
|
|
def _created(node):
|
|
|
|
self.failUnless(IDirectoryNode.providedBy(node))
|
|
|
|
self.failUnless(node.is_mutable())
|
|
|
|
d.addCallback(_created)
|
|
|
|
return d
|
|
|
|
|
|
|
|
def test_one(self):
|
2007-06-26 22:36:46 +00:00
|
|
|
self.basedir = basedir = "vdrive/test_one/vdrive"
|
2007-06-25 20:23:51 +00:00
|
|
|
vds = filetable.VirtualDriveServer(basedir)
|
|
|
|
vds.set_furl("myFURL")
|
|
|
|
root_uri = vds.get_public_root_uri()
|
|
|
|
|
|
|
|
self.client = client = MyClient(vds, "myFURL")
|
|
|
|
d1 = vdrive.create_directory_node(client, root_uri)
|
|
|
|
d2 = vdrive.create_directory_node(client, root_uri)
|
|
|
|
d = defer.gatherResults( [d1,d2] )
|
|
|
|
d.addCallback(self._test_one_1)
|
|
|
|
return d
|
|
|
|
|
|
|
|
def _test_one_1(self, (rootnode1, rootnode2) ):
|
|
|
|
self.failUnlessEqual(rootnode1, rootnode2)
|
|
|
|
self.failIfEqual(rootnode1, "not")
|
|
|
|
|
|
|
|
self.rootnode = rootnode = rootnode1
|
|
|
|
self.failUnless(rootnode.is_mutable())
|
|
|
|
self.readonly_uri = rootnode.get_immutable_uri()
|
|
|
|
d = vdrive.create_directory_node(self.client, self.readonly_uri)
|
|
|
|
d.addCallback(self._test_one_2)
|
|
|
|
return d
|
|
|
|
|
|
|
|
def _test_one_2(self, ro_rootnode):
|
|
|
|
self.ro_rootnode = ro_rootnode
|
|
|
|
self.failIf(ro_rootnode.is_mutable())
|
|
|
|
self.failUnlessEqual(ro_rootnode.get_immutable_uri(),
|
|
|
|
self.readonly_uri)
|
|
|
|
|
|
|
|
rootnode = self.rootnode
|
|
|
|
|
|
|
|
ignored = rootnode.dump()
|
|
|
|
|
|
|
|
# root/
|
|
|
|
d = rootnode.list()
|
|
|
|
def _listed(res):
|
|
|
|
self.failUnlessEqual(res, {})
|
|
|
|
d.addCallback(_listed)
|
|
|
|
|
|
|
|
file1 = uri.pack_uri("i"*32, "k"*16, "e"*32, 25, 100, 12345)
|
|
|
|
file2 = uri.pack_uri("i"*31 + "2", "k"*16, "e"*32, 25, 100, 12345)
|
|
|
|
file2_node = vdrive.FileNode(file2, None)
|
|
|
|
d.addCallback(lambda res: rootnode.set_uri("foo", file1))
|
|
|
|
# root/
|
|
|
|
# root/foo =file1
|
|
|
|
|
|
|
|
d.addCallback(lambda res: rootnode.list())
|
|
|
|
def _listed2(res):
|
|
|
|
self.failUnlessEqual(res.keys(), ["foo"])
|
|
|
|
file1_node = res["foo"]
|
|
|
|
self.failUnless(isinstance(file1_node, vdrive.FileNode))
|
|
|
|
self.failUnlessEqual(file1_node.uri, file1)
|
|
|
|
d.addCallback(_listed2)
|
|
|
|
|
|
|
|
d.addCallback(lambda res: rootnode.get("foo"))
|
|
|
|
def _got_foo(res):
|
|
|
|
self.failUnless(isinstance(res, vdrive.FileNode))
|
|
|
|
self.failUnlessEqual(res.uri, file1)
|
|
|
|
d.addCallback(_got_foo)
|
|
|
|
|
|
|
|
d.addCallback(lambda res: rootnode.get("missing"))
|
|
|
|
# this should raise an exception
|
|
|
|
d.addBoth(self.shouldFail, IndexError, "get('missing')",
|
|
|
|
"unable to find child named 'missing'")
|
|
|
|
|
|
|
|
d.addCallback(lambda res: rootnode.create_empty_directory("bar"))
|
|
|
|
# root/
|
|
|
|
# root/foo =file1
|
|
|
|
# root/bar/
|
|
|
|
|
|
|
|
d.addCallback(lambda res: rootnode.list())
|
|
|
|
d.addCallback(self.failUnlessKeysMatch, ["foo", "bar"])
|
|
|
|
def _listed3(res):
|
|
|
|
self.failIfEqual(res["foo"], res["bar"])
|
|
|
|
self.failIfEqual(res["bar"], res["foo"])
|
|
|
|
self.failIfEqual(res["foo"], "not")
|
|
|
|
self.failIfEqual(res["bar"], self.rootnode)
|
|
|
|
self.failUnlessEqual(res["foo"], res["foo"])
|
|
|
|
# make sure the objects can be used as dict keys
|
|
|
|
testdict = {res["foo"]: 1, res["bar"]: 2}
|
|
|
|
bar_node = res["bar"]
|
|
|
|
self.failUnless(isinstance(bar_node, vdrive.MutableDirectoryNode))
|
|
|
|
self.bar_node = bar_node
|
|
|
|
bar_ro_uri = bar_node.get_immutable_uri()
|
|
|
|
return rootnode.set_uri("bar-ro", bar_ro_uri)
|
|
|
|
d.addCallback(_listed3)
|
|
|
|
# root/
|
|
|
|
# root/foo =file1
|
|
|
|
# root/bar/
|
|
|
|
# root/bar-ro/ (read-only)
|
|
|
|
|
|
|
|
d.addCallback(lambda res: rootnode.list())
|
|
|
|
d.addCallback(self.failUnlessKeysMatch, ["foo", "bar", "bar-ro"])
|
|
|
|
def _listed4(res):
|
|
|
|
self.failIf(res["bar-ro"].is_mutable())
|
|
|
|
self.bar_node_readonly = res["bar-ro"]
|
|
|
|
|
|
|
|
# add another file to bar/
|
|
|
|
bar = res["bar"]
|
|
|
|
return bar.set_node("file2", file2_node)
|
|
|
|
d.addCallback(_listed4)
|
|
|
|
d.addCallback(self.failUnlessIdentical, file2_node)
|
|
|
|
# and a directory
|
|
|
|
d.addCallback(lambda res: self.bar_node.create_empty_directory("baz"))
|
|
|
|
# root/
|
|
|
|
# root/foo =file1
|
|
|
|
# root/bar/
|
|
|
|
# root/bar/file2 =file2
|
|
|
|
# root/bar/baz/
|
|
|
|
# root/bar-ro/ (read-only)
|
|
|
|
# root/bar-ro/file2 =file2
|
|
|
|
# root/bar-ro/baz/
|
|
|
|
|
|
|
|
d.addCallback(lambda res: self.bar_node.list())
|
|
|
|
d.addCallback(self.failUnlessKeysMatch, ["file2", "baz"])
|
|
|
|
d.addCallback(lambda res:
|
|
|
|
self.failUnless(res["baz"].is_mutable()))
|
|
|
|
|
|
|
|
d.addCallback(lambda res: self.bar_node_readonly.list())
|
|
|
|
d.addCallback(self.failUnlessKeysMatch, ["file2", "baz"])
|
|
|
|
d.addCallback(lambda res:
|
|
|
|
self.failIf(res["baz"].is_mutable()))
|
|
|
|
|
|
|
|
# try to add a file to bar-ro, should get exception
|
|
|
|
d.addCallback(lambda res:
|
|
|
|
self.bar_node_readonly.set_uri("file3", file2))
|
|
|
|
d.addBoth(self.shouldFail, vdrive.NotMutableError,
|
|
|
|
"bar-ro.set('file3')")
|
|
|
|
|
|
|
|
# try to delete a file from bar-ro, should get exception
|
|
|
|
d.addCallback(lambda res: self.bar_node_readonly.delete("file2"))
|
|
|
|
d.addBoth(self.shouldFail, vdrive.NotMutableError,
|
|
|
|
"bar-ro.delete('file2')")
|
|
|
|
|
|
|
|
# try to mkdir in bar-ro, should get exception
|
|
|
|
d.addCallback(lambda res:
|
|
|
|
self.bar_node_readonly.create_empty_directory("boffo"))
|
|
|
|
d.addBoth(self.shouldFail, vdrive.NotMutableError,
|
|
|
|
"bar-ro.mkdir('boffo')")
|
|
|
|
|
|
|
|
d.addCallback(lambda res: rootnode.delete("foo"))
|
|
|
|
# root/
|
|
|
|
# root/bar/
|
|
|
|
# root/bar/file2 =file2
|
|
|
|
# root/bar/baz/
|
|
|
|
# root/bar-ro/ (read-only)
|
|
|
|
# root/bar-ro/file2 =file2
|
|
|
|
# root/bar-ro/baz/
|
|
|
|
|
|
|
|
d.addCallback(lambda res: rootnode.list())
|
|
|
|
d.addCallback(self.failUnlessKeysMatch, ["bar", "bar-ro"])
|
|
|
|
|
|
|
|
d.addCallback(lambda res:
|
|
|
|
self.bar_node.move_child_to("file2",
|
|
|
|
self.rootnode, "file4"))
|
|
|
|
# root/
|
|
|
|
# root/file4 = file4
|
|
|
|
# root/bar/
|
|
|
|
# root/bar/baz/
|
|
|
|
# root/bar-ro/ (read-only)
|
|
|
|
# root/bar-ro/baz/
|
|
|
|
|
|
|
|
d.addCallback(lambda res: rootnode.list())
|
|
|
|
d.addCallback(self.failUnlessKeysMatch, ["bar", "bar-ro", "file4"])
|
|
|
|
d.addCallback(lambda res:self.bar_node.list())
|
|
|
|
d.addCallback(self.failUnlessKeysMatch, ["baz"])
|
|
|
|
d.addCallback(lambda res:self.bar_node_readonly.list())
|
|
|
|
d.addCallback(self.failUnlessKeysMatch, ["baz"])
|
|
|
|
|
|
|
|
|
|
|
|
d.addCallback(lambda res:
|
|
|
|
rootnode.move_child_to("file4",
|
|
|
|
self.bar_node_readonly, "boffo"))
|
|
|
|
d.addBoth(self.shouldFail, vdrive.NotMutableError,
|
|
|
|
"mv root/file4 root/bar-ro/boffo")
|
|
|
|
|
|
|
|
d.addCallback(lambda res: rootnode.list())
|
|
|
|
d.addCallback(self.failUnlessKeysMatch, ["bar", "bar-ro", "file4"])
|
|
|
|
d.addCallback(lambda res:self.bar_node.list())
|
|
|
|
d.addCallback(self.failUnlessKeysMatch, ["baz"])
|
|
|
|
d.addCallback(lambda res:self.bar_node_readonly.list())
|
|
|
|
d.addCallback(self.failUnlessKeysMatch, ["baz"])
|
|
|
|
|
|
|
|
|
|
|
|
d.addCallback(lambda res:
|
|
|
|
rootnode.move_child_to("file4", self.bar_node))
|
|
|
|
|
|
|
|
d.addCallback(lambda res: rootnode.list())
|
|
|
|
d.addCallback(self.failUnlessKeysMatch, ["bar", "bar-ro"])
|
|
|
|
d.addCallback(lambda res:self.bar_node.list())
|
|
|
|
d.addCallback(self.failUnlessKeysMatch, ["baz", "file4"])
|
|
|
|
d.addCallback(lambda res:self.bar_node_readonly.list())
|
|
|
|
d.addCallback(self.failUnlessKeysMatch, ["baz", "file4"])
|
|
|
|
|
2007-06-26 22:36:46 +00:00
|
|
|
d.addCallback(self._test_one_3)
|
2007-06-25 20:23:51 +00:00
|
|
|
return d
|
|
|
|
|
2007-06-26 22:36:46 +00:00
|
|
|
def _test_one_3(self, res):
|
|
|
|
# now test some of the diag tools with the data we've created
|
2007-06-26 23:51:38 +00:00
|
|
|
out,err = StringIO(), StringIO()
|
|
|
|
rc = runner.runner(["dump-root-dirnode", "vdrive/test_one"],
|
|
|
|
stdout=out, stderr=err)
|
|
|
|
output = out.getvalue()
|
2007-06-26 22:36:46 +00:00
|
|
|
self.failUnless(output.startswith("URI:DIR:fakeFURL:"))
|
|
|
|
self.failUnlessEqual(rc, 0)
|
|
|
|
|
2007-06-26 23:51:38 +00:00
|
|
|
out,err = StringIO(), StringIO()
|
|
|
|
rc = runner.runner(["dump-dirnode",
|
|
|
|
"--basedir", "vdrive/test_one",
|
|
|
|
"--verbose",
|
|
|
|
self.bar_node.get_uri()],
|
|
|
|
stdout=out, stderr=err)
|
|
|
|
output = out.getvalue()
|
2007-06-26 22:36:46 +00:00
|
|
|
#print output
|
2007-06-26 23:51:38 +00:00
|
|
|
self.failUnlessEqual(rc, 0)
|
2007-06-26 22:36:46 +00:00
|
|
|
self.failUnless("dirnode uri: URI:DIR:myFURL" in output)
|
|
|
|
self.failUnless("write_enabler" in output)
|
|
|
|
self.failIf("write_enabler: None" in output)
|
|
|
|
self.failUnless("key baz\n" in output)
|
|
|
|
self.failUnless(" write: URI:DIR:myFURL:" in output)
|
|
|
|
self.failUnless(" read: URI:DIR-RO:myFURL:" in output)
|
|
|
|
self.failUnless("key file4\n" in output)
|
|
|
|
self.failUnless("H_key " in output)
|
|
|
|
|
2007-06-26 23:51:38 +00:00
|
|
|
out,err = StringIO(), StringIO()
|
|
|
|
rc = runner.runner(["dump-dirnode",
|
|
|
|
"--basedir", "vdrive/test_one",
|
|
|
|
# non-verbose
|
|
|
|
"--uri", self.bar_node.get_uri()],
|
|
|
|
stdout=out, stderr=err)
|
|
|
|
output = out.getvalue()
|
2007-06-26 22:36:46 +00:00
|
|
|
#print output
|
2007-06-26 23:51:38 +00:00
|
|
|
self.failUnlessEqual(rc, 0)
|
2007-06-26 22:36:46 +00:00
|
|
|
self.failUnless("dirnode uri: URI:DIR:myFURL" in output)
|
|
|
|
self.failUnless("write_enabler" in output)
|
|
|
|
self.failIf("write_enabler: None" in output)
|
|
|
|
self.failUnless("key baz\n" in output)
|
|
|
|
self.failUnless(" write: URI:DIR:myFURL:" in output)
|
|
|
|
self.failUnless(" read: URI:DIR-RO:myFURL:" in output)
|
|
|
|
self.failUnless("key file4\n" in output)
|
|
|
|
self.failIf("H_key " in output)
|
|
|
|
|
2007-06-26 23:51:38 +00:00
|
|
|
out,err = StringIO(), StringIO()
|
|
|
|
rc = runner.runner(["dump-dirnode",
|
|
|
|
"--basedir", "vdrive/test_one",
|
|
|
|
"--verbose",
|
|
|
|
self.bar_node_readonly.get_uri()],
|
|
|
|
stdout=out, stderr=err)
|
|
|
|
output = out.getvalue()
|
2007-06-26 22:36:46 +00:00
|
|
|
#print output
|
2007-06-26 23:51:38 +00:00
|
|
|
self.failUnlessEqual(rc, 0)
|
2007-06-26 22:36:46 +00:00
|
|
|
self.failUnless("dirnode uri: URI:DIR-RO:myFURL" in output)
|
|
|
|
self.failUnless("write_enabler: None" in output)
|
|
|
|
self.failUnless("key baz\n" in output)
|
|
|
|
self.failIf(" write: URI:DIR:myFURL:" in output)
|
|
|
|
self.failUnless(" read: URI:DIR-RO:myFURL:" in output)
|
|
|
|
self.failUnless("key file4\n" in output)
|
|
|
|
|
2007-06-25 20:23:51 +00:00
|
|
|
def shouldFail(self, res, expected_failure, which, substring=None):
|
|
|
|
if isinstance(res, failure.Failure):
|
|
|
|
res.trap(expected_failure)
|
|
|
|
if substring:
|
|
|
|
self.failUnless(substring in str(res),
|
|
|
|
"substring '%s' not in '%s'"
|
|
|
|
% (substring, str(res)))
|
|
|
|
else:
|
|
|
|
self.fail("%s was supposed to raise %s, not get '%s'" %
|
|
|
|
(which, expected_failure, res))
|
|
|
|
|
|
|
|
def failUnlessKeysMatch(self, res, expected_keys):
|
|
|
|
self.failUnlessEqual(sorted(res.keys()),
|
|
|
|
sorted(expected_keys))
|
|
|
|
return res
|
2006-12-04 04:11:26 +00:00
|
|
|
|
2007-06-26 19:36:21 +00:00
|
|
|
def flip_bit(data, offset):
|
|
|
|
if offset < 0:
|
|
|
|
offset = len(data) + offset
|
|
|
|
return data[:offset] + chr(ord(data[offset]) ^ 0x01) + data[offset+1:]
|
|
|
|
|
|
|
|
class Encryption(unittest.TestCase):
|
|
|
|
def test_loopback(self):
|
|
|
|
key = "k" * 16
|
|
|
|
data = "This is some plaintext data."
|
|
|
|
crypttext = vdrive.encrypt(key, data)
|
|
|
|
plaintext = vdrive.decrypt(key, crypttext)
|
|
|
|
self.failUnlessEqual(data, plaintext)
|
|
|
|
|
|
|
|
def test_hmac(self):
|
|
|
|
key = "j" * 16
|
|
|
|
data = "This is some more plaintext data."
|
|
|
|
crypttext = vdrive.encrypt(key, data)
|
|
|
|
# flip a bit in the IV
|
|
|
|
self.failUnlessRaises(vdrive.IntegrityCheckError,
|
|
|
|
vdrive.decrypt,
|
|
|
|
key, flip_bit(crypttext, 0))
|
|
|
|
# flip a bit in the crypttext
|
|
|
|
self.failUnlessRaises(vdrive.IntegrityCheckError,
|
|
|
|
vdrive.decrypt,
|
|
|
|
key, flip_bit(crypttext, 16))
|
|
|
|
# flip a bit in the HMAC
|
|
|
|
self.failUnlessRaises(vdrive.IntegrityCheckError,
|
|
|
|
vdrive.decrypt,
|
|
|
|
key, flip_bit(crypttext, -1))
|
|
|
|
plaintext = vdrive.decrypt(key, crypttext)
|
|
|
|
self.failUnlessEqual(data, plaintext)
|
|
|
|
|