-import os.path, re, urllib
+import os.path, re, urllib, time
import simplejson
from StringIO import StringIO
from twisted.application import service
from allmydata import interfaces, uri, webish, dirnode
from allmydata.storage.shares import get_share_file
from allmydata.storage_client import StorageFarmBroker
-from allmydata.immutable import upload, download
+from allmydata.immutable import upload
+from allmydata.immutable.downloader.status import DownloadStatus
from allmydata.dirnode import DirectoryNode
from allmydata.nodemaker import NodeMaker
from allmydata.unknown import UnknownNode
from allmydata.web import status, common
from allmydata.scripts.debug import CorruptShareOptions, corrupt_share
-from allmydata.util import fileutil, base32
+from allmydata.util import fileutil, base32, hashutil
from allmydata.util.consumer import download_to_data
from allmydata.util.netstring import split_netstring
+from allmydata.util.encodingutil import to_str
from allmydata.test.common import FakeCHKFileNode, FakeMutableFileNode, \
- create_chk_filenode, WebErrorMixin, ShouldFailMixin, make_mutable_file_uri
-from allmydata.interfaces import IMutableFileNode
+ create_chk_filenode, WebErrorMixin, ShouldFailMixin, \
+ make_mutable_file_uri, create_mutable_filenode
+from allmydata.interfaces import IMutableFileNode, SDMF_VERSION, MDMF_VERSION
from allmydata.mutable import servermap, publish, retrieve
import allmydata.test.common_util as testutil
from allmydata.test.no_network import GridTestMixin
timeout = 480 # Most of these take longer than 240 seconds on Francois's arm box.
-unknown_rwcap = "lafs://from_the_future"
-unknown_rocap = "ro.lafs://readonly_from_the_future"
-unknown_immcap = "imm.lafs://immutable_from_the_future"
+unknown_rwcap = u"lafs://from_the_future_rw_\u263A".encode('utf-8')
+unknown_rocap = u"ro.lafs://readonly_from_the_future_ro_\u263A".encode('utf-8')
+unknown_immcap = u"imm.lafs://immutable_from_the_future_imm_\u263A".encode('utf-8')
class FakeStatsProvider:
def get_stats(self):
return stats
class FakeNodeMaker(NodeMaker):
+ encoding_params = {
+ 'k': 3,
+ 'n': 10,
+ 'happy': 7,
+ 'max_segment_size':128*1024 # 1024=KiB
+ }
def _create_lit(self, cap):
return FakeCHKFileNode(cap)
def _create_immutable(self, cap):
return FakeCHKFileNode(cap)
def _create_mutable(self, cap):
- return FakeMutableFileNode(None, None, None, None).init_from_cap(cap)
- def create_mutable_file(self, contents="", keysize=None):
- n = FakeMutableFileNode(None, None, None, None)
- return n.create(contents)
+ return FakeMutableFileNode(None,
+ None,
+ self.encoding_params, None).init_from_cap(cap)
+ def create_mutable_file(self, contents="", keysize=None,
+ version=SDMF_VERSION):
+ n = FakeMutableFileNode(None, None, self.encoding_params, None)
+ return n.create(contents, version=version)
class FakeUploader(service.Service):
name = "uploader"
def get_helper_info(self):
return (None, False)
+class FakeIServer:
+ def __init__(self, binaryserverid):
+ self.binaryserverid = binaryserverid
+ def get_name(self): return "short"
+ def get_longname(self): return "long"
+ def get_serverid(self): return self.binaryserverid
+
+def build_one_ds():
+ ds = DownloadStatus("storage_index", 1234)
+ now = time.time()
+
+ serverA = FakeIServer(hashutil.tagged_hash("foo", "serverid_a")[:20])
+ serverB = FakeIServer(hashutil.tagged_hash("foo", "serverid_b")[:20])
+ storage_index = hashutil.storage_index_hash("SI")
+ e0 = ds.add_segment_request(0, now)
+ e0.activate(now+0.5)
+ e0.deliver(now+1, 0, 100, 0.5) # when, start,len, decodetime
+ e1 = ds.add_segment_request(1, now+2)
+ e1.error(now+3)
+ # two outstanding requests
+ e2 = ds.add_segment_request(2, now+4)
+ e3 = ds.add_segment_request(3, now+5)
+ del e2,e3 # hush pyflakes
+
+ # simulate a segment which gets delivered faster than a system clock tick (ticket #1166)
+ e = ds.add_segment_request(4, now)
+ e.activate(now)
+ e.deliver(now, 0, 140, 0.5)
+
+ e = ds.add_dyhb_request(serverA, now)
+ e.finished([1,2], now+1)
+ e = ds.add_dyhb_request(serverB, now+2) # left unfinished
+
+ e = ds.add_read_event(0, 120, now)
+ e.update(60, 0.5, 0.1) # bytes, decrypttime, pausetime
+ e.finished(now+1)
+ e = ds.add_read_event(120, 30, now+2) # left unfinished
+
+ e = ds.add_block_request(serverA, 1, 100, 20, now)
+ e.finished(20, now+1)
+ e = ds.add_block_request(serverB, 1, 120, 30, now+1) # left unfinished
+
+ # make sure that add_read_event() can come first too
+ ds1 = DownloadStatus(storage_index, 1234)
+ e = ds1.add_read_event(0, 120, now)
+ e.update(60, 0.5, 0.1) # bytes, decrypttime, pausetime
+ e.finished(now+1)
+
+ return ds
+
class FakeHistory:
_all_upload_status = [upload.UploadStatus()]
- _all_download_status = [download.DownloadStatus()]
+ _all_download_status = [build_one_ds()]
_all_mapupdate_statuses = [servermap.UpdateStatus()]
_all_publish_statuses = [publish.PublishStatus()]
_all_retrieve_statuses = [retrieve.RetrieveStatus()]
self.history = FakeHistory()
self.uploader = FakeUploader()
self.uploader.setServiceParent(self)
+ self.blacklist = None
self.nodemaker = FakeNodeMaker(None, self._secret_holder, None,
- self.uploader, None, None,
+ self.uploader, None,
None, None)
+ self.mutable_file_default = SDMF_VERSION
def startService(self):
return service.MultiService.startService(self)
self.ws = webish.WebishServer(self.s, "0", staticdir=self.staticdir,
clock=self.clock)
self.ws.setServiceParent(self.s)
- self.webish_port = port = self.ws.listener._port.getHost().port
- self.webish_url = "http://localhost:%d" % port
+ self.webish_port = self.ws.getPortnum()
+ self.webish_url = self.ws.getURL()
+ assert self.webish_url.endswith("/")
+ self.webish_url = self.webish_url[:-1] # these tests add their own /
l = [ self.s.create_dirnode() for x in range(6) ]
d = defer.DeferredList(l)
foo.set_uri(u"bar.txt", self._bar_txt_uri, self._bar_txt_uri)
self._bar_txt_verifycap = n.get_verify_cap().to_string()
+ # sdmf
+ # XXX: Do we ever use this?
+ self.BAZ_CONTENTS, n, self._baz_txt_uri, self._baz_txt_readonly_uri = self.makefile_mutable(0)
+
+ foo.set_uri(u"baz.txt", self._baz_txt_uri, self._baz_txt_readonly_uri)
+
+ # mdmf
+ self.QUUX_CONTENTS, n, self._quux_txt_uri, self._quux_txt_readonly_uri = self.makefile_mutable(0, mdmf=True)
+ assert self._quux_txt_uri.startswith("URI:MDMF")
+ foo.set_uri(u"quux.txt", self._quux_txt_uri, self._quux_txt_readonly_uri)
+
foo.set_uri(u"empty", res[3][1].get_uri(),
res[3][1].get_readonly_uri())
sub_uri = res[4][1].get_uri()
# public/
# public/foo/
# public/foo/bar.txt
+ # public/foo/baz.txt
+ # public/foo/quux.txt
# public/foo/blockingfile
# public/foo/empty/
# public/foo/sub/
n = create_chk_filenode(contents)
return contents, n, n.get_uri()
+ def makefile_mutable(self, number, mdmf=False):
+ contents = "contents of mutable file %s\n" % number
+ n = create_mutable_filenode(contents, mdmf)
+ return contents, n, n.get_uri(), n.get_readonly_uri()
+
def tearDown(self):
return self.s.stopService()
def failUnlessIsBarDotTxt(self, res):
- self.failUnlessEqual(res, self.BAR_CONTENTS, res)
+ self.failUnlessReallyEqual(res, self.BAR_CONTENTS, res)
+
+ def failUnlessIsQuuxDotTxt(self, res):
+ self.failUnlessReallyEqual(res, self.QUUX_CONTENTS, res)
+
+ def failUnlessIsBazDotTxt(self, res):
+ self.failUnlessReallyEqual(res, self.BAZ_CONTENTS, res)
def failUnlessIsBarJSON(self, res):
data = simplejson.loads(res)
self.failUnless(isinstance(data, list))
- self.failUnlessEqual(data[0], u"filenode")
+ self.failUnlessEqual(data[0], "filenode")
self.failUnless(isinstance(data[1], dict))
self.failIf(data[1]["mutable"])
self.failIf("rw_uri" in data[1]) # immutable
- self.failUnlessEqual(data[1]["ro_uri"], self._bar_txt_uri)
- self.failUnlessEqual(data[1]["verify_uri"], self._bar_txt_verifycap)
- self.failUnlessEqual(data[1]["size"], len(self.BAR_CONTENTS))
+ self.failUnlessReallyEqual(to_str(data[1]["ro_uri"]), self._bar_txt_uri)
+ self.failUnlessReallyEqual(to_str(data[1]["verify_uri"]), self._bar_txt_verifycap)
+ self.failUnlessReallyEqual(data[1]["size"], len(self.BAR_CONTENTS))
+
+ def failUnlessIsQuuxJSON(self, res, readonly=False):
+ data = simplejson.loads(res)
+ self.failUnless(isinstance(data, list))
+ self.failUnlessEqual(data[0], "filenode")
+ self.failUnless(isinstance(data[1], dict))
+ metadata = data[1]
+ return self.failUnlessIsQuuxDotTxtMetadata(metadata, readonly)
+
+ def failUnlessIsQuuxDotTxtMetadata(self, metadata, readonly):
+ self.failUnless(metadata['mutable'])
+ if readonly:
+ self.failIf("rw_uri" in metadata)
+ else:
+ self.failUnless("rw_uri" in metadata)
+ self.failUnlessEqual(metadata['rw_uri'], self._quux_txt_uri)
+ self.failUnless("ro_uri" in metadata)
+ self.failUnlessEqual(metadata['ro_uri'], self._quux_txt_readonly_uri)
+ self.failUnlessReallyEqual(metadata['size'], len(self.QUUX_CONTENTS))
def failUnlessIsFooJSON(self, res):
data = simplejson.loads(res)
self.failUnless(isinstance(data[1], dict))
self.failUnless(data[1]["mutable"])
self.failUnless("rw_uri" in data[1]) # mutable
- self.failUnlessEqual(data[1]["rw_uri"], self._foo_uri)
- self.failUnlessEqual(data[1]["ro_uri"], self._foo_readonly_uri)
- self.failUnlessEqual(data[1]["verify_uri"], self._foo_verifycap)
+ self.failUnlessReallyEqual(to_str(data[1]["rw_uri"]), self._foo_uri)
+ self.failUnlessReallyEqual(to_str(data[1]["ro_uri"]), self._foo_readonly_uri)
+ self.failUnlessReallyEqual(to_str(data[1]["verify_uri"]), self._foo_verifycap)
kidnames = sorted([unicode(n) for n in data[1]["children"]])
self.failUnlessEqual(kidnames,
- [u"bar.txt", u"blockingfile", u"empty",
- u"n\u00fc.txt", u"sub"])
+ [u"bar.txt", u"baz.txt", u"blockingfile",
+ u"empty", u"n\u00fc.txt", u"quux.txt", u"sub"])
kids = dict( [(unicode(name),value)
for (name,value)
in data[1]["children"].iteritems()] )
self.failUnlessEqual(kids[u"sub"][0], "dirnode")
- self.failUnless("metadata" in kids[u"sub"][1])
- self.failUnless("ctime" in kids[u"sub"][1]["metadata"])
- self.failUnless("mtime" in kids[u"sub"][1]["metadata"])
+ self.failUnlessIn("metadata", kids[u"sub"][1])
+ self.failUnlessIn("tahoe", kids[u"sub"][1]["metadata"])
+ tahoe_md = kids[u"sub"][1]["metadata"]["tahoe"]
+ self.failUnlessIn("linkcrtime", tahoe_md)
+ self.failUnlessIn("linkmotime", tahoe_md)
self.failUnlessEqual(kids[u"bar.txt"][0], "filenode")
- self.failUnlessEqual(kids[u"bar.txt"][1]["size"], len(self.BAR_CONTENTS))
- self.failUnlessEqual(kids[u"bar.txt"][1]["ro_uri"], self._bar_txt_uri)
- self.failUnlessEqual(kids[u"bar.txt"][1]["verify_uri"],
- self._bar_txt_verifycap)
- self.failUnlessEqual(kids[u"bar.txt"][1]["metadata"]["ctime"],
- self._bar_txt_metadata["ctime"])
- self.failUnlessEqual(kids[u"n\u00fc.txt"][1]["ro_uri"],
- self._bar_txt_uri)
+ self.failUnlessReallyEqual(kids[u"bar.txt"][1]["size"], len(self.BAR_CONTENTS))
+ self.failUnlessReallyEqual(to_str(kids[u"bar.txt"][1]["ro_uri"]), self._bar_txt_uri)
+ self.failUnlessReallyEqual(to_str(kids[u"bar.txt"][1]["verify_uri"]),
+ self._bar_txt_verifycap)
+ self.failUnlessIn("metadata", kids[u"bar.txt"][1])
+ self.failUnlessIn("tahoe", kids[u"bar.txt"][1]["metadata"])
+ self.failUnlessReallyEqual(kids[u"bar.txt"][1]["metadata"]["tahoe"]["linkcrtime"],
+ self._bar_txt_metadata["tahoe"]["linkcrtime"])
+ self.failUnlessReallyEqual(to_str(kids[u"n\u00fc.txt"][1]["ro_uri"]),
+ self._bar_txt_uri)
+ self.failUnlessIn("quux.txt", kids)
+ self.failUnlessReallyEqual(to_str(kids[u"quux.txt"][1]["rw_uri"]),
+ self._quux_txt_uri)
+ self.failUnlessReallyEqual(to_str(kids[u"quux.txt"][1]["ro_uri"]),
+ self._quux_txt_readonly_uri)
def GET(self, urlpath, followRedirect=False, return_response=False,
**kwargs):
def should404(self, res, which):
if isinstance(res, failure.Failure):
res.trap(error.Error)
- self.failUnlessEqual(res.value.status, "404")
+ self.failUnlessReallyEqual(res.value.status, "404")
else:
self.fail("%s was supposed to Error(404), not get '%s'" %
(which, res))
def should302(self, res, which):
if isinstance(res, failure.Failure):
res.trap(error.Error)
- self.failUnlessEqual(res.value.status, "302")
+ self.failUnlessReallyEqual(res.value.status, "302")
else:
self.fail("%s was supposed to Error(302), not get '%s'" %
(which, res))
-class Web(WebMixin, WebErrorMixin, testutil.StallMixin, unittest.TestCase):
+class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixin, unittest.TestCase):
def test_create(self):
pass
def _check_dl(res):
self.failUnless("File Download Status" in res, res)
d.addCallback(_check_dl)
+ d.addCallback(lambda res: self.GET("/status/down-%d/event_json" % dl_num))
+ def _check_dl_json(res):
+ data = simplejson.loads(res)
+ self.failUnless(isinstance(data, dict))
+ self.failUnless("read" in data)
+ self.failUnlessEqual(data["read"][0]["length"], 120)
+ self.failUnlessEqual(data["segment"][0]["segment_length"], 100)
+ self.failUnlessEqual(data["segment"][2]["segment_number"], 2)
+ self.failUnlessEqual(data["segment"][2]["finish_time"], None)
+ phwr_id = base32.b2a(hashutil.tagged_hash("foo", "serverid_a")[:20])
+ cmpu_id = base32.b2a(hashutil.tagged_hash("foo", "serverid_b")[:20])
+ # serverids[] keys are strings, since that's what JSON does, but
+ # we'd really like them to be ints
+ self.failUnlessEqual(data["serverids"]["0"], "phwr")
+ self.failUnless(data["serverids"].has_key("1"), data["serverids"])
+ self.failUnlessEqual(data["serverids"]["1"], "cmpu", data["serverids"])
+ self.failUnlessEqual(data["server_info"][phwr_id]["short"], "phwr")
+ self.failUnlessEqual(data["server_info"][cmpu_id]["short"], "cmpu")
+ self.failUnless("dyhb" in data)
+ d.addCallback(_check_dl_json)
d.addCallback(lambda res: self.GET("/status/up-%d" % ul_num))
def _check_ul(res):
self.failUnless("File Upload Status" in res, res)
def test_status_numbers(self):
drrm = status.DownloadResultsRendererMixin()
- self.failUnlessEqual(drrm.render_time(None, None), "")
- self.failUnlessEqual(drrm.render_time(None, 2.5), "2.50s")
- self.failUnlessEqual(drrm.render_time(None, 0.25), "250ms")
- self.failUnlessEqual(drrm.render_time(None, 0.0021), "2.1ms")
- self.failUnlessEqual(drrm.render_time(None, 0.000123), "123us")
- self.failUnlessEqual(drrm.render_rate(None, None), "")
- self.failUnlessEqual(drrm.render_rate(None, 2500000), "2.50MBps")
- self.failUnlessEqual(drrm.render_rate(None, 30100), "30.1kBps")
- self.failUnlessEqual(drrm.render_rate(None, 123), "123Bps")
+ self.failUnlessReallyEqual(drrm.render_time(None, None), "")
+ self.failUnlessReallyEqual(drrm.render_time(None, 2.5), "2.50s")
+ self.failUnlessReallyEqual(drrm.render_time(None, 0.25), "250ms")
+ self.failUnlessReallyEqual(drrm.render_time(None, 0.0021), "2.1ms")
+ self.failUnlessReallyEqual(drrm.render_time(None, 0.000123), "123us")
+ self.failUnlessReallyEqual(drrm.render_rate(None, None), "")
+ self.failUnlessReallyEqual(drrm.render_rate(None, 2500000), "2.50MBps")
+ self.failUnlessReallyEqual(drrm.render_rate(None, 30100), "30.1kBps")
+ self.failUnlessReallyEqual(drrm.render_rate(None, 123), "123Bps")
urrm = status.UploadResultsRendererMixin()
- self.failUnlessEqual(urrm.render_time(None, None), "")
- self.failUnlessEqual(urrm.render_time(None, 2.5), "2.50s")
- self.failUnlessEqual(urrm.render_time(None, 0.25), "250ms")
- self.failUnlessEqual(urrm.render_time(None, 0.0021), "2.1ms")
- self.failUnlessEqual(urrm.render_time(None, 0.000123), "123us")
- self.failUnlessEqual(urrm.render_rate(None, None), "")
- self.failUnlessEqual(urrm.render_rate(None, 2500000), "2.50MBps")
- self.failUnlessEqual(urrm.render_rate(None, 30100), "30.1kBps")
- self.failUnlessEqual(urrm.render_rate(None, 123), "123Bps")
+ self.failUnlessReallyEqual(urrm.render_time(None, None), "")
+ self.failUnlessReallyEqual(urrm.render_time(None, 2.5), "2.50s")
+ self.failUnlessReallyEqual(urrm.render_time(None, 0.25), "250ms")
+ self.failUnlessReallyEqual(urrm.render_time(None, 0.0021), "2.1ms")
+ self.failUnlessReallyEqual(urrm.render_time(None, 0.000123), "123us")
+ self.failUnlessReallyEqual(urrm.render_rate(None, None), "")
+ self.failUnlessReallyEqual(urrm.render_rate(None, 2500000), "2.50MBps")
+ self.failUnlessReallyEqual(urrm.render_rate(None, 30100), "30.1kBps")
+ self.failUnlessReallyEqual(urrm.render_rate(None, 123), "123Bps")
def test_GET_FILEURL(self):
d = self.GET(self.public_url + "/foo/bar.txt")
d = self.GET(self.public_url + "/foo/bar.txt", headers=headers,
return_response=True)
def _got((res, status, headers)):
- self.failUnlessEqual(int(status), 206)
+ self.failUnlessReallyEqual(int(status), 206)
self.failUnless(headers.has_key("content-range"))
- self.failUnlessEqual(headers["content-range"][0],
- "bytes 1-10/%d" % len(self.BAR_CONTENTS))
- self.failUnlessEqual(res, self.BAR_CONTENTS[1:11])
+ self.failUnlessReallyEqual(headers["content-range"][0],
+ "bytes 1-10/%d" % len(self.BAR_CONTENTS))
+ self.failUnlessReallyEqual(res, self.BAR_CONTENTS[1:11])
d.addCallback(_got)
return d
d = self.GET(self.public_url + "/foo/bar.txt", headers=headers,
return_response=True)
def _got((res, status, headers)):
- self.failUnlessEqual(int(status), 206)
+ self.failUnlessReallyEqual(int(status), 206)
self.failUnless(headers.has_key("content-range"))
- self.failUnlessEqual(headers["content-range"][0],
- "bytes 5-%d/%d" % (length-1, length))
- self.failUnlessEqual(res, self.BAR_CONTENTS[5:])
+ self.failUnlessReallyEqual(headers["content-range"][0],
+ "bytes 5-%d/%d" % (length-1, length))
+ self.failUnlessReallyEqual(res, self.BAR_CONTENTS[5:])
d.addCallback(_got)
return d
d = self.GET(self.public_url + "/foo/bar.txt", headers=headers,
return_response=True)
def _got((res, status, headers)):
- self.failUnlessEqual(int(status), 206)
+ self.failUnlessReallyEqual(int(status), 206)
self.failUnless(headers.has_key("content-range"))
- self.failUnlessEqual(headers["content-range"][0],
- "bytes %d-%d/%d" % (length-5, length-1, length))
- self.failUnlessEqual(res, self.BAR_CONTENTS[-5:])
+ self.failUnlessReallyEqual(headers["content-range"][0],
+ "bytes %d-%d/%d" % (length-5, length-1, length))
+ self.failUnlessReallyEqual(res, self.BAR_CONTENTS[-5:])
d.addCallback(_got)
return d
def test_GET_FILEURL_partial_range_overrun(self):
headers = {"range": "bytes=100-200"}
- length = len(self.BAR_CONTENTS)
d = self.shouldFail2(error.Error, "test_GET_FILEURL_range_overrun",
"416 Requested Range not satisfiable",
"First beyond end of file",
d = self.HEAD(self.public_url + "/foo/bar.txt", headers=headers,
return_response=True)
def _got((res, status, headers)):
- self.failUnlessEqual(res, "")
- self.failUnlessEqual(int(status), 206)
+ self.failUnlessReallyEqual(res, "")
+ self.failUnlessReallyEqual(int(status), 206)
self.failUnless(headers.has_key("content-range"))
- self.failUnlessEqual(headers["content-range"][0],
- "bytes 1-10/%d" % len(self.BAR_CONTENTS))
+ self.failUnlessReallyEqual(headers["content-range"][0],
+ "bytes 1-10/%d" % len(self.BAR_CONTENTS))
d.addCallback(_got)
return d
d = self.HEAD(self.public_url + "/foo/bar.txt", headers=headers,
return_response=True)
def _got((res, status, headers)):
- self.failUnlessEqual(int(status), 206)
+ self.failUnlessReallyEqual(int(status), 206)
self.failUnless(headers.has_key("content-range"))
- self.failUnlessEqual(headers["content-range"][0],
- "bytes 5-%d/%d" % (length-1, length))
+ self.failUnlessReallyEqual(headers["content-range"][0],
+ "bytes 5-%d/%d" % (length-1, length))
d.addCallback(_got)
return d
d = self.HEAD(self.public_url + "/foo/bar.txt", headers=headers,
return_response=True)
def _got((res, status, headers)):
- self.failUnlessEqual(int(status), 206)
+ self.failUnlessReallyEqual(int(status), 206)
self.failUnless(headers.has_key("content-range"))
- self.failUnlessEqual(headers["content-range"][0],
- "bytes %d-%d/%d" % (length-5, length-1, length))
+ self.failUnlessReallyEqual(headers["content-range"][0],
+ "bytes %d-%d/%d" % (length-5, length-1, length))
d.addCallback(_got)
return d
def test_HEAD_FILEURL_partial_range_overrun(self):
headers = {"range": "bytes=100-200"}
- length = len(self.BAR_CONTENTS)
d = self.shouldFail2(error.Error, "test_HEAD_FILEURL_range_overrun",
"416 Requested Range not satisfiable",
"",
d = self.GET(self.public_url + "/foo/bar.txt", headers=headers,
return_response=True)
def _got((res, status, headers)):
- self.failUnlessEqual(int(status), 200)
+ self.failUnlessReallyEqual(int(status), 200)
self.failUnless(not headers.has_key("content-range"))
- self.failUnlessEqual(res, self.BAR_CONTENTS)
+ self.failUnlessReallyEqual(res, self.BAR_CONTENTS)
d.addCallback(_got)
return d
def test_HEAD_FILEURL(self):
d = self.HEAD(self.public_url + "/foo/bar.txt", return_response=True)
def _got((res, status, headers)):
- self.failUnlessEqual(res, "")
- self.failUnlessEqual(headers["content-length"][0],
- str(len(self.BAR_CONTENTS)))
- self.failUnlessEqual(headers["content-type"], ["text/plain"])
+ self.failUnlessReallyEqual(res, "")
+ self.failUnlessReallyEqual(headers["content-length"][0],
+ str(len(self.BAR_CONTENTS)))
+ self.failUnlessReallyEqual(headers["content-type"], ["text/plain"])
d.addCallback(_got)
return d
self.PUT, base + "/@@name=/blah.txt", "")
return d
+
def test_GET_DIRURL_named_bad(self):
base = "/file/%s" % urllib.quote(self._foo_uri)
d = self.shouldFail2(error.Error, "test_PUT_DIRURL_named_bad",
d.addCallback(self.failUnlessIsBarDotTxt)
return d
+ def test_GET_FILE_URI_mdmf(self):
+ base = "/uri/%s" % urllib.quote(self._quux_txt_uri)
+ d = self.GET(base)
+ d.addCallback(self.failUnlessIsQuuxDotTxt)
+ return d
+
+ def test_GET_FILE_URI_mdmf_extensions(self):
+ base = "/uri/%s" % urllib.quote("%s:3:131073" % self._quux_txt_uri)
+ d = self.GET(base)
+ d.addCallback(self.failUnlessIsQuuxDotTxt)
+ return d
+
+ def test_GET_FILE_URI_mdmf_bare_cap(self):
+ cap_elements = self._quux_txt_uri.split(":")
+ # 6 == expected cap length with two extensions.
+ self.failUnlessEqual(len(cap_elements), 6)
+
+ # Now lop off the extension parameters and stitch everything
+ # back together
+ quux_uri = ":".join(cap_elements[:len(cap_elements) - 2])
+
+ # Now GET that. We should get back quux.
+ base = "/uri/%s" % urllib.quote(quux_uri)
+ d = self.GET(base)
+ d.addCallback(self.failUnlessIsQuuxDotTxt)
+ return d
+
+ def test_GET_FILE_URI_mdmf_readonly(self):
+ base = "/uri/%s" % urllib.quote(self._quux_txt_readonly_uri)
+ d = self.GET(base)
+ d.addCallback(self.failUnlessIsQuuxDotTxt)
+ return d
+
def test_GET_FILE_URI_badchild(self):
base = "/uri/%s/boguschild" % urllib.quote(self._bar_txt_uri)
errmsg = "Files have no children, certainly not named 'boguschild'"
self.PUT, base, "")
return d
+ def test_PUT_FILE_URI_mdmf(self):
+ base = "/uri/%s" % urllib.quote(self._quux_txt_uri)
+ self._quux_new_contents = "new_contents"
+ d = self.GET(base)
+ d.addCallback(lambda res:
+ self.failUnlessIsQuuxDotTxt(res))
+ d.addCallback(lambda ignored:
+ self.PUT(base, self._quux_new_contents))
+ d.addCallback(lambda ignored:
+ self.GET(base))
+ d.addCallback(lambda res:
+ self.failUnlessReallyEqual(res, self._quux_new_contents))
+ return d
+
+ def test_PUT_FILE_URI_mdmf_extensions(self):
+ base = "/uri/%s" % urllib.quote("%s:3:131073" % self._quux_txt_uri)
+ self._quux_new_contents = "new_contents"
+ d = self.GET(base)
+ d.addCallback(lambda res: self.failUnlessIsQuuxDotTxt(res))
+ d.addCallback(lambda ignored: self.PUT(base, self._quux_new_contents))
+ d.addCallback(lambda ignored: self.GET(base))
+ d.addCallback(lambda res: self.failUnlessEqual(self._quux_new_contents,
+ res))
+ return d
+
+ def test_PUT_FILE_URI_mdmf_bare_cap(self):
+ elements = self._quux_txt_uri.split(":")
+ self.failUnlessEqual(len(elements), 6)
+
+ quux_uri = ":".join(elements[:len(elements) - 2])
+ base = "/uri/%s" % urllib.quote(quux_uri)
+ self._quux_new_contents = "new_contents" * 50000
+
+ d = self.GET(base)
+ d.addCallback(self.failUnlessIsQuuxDotTxt)
+ d.addCallback(lambda ignored: self.PUT(base, self._quux_new_contents))
+ d.addCallback(lambda ignored: self.GET(base))
+ d.addCallback(lambda res:
+ self.failUnlessEqual(res, self._quux_new_contents))
+ return d
+
+ def test_PUT_FILE_URI_mdmf_readonly(self):
+ # We're not allowed to PUT things to a readonly cap.
+ base = "/uri/%s" % self._quux_txt_readonly_uri
+ d = self.GET(base)
+ d.addCallback(lambda res:
+ self.failUnlessIsQuuxDotTxt(res))
+ # What should we get here? We get a 500 error now; that's not right.
+ d.addCallback(lambda ignored:
+ self.shouldFail2(error.Error, "test_PUT_FILE_URI_mdmf_readonly",
+ "400 Bad Request", "read-only cap",
+ self.PUT, base, "new data"))
+ return d
+
+ def test_PUT_FILE_URI_sdmf_readonly(self):
+ # We're not allowed to put things to a readonly cap.
+ base = "/uri/%s" % self._baz_txt_readonly_uri
+ d = self.GET(base)
+ d.addCallback(lambda res:
+ self.failUnlessIsBazDotTxt(res))
+ d.addCallback(lambda ignored:
+ self.shouldFail2(error.Error, "test_PUT_FILE_URI_sdmf_readonly",
+ "400 Bad Request", "read-only cap",
+ self.PUT, base, "new_data"))
+ return d
+
# TODO: version of this with a Unicode filename
def test_GET_FILEURL_save(self):
d = self.GET(self.public_url + "/foo/bar.txt?filename=bar.txt&save=true",
d.addBoth(self.should404, "test_GET_FILEURL_missing")
return d
+ def test_GET_FILEURL_info_mdmf(self):
+ d = self.GET("/uri/%s?t=info" % self._quux_txt_uri)
+ def _got(res):
+ self.failUnlessIn("mutable file (mdmf)", res)
+ self.failUnlessIn(self._quux_txt_uri, res)
+ self.failUnlessIn(self._quux_txt_readonly_uri, res)
+ d.addCallback(_got)
+ return d
+
+ def test_GET_FILEURL_info_mdmf_readonly(self):
+ d = self.GET("/uri/%s?t=info" % self._quux_txt_readonly_uri)
+ def _got(res):
+ self.failUnlessIn("mutable file (mdmf)", res)
+ self.failIfIn(self._quux_txt_uri, res)
+ self.failUnlessIn(self._quux_txt_readonly_uri, res)
+ d.addCallback(_got)
+ return d
+
+ def test_GET_FILEURL_info_sdmf(self):
+ d = self.GET("/uri/%s?t=info" % self._baz_txt_uri)
+ def _got(res):
+ self.failUnlessIn("mutable file (sdmf)", res)
+ self.failUnlessIn(self._baz_txt_uri, res)
+ d.addCallback(_got)
+ return d
+
+ def test_GET_FILEURL_info_mdmf_extensions(self):
+ d = self.GET("/uri/%s:3:131073?t=info" % self._quux_txt_uri)
+ def _got(res):
+ self.failUnlessIn("mutable file (mdmf)", res)
+ self.failUnlessIn(self._quux_txt_uri, res)
+ self.failUnlessIn(self._quux_txt_readonly_uri, res)
+ d.addCallback(_got)
+ return d
+
+ def test_GET_FILEURL_info_mdmf_bare_cap(self):
+ elements = self._quux_txt_uri.split(":")
+ self.failUnlessEqual(len(elements), 6)
+
+ quux_uri = ":".join(elements[:len(elements) - 2])
+ base = "/uri/%s?t=info" % urllib.quote(quux_uri)
+ d = self.GET(base)
+ def _got(res):
+ self.failUnlessIn("mutable file (mdmf)", res)
+ self.failUnlessIn(quux_uri, res)
+ d.addCallback(_got)
+ return d
+
def test_PUT_overwrite_only_files(self):
# create a directory, put a file in that directory.
contents, n, filecap = self.makefile(8)
def test_PUT_NEWFILEURL(self):
d = self.PUT(self.public_url + "/foo/new.txt", self.NEWFILE_CONTENTS)
# TODO: we lose the response code, so we can't check this
- #self.failUnlessEqual(responsecode, 201)
+ #self.failUnlessReallyEqual(responsecode, 201)
d.addCallback(self.failUnlessURIMatchesROChild, self._foo_node, u"new.txt")
d.addCallback(lambda res:
self.failUnlessChildContentsAre(self._foo_node, u"new.txt",
d = self.PUT(self.public_url + "/foo/new.txt?mutable=false",
self.NEWFILE_CONTENTS)
# TODO: we lose the response code, so we can't check this
- #self.failUnlessEqual(responsecode, 201)
+ #self.failUnlessReallyEqual(responsecode, 201)
d.addCallback(self.failUnlessURIMatchesROChild, self._foo_node, u"new.txt")
d.addCallback(lambda res:
self.failUnlessChildContentsAre(self._foo_node, u"new.txt",
self.NEWFILE_CONTENTS))
return d
+ def test_PUT_NEWFILEURL_unlinked_mdmf(self):
+ # this should get us a few segments of an MDMF mutable file,
+ # which we can then test for.
+ contents = self.NEWFILE_CONTENTS * 300000
+ d = self.PUT("/uri?mutable=true&mutable-type=mdmf",
+ contents)
+ def _got_filecap(filecap):
+ self.failUnless(filecap.startswith("URI:MDMF"))
+ return filecap
+ d.addCallback(_got_filecap)
+ d.addCallback(lambda filecap: self.GET("/uri/%s?t=json" % filecap))
+ d.addCallback(lambda json: self.failUnlessIn("mdmf", json))
+ return d
+
+ def test_PUT_NEWFILEURL_unlinked_sdmf(self):
+ contents = self.NEWFILE_CONTENTS * 300000
+ d = self.PUT("/uri?mutable=true&mutable-type=sdmf",
+ contents)
+ d.addCallback(lambda filecap: self.GET("/uri/%s?t=json" % filecap))
+ d.addCallback(lambda json: self.failUnlessIn("sdmf", json))
+ return d
+
+ def test_PUT_NEWFILEURL_unlinked_bad_mutable_type(self):
+ contents = self.NEWFILE_CONTENTS * 300000
+ return self.shouldHTTPError("test bad mutable type",
+ 400, "Bad Request", "Unknown type: foo",
+ self.PUT, "/uri?mutable=true&mutable-type=foo",
+ contents)
+
def test_PUT_NEWFILEURL_range_bad(self):
headers = {"content-range": "bytes 1-10/%d" % len(self.NEWFILE_CONTENTS)}
target = self.public_url + "/foo/new.txt"
d = self.PUT(self.public_url + "/foo/new.txt?mutable=true",
self.NEWFILE_CONTENTS)
# TODO: we lose the response code, so we can't check this
- #self.failUnlessEqual(responsecode, 201)
+ #self.failUnlessReallyEqual(responsecode, 201)
def _check_uri(res):
u = uri.from_string_mutable_filenode(res)
self.failUnless(u.is_mutable())
return d
def test_PUT_NEWFILEURL_mutable_toobig(self):
- d = self.shouldFail2(error.Error, "test_PUT_NEWFILEURL_mutable_toobig",
- "413 Request Entity Too Large",
- "SDMF is limited to one segment, and 10001 > 10000",
- self.PUT,
- self.public_url + "/foo/new.txt?mutable=true",
- "b" * (self.s.MUTABLE_SIZELIMIT+1))
+ # It is okay to upload large mutable files, so we should be able
+ # to do that.
+ d = self.PUT(self.public_url + "/foo/new.txt?mutable=true",
+ "b" * (self.s.MUTABLE_SIZELIMIT + 1))
return d
def test_PUT_NEWFILEURL_replace(self):
d = self.PUT(self.public_url + "/foo/bar.txt", self.NEWFILE_CONTENTS)
# TODO: we lose the response code, so we can't check this
- #self.failUnlessEqual(responsecode, 200)
+ #self.failUnlessReallyEqual(responsecode, 200)
d.addCallback(self.failUnlessURIMatchesROChild, self._foo_node, u"bar.txt")
d.addCallback(lambda res:
self.failUnlessChildContentsAre(self._foo_node, u"bar.txt",
def failUnlessHasBarDotTxtMetadata(self, res):
data = simplejson.loads(res)
self.failUnless(isinstance(data, list))
- self.failUnless(data[1].has_key("metadata"))
- self.failUnless(data[1]["metadata"].has_key("ctime"))
- self.failUnless(data[1]["metadata"].has_key("mtime"))
- self.failUnlessEqual(data[1]["metadata"]["ctime"],
- self._bar_txt_metadata["ctime"])
+ self.failUnlessIn("metadata", data[1])
+ self.failUnlessIn("tahoe", data[1]["metadata"])
+ self.failUnlessIn("linkcrtime", data[1]["metadata"]["tahoe"])
+ self.failUnlessIn("linkmotime", data[1]["metadata"]["tahoe"])
+ self.failUnlessReallyEqual(data[1]["metadata"]["tahoe"]["linkcrtime"],
+ self._bar_txt_metadata["tahoe"]["linkcrtime"])
def test_GET_FILEURL_json(self):
# twisted.web.http.parse_qs ignores any query args without an '=', so
d.addCallback(_check1)
return d
+ def test_GET_FILEURL_json_mutable_type(self):
+ # The JSON should include mutable-type, which says whether the
+ # file is SDMF or MDMF
+ d = self.PUT("/uri?mutable=true&mutable-type=mdmf",
+ self.NEWFILE_CONTENTS * 300000)
+ d.addCallback(lambda filecap: self.GET("/uri/%s?t=json" % filecap))
+ def _got_json(json, version):
+ data = simplejson.loads(json)
+ assert "filenode" == data[0]
+ data = data[1]
+ assert isinstance(data, dict)
+
+ self.failUnlessIn("mutable-type", data)
+ self.failUnlessEqual(data['mutable-type'], version)
+
+ d.addCallback(_got_json, "mdmf")
+ # Now make an SDMF file and check that it is reported correctly.
+ d.addCallback(lambda ignored:
+ self.PUT("/uri?mutable=true&mutable-type=sdmf",
+ self.NEWFILE_CONTENTS * 300000))
+ d.addCallback(lambda filecap: self.GET("/uri/%s?t=json" % filecap))
+ d.addCallback(_got_json, "sdmf")
+ return d
+
+ def test_GET_FILEURL_json_mdmf_extensions(self):
+ # A GET invoked against a URL that includes an MDMF cap with
+ # extensions should fetch the same JSON information as a GET
+ # invoked against a bare cap.
+ self._quux_txt_uri = "%s:3:131073" % self._quux_txt_uri
+ self._quux_txt_readonly_uri = "%s:3:131073" % self._quux_txt_readonly_uri
+ d = self.GET("/uri/%s?t=json" % urllib.quote(self._quux_txt_uri))
+ d.addCallback(self.failUnlessIsQuuxJSON)
+ return d
+
+ def test_GET_FILEURL_json_mdmf_bare_cap(self):
+ elements = self._quux_txt_uri.split(":")
+ self.failUnlessEqual(len(elements), 6)
+
+ quux_uri = ":".join(elements[:len(elements) - 2])
+ # so failUnlessIsQuuxJSON will work.
+ self._quux_txt_uri = quux_uri
+
+ # we need to alter the readonly URI in the same way, again so
+ # failUnlessIsQuuxJSON will work
+ elements = self._quux_txt_readonly_uri.split(":")
+ self.failUnlessEqual(len(elements), 6)
+ quux_ro_uri = ":".join(elements[:len(elements) - 2])
+ self._quux_txt_readonly_uri = quux_ro_uri
+
+ base = "/uri/%s?t=json" % urllib.quote(quux_uri)
+ d = self.GET(base)
+ d.addCallback(self.failUnlessIsQuuxJSON)
+ return d
+
+ def test_GET_FILEURL_json_mdmf_bare_readonly_cap(self):
+ elements = self._quux_txt_readonly_uri.split(":")
+ self.failUnlessEqual(len(elements), 6)
+
+ quux_readonly_uri = ":".join(elements[:len(elements) - 2])
+ # so failUnlessIsQuuxJSON will work
+ self._quux_txt_readonly_uri = quux_readonly_uri
+ base = "/uri/%s?t=json" % quux_readonly_uri
+ d = self.GET(base)
+ # XXX: We may need to make a method that knows how to check for
+ # readonly JSON, or else alter that one so that it knows how to
+ # do that.
+ d.addCallback(self.failUnlessIsQuuxJSON, readonly=True)
+ return d
+
+ def test_GET_FILEURL_json_mdmf(self):
+ d = self.GET("/uri/%s?t=json" % urllib.quote(self._quux_txt_uri))
+ d.addCallback(self.failUnlessIsQuuxJSON)
+ return d
+
def test_GET_FILEURL_json_missing(self):
d = self.GET(self.public_url + "/foo/missing?json")
d.addBoth(self.should404, "test_GET_FILEURL_json_missing")
def test_GET_FILEURL_uri(self):
d = self.GET(self.public_url + "/foo/bar.txt?t=uri")
def _check(res):
- self.failUnlessEqual(res, self._bar_txt_uri)
+ self.failUnlessReallyEqual(res, self._bar_txt_uri)
d.addCallback(_check)
d.addCallback(lambda res:
self.GET(self.public_url + "/foo/bar.txt?t=readonly-uri"))
def _check2(res):
# for now, for files, uris and readonly-uris are the same
- self.failUnlessEqual(res, self._bar_txt_uri)
+ self.failUnlessReallyEqual(res, self._bar_txt_uri)
d.addCallback(_check2)
return d
self.public_url + "/foo/bar.txt?t=bogus")
return d
+ def test_CSS_FILE(self):
+ d = self.GET("/tahoe_css", followRedirect=True)
+ def _check(res):
+ CSS_STYLE=re.compile('toolbar\s{.+text-align:\scenter.+toolbar-item.+display:\sinline',re.DOTALL)
+ self.failUnless(CSS_STYLE.search(res), res)
+ d.addCallback(_check)
+ return d
+
def test_GET_FILEURL_uri_missing(self):
d = self.GET(self.public_url + "/foo/missing?t=uri")
d.addBoth(self.should404, "test_GET_FILEURL_uri_missing")
return d
+ def test_GET_DIRECTORY_html(self):
+ d = self.GET(self.public_url + "/foo", followRedirect=True)
+ def _check(res):
+ self.failUnlessIn('<div class="toolbar-item"><a href="../../..">Return to Welcome page</a></div>',res)
+ # These are radio buttons that allow a user to toggle
+ # whether a particular mutable file is SDMF or MDMF.
+ self.failUnlessIn("mutable-type-mdmf", res)
+ self.failUnlessIn("mutable-type-sdmf", res)
+ # Similarly, these toggle whether a particular directory
+ # should be MDMF or SDMF.
+ self.failUnlessIn("mutable-directory-mdmf", res)
+ self.failUnlessIn("mutable-directory-sdmf", res)
+ self.failUnlessIn("quux", res)
+ d.addCallback(_check)
+ return d
+
+ def test_GET_root_html(self):
+ # make sure that we have the option to upload an unlinked
+ # mutable file in SDMF and MDMF formats.
+ d = self.GET("/")
+ def _got_html(html):
+ # These are radio buttons that allow the user to toggle
+ # whether a particular mutable file is MDMF or SDMF.
+ self.failUnlessIn("mutable-type-mdmf", html)
+ self.failUnlessIn("mutable-type-sdmf", html)
+ # We should also have the ability to create a mutable directory.
+ self.failUnlessIn("mkdir", html)
+ # ...and we should have the ability to say whether that's an
+ # MDMF or SDMF directory
+ self.failUnlessIn("mutable-directory-mdmf", html)
+ self.failUnlessIn("mutable-directory-sdmf", html)
+ d.addCallback(_got_html)
+ return d
+
+ def test_mutable_type_defaults(self):
+ # The checked="checked" attribute of the inputs corresponding to
+ # the mutable-type parameter should change as expected with the
+ # value configured in tahoe.cfg.
+ #
+ # By default, the value configured with the client is
+ # SDMF_VERSION, so that should be checked.
+ assert self.s.mutable_file_default == SDMF_VERSION
+
+ d = self.GET("/")
+ def _got_html(html, value):
+ i = 'input checked="checked" type="radio" id="mutable-type-%s"'
+ self.failUnlessIn(i % value, html)
+ d.addCallback(_got_html, "sdmf")
+ d.addCallback(lambda ignored:
+ self.GET(self.public_url + "/foo", followRedirect=True))
+ d.addCallback(_got_html, "sdmf")
+ # Now switch the configuration value to MDMF. The MDMF radio
+ # buttons should now be checked on these pages.
+ def _swap_values(ignored):
+ self.s.mutable_file_default = MDMF_VERSION
+ d.addCallback(_swap_values)
+ d.addCallback(lambda ignored: self.GET("/"))
+ d.addCallback(_got_html, "mdmf")
+ d.addCallback(lambda ignored:
+ self.GET(self.public_url + "/foo", followRedirect=True))
+ d.addCallback(_got_html, "mdmf")
+ return d
+
def test_GET_DIRURL(self):
# the addSlash means we get a redirect here
# from /uri/$URI/foo/ , we need ../../../ to get back to the root
r'\s+<td>',
r'<a href="%s">bar.txt</a>' % bar_url,
r'</td>',
- r'\s+<td>%d</td>' % len(self.BAR_CONTENTS),
+ r'\s+<td align="right">%d</td>' % len(self.BAR_CONTENTS),
])
self.failUnless(re.search(get_bar, res), res)
- for line in res.split("\n"):
- # find the line that contains the delete button for bar.txt
- if ("form action" in line and
- 'value="delete"' in line and
- 'value="bar.txt"' in line):
- # the form target should use a relative URL
- foo_url = urllib.quote("%s/uri/%s/" % (ROOT, self._foo_uri))
- self.failUnless(('action="%s"' % foo_url) in line, line)
- # and the when_done= should too
- #done_url = urllib.quote(???)
- #self.failUnless(('name="when_done" value="%s"' % done_url)
- # in line, line)
- break
- else:
- self.fail("unable to find delete-bar.txt line", res)
+ for label in ['unlink', 'rename']:
+ for line in res.split("\n"):
+ # find the line that contains the relevant button for bar.txt
+ if ("form action" in line and
+ ('value="%s"' % (label,)) in line and
+ 'value="bar.txt"' in line):
+ # the form target should use a relative URL
+ foo_url = urllib.quote("%s/uri/%s/" % (ROOT, self._foo_uri))
+ self.failUnlessIn('action="%s"' % foo_url, line)
+ # and the when_done= should too
+ #done_url = urllib.quote(???)
+ #self.failUnlessIn('name="when_done" value="%s"' % done_url, line)
+
+ # 'unlink' needs to use POST because it directly has a side effect
+ if label == 'unlink':
+ self.failUnlessIn('method="post"', line)
+ break
+ else:
+ self.fail("unable to find '%s bar.txt' line" % (label,), res)
# the DIR reference just points to a URI
sub_url = ("%s/uri/%s/" % (ROOT, urllib.quote(self._sub_uri)))
self.failUnless(re.search(get_sub, res), res)
d.addCallback(_check)
- # look at a readonly directory
+ # look at a readonly directory
d.addCallback(lambda res:
self.GET(self.public_url + "/reedownlee", followRedirect=True))
def _check2(res):
d.addCallback(self.failUnlessIsFooJSON)
return d
+ def test_GET_DIRURL_json_mutable_type(self):
+ d = self.PUT(self.public_url + \
+ "/foo/sdmf.txt?mutable=true&mutable-type=sdmf",
+ self.NEWFILE_CONTENTS * 300000)
+ d.addCallback(lambda ignored:
+ self.PUT(self.public_url + \
+ "/foo/mdmf.txt?mutable=true&mutable-type=mdmf",
+ self.NEWFILE_CONTENTS * 300000))
+ # Now we have an MDMF and SDMF file in the directory. If we GET
+ # its JSON, we should see their encodings.
+ d.addCallback(lambda ignored:
+ self.GET(self.public_url + "/foo?t=json"))
+ def _got_json(json):
+ data = simplejson.loads(json)
+ assert data[0] == "dirnode"
+
+ data = data[1]
+ kids = data['children']
+
+ mdmf_data = kids['mdmf.txt'][1]
+ self.failUnlessIn("mutable-type", mdmf_data)
+ self.failUnlessEqual(mdmf_data['mutable-type'], "mdmf")
+
+ sdmf_data = kids['sdmf.txt'][1]
+ self.failUnlessIn("mutable-type", sdmf_data)
+ self.failUnlessEqual(sdmf_data['mutable-type'], "sdmf")
+ d.addCallback(_got_json)
+ return d
+
def test_POST_DIRURL_manifest_no_ophandle(self):
d = self.shouldFail2(error.Error,
got = {}
for (path_list, cap) in data:
got[tuple(path_list)] = cap
- self.failUnlessEqual(got[(u"sub",)], self._sub_uri)
+ self.failUnlessReallyEqual(to_str(got[(u"sub",)]), self._sub_uri)
self.failUnless((u"sub",u"baz.txt") in got)
self.failUnless("finished" in res)
self.failUnless("origin" in res)
d.addCallback(self.wait_for_operation, "126")
d.addCallback(self.get_operation_results, "126", "json")
def _got_json(data):
- self.failUnlessEqual(data["finished"], True)
+ self.failUnlessReallyEqual(data["finished"], True)
size = data["size"]
self.failUnless(size > 1000)
d.addCallback(_got_json)
d.addCallback(self.get_operation_results, "127", "json")
def _got_json(stats):
expected = {"count-immutable-files": 3,
- "count-mutable-files": 0,
+ "count-mutable-files": 2,
"count-literal-files": 0,
- "count-files": 3,
+ "count-files": 5,
"count-directories": 3,
"size-immutable-files": 57,
"size-literal-files": 0,
#"size-directories": 1912, # varies
#"largest-directory": 1590,
- "largest-directory-children": 5,
+ "largest-directory-children": 7,
"largest-immutable-file": 19,
}
for k,v in expected.iteritems():
- self.failUnlessEqual(stats[k], v,
- "stats[%s] was %s, not %s" %
- (k, stats[k], v))
- self.failUnlessEqual(stats["size-files-histogram"],
- [ [11, 31, 3] ])
+ self.failUnlessReallyEqual(stats[k], v,
+ "stats[%s] was %s, not %s" %
+ (k, stats[k], v))
+ self.failUnlessReallyEqual(stats["size-files-histogram"],
+ [ [11, 31, 3] ])
d.addCallback(_got_json)
return d
def _check(res):
self.failUnless(res.endswith("\n"))
units = [simplejson.loads(t) for t in res[:-1].split("\n")]
- self.failUnlessEqual(len(units), 7)
+ self.failUnlessReallyEqual(len(units), 9)
self.failUnlessEqual(units[-1]["type"], "stats")
first = units[0]
self.failUnlessEqual(first["path"], [])
- self.failUnlessEqual(first["cap"], self._foo_uri)
+ self.failUnlessReallyEqual(to_str(first["cap"]), self._foo_uri)
self.failUnlessEqual(first["type"], "directory")
- baz = [u for u in units[:-1] if u["cap"] == self._baz_file_uri][0]
+ baz = [u for u in units[:-1] if to_str(u["cap"]) == self._baz_file_uri][0]
self.failUnlessEqual(baz["path"], ["sub", "baz.txt"])
self.failIfEqual(baz["storage-index"], None)
self.failIfEqual(baz["verifycap"], None)
self.failIfEqual(baz["repaircap"], None)
+ # XXX: Add quux and baz to this test.
return
d.addCallback(_check)
return d
def test_GET_DIRURL_uri(self):
d = self.GET(self.public_url + "/foo?t=uri")
def _check(res):
- self.failUnlessEqual(res, self._foo_uri)
+ self.failUnlessReallyEqual(to_str(res), self._foo_uri)
d.addCallback(_check)
return d
def test_GET_DIRURL_readonly_uri(self):
d = self.GET(self.public_url + "/foo?t=readonly-uri")
def _check(res):
- self.failUnlessEqual(res, self._foo_readonly_uri)
+ self.failUnlessReallyEqual(to_str(res), self._foo_readonly_uri)
d.addCallback(_check)
return d
d.addCallback(self.failUnlessNodeKeysAre, [])
return d
+ def test_PUT_NEWDIRURL_mdmf(self):
+ d = self.PUT(self.public_url + "/foo/newdir?t=mkdir&mutable-type=mdmf", "")
+ d.addCallback(lambda res:
+ self.failUnlessNodeHasChild(self._foo_node, u"newdir"))
+ d.addCallback(lambda res: self._foo_node.get(u"newdir"))
+ d.addCallback(lambda node:
+ self.failUnlessEqual(node._node.get_version(), MDMF_VERSION))
+ return d
+
+ def test_PUT_NEWDIRURL_sdmf(self):
+ d = self.PUT(self.public_url + "/foo/newdir?t=mkdir&mutable-type=sdmf",
+ "")
+ d.addCallback(lambda res:
+ self.failUnlessNodeHasChild(self._foo_node, u"newdir"))
+ d.addCallback(lambda res: self._foo_node.get(u"newdir"))
+ d.addCallback(lambda node:
+ self.failUnlessEqual(node._node.get_version(), SDMF_VERSION))
+ return d
+
+ def test_PUT_NEWDIRURL_bad_mutable_type(self):
+ return self.shouldHTTPError("test bad mutable type",
+ 400, "Bad Request", "Unknown type: foo",
+ self.PUT, self.public_url + \
+ "/foo/newdir=?t=mkdir&mutable-type=foo", "")
+
def test_POST_NEWDIRURL(self):
d = self.POST2(self.public_url + "/foo/newdir?t=mkdir", "")
d.addCallback(lambda res:
d.addCallback(self.failUnlessNodeKeysAre, [])
return d
+ def test_POST_NEWDIRURL_mdmf(self):
+ d = self.POST2(self.public_url + "/foo/newdir?t=mkdir&mutable-type=mdmf", "")
+ d.addCallback(lambda res:
+ self.failUnlessNodeHasChild(self._foo_node, u"newdir"))
+ d.addCallback(lambda res: self._foo_node.get(u"newdir"))
+ d.addCallback(lambda node:
+ self.failUnlessEqual(node._node.get_version(), MDMF_VERSION))
+ return d
+
+ def test_POST_NEWDIRURL_sdmf(self):
+ d = self.POST2(self.public_url + "/foo/newdir?t=mkdir&mutable-type=sdmf", "")
+ d.addCallback(lambda res:
+ self.failUnlessNodeHasChild(self._foo_node, u"newdir"))
+ d.addCallback(lambda res: self._foo_node.get(u"newdir"))
+ d.addCallback(lambda node:
+ self.failUnlessEqual(node._node.get_version(), SDMF_VERSION))
+ return d
+
+ def test_POST_NEWDIRURL_bad_mutable_type(self):
+ return self.shouldHTTPError("test bad mutable type",
+ 400, "Bad Request", "Unknown type: foo",
+ self.POST2, self.public_url + \
+ "/foo/newdir?t=mkdir&mutable-type=foo", "")
+
def test_POST_NEWDIRURL_emptyname(self):
# an empty pathname component (i.e. a double-slash) is disallowed
d = self.shouldFail2(error.Error, "test_POST_NEWDIRURL_emptyname",
self.POST, self.public_url + "//?t=mkdir")
return d
- def test_POST_NEWDIRURL_initial_children(self):
+ def _do_POST_NEWDIRURL_initial_children_test(self, version=None):
(newkids, caps) = self._create_initial_children()
- d = self.POST2(self.public_url + "/foo/newdir?t=mkdir-with-children",
+ query = "/foo/newdir?t=mkdir-with-children"
+ if version == MDMF_VERSION:
+ query += "&mutable-type=mdmf"
+ elif version == SDMF_VERSION:
+ query += "&mutable-type=sdmf"
+ else:
+ version = SDMF_VERSION # for later
+ d = self.POST2(self.public_url + query,
simplejson.dumps(newkids))
def _check(uri):
n = self.s.create_node_from_uri(uri.strip())
d2 = self.failUnlessNodeKeysAre(n, newkids.keys())
+ self.failUnlessEqual(n._node.get_version(), version)
d2.addCallback(lambda ign:
self.failUnlessROChildURIIs(n, u"child-imm",
caps['filecap1']))
d.addCallback(self.failUnlessROChildURIIs, u"child-imm", caps['filecap1'])
return d
+ def test_POST_NEWDIRURL_initial_children(self):
+ return self._do_POST_NEWDIRURL_initial_children_test()
+
+ def test_POST_NEWDIRURL_initial_children_mdmf(self):
+ return self._do_POST_NEWDIRURL_initial_children_test(MDMF_VERSION)
+
+ def test_POST_NEWDIRURL_initial_children_sdmf(self):
+ return self._do_POST_NEWDIRURL_initial_children_test(SDMF_VERSION)
+
+ def test_POST_NEWDIRURL_initial_children_bad_mutable_type(self):
+ (newkids, caps) = self._create_initial_children()
+ return self.shouldHTTPError("test bad mutable type",
+ 400, "Bad Request", "Unknown type: foo",
+ self.POST2, self.public_url + \
+ "/foo/newdir?t=mkdir-with-children&mutable-type=foo",
+ simplejson.dumps(newkids))
+
def test_POST_NEWDIRURL_immutable(self):
(newkids, caps) = self._create_immutable_children()
d = self.POST2(self.public_url + "/foo/newdir?t=mkdir-immutable",
d = self.POST(url)
def made_subsub(ssuri):
d = self._foo_node.get_child_at_path(u"mkp/sub1/sub2")
- d.addCallback(lambda ssnode: self.failUnlessEqual(ssnode.get_uri(), ssuri))
+ d.addCallback(lambda ssnode: self.failUnlessReallyEqual(ssnode.get_uri(), ssuri))
d = self.POST(url)
- d.addCallback(lambda uri2: self.failUnlessEqual(uri2, ssuri))
+ d.addCallback(lambda uri2: self.failUnlessReallyEqual(uri2, ssuri))
return d
d.addCallback(made_subsub)
return d
d.addCallback(self.failUnlessNodeKeysAre, [])
return d
+ def test_PUT_NEWDIRURL_mkdirs_mdmf(self):
+ d = self.PUT(self.public_url + "/foo/subdir/newdir?t=mkdir&mutable-type=mdmf", "")
+ d.addCallback(lambda ignored:
+ self.failUnlessNodeHasChild(self._foo_node, u"subdir"))
+ d.addCallback(lambda ignored:
+ self.failIfNodeHasChild(self._foo_node, u"newdir"))
+ d.addCallback(lambda ignored:
+ self._foo_node.get_child_at_path(u"subdir"))
+ def _got_subdir(subdir):
+ # XXX: What we want?
+ #self.failUnlessEqual(subdir._node.get_version(), MDMF_VERSION)
+ self.failUnlessNodeHasChild(subdir, u"newdir")
+ return subdir.get_child_at_path(u"newdir")
+ d.addCallback(_got_subdir)
+ d.addCallback(lambda newdir:
+ self.failUnlessEqual(newdir._node.get_version(), MDMF_VERSION))
+ return d
+
+ def test_PUT_NEWDIRURL_mkdirs_sdmf(self):
+ d = self.PUT(self.public_url + "/foo/subdir/newdir?t=mkdir&mutable-type=sdmf", "")
+ d.addCallback(lambda ignored:
+ self.failUnlessNodeHasChild(self._foo_node, u"subdir"))
+ d.addCallback(lambda ignored:
+ self.failIfNodeHasChild(self._foo_node, u"newdir"))
+ d.addCallback(lambda ignored:
+ self._foo_node.get_child_at_path(u"subdir"))
+ def _got_subdir(subdir):
+ # XXX: What we want?
+ #self.failUnlessEqual(subdir._node.get_version(), MDMF_VERSION)
+ self.failUnlessNodeHasChild(subdir, u"newdir")
+ return subdir.get_child_at_path(u"newdir")
+ d.addCallback(_got_subdir)
+ d.addCallback(lambda newdir:
+ self.failUnlessEqual(newdir._node.get_version(), SDMF_VERSION))
+ return d
+
+ def test_PUT_NEWDIRURL_mkdirs_bad_mutable_type(self):
+ return self.shouldHTTPError("test bad mutable type",
+ 400, "Bad Request", "Unknown type: foo",
+ self.PUT, self.public_url + \
+ "/foo/subdir/newdir?t=mkdir&mutable-type=foo",
+ "")
+
def test_DELETE_DIRURL(self):
d = self.DELETE(self.public_url + "/foo")
d.addCallback(lambda res:
assert isinstance(k, unicode)
d = node.list()
def _check(children):
- self.failUnlessEqual(sorted(children.keys()), sorted(expected_keys))
+ self.failUnlessReallyEqual(sorted(children.keys()), sorted(expected_keys))
d.addCallback(_check)
return d
def failUnlessNodeHasChild(self, node, name):
d = node.get_child_at_path(name)
d.addCallback(lambda node: download_to_data(node))
def _check(contents):
- self.failUnlessEqual(contents, expected_contents)
+ self.failUnlessReallyEqual(contents, expected_contents)
d.addCallback(_check)
return d
d = node.get_child_at_path(name)
d.addCallback(lambda node: node.download_best_version())
def _check(contents):
- self.failUnlessEqual(contents, expected_contents)
+ self.failUnlessReallyEqual(contents, expected_contents)
d.addCallback(_check)
return d
d = node.get_child_at_path(name)
def _check(child):
self.failUnless(child.is_unknown() or not child.is_readonly())
- self.failUnlessEqual(child.get_uri(), expected_uri.strip())
- self.failUnlessEqual(child.get_write_uri(), expected_uri.strip())
+ self.failUnlessReallyEqual(child.get_uri(), expected_uri.strip())
+ self.failUnlessReallyEqual(child.get_write_uri(), expected_uri.strip())
expected_ro_uri = self._make_readonly(expected_uri)
if expected_ro_uri:
- self.failUnlessEqual(child.get_readonly_uri(), expected_ro_uri.strip())
+ self.failUnlessReallyEqual(child.get_readonly_uri(), expected_ro_uri.strip())
d.addCallback(_check)
return d
d = node.get_child_at_path(name)
def _check(child):
self.failUnless(child.is_unknown() or child.is_readonly())
- self.failUnlessEqual(child.get_write_uri(), None)
- self.failUnlessEqual(child.get_uri(), expected_uri.strip())
- self.failUnlessEqual(child.get_readonly_uri(), expected_uri.strip())
+ self.failUnlessReallyEqual(child.get_write_uri(), None)
+ self.failUnlessReallyEqual(child.get_uri(), expected_uri.strip())
+ self.failUnlessReallyEqual(child.get_readonly_uri(), expected_uri.strip())
d.addCallback(_check)
return d
d = node.get_child_at_path(name)
def _check(child):
self.failUnless(child.is_unknown() or not child.is_readonly())
- self.failUnlessEqual(child.get_uri(), got_uri.strip())
- self.failUnlessEqual(child.get_write_uri(), got_uri.strip())
+ self.failUnlessReallyEqual(child.get_uri(), got_uri.strip())
+ self.failUnlessReallyEqual(child.get_write_uri(), got_uri.strip())
expected_ro_uri = self._make_readonly(got_uri)
if expected_ro_uri:
- self.failUnlessEqual(child.get_readonly_uri(), expected_ro_uri.strip())
+ self.failUnlessReallyEqual(child.get_readonly_uri(), expected_ro_uri.strip())
d.addCallback(_check)
return d
d = node.get_child_at_path(name)
def _check(child):
self.failUnless(child.is_unknown() or child.is_readonly())
- self.failUnlessEqual(child.get_write_uri(), None)
- self.failUnlessEqual(got_uri.strip(), child.get_uri())
- self.failUnlessEqual(got_uri.strip(), child.get_readonly_uri())
+ self.failUnlessReallyEqual(child.get_write_uri(), None)
+ self.failUnlessReallyEqual(got_uri.strip(), child.get_uri())
+ self.failUnlessReallyEqual(got_uri.strip(), child.get_readonly_uri())
d.addCallback(_check)
return d
self.NEWFILE_CONTENTS))
target_url = self.public_url + "/foo/" + filename.encode("utf-8")
d.addCallback(lambda res: self.GET(target_url))
- d.addCallback(lambda contents: self.failUnlessEqual(contents,
- self.NEWFILE_CONTENTS,
- contents))
+ d.addCallback(lambda contents: self.failUnlessReallyEqual(contents,
+ self.NEWFILE_CONTENTS,
+ contents))
return d
def test_POST_upload_unicode_named(self):
self.NEWFILE_CONTENTS))
target_url = self.public_url + "/foo/" + filename.encode("utf-8")
d.addCallback(lambda res: self.GET(target_url))
- d.addCallback(lambda contents: self.failUnlessEqual(contents,
- self.NEWFILE_CONTENTS,
- contents))
+ d.addCallback(lambda contents: self.failUnlessReallyEqual(contents,
+ self.NEWFILE_CONTENTS,
+ contents))
return d
def test_POST_upload_no_link(self):
def test_POST_upload_no_link_whendone_results(self):
def check(statuscode, target):
- self.failUnlessEqual(statuscode, str(http.FOUND))
+ self.failUnlessReallyEqual(statuscode, str(http.FOUND))
self.failUnless(target.startswith(self.webish_url), target)
return client.getPage(target, method="GET")
d = self.shouldRedirect2("test_POST_upload_no_link_whendone_results",
when_done="/uri/%(uri)s",
file=("new.txt", self.NEWFILE_CONTENTS))
d.addCallback(lambda res:
- self.failUnlessEqual(res, self.NEWFILE_CONTENTS))
+ self.failUnlessReallyEqual(res, self.NEWFILE_CONTENTS))
return d
def test_POST_upload_no_link_mutable(self):
return n.download_best_version()
d.addCallback(_check)
def _check2(data):
- self.failUnlessEqual(data, self.NEWFILE_CONTENTS)
+ self.failUnlessReallyEqual(data, self.NEWFILE_CONTENTS)
return self.GET("/uri/%s" % urllib.quote(self.filecap))
d.addCallback(_check2)
def _check3(data):
- self.failUnlessEqual(data, self.NEWFILE_CONTENTS)
+ self.failUnlessReallyEqual(data, self.NEWFILE_CONTENTS)
return self.GET("/file/%s" % urllib.quote(self.filecap))
d.addCallback(_check3)
def _check4(data):
- self.failUnlessEqual(data, self.NEWFILE_CONTENTS)
+ self.failUnlessReallyEqual(data, self.NEWFILE_CONTENTS)
d.addCallback(_check4)
return d
def test_POST_upload_no_link_mutable_toobig(self):
- d = self.shouldFail2(error.Error,
- "test_POST_upload_no_link_mutable_toobig",
- "413 Request Entity Too Large",
- "SDMF is limited to one segment, and 10001 > 10000",
- self.POST,
- "/uri", t="upload", mutable="true",
- file=("new.txt",
- "b" * (self.s.MUTABLE_SIZELIMIT+1)) )
+ # The SDMF size limit is no longer in place, so we should be
+ # able to upload mutable files that are as large as we want them
+ # to be.
+ d = self.POST("/uri", t="upload", mutable="true",
+ file=("new.txt", "b" * (self.s.MUTABLE_SIZELIMIT + 1)))
+ return d
+
+
+ def test_POST_upload_mutable_type_unlinked(self):
+ d = self.POST("/uri?t=upload&mutable=true&mutable-type=sdmf",
+ file=("sdmf.txt", self.NEWFILE_CONTENTS * 300000))
+ d.addCallback(lambda filecap: self.GET("/uri/%s?t=json" % filecap))
+ def _got_json(json, version):
+ data = simplejson.loads(json)
+ data = data[1]
+
+ self.failUnlessIn("mutable-type", data)
+ self.failUnlessEqual(data['mutable-type'], version)
+ d.addCallback(_got_json, "sdmf")
+ d.addCallback(lambda ignored:
+ self.POST("/uri?t=upload&mutable=true&mutable-type=mdmf",
+ file=('mdmf.txt', self.NEWFILE_CONTENTS * 300000)))
+ def _got_filecap(filecap):
+ self.failUnless(filecap.startswith("URI:MDMF"))
+ return filecap
+ d.addCallback(_got_filecap)
+ d.addCallback(lambda filecap: self.GET("/uri/%s?t=json" % filecap))
+ d.addCallback(_got_json, "mdmf")
+ return d
+
+ def test_POST_upload_mutable_type_unlinked_bad_mutable_type(self):
+ return self.shouldHTTPError("test bad mutable type",
+ 400, "Bad Request", "Unknown type: foo",
+ self.POST,
+ "/uri?5=upload&mutable=true&mutable-type=foo",
+ file=("foo.txt", self.NEWFILE_CONTENTS * 300000))
+
+ def test_POST_upload_mutable_type(self):
+ d = self.POST(self.public_url + \
+ "/foo?t=upload&mutable=true&mutable-type=sdmf",
+ file=("sdmf.txt", self.NEWFILE_CONTENTS * 300000))
+ fn = self._foo_node
+ def _got_cap(filecap, filename):
+ filenameu = unicode(filename)
+ self.failUnlessURIMatchesRWChild(filecap, fn, filenameu)
+ return self.GET(self.public_url + "/foo/%s?t=json" % filename)
+ def _got_mdmf_cap(filecap):
+ self.failUnless(filecap.startswith("URI:MDMF"))
+ return filecap
+ d.addCallback(_got_cap, "sdmf.txt")
+ def _got_json(json, version):
+ data = simplejson.loads(json)
+ data = data[1]
+
+ self.failUnlessIn("mutable-type", data)
+ self.failUnlessEqual(data['mutable-type'], version)
+ d.addCallback(_got_json, "sdmf")
+ d.addCallback(lambda ignored:
+ self.POST(self.public_url + \
+ "/foo?t=upload&mutable=true&mutable-type=mdmf",
+ file=("mdmf.txt", self.NEWFILE_CONTENTS * 300000)))
+ d.addCallback(_got_mdmf_cap)
+ d.addCallback(_got_cap, "mdmf.txt")
+ d.addCallback(_got_json, "mdmf")
return d
+ def test_POST_upload_bad_mutable_type(self):
+ return self.shouldHTTPError("test bad mutable type",
+ 400, "Bad Request", "Unknown type: foo",
+ self.POST, self.public_url + \
+ "/foo?t=upload&mutable=true&mutable-type=foo",
+ file=("foo.txt", self.NEWFILE_CONTENTS * 300000))
+
def test_POST_upload_mutable(self):
# this creates a mutable file
d = self.POST(self.public_url + "/foo", t="upload", mutable="true",
self.failUnless(IMutableFileNode.providedBy(newnode))
self.failUnless(newnode.is_mutable())
self.failIf(newnode.is_readonly())
- self.failUnlessEqual(self._mutable_uri, newnode.get_uri())
+ self.failUnlessReallyEqual(self._mutable_uri, newnode.get_uri())
d.addCallback(_got2)
# upload a second time, using PUT instead of POST
self.failUnless(IMutableFileNode.providedBy(newnode))
self.failUnless(newnode.is_mutable())
self.failIf(newnode.is_readonly())
- self.failUnlessEqual(self._mutable_uri, newnode.get_uri())
+ self.failUnlessReallyEqual(self._mutable_uri, newnode.get_uri())
d.addCallback(_got3)
# look at the JSON form of the enclosing directory
children = dict( [(unicode(name),value)
for (name,value)
in parsed[1]["children"].iteritems()] )
- self.failUnless("new.txt" in children)
- new_json = children["new.txt"]
+ self.failUnless(u"new.txt" in children)
+ new_json = children[u"new.txt"]
self.failUnlessEqual(new_json[0], "filenode")
self.failUnless(new_json[1]["mutable"])
- self.failUnlessEqual(new_json[1]["rw_uri"], self._mutable_uri)
- ro_uri = unicode(self._mutable_node.get_readonly().to_string())
- self.failUnlessEqual(new_json[1]["ro_uri"], ro_uri)
+ self.failUnlessReallyEqual(to_str(new_json[1]["rw_uri"]), self._mutable_uri)
+ ro_uri = self._mutable_node.get_readonly().to_string()
+ self.failUnlessReallyEqual(to_str(new_json[1]["ro_uri"]), ro_uri)
d.addCallback(_check_page_json)
# and the JSON form of the file
parsed = simplejson.loads(res)
self.failUnlessEqual(parsed[0], "filenode")
self.failUnless(parsed[1]["mutable"])
- self.failUnlessEqual(parsed[1]["rw_uri"], self._mutable_uri)
- ro_uri = unicode(self._mutable_node.get_readonly().to_string())
- self.failUnlessEqual(parsed[1]["ro_uri"], ro_uri)
+ self.failUnlessReallyEqual(to_str(parsed[1]["rw_uri"]), self._mutable_uri)
+ ro_uri = self._mutable_node.get_readonly().to_string()
+ self.failUnlessReallyEqual(to_str(parsed[1]["ro_uri"]), ro_uri)
d.addCallback(_check_file_json)
# and look at t=uri and t=readonly-uri
d.addCallback(lambda res:
self.GET(self.public_url + "/foo/new.txt?t=uri"))
- d.addCallback(lambda res: self.failUnlessEqual(res, self._mutable_uri))
+ d.addCallback(lambda res: self.failUnlessReallyEqual(res, self._mutable_uri))
d.addCallback(lambda res:
self.GET(self.public_url + "/foo/new.txt?t=readonly-uri"))
def _check_ro_uri(res):
- ro_uri = unicode(self._mutable_node.get_readonly().to_string())
- self.failUnlessEqual(res, ro_uri)
+ ro_uri = self._mutable_node.get_readonly().to_string()
+ self.failUnlessReallyEqual(res, ro_uri)
d.addCallback(_check_ro_uri)
# make sure we can get to it from /uri/URI
d.addCallback(lambda res:
self.GET("/uri/%s" % urllib.quote(self._mutable_uri)))
d.addCallback(lambda res:
- self.failUnlessEqual(res, NEW2_CONTENTS))
+ self.failUnlessReallyEqual(res, NEW2_CONTENTS))
# and that HEAD computes the size correctly
d.addCallback(lambda res:
self.HEAD(self.public_url + "/foo/new.txt",
return_response=True))
def _got_headers((res, status, headers)):
- self.failUnlessEqual(res, "")
- self.failUnlessEqual(headers["content-length"][0],
- str(len(NEW2_CONTENTS)))
- self.failUnlessEqual(headers["content-type"], ["text/plain"])
+ self.failUnlessReallyEqual(res, "")
+ self.failUnlessReallyEqual(headers["content-length"][0],
+ str(len(NEW2_CONTENTS)))
+ self.failUnlessReallyEqual(headers["content-type"], ["text/plain"])
d.addCallback(_got_headers)
- # make sure that size errors are displayed correctly for overwrite
- d.addCallback(lambda res:
- self.shouldFail2(error.Error,
- "test_POST_upload_mutable-toobig",
- "413 Request Entity Too Large",
- "SDMF is limited to one segment, and 10001 > 10000",
- self.POST,
- self.public_url + "/foo", t="upload",
- mutable="true",
- file=("new.txt",
- "b" * (self.s.MUTABLE_SIZELIMIT+1)),
- ))
-
+ # make sure that outdated size limits aren't enforced anymore.
+ d.addCallback(lambda ignored:
+ self.POST(self.public_url + "/foo", t="upload",
+ mutable="true",
+ file=("new.txt",
+ "b" * (self.s.MUTABLE_SIZELIMIT+1))))
d.addErrback(self.dump_error)
return d
def test_POST_upload_mutable_toobig(self):
- d = self.shouldFail2(error.Error,
- "test_POST_upload_mutable_toobig",
- "413 Request Entity Too Large",
- "SDMF is limited to one segment, and 10001 > 10000",
- self.POST,
- self.public_url + "/foo",
- t="upload", mutable="true",
- file=("new.txt",
- "b" * (self.s.MUTABLE_SIZELIMIT+1)) )
+ # SDMF had a size limti that was removed a while ago. MDMF has
+ # never had a size limit. Test to make sure that we do not
+ # encounter errors when trying to upload large mutable files,
+ # since there should be no coded prohibitions regarding large
+ # mutable files.
+ d = self.POST(self.public_url + "/foo",
+ t="upload", mutable="true",
+ file=("new.txt", "b" * (self.s.MUTABLE_SIZELIMIT + 1)))
return d
def dump_error(self, f):
d = self.POST(self.public_url + "/foo?replace=false", t="upload",
file=("new.txt", self.NEWFILE_CONTENTS))
d.addCallback(lambda res: self.GET(self.public_url + "/foo/new.txt"))
- d.addCallback(lambda res: self.failUnlessEqual(res,
- self.NEWFILE_CONTENTS))
+ d.addCallback(lambda res: self.failUnlessReallyEqual(res,
+ self.NEWFILE_CONTENTS))
return d
def test_POST_upload_no_replace_queryarg(self):
# make sure that nothing was added
d.addCallback(lambda res:
self.failUnlessNodeKeysAre(self._foo_node,
- [u"bar.txt", u"blockingfile",
- u"empty", u"n\u00fc.txt",
+ [u"bar.txt", u"baz.txt", u"blockingfile",
+ u"empty", u"n\u00fc.txt", u"quux.txt",
u"sub"]))
return d
d.addCallback(_check)
redir_url = "http://allmydata.org/TARGET"
def _check2(statuscode, target):
- self.failUnlessEqual(statuscode, str(http.FOUND))
- self.failUnlessEqual(target, redir_url)
+ self.failUnlessReallyEqual(statuscode, str(http.FOUND))
+ self.failUnlessReallyEqual(target, redir_url)
d.addCallback(lambda res:
self.shouldRedirect2("test_POST_FILEURL_check",
_check2,
d.addCallback(_check)
redir_url = "http://allmydata.org/TARGET"
def _check2(statuscode, target):
- self.failUnlessEqual(statuscode, str(http.FOUND))
- self.failUnlessEqual(target, redir_url)
+ self.failUnlessReallyEqual(statuscode, str(http.FOUND))
+ self.failUnlessReallyEqual(target, redir_url)
d.addCallback(lambda res:
self.shouldRedirect2("test_POST_FILEURL_check_and_repair",
_check2,
d.addCallback(_check)
redir_url = "http://allmydata.org/TARGET"
def _check2(statuscode, target):
- self.failUnlessEqual(statuscode, str(http.FOUND))
- self.failUnlessEqual(target, redir_url)
+ self.failUnlessReallyEqual(statuscode, str(http.FOUND))
+ self.failUnlessReallyEqual(target, redir_url)
d.addCallback(lambda res:
self.shouldRedirect2("test_POST_DIRURL_check",
_check2,
d.addCallback(_check)
redir_url = "http://allmydata.org/TARGET"
def _check2(statuscode, target):
- self.failUnlessEqual(statuscode, str(http.FOUND))
- self.failUnlessEqual(target, redir_url)
+ self.failUnlessReallyEqual(statuscode, str(http.FOUND))
+ self.failUnlessReallyEqual(target, redir_url)
d.addCallback(lambda res:
self.shouldRedirect2("test_POST_DIRURL_check_and_repair",
_check2,
d.addCallback(_check3)
return d
+ def test_POST_FILEURL_mdmf_check(self):
+ quux_url = "/uri/%s" % urllib.quote(self._quux_txt_uri)
+ d = self.POST(quux_url, t="check")
+ def _check(res):
+ self.failUnlessIn("Healthy", res)
+ d.addCallback(_check)
+ quux_extension_url = "/uri/%s" % urllib.quote("%s:3:131073" % self._quux_txt_uri)
+ d.addCallback(lambda ignored:
+ self.POST(quux_extension_url, t="check"))
+ d.addCallback(_check)
+ return d
+
+ def test_POST_FILEURL_mdmf_check_and_repair(self):
+ quux_url = "/uri/%s" % urllib.quote(self._quux_txt_uri)
+ d = self.POST(quux_url, t="check", repair="true")
+ def _check(res):
+ self.failUnlessIn("Healthy", res)
+ d.addCallback(_check)
+ quux_extension_url = "/uri/%s" %\
+ urllib.quote("%s:3:131073" % self._quux_txt_uri)
+ d.addCallback(lambda ignored:
+ self.POST(quux_extension_url, t="check", repair="true"))
+ d.addCallback(_check)
+ return d
+
def wait_for_operation(self, ignored, ophandle):
url = "/operations/" + ophandle
url += "?t=status&output=JSON"
def test_POST_DIRURL_deepcheck(self):
def _check_redirect(statuscode, target):
- self.failUnlessEqual(statuscode, str(http.FOUND))
+ self.failUnlessReallyEqual(statuscode, str(http.FOUND))
self.failUnless(target.endswith("/operations/123"))
d = self.shouldRedirect2("test_POST_DIRURL_deepcheck", _check_redirect,
self.POST, self.public_url,
t="start-deep-check", ophandle="123")
d.addCallback(self.wait_for_operation, "123")
def _check_json(data):
- self.failUnlessEqual(data["finished"], True)
- self.failUnlessEqual(data["count-objects-checked"], 8)
- self.failUnlessEqual(data["count-objects-healthy"], 8)
+ self.failUnlessReallyEqual(data["finished"], True)
+ self.failUnlessReallyEqual(data["count-objects-checked"], 10)
+ self.failUnlessReallyEqual(data["count-objects-healthy"], 10)
d.addCallback(_check_json)
d.addCallback(self.get_operation_results, "123", "html")
def _check_html(res):
- self.failUnless("Objects Checked: <span>8</span>" in res)
- self.failUnless("Objects Healthy: <span>8</span>" in res)
+ self.failUnless("Objects Checked: <span>10</span>" in res)
+ self.failUnless("Objects Healthy: <span>10</span>" in res)
d.addCallback(_check_html)
d.addCallback(lambda res:
ophandle="124", output="json", followRedirect=True)
d.addCallback(self.wait_for_operation, "124")
def _check_json(data):
- self.failUnlessEqual(data["finished"], True)
- self.failUnlessEqual(data["count-objects-checked"], 8)
- self.failUnlessEqual(data["count-objects-healthy-pre-repair"], 8)
- self.failUnlessEqual(data["count-objects-unhealthy-pre-repair"], 0)
- self.failUnlessEqual(data["count-corrupt-shares-pre-repair"], 0)
- self.failUnlessEqual(data["count-repairs-attempted"], 0)
- self.failUnlessEqual(data["count-repairs-successful"], 0)
- self.failUnlessEqual(data["count-repairs-unsuccessful"], 0)
- self.failUnlessEqual(data["count-objects-healthy-post-repair"], 8)
- self.failUnlessEqual(data["count-objects-unhealthy-post-repair"], 0)
- self.failUnlessEqual(data["count-corrupt-shares-post-repair"], 0)
+ self.failUnlessReallyEqual(data["finished"], True)
+ self.failUnlessReallyEqual(data["count-objects-checked"], 10)
+ self.failUnlessReallyEqual(data["count-objects-healthy-pre-repair"], 10)
+ self.failUnlessReallyEqual(data["count-objects-unhealthy-pre-repair"], 0)
+ self.failUnlessReallyEqual(data["count-corrupt-shares-pre-repair"], 0)
+ self.failUnlessReallyEqual(data["count-repairs-attempted"], 0)
+ self.failUnlessReallyEqual(data["count-repairs-successful"], 0)
+ self.failUnlessReallyEqual(data["count-repairs-unsuccessful"], 0)
+ self.failUnlessReallyEqual(data["count-objects-healthy-post-repair"], 10)
+ self.failUnlessReallyEqual(data["count-objects-unhealthy-post-repair"], 0)
+ self.failUnlessReallyEqual(data["count-corrupt-shares-post-repair"], 0)
d.addCallback(_check_json)
d.addCallback(self.get_operation_results, "124", "html")
def _check_html(res):
- self.failUnless("Objects Checked: <span>8</span>" in res)
+ self.failUnless("Objects Checked: <span>10</span>" in res)
- self.failUnless("Objects Healthy (before repair): <span>8</span>" in res)
+ self.failUnless("Objects Healthy (before repair): <span>10</span>" in res)
self.failUnless("Objects Unhealthy (before repair): <span>0</span>" in res)
self.failUnless("Corrupt Shares (before repair): <span>0</span>" in res)
self.failUnless("Repairs Successful: <span>0</span>" in res)
self.failUnless("Repairs Unsuccessful: <span>0</span>" in res)
- self.failUnless("Objects Healthy (after repair): <span>8</span>" in res)
+ self.failUnless("Objects Healthy (after repair): <span>10</span>" in res)
self.failUnless("Objects Unhealthy (after repair): <span>0</span>" in res)
self.failUnless("Corrupt Shares (after repair): <span>0</span>" in res)
d.addCallback(_check_html)
d.addCallback(self.failUnlessNodeKeysAre, [])
return d
+ def test_POST_mkdir_mdmf(self):
+ d = self.POST(self.public_url + "/foo?t=mkdir&name=newdir&mutable-type=mdmf")
+ d.addCallback(lambda res: self._foo_node.get(u"newdir"))
+ d.addCallback(lambda node:
+ self.failUnlessEqual(node._node.get_version(), MDMF_VERSION))
+ return d
+
+ def test_POST_mkdir_sdmf(self):
+ d = self.POST(self.public_url + "/foo?t=mkdir&name=newdir&mutable-type=sdmf")
+ d.addCallback(lambda res: self._foo_node.get(u"newdir"))
+ d.addCallback(lambda node:
+ self.failUnlessEqual(node._node.get_version(), SDMF_VERSION))
+ return d
+
+ def test_POST_mkdir_bad_mutable_type(self):
+ return self.shouldHTTPError("test bad mutable type",
+ 400, "Bad Request", "Unknown type: foo",
+ self.POST, self.public_url + \
+ "/foo?t=mkdir&name=newdir&mutable-type=foo")
+
def test_POST_mkdir_initial_children(self):
(newkids, caps) = self._create_initial_children()
d = self.POST2(self.public_url +
d.addCallback(self.failUnlessROChildURIIs, u"child-imm", caps['filecap1'])
return d
+ def test_POST_mkdir_initial_children_mdmf(self):
+ (newkids, caps) = self._create_initial_children()
+ d = self.POST2(self.public_url +
+ "/foo?t=mkdir-with-children&name=newdir&mutable-type=mdmf",
+ simplejson.dumps(newkids))
+ d.addCallback(lambda res:
+ self.failUnlessNodeHasChild(self._foo_node, u"newdir"))
+ d.addCallback(lambda res: self._foo_node.get(u"newdir"))
+ d.addCallback(lambda node:
+ self.failUnlessEqual(node._node.get_version(), MDMF_VERSION))
+ d.addCallback(lambda res: self._foo_node.get(u"newdir"))
+ d.addCallback(self.failUnlessROChildURIIs, u"child-imm",
+ caps['filecap1'])
+ return d
+
+ # XXX: Duplication.
+ def test_POST_mkdir_initial_children_sdmf(self):
+ (newkids, caps) = self._create_initial_children()
+ d = self.POST2(self.public_url +
+ "/foo?t=mkdir-with-children&name=newdir&mutable-type=sdmf",
+ simplejson.dumps(newkids))
+ d.addCallback(lambda res:
+ self.failUnlessNodeHasChild(self._foo_node, u"newdir"))
+ d.addCallback(lambda res: self._foo_node.get(u"newdir"))
+ d.addCallback(lambda node:
+ self.failUnlessEqual(node._node.get_version(), SDMF_VERSION))
+ d.addCallback(lambda res: self._foo_node.get(u"newdir"))
+ d.addCallback(self.failUnlessROChildURIIs, u"child-imm",
+ caps['filecap1'])
+ return d
+
+ def test_POST_mkdir_initial_children_bad_mutable_type(self):
+ (newkids, caps) = self._create_initial_children()
+ return self.shouldHTTPError("test bad mutable type",
+ 400, "Bad Request", "Unknown type: foo",
+ self.POST, self.public_url + \
+ "/foo?t=mkdir-with-children&name=newdir&mutable-type=foo",
+ simplejson.dumps(newkids))
+
def test_POST_mkdir_immutable(self):
(newkids, caps) = self._create_immutable_children()
d = self.POST2(self.public_url +
d.addCallback(_after_mkdir)
return d
+ def test_POST_mkdir_no_parentdir_noredirect_mdmf(self):
+ d = self.POST("/uri?t=mkdir&mutable-type=mdmf")
+ def _after_mkdir(res):
+ u = uri.from_string(res)
+ # Check that this is an MDMF writecap
+ self.failUnlessIsInstance(u, uri.MDMFDirectoryURI)
+ d.addCallback(_after_mkdir)
+ return d
+
+ def test_POST_mkdir_no_parentdir_noredirect_sdmf(self):
+ d = self.POST("/uri?t=mkdir&mutable-type=sdmf")
+ def _after_mkdir(res):
+ u = uri.from_string(res)
+ self.failUnlessIsInstance(u, uri.DirectoryURI)
+ d.addCallback(_after_mkdir)
+ return d
+
+ def test_POST_mkdir_no_parentdir_noredirect_bad_mutable_type(self):
+ return self.shouldHTTPError("test bad mutable type",
+ 400, "Bad Request", "Unknown type: foo",
+ self.POST, self.public_url + \
+ "/uri?t=mkdir&mutable-type=foo")
+
def test_POST_mkdir_no_parentdir_noredirect2(self):
# make sure form-based arguments (as on the welcome page) still work
d = self.POST("/uri", t="mkdir")
filecap3 = node3.get_readonly_uri()
node4 = self.s.create_node_from_uri(make_mutable_file_uri())
dircap = DirectoryNode(node4, None, None).get_uri()
+ mdmfcap = make_mutable_file_uri(mdmf=True)
litdircap = "URI:DIR2-LIT:ge3dumj2mewdcotyfqydulbshj5x2lbm"
emptydircap = "URI:DIR2-LIT:"
newkids = {u"child-imm": ["filenode", {"rw_uri": filecap1,
"ro_uri": self._make_readonly(dircap)}],
u"dirchild-lit": ["dirnode", {"ro_uri": litdircap}],
u"dirchild-empty": ["dirnode", {"ro_uri": emptydircap}],
+ u"child-mutable-mdmf": ["filenode", {"rw_uri": mdmfcap,
+ "ro_uri": self._make_readonly(mdmfcap)}],
}
return newkids, {'filecap1': filecap1,
'filecap2': filecap2,
'unknown_immcap': unknown_immcap,
'dircap': dircap,
'litdircap': litdircap,
- 'emptydircap': emptydircap}
+ 'emptydircap': emptydircap,
+ 'mdmfcap': mdmfcap}
def _create_immutable_children(self):
contents, n, filecap1 = self.makefile(12)
d.addCallback(self.failUnlessIsBarDotTxt)
return d
- def test_POST_delete(self):
- d = self.POST(self.public_url + "/foo", t="delete", name="bar.txt")
+ def test_POST_delete(self, command_name='delete'):
+ d = self._foo_node.list()
+ def _check_before(children):
+ self.failUnless(u"bar.txt" in children)
+ d.addCallback(_check_before)
+ d.addCallback(lambda res: self.POST(self.public_url + "/foo", t=command_name, name="bar.txt"))
d.addCallback(lambda res: self._foo_node.list())
- def _check(children):
+ def _check_after(children):
self.failIf(u"bar.txt" in children)
- d.addCallback(_check)
+ d.addCallback(_check_after)
return d
+ def test_POST_unlink(self):
+ return self.test_POST_delete(command_name='unlink')
+
def test_POST_rename_file(self):
d = self.POST(self.public_url + "/foo", t="rename",
from_name="bar.txt", to_name='wibble.txt')
def failUnlessIsEmptyJSON(self, res):
data = simplejson.loads(res)
self.failUnlessEqual(data[0], "dirnode", data)
- self.failUnlessEqual(len(data[1]["children"]), 0)
+ self.failUnlessReallyEqual(len(data[1]["children"]), 0)
def test_POST_rename_file_slash_fail(self):
d = self.POST(self.public_url + "/foo", t="rename",
" actual page: %s" % (which, to_where, res))
res.trap(error.PageRedirect)
if statuscode is not None:
- self.failUnlessEqual(res.value.status, statuscode,
- "%s: not a redirect" % which)
+ self.failUnlessReallyEqual(res.value.status, statuscode,
+ "%s: not a redirect" % which)
if target is not None:
# the PageRedirect does not seem to capture the uri= query arg
# properly, so we can't check for it.
realtarget = self.webish_url + target
- self.failUnlessEqual(res.value.location, realtarget,
- "%s: wrong target" % which)
+ self.failUnlessReallyEqual(res.value.location, realtarget,
+ "%s: wrong target" % which)
return res.value.location
def test_GET_URI_form(self):
# replace /foo with a new (empty) directory
d = self.PUT(self.public_url + "/foo?t=uri", new_uri)
d.addCallback(lambda res:
- self.failUnlessEqual(res.strip(), new_uri))
+ self.failUnlessReallyEqual(res.strip(), new_uri))
d.addCallback(lambda res:
self.failUnlessRWChildURIIs(self.public_root,
u"foo",
def test_PUT_NEWFILEURL_uri(self):
contents, n, new_uri = self.makefile(8)
d = self.PUT(self.public_url + "/foo/new.txt?t=uri", new_uri)
- d.addCallback(lambda res: self.failUnlessEqual(res.strip(), new_uri))
+ d.addCallback(lambda res: self.failUnlessReallyEqual(res.strip(), new_uri))
d.addCallback(lambda res:
self.failUnlessChildContentsAre(self._foo_node, u"new.txt",
contents))
return d
+ def test_PUT_NEWFILEURL_mdmf(self):
+ new_contents = self.NEWFILE_CONTENTS * 300000
+ d = self.PUT(self.public_url + \
+ "/foo/mdmf.txt?mutable=true&mutable-type=mdmf",
+ new_contents)
+ d.addCallback(lambda ignored:
+ self.GET(self.public_url + "/foo/mdmf.txt?t=json"))
+ def _got_json(json):
+ data = simplejson.loads(json)
+ data = data[1]
+ self.failUnlessIn("mutable-type", data)
+ self.failUnlessEqual(data['mutable-type'], "mdmf")
+ self.failUnless(data['rw_uri'].startswith("URI:MDMF"))
+ self.failUnless(data['ro_uri'].startswith("URI:MDMF"))
+ d.addCallback(_got_json)
+ return d
+
+ def test_PUT_NEWFILEURL_sdmf(self):
+ new_contents = self.NEWFILE_CONTENTS * 300000
+ d = self.PUT(self.public_url + \
+ "/foo/sdmf.txt?mutable=true&mutable-type=sdmf",
+ new_contents)
+ d.addCallback(lambda ignored:
+ self.GET(self.public_url + "/foo/sdmf.txt?t=json"))
+ def _got_json(json):
+ data = simplejson.loads(json)
+ data = data[1]
+ self.failUnlessIn("mutable-type", data)
+ self.failUnlessEqual(data['mutable-type'], "sdmf")
+ d.addCallback(_got_json)
+ return d
+
+ def test_PUT_NEWFILEURL_bad_mutable_type(self):
+ new_contents = self.NEWFILE_CONTENTS * 300000
+ return self.shouldHTTPError("test bad mutable type",
+ 400, "Bad Request", "Unknown type: foo",
+ self.PUT, self.public_url + \
+ "/foo/foo.txt?mutable=true&mutable-type=foo",
+ new_contents)
+
def test_PUT_NEWFILEURL_uri_replace(self):
contents, n, new_uri = self.makefile(8)
d = self.PUT(self.public_url + "/foo/bar.txt?t=uri", new_uri)
- d.addCallback(lambda res: self.failUnlessEqual(res.strip(), new_uri))
+ d.addCallback(lambda res: self.failUnlessReallyEqual(res.strip(), new_uri))
d.addCallback(lambda res:
self.failUnlessChildContentsAre(self._foo_node, u"bar.txt",
contents))
def _check(uri):
assert isinstance(uri, str), uri
self.failUnless(uri in FakeCHKFileNode.all_contents)
- self.failUnlessEqual(FakeCHKFileNode.all_contents[uri],
- file_contents)
+ self.failUnlessReallyEqual(FakeCHKFileNode.all_contents[uri],
+ file_contents)
return self.GET("/uri/%s" % uri)
d.addCallback(_check)
def _check2(res):
- self.failUnlessEqual(res, file_contents)
+ self.failUnlessReallyEqual(res, file_contents)
d.addCallback(_check2)
return d
def _check(uri):
assert isinstance(uri, str), uri
self.failUnless(uri in FakeCHKFileNode.all_contents)
- self.failUnlessEqual(FakeCHKFileNode.all_contents[uri],
- file_contents)
+ self.failUnlessReallyEqual(FakeCHKFileNode.all_contents[uri],
+ file_contents)
return self.GET("/uri/%s" % uri)
d.addCallback(_check)
def _check2(res):
- self.failUnlessEqual(res, file_contents)
+ self.failUnlessReallyEqual(res, file_contents)
d.addCallback(_check2)
return d
return n.download_best_version()
d.addCallback(_check1)
def _check2(data):
- self.failUnlessEqual(data, file_contents)
+ self.failUnlessReallyEqual(data, file_contents)
return self.GET("/uri/%s" % urllib.quote(self.filecap))
d.addCallback(_check2)
def _check3(res):
- self.failUnlessEqual(res, file_contents)
+ self.failUnlessReallyEqual(res, file_contents)
d.addCallback(_check3)
return d
d.addCallback(self.failUnlessIsEmptyJSON)
return d
+ def test_PUT_mkdir_mdmf(self):
+ d = self.PUT("/uri?t=mkdir&mutable-type=mdmf", "")
+ def _got(res):
+ u = uri.from_string(res)
+ # Check that this is an MDMF writecap
+ self.failUnlessIsInstance(u, uri.MDMFDirectoryURI)
+ d.addCallback(_got)
+ return d
+
+ def test_PUT_mkdir_sdmf(self):
+ d = self.PUT("/uri?t=mkdir&mutable-type=sdmf", "")
+ def _got(res):
+ u = uri.from_string(res)
+ self.failUnlessIsInstance(u, uri.DirectoryURI)
+ d.addCallback(_got)
+ return d
+
+ def test_PUT_mkdir_bad_mutable_type(self):
+ return self.shouldHTTPError("bad mutable type",
+ 400, "Bad Request", "Unknown type: foo",
+ self.PUT, "/uri?t=mkdir&mutable-type=foo",
+ "")
+
def test_POST_check(self):
d = self.POST(self.public_url + "/foo", t="check", name="bar.txt")
def _done(res):
d.addCallback(_done)
return d
+
+ def test_PUT_update_at_offset(self):
+ file_contents = "test file" * 100000 # about 900 KiB
+ d = self.PUT("/uri?mutable=true", file_contents)
+ def _then(filecap):
+ self.filecap = filecap
+ new_data = file_contents[:100]
+ new = "replaced and so on"
+ new_data += new
+ new_data += file_contents[len(new_data):]
+ assert len(new_data) == len(file_contents)
+ self.new_data = new_data
+ d.addCallback(_then)
+ d.addCallback(lambda ignored:
+ self.PUT("/uri/%s?replace=True&offset=100" % self.filecap,
+ "replaced and so on"))
+ def _get_data(filecap):
+ n = self.s.create_node_from_uri(filecap)
+ return n.download_best_version()
+ d.addCallback(_get_data)
+ d.addCallback(lambda results:
+ self.failUnlessEqual(results, self.new_data))
+ # Now try appending things to the file
+ d.addCallback(lambda ignored:
+ self.PUT("/uri/%s?offset=%d" % (self.filecap, len(self.new_data)),
+ "puppies" * 100))
+ d.addCallback(_get_data)
+ d.addCallback(lambda results:
+ self.failUnlessEqual(results, self.new_data + ("puppies" * 100)))
+ # and try replacing the beginning of the file
+ d.addCallback(lambda ignored:
+ self.PUT("/uri/%s?offset=0" % self.filecap, "begin"))
+ d.addCallback(_get_data)
+ d.addCallback(lambda results:
+ self.failUnlessEqual(results, "begin"+self.new_data[len("begin"):]+("puppies"*100)))
+ return d
+
+ def test_PUT_update_at_invalid_offset(self):
+ file_contents = "test file" * 100000 # about 900 KiB
+ d = self.PUT("/uri?mutable=true", file_contents)
+ def _then(filecap):
+ self.filecap = filecap
+ d.addCallback(_then)
+ # Negative offsets should cause an error.
+ d.addCallback(lambda ignored:
+ self.shouldHTTPError("test mutable invalid offset negative",
+ 400, "Bad Request",
+ "Invalid offset",
+ self.PUT,
+ "/uri/%s?offset=-1" % self.filecap,
+ "foo"))
+ return d
+
+ def test_PUT_update_at_offset_immutable(self):
+ file_contents = "Test file" * 100000
+ d = self.PUT("/uri", file_contents)
+ def _then(filecap):
+ self.filecap = filecap
+ d.addCallback(_then)
+ d.addCallback(lambda ignored:
+ self.shouldHTTPError("test immutable update",
+ 400, "Bad Request",
+ "immutable",
+ self.PUT,
+ "/uri/%s?offset=50" % self.filecap,
+ "foo"))
+ return d
+
+
def test_bad_method(self):
url = self.webish_url + self.public_url + "/foo/bar.txt"
d = self.shouldHTTPError("test_bad_method",
d = self.POST(self.public_url +
"/foo/?t=start-manifest&ophandle=%d" % ophandle,
followRedirect=True)
- # By following the initial redirect, we collect the ophandle
+ # By following the initial redirect, we collect the ophandle
# we've just created.
return d
- # Create a collected ophandle, then collect it after 23 hours
+ # Create a collected ophandle, then collect it after 23 hours
# and 59 seconds to make sure that it is still there.
d = _make_collected_ophandle(133)
d.addCallback(lambda ign:
d = self.GET("/static/subdir/hello.txt")
def _check(res):
- self.failUnlessEqual(res, "hello")
+ self.failUnlessReallyEqual(res, "hello")
d.addCallback(_check)
return d
-class Util(unittest.TestCase, ShouldFailMixin):
+class Util(ShouldFailMixin, testutil.ReallyEqualMixin, unittest.TestCase):
def test_load_file(self):
# This will raise an exception unless a well-formed XML file is found under that name.
common.getxmlfile('directory.xhtml').load()
def test_parse_replace_arg(self):
- self.failUnlessEqual(common.parse_replace_arg("true"), True)
- self.failUnlessEqual(common.parse_replace_arg("false"), False)
- self.failUnlessEqual(common.parse_replace_arg("only-files"),
- "only-files")
+ self.failUnlessReallyEqual(common.parse_replace_arg("true"), True)
+ self.failUnlessReallyEqual(common.parse_replace_arg("false"), False)
+ self.failUnlessReallyEqual(common.parse_replace_arg("only-files"),
+ "only-files")
self.shouldFail(AssertionError, "test_parse_replace_arg", "",
common.parse_replace_arg, "only_fles")
def test_abbreviate_time(self):
- self.failUnlessEqual(common.abbreviate_time(None), "")
- self.failUnlessEqual(common.abbreviate_time(1.234), "1.23s")
- self.failUnlessEqual(common.abbreviate_time(0.123), "123ms")
- self.failUnlessEqual(common.abbreviate_time(0.00123), "1.2ms")
- self.failUnlessEqual(common.abbreviate_time(0.000123), "123us")
+ self.failUnlessReallyEqual(common.abbreviate_time(None), "")
+ self.failUnlessReallyEqual(common.abbreviate_time(1.234), "1.23s")
+ self.failUnlessReallyEqual(common.abbreviate_time(0.123), "123ms")
+ self.failUnlessReallyEqual(common.abbreviate_time(0.00123), "1.2ms")
+ self.failUnlessReallyEqual(common.abbreviate_time(0.000123), "123us")
+ self.failUnlessReallyEqual(common.abbreviate_time(-123000), "-123000000000us")
+
+ def test_compute_rate(self):
+ self.failUnlessReallyEqual(common.compute_rate(None, None), None)
+ self.failUnlessReallyEqual(common.compute_rate(None, 1), None)
+ self.failUnlessReallyEqual(common.compute_rate(250000, None), None)
+ self.failUnlessReallyEqual(common.compute_rate(250000, 0), None)
+ self.failUnlessReallyEqual(common.compute_rate(250000, 10), 25000.0)
+ self.failUnlessReallyEqual(common.compute_rate(0, 10), 0.0)
+ self.shouldFail(AssertionError, "test_compute_rate", "",
+ common.compute_rate, -100, 10)
+ self.shouldFail(AssertionError, "test_compute_rate", "",
+ common.compute_rate, 100, -10)
+
+ # Sanity check
+ rate = common.compute_rate(10*1000*1000, 1)
+ self.failUnlessReallyEqual(common.abbreviate_rate(rate), "10.00MBps")
def test_abbreviate_rate(self):
- self.failUnlessEqual(common.abbreviate_rate(None), "")
- self.failUnlessEqual(common.abbreviate_rate(1234000), "1.23MBps")
- self.failUnlessEqual(common.abbreviate_rate(12340), "12.3kBps")
- self.failUnlessEqual(common.abbreviate_rate(123), "123Bps")
+ self.failUnlessReallyEqual(common.abbreviate_rate(None), "")
+ self.failUnlessReallyEqual(common.abbreviate_rate(1234000), "1.23MBps")
+ self.failUnlessReallyEqual(common.abbreviate_rate(12340), "12.3kBps")
+ self.failUnlessReallyEqual(common.abbreviate_rate(123), "123Bps")
def test_abbreviate_size(self):
- self.failUnlessEqual(common.abbreviate_size(None), "")
- self.failUnlessEqual(common.abbreviate_size(1.23*1000*1000*1000), "1.23GB")
- self.failUnlessEqual(common.abbreviate_size(1.23*1000*1000), "1.23MB")
- self.failUnlessEqual(common.abbreviate_size(1230), "1.2kB")
- self.failUnlessEqual(common.abbreviate_size(123), "123B")
+ self.failUnlessReallyEqual(common.abbreviate_size(None), "")
+ self.failUnlessReallyEqual(common.abbreviate_size(1.23*1000*1000*1000), "1.23GB")
+ self.failUnlessReallyEqual(common.abbreviate_size(1.23*1000*1000), "1.23MB")
+ self.failUnlessReallyEqual(common.abbreviate_size(1230), "1.2kB")
+ self.failUnlessReallyEqual(common.abbreviate_size(123), "123B")
def test_plural(self):
def convert(s):
return "%d second%s" % (s, status.plural(s))
- self.failUnlessEqual(convert(0), "0 seconds")
- self.failUnlessEqual(convert(1), "1 second")
- self.failUnlessEqual(convert(2), "2 seconds")
+ self.failUnlessReallyEqual(convert(0), "0 seconds")
+ self.failUnlessReallyEqual(convert(1), "1 second")
+ self.failUnlessReallyEqual(convert(2), "2 seconds")
def convert2(s):
return "has share%s: %s" % (status.plural(s), ",".join(s))
- self.failUnlessEqual(convert2([]), "has shares: ")
- self.failUnlessEqual(convert2(["1"]), "has share: 1")
- self.failUnlessEqual(convert2(["1","2"]), "has shares: 1,2")
+ self.failUnlessReallyEqual(convert2([]), "has shares: ")
+ self.failUnlessReallyEqual(convert2(["1"]), "has share: 1")
+ self.failUnlessReallyEqual(convert2(["1","2"]), "has shares: 1,2")
-class Grid(GridTestMixin, WebErrorMixin, unittest.TestCase, ShouldFailMixin):
+class Grid(GridTestMixin, WebErrorMixin, ShouldFailMixin, testutil.ReallyEqualMixin, unittest.TestCase):
def CHECK(self, ign, which, args, clientnum=0):
fileurl = self.fileurls[which]
def _stash_mutable_uri(n, which):
self.uris[which] = n.get_uri()
assert isinstance(self.uris[which], str)
- d.addCallback(lambda ign: c0.create_mutable_file(DATA+"3"))
+ d.addCallback(lambda ign:
+ c0.create_mutable_file(publish.MutableData(DATA+"3")))
d.addCallback(_stash_mutable_uri, "corrupt")
d.addCallback(lambda ign:
c0.upload(upload.Data("literal", convergence="")))
d.addCallback(_compute_fileurls)
def _clobber_shares(ignored):
- good_shares = self.find_shares(self.uris["good"])
- self.failUnlessEqual(len(good_shares), 10)
- sick_shares = self.find_shares(self.uris["sick"])
+ good_shares = self.find_uri_shares(self.uris["good"])
+ self.failUnlessReallyEqual(len(good_shares), 10)
+ sick_shares = self.find_uri_shares(self.uris["sick"])
os.unlink(sick_shares[0][2])
- dead_shares = self.find_shares(self.uris["dead"])
+ dead_shares = self.find_uri_shares(self.uris["dead"])
for i in range(1, 10):
os.unlink(dead_shares[i][2])
- c_shares = self.find_shares(self.uris["corrupt"])
+ c_shares = self.find_uri_shares(self.uris["corrupt"])
cso = CorruptShareOptions()
cso.stdout = StringIO()
cso.parseOptions([c_shares[0][2]])
r["summary"])
self.failIf(r["results"]["healthy"])
self.failUnless(r["results"]["recoverable"])
- self.failUnlessEqual(r["results"]["count-shares-good"], 9)
- self.failUnlessEqual(r["results"]["count-corrupt-shares"], 1)
+ self.failUnlessReallyEqual(r["results"]["count-shares-good"], 9)
+ self.failUnlessReallyEqual(r["results"]["count-corrupt-shares"], 1)
d.addCallback(_got_json_corrupt)
d.addErrback(self.explain_web_error)
def _stash_mutable_uri(n, which):
self.uris[which] = n.get_uri()
assert isinstance(self.uris[which], str)
- d.addCallback(lambda ign: c0.create_mutable_file(DATA+"3"))
+ d.addCallback(lambda ign:
+ c0.create_mutable_file(publish.MutableData(DATA+"3")))
d.addCallback(_stash_mutable_uri, "corrupt")
def _compute_fileurls(ignored):
d.addCallback(_compute_fileurls)
def _clobber_shares(ignored):
- good_shares = self.find_shares(self.uris["good"])
- self.failUnlessEqual(len(good_shares), 10)
- sick_shares = self.find_shares(self.uris["sick"])
+ good_shares = self.find_uri_shares(self.uris["good"])
+ self.failUnlessReallyEqual(len(good_shares), 10)
+ sick_shares = self.find_uri_shares(self.uris["sick"])
os.unlink(sick_shares[0][2])
- dead_shares = self.find_shares(self.uris["dead"])
+ dead_shares = self.find_uri_shares(self.uris["dead"])
for i in range(1, 10):
os.unlink(dead_shares[i][2])
- c_shares = self.find_shares(self.uris["corrupt"])
+ c_shares = self.find_uri_shares(self.uris["corrupt"])
cso = CorruptShareOptions()
cso.stdout = StringIO()
cso.parseOptions([c_shares[0][2]])
d.addCallback(_compute_fileurls)
def _clobber_shares(ignored):
- sick_shares = self.find_shares(self.uris["sick"])
+ sick_shares = self.find_uri_shares(self.uris["sick"])
os.unlink(sick_shares[0][2])
d.addCallback(_clobber_shares)
d.addCallback(self.CHECK, "sick", "t=check&repair=true&output=json")
def _got_json_sick(res):
r = simplejson.loads(res)
- self.failUnlessEqual(r["repair-attempted"], True)
- self.failUnlessEqual(r["repair-successful"], True)
+ self.failUnlessReallyEqual(r["repair-attempted"], True)
+ self.failUnlessReallyEqual(r["repair-successful"], True)
self.failUnlessEqual(r["pre-repair-results"]["summary"],
"Not Healthy: 9 shares (enc 3-of-10)")
self.failIf(r["pre-repair-results"]["results"]["healthy"])
# find the More Info link for name, should be relative
mo = re.search(r'<a href="([^"]+)">More Info</a>', res)
info_url = mo.group(1)
- self.failUnlessEqual(info_url, "%s?t=info" % (str(name),))
+ self.failUnlessReallyEqual(info_url, "%s?t=info" % (str(name),))
if immutable:
d.addCallback(_check_directory_html, "-IMM")
else:
f = data[1]["children"][name]
self.failUnlessEqual(f[0], "unknown")
if expect_rw_uri:
- self.failUnlessEqual(f[1]["rw_uri"], unknown_rwcap)
+ self.failUnlessReallyEqual(to_str(f[1]["rw_uri"]), unknown_rwcap, data)
else:
self.failIfIn("rw_uri", f[1])
if immutable:
- self.failUnlessEqual(f[1]["ro_uri"], unknown_immcap, data)
+ self.failUnlessReallyEqual(to_str(f[1]["ro_uri"]), unknown_immcap, data)
else:
- self.failUnlessEqual(f[1]["ro_uri"], unknown_rocap)
+ self.failUnlessReallyEqual(to_str(f[1]["ro_uri"]), unknown_rocap, data)
self.failUnless("metadata" in f[1])
d.addCallback(_check_directory_json, expect_rw_uri=not immutable)
data = simplejson.loads(res)
self.failUnlessEqual(data[0], "unknown")
if expect_rw_uri:
- self.failUnlessEqual(data[1]["rw_uri"], unknown_rwcap)
+ self.failUnlessReallyEqual(to_str(data[1]["rw_uri"]), unknown_rwcap, data)
else:
self.failIfIn("rw_uri", data[1])
if immutable:
- self.failUnlessEqual(data[1]["ro_uri"], unknown_immcap)
- self.failUnlessEqual(data[1]["mutable"], False)
+ self.failUnlessReallyEqual(to_str(data[1]["ro_uri"]), unknown_immcap, data)
+ self.failUnlessReallyEqual(data[1]["mutable"], False)
elif expect_rw_uri:
- self.failUnlessEqual(data[1]["ro_uri"], unknown_rocap)
- self.failUnlessEqual(data[1]["mutable"], True)
+ self.failUnlessReallyEqual(to_str(data[1]["ro_uri"]), unknown_rocap, data)
+ self.failUnlessReallyEqual(data[1]["mutable"], True)
else:
- self.failUnlessEqual(data[1]["ro_uri"], unknown_rocap)
+ self.failUnlessReallyEqual(to_str(data[1]["ro_uri"]), unknown_rocap, data)
self.failIf("mutable" in data[1], data[1])
# TODO: check metadata contents
d.addCallback(lambda ign: self.GET("%s%s?t=json" % (self.rourl, str(name))))
d.addCallback(_check_json, expect_rw_uri=False)
-
+
# TODO: check that getting t=info from the Info link in the ro directory
# works, and does not include the writecap URI.
return d
lonely_uri = "URI:LIT:n5xgk" # LIT for "one"
mut_write_uri = "URI:SSK:vfvcbdfbszyrsaxchgevhmmlii:euw4iw7bbnkrrwpzuburbhppuxhc3gwxv26f6imekhz7zyw2ojnq"
mut_read_uri = "URI:SSK-RO:e3mdrzfwhoq42hy5ubcz6rp3o4:ybyibhnp3vvwuq2vaw2ckjmesgkklfs6ghxleztqidihjyofgw7q"
-
+
# This method tests mainly dirnode, but we'd have to duplicate code in order to
# test the dirnode and web layers separately.
-
+
# 'lonely' is a valid LIT child, 'ro' is a mutant child with an SSK-RO readcap,
- # and 'write-in-ro' is a mutant child with an SSK writecap in the ro_uri field.
+ # and 'write-in-ro' is a mutant child with an SSK writecap in the ro_uri field.
# When the directory is read, the mutants should be silently disposed of, leaving
# their lonely sibling.
# We don't test the case of a retrieving a cap from the encrypted rw_uri field,
u"write-in-ro": (mutant_write_in_ro_child, {}),
}
d = c.create_immutable_dirnode(kids)
-
+
def _created(dn):
self.failUnless(isinstance(dn, dirnode.DirectoryNode))
self.failIf(dn.is_mutable())
self.failUnless(rwcapdata == "")
self.failUnless(name in kids)
(expected_child, ign) = kids[name]
- self.failUnlessEqual(ro_uri, expected_child.get_readonly_uri())
+ self.failUnlessReallyEqual(ro_uri, expected_child.get_readonly_uri())
numkids += 1
- self.failUnlessEqual(numkids, 3)
+ self.failUnlessReallyEqual(numkids, 3)
return self.rootnode.list()
d.addCallback(_check_data)
-
+
# Now when we use the real directory listing code, the mutants should be absent.
def _check_kids(children):
- self.failUnlessEqual(sorted(children.keys()), [u"lonely"])
+ self.failUnlessReallyEqual(sorted(children.keys()), [u"lonely"])
lonely_node, lonely_metadata = children[u"lonely"]
- self.failUnlessEqual(lonely_node.get_write_uri(), None)
- self.failUnlessEqual(lonely_node.get_readonly_uri(), lonely_uri)
+ self.failUnlessReallyEqual(lonely_node.get_write_uri(), None)
+ self.failUnlessReallyEqual(lonely_node.get_readonly_uri(), lonely_uri)
d.addCallback(_check_kids)
d.addCallback(lambda ign: nm.create_from_cap(self.cap.to_string()))
r'\s+<td>',
r'<a href="[^"]+%s[^"]+">lonely</a>' % (urllib.quote(lonely_uri),),
r'</td>',
- r'\s+<td>%d</td>' % len("one"),
+ r'\s+<td align="right">%d</td>' % len("one"),
])
self.failUnless(re.search(get_lonely, res), res)
data = simplejson.loads(res)
self.failUnlessEqual(data[0], "dirnode")
listed_children = data[1]["children"]
- self.failUnlessEqual(sorted(listed_children.keys()), [u"lonely"])
+ self.failUnlessReallyEqual(sorted(listed_children.keys()), [u"lonely"])
ll_type, ll_data = listed_children[u"lonely"]
self.failUnlessEqual(ll_type, "filenode")
self.failIf("rw_uri" in ll_data)
- self.failUnlessEqual(ll_data["ro_uri"], lonely_uri)
+ self.failUnlessReallyEqual(to_str(ll_data["ro_uri"]), lonely_uri)
d.addCallback(_check_json)
return d
print "response is:", res
print "undecodeable line was '%s'" % line
raise
- self.failUnlessEqual(len(units), 5+1)
+ self.failUnlessReallyEqual(len(units), 5+1)
# should be parent-first
u0 = units[0]
self.failUnlessEqual(u0["path"], [])
self.failUnlessEqual(u0["type"], "directory")
- self.failUnlessEqual(u0["cap"], self.rootnode.get_uri())
+ self.failUnlessReallyEqual(to_str(u0["cap"]), self.rootnode.get_uri())
u0cr = u0["check-results"]
- self.failUnlessEqual(u0cr["results"]["count-shares-good"], 10)
+ self.failUnlessReallyEqual(u0cr["results"]["count-shares-good"], 10)
ugood = [u for u in units
if u["type"] == "file" and u["path"] == [u"good"]][0]
- self.failUnlessEqual(ugood["cap"], self.uris["good"])
+ self.failUnlessReallyEqual(to_str(ugood["cap"]), self.uris["good"])
ugoodcr = ugood["check-results"]
- self.failUnlessEqual(ugoodcr["results"]["count-shares-good"], 10)
+ self.failUnlessReallyEqual(ugoodcr["results"]["count-shares-good"], 10)
stats = units[-1]
self.failUnlessEqual(stats["type"], "stats")
s = stats["stats"]
- self.failUnlessEqual(s["count-immutable-files"], 2)
- self.failUnlessEqual(s["count-literal-files"], 1)
- self.failUnlessEqual(s["count-directories"], 1)
- self.failUnlessEqual(s["count-unknown"], 1)
+ self.failUnlessReallyEqual(s["count-immutable-files"], 2)
+ self.failUnlessReallyEqual(s["count-literal-files"], 1)
+ self.failUnlessReallyEqual(s["count-directories"], 1)
+ self.failUnlessReallyEqual(s["count-unknown"], 1)
d.addCallback(_done)
d.addCallback(self.CHECK, "root", "t=stream-manifest")
def _check_manifest(res):
self.failUnless(res.endswith("\n"))
units = [simplejson.loads(t) for t in res[:-1].split("\n")]
- self.failUnlessEqual(len(units), 5+1)
+ self.failUnlessReallyEqual(len(units), 5+1)
self.failUnlessEqual(units[-1]["type"], "stats")
first = units[0]
self.failUnlessEqual(first["path"], [])
- self.failUnlessEqual(first["cap"], self.rootnode.get_uri())
+ self.failUnlessEqual(to_str(first["cap"]), self.rootnode.get_uri())
self.failUnlessEqual(first["type"], "directory")
stats = units[-1]["stats"]
- self.failUnlessEqual(stats["count-immutable-files"], 2)
- self.failUnlessEqual(stats["count-literal-files"], 1)
- self.failUnlessEqual(stats["count-mutable-files"], 0)
- self.failUnlessEqual(stats["count-immutable-files"], 2)
- self.failUnlessEqual(stats["count-unknown"], 1)
+ self.failUnlessReallyEqual(stats["count-immutable-files"], 2)
+ self.failUnlessReallyEqual(stats["count-literal-files"], 1)
+ self.failUnlessReallyEqual(stats["count-mutable-files"], 0)
+ self.failUnlessReallyEqual(stats["count-immutable-files"], 2)
+ self.failUnlessReallyEqual(stats["count-unknown"], 1)
d.addCallback(_check_manifest)
# now add root/subdir and root/subdir/grandchild, then make subdir
error_line)
self.failUnless(len(error_msg) > 2, error_msg_s) # some traceback
units = [simplejson.loads(line) for line in lines[:first_error]]
- self.failUnlessEqual(len(units), 6) # includes subdir
+ self.failUnlessReallyEqual(len(units), 6) # includes subdir
last_unit = units[-1]
self.failUnlessEqual(last_unit["path"], ["subdir"])
d.addCallback(_check_broken_manifest)
error_line)
self.failUnless(len(error_msg) > 2, error_msg_s) # some traceback
units = [simplejson.loads(line) for line in lines[:first_error]]
- self.failUnlessEqual(len(units), 6) # includes subdir
+ self.failUnlessReallyEqual(len(units), 6) # includes subdir
last_unit = units[-1]
self.failUnlessEqual(last_unit["path"], ["subdir"])
r = last_unit["check-results"]["results"]
- self.failUnlessEqual(r["count-recoverable-versions"], 0)
- self.failUnlessEqual(r["count-shares-good"], 1)
- self.failUnlessEqual(r["recoverable"], False)
+ self.failUnlessReallyEqual(r["count-recoverable-versions"], 0)
+ self.failUnlessReallyEqual(r["count-shares-good"], 1)
+ self.failUnlessReallyEqual(r["recoverable"], False)
d.addCallback(_check_broken_deepcheck)
d.addErrback(self.explain_web_error)
#d.addCallback(_stash_uri, "corrupt")
def _clobber_shares(ignored):
- good_shares = self.find_shares(self.uris["good"])
- self.failUnlessEqual(len(good_shares), 10)
- sick_shares = self.find_shares(self.uris["sick"])
+ good_shares = self.find_uri_shares(self.uris["good"])
+ self.failUnlessReallyEqual(len(good_shares), 10)
+ sick_shares = self.find_uri_shares(self.uris["sick"])
os.unlink(sick_shares[0][2])
- #dead_shares = self.find_shares(self.uris["dead"])
+ #dead_shares = self.find_uri_shares(self.uris["dead"])
#for i in range(1, 10):
# os.unlink(dead_shares[i][2])
- #c_shares = self.find_shares(self.uris["corrupt"])
+ #c_shares = self.find_uri_shares(self.uris["corrupt"])
#cso = CorruptShareOptions()
#cso.stdout = StringIO()
#cso.parseOptions([c_shares[0][2]])
units = [simplejson.loads(line)
for line in res.splitlines()
if line]
- self.failUnlessEqual(len(units), 4+1)
+ self.failUnlessReallyEqual(len(units), 4+1)
# should be parent-first
u0 = units[0]
self.failUnlessEqual(u0["path"], [])
self.failUnlessEqual(u0["type"], "directory")
- self.failUnlessEqual(u0["cap"], self.rootnode.get_uri())
+ self.failUnlessReallyEqual(to_str(u0["cap"]), self.rootnode.get_uri())
u0crr = u0["check-and-repair-results"]
- self.failUnlessEqual(u0crr["repair-attempted"], False)
- self.failUnlessEqual(u0crr["pre-repair-results"]["results"]["count-shares-good"], 10)
+ self.failUnlessReallyEqual(u0crr["repair-attempted"], False)
+ self.failUnlessReallyEqual(u0crr["pre-repair-results"]["results"]["count-shares-good"], 10)
ugood = [u for u in units
if u["type"] == "file" and u["path"] == [u"good"]][0]
- self.failUnlessEqual(ugood["cap"], self.uris["good"])
+ self.failUnlessEqual(to_str(ugood["cap"]), self.uris["good"])
ugoodcrr = ugood["check-and-repair-results"]
- self.failUnlessEqual(ugoodcrr["repair-attempted"], False)
- self.failUnlessEqual(ugoodcrr["pre-repair-results"]["results"]["count-shares-good"], 10)
+ self.failUnlessReallyEqual(ugoodcrr["repair-attempted"], False)
+ self.failUnlessReallyEqual(ugoodcrr["pre-repair-results"]["results"]["count-shares-good"], 10)
usick = [u for u in units
if u["type"] == "file" and u["path"] == [u"sick"]][0]
- self.failUnlessEqual(usick["cap"], self.uris["sick"])
+ self.failUnlessReallyEqual(to_str(usick["cap"]), self.uris["sick"])
usickcrr = usick["check-and-repair-results"]
- self.failUnlessEqual(usickcrr["repair-attempted"], True)
- self.failUnlessEqual(usickcrr["repair-successful"], True)
- self.failUnlessEqual(usickcrr["pre-repair-results"]["results"]["count-shares-good"], 9)
- self.failUnlessEqual(usickcrr["post-repair-results"]["results"]["count-shares-good"], 10)
+ self.failUnlessReallyEqual(usickcrr["repair-attempted"], True)
+ self.failUnlessReallyEqual(usickcrr["repair-successful"], True)
+ self.failUnlessReallyEqual(usickcrr["pre-repair-results"]["results"]["count-shares-good"], 9)
+ self.failUnlessReallyEqual(usickcrr["post-repair-results"]["results"]["count-shares-good"], 10)
stats = units[-1]
self.failUnlessEqual(stats["type"], "stats")
s = stats["stats"]
- self.failUnlessEqual(s["count-immutable-files"], 2)
- self.failUnlessEqual(s["count-literal-files"], 1)
- self.failUnlessEqual(s["count-directories"], 1)
+ self.failUnlessReallyEqual(s["count-immutable-files"], 2)
+ self.failUnlessReallyEqual(s["count-literal-files"], 1)
+ self.failUnlessReallyEqual(s["count-directories"], 1)
d.addCallback(_done)
d.addErrback(self.explain_web_error)
def _count_leases(self, ignored, which):
u = self.uris[which]
- shares = self.find_shares(u)
+ shares = self.find_uri_shares(u)
lease_counts = []
for shnum, serverid, fn in shares:
sf = get_share_file(fn)
def _stash_mutable_uri(n, which):
self.uris[which] = n.get_uri()
assert isinstance(self.uris[which], str)
- d.addCallback(lambda ign: c0.create_mutable_file(DATA+"2"))
+ d.addCallback(lambda ign:
+ c0.create_mutable_file(publish.MutableData(DATA+"2")))
d.addCallback(_stash_mutable_uri, "mutable")
def _compute_fileurls(ignored):
convergence="")))
d.addCallback(_stash_uri, "small")
- d.addCallback(lambda ign: c0.create_mutable_file("mutable"))
+ d.addCallback(lambda ign:
+ c0.create_mutable_file(publish.MutableData("mutable")))
d.addCallback(lambda fn: self.rootnode.set_node(u"mutable", fn))
d.addCallback(_stash_uri, "mutable")
for line in res.splitlines()
if line]
# root, one, small, mutable, stats
- self.failUnlessEqual(len(units), 4+1)
+ self.failUnlessReallyEqual(len(units), 4+1)
d.addCallback(_done)
d.addCallback(self._count_leases, "root")
"no servers were connected, but it might also indicate "
"severe corruption. You should perform a filecheck on "
"this object to learn more. The full error message is: "
- "Failed to get enough shareholders: have 0, need 3")
- self.failUnlessEqual(exp, body)
+ "no shares (need 3). Last failure: None")
+ self.failUnlessReallyEqual(exp, body)
d.addCallback(_check_zero_shares)
def _check_one_share(body):
self.failIf("<html>" in body, body)
body = " ".join(body.strip().split())
- exp = ("NotEnoughSharesError: This indicates that some "
- "servers were unavailable, or that shares have been "
- "lost to server departure, hard drive failure, or disk "
- "corruption. You should perform a filecheck on "
- "this object to learn more. The full error message is:"
- " Failed to get enough shareholders: have 1, need 3")
- self.failUnlessEqual(exp, body)
+ msgbase = ("NotEnoughSharesError: This indicates that some "
+ "servers were unavailable, or that shares have been "
+ "lost to server departure, hard drive failure, or disk "
+ "corruption. You should perform a filecheck on "
+ "this object to learn more. The full error message is:"
+ )
+ msg1 = msgbase + (" ran out of shares:"
+ " complete=sh0"
+ " pending="
+ " overdue= unused= need 3. Last failure: None")
+ msg2 = msgbase + (" ran out of shares:"
+ " complete="
+ " pending=Share(sh0-on-xgru5)"
+ " overdue= unused= need 3. Last failure: None")
+ self.failUnless(body == msg1 or body == msg2, body)
d.addCallback(_check_one_share)
d.addCallback(lambda ignored:
"was corrupt, or that shares have been lost due to server "
"departure, hard drive failure, or disk corruption. You "
"should perform a filecheck on this object to learn more.")
- self.failUnlessEqual(exp, body)
+ self.failUnlessReallyEqual(exp, body)
d.addCallback(_check_unrecoverable_file)
d.addCallback(lambda ignored:
return d
+ def test_blacklist(self):
+ # download from a blacklisted URI, get an error
+ self.basedir = "web/Grid/blacklist"
+ self.set_up_grid()
+ c0 = self.g.clients[0]
+ c0_basedir = c0.basedir
+ fn = os.path.join(c0_basedir, "access.blacklist")
+ self.uris = {}
+ DATA = "off-limits " * 50
+
+ d = c0.upload(upload.Data(DATA, convergence=""))
+ def _stash_uri_and_create_dir(ur):
+ self.uri = ur.uri
+ self.url = "uri/"+self.uri
+ u = uri.from_string_filenode(self.uri)
+ self.si = u.get_storage_index()
+ childnode = c0.create_node_from_uri(self.uri, None)
+ return c0.create_dirnode({u"blacklisted.txt": (childnode,{}) })
+ d.addCallback(_stash_uri_and_create_dir)
+ def _stash_dir(node):
+ self.dir_node = node
+ self.dir_uri = node.get_uri()
+ self.dir_url = "uri/"+self.dir_uri
+ d.addCallback(_stash_dir)
+ d.addCallback(lambda ign: self.GET(self.dir_url, followRedirect=True))
+ def _check_dir_html(body):
+ self.failUnlessIn("<html>", body)
+ self.failUnlessIn("blacklisted.txt</a>", body)
+ d.addCallback(_check_dir_html)
+ d.addCallback(lambda ign: self.GET(self.url))
+ d.addCallback(lambda body: self.failUnlessEqual(DATA, body))
+
+ def _blacklist(ign):
+ f = open(fn, "w")
+ f.write(" # this is a comment\n")
+ f.write(" \n")
+ f.write("\n") # also exercise blank lines
+ f.write("%s %s\n" % (base32.b2a(self.si), "off-limits to you"))
+ f.close()
+ # clients should be checking the blacklist each time, so we don't
+ # need to restart the client
+ d.addCallback(_blacklist)
+ d.addCallback(lambda ign: self.shouldHTTPError("get_from_blacklisted_uri",
+ 403, "Forbidden",
+ "Access Prohibited: off-limits",
+ self.GET, self.url))
+
+ # We should still be able to list the parent directory, in HTML...
+ d.addCallback(lambda ign: self.GET(self.dir_url, followRedirect=True))
+ def _check_dir_html2(body):
+ self.failUnlessIn("<html>", body)
+ self.failUnlessIn("blacklisted.txt</strike>", body)
+ d.addCallback(_check_dir_html2)
+
+ # ... and in JSON (used by CLI).
+ d.addCallback(lambda ign: self.GET(self.dir_url+"?t=json", followRedirect=True))
+ def _check_dir_json(res):
+ data = simplejson.loads(res)
+ self.failUnless(isinstance(data, list), data)
+ self.failUnlessEqual(data[0], "dirnode")
+ self.failUnless(isinstance(data[1], dict), data)
+ self.failUnlessIn("children", data[1])
+ self.failUnlessIn("blacklisted.txt", data[1]["children"])
+ childdata = data[1]["children"]["blacklisted.txt"]
+ self.failUnless(isinstance(childdata, list), data)
+ self.failUnlessEqual(childdata[0], "filenode")
+ self.failUnless(isinstance(childdata[1], dict), data)
+ d.addCallback(_check_dir_json)
+
+ def _unblacklist(ign):
+ open(fn, "w").close()
+ # the Blacklist object watches mtime to tell when the file has
+ # changed, but on windows this test will run faster than the
+ # filesystem's mtime resolution. So we edit Blacklist.last_mtime
+ # to force a reload.
+ self.g.clients[0].blacklist.last_mtime -= 2.0
+ d.addCallback(_unblacklist)
+
+ # now a read should work
+ d.addCallback(lambda ign: self.GET(self.url))
+ d.addCallback(lambda body: self.failUnlessEqual(DATA, body))
+
+ # read again to exercise the blacklist-is-unchanged logic
+ d.addCallback(lambda ign: self.GET(self.url))
+ d.addCallback(lambda body: self.failUnlessEqual(DATA, body))
+
+ # now add a blacklisted directory, and make sure files under it are
+ # refused too
+ def _add_dir(ign):
+ childnode = c0.create_node_from_uri(self.uri, None)
+ return c0.create_dirnode({u"child": (childnode,{}) })
+ d.addCallback(_add_dir)
+ def _get_dircap(dn):
+ self.dir_si_b32 = base32.b2a(dn.get_storage_index())
+ self.dir_url_base = "uri/"+dn.get_write_uri()
+ self.dir_url_json1 = "uri/"+dn.get_write_uri()+"?t=json"
+ self.dir_url_json2 = "uri/"+dn.get_write_uri()+"/?t=json"
+ self.dir_url_json_ro = "uri/"+dn.get_readonly_uri()+"/?t=json"
+ self.child_url = "uri/"+dn.get_readonly_uri()+"/child"
+ d.addCallback(_get_dircap)
+ d.addCallback(lambda ign: self.GET(self.dir_url_base, followRedirect=True))
+ d.addCallback(lambda body: self.failUnlessIn("<html>", body))
+ d.addCallback(lambda ign: self.GET(self.dir_url_json1))
+ d.addCallback(lambda res: simplejson.loads(res)) # just check it decodes
+ d.addCallback(lambda ign: self.GET(self.dir_url_json2))
+ d.addCallback(lambda res: simplejson.loads(res)) # just check it decodes
+ d.addCallback(lambda ign: self.GET(self.dir_url_json_ro))
+ d.addCallback(lambda res: simplejson.loads(res)) # just check it decodes
+ d.addCallback(lambda ign: self.GET(self.child_url))
+ d.addCallback(lambda body: self.failUnlessEqual(DATA, body))
+
+ def _block_dir(ign):
+ f = open(fn, "w")
+ f.write("%s %s\n" % (self.dir_si_b32, "dir-off-limits to you"))
+ f.close()
+ self.g.clients[0].blacklist.last_mtime -= 2.0
+ d.addCallback(_block_dir)
+ d.addCallback(lambda ign: self.shouldHTTPError("get_from_blacklisted_dir base",
+ 403, "Forbidden",
+ "Access Prohibited: dir-off-limits",
+ self.GET, self.dir_url_base))
+ d.addCallback(lambda ign: self.shouldHTTPError("get_from_blacklisted_dir json1",
+ 403, "Forbidden",
+ "Access Prohibited: dir-off-limits",
+ self.GET, self.dir_url_json1))
+ d.addCallback(lambda ign: self.shouldHTTPError("get_from_blacklisted_dir json2",
+ 403, "Forbidden",
+ "Access Prohibited: dir-off-limits",
+ self.GET, self.dir_url_json2))
+ d.addCallback(lambda ign: self.shouldHTTPError("get_from_blacklisted_dir json_ro",
+ 403, "Forbidden",
+ "Access Prohibited: dir-off-limits",
+ self.GET, self.dir_url_json_ro))
+ d.addCallback(lambda ign: self.shouldHTTPError("get_from_blacklisted_dir child",
+ 403, "Forbidden",
+ "Access Prohibited: dir-off-limits",
+ self.GET, self.child_url))
+ return d
+
+
class CompletelyUnhandledError(Exception):
pass
class ErrorBoom(rend.Page):