X-Git-Url: https://git.rkrishnan.org/?a=blobdiff_plain;f=src%2Fallmydata%2Ftest%2Ftest_web.py;h=18514a3a57b012bbebf4cbe3d35b9a9e9d3571cf;hb=e1285d27b9b3203c1e968720177a46ae0a696983;hp=69d8211d7c53ce399a86aa808868b919fc31bb73;hpb=a9cada2e03bd542678109a05832f6b9a3fa4bca8;p=tahoe-lafs%2Ftahoe-lafs.git
diff --git a/src/allmydata/test/test_web.py b/src/allmydata/test/test_web.py
index 69d8211d..18514a3a 100644
--- a/src/allmydata/test/test_web.py
+++ b/src/allmydata/test/test_web.py
@@ -1,17 +1,22 @@
-
-import os.path, re, urllib, time
+import os.path, re, urllib, time, cgi
import simplejson
from StringIO import StringIO
+
from twisted.application import service
from twisted.trial import unittest
from twisted.internet import defer, reactor
from twisted.internet.task import Clock
from twisted.web import client, error, http
from twisted.python import failure, log
+
+from foolscap.api import fireEventually, flushEventualQueue
+
+from nevow.util import escapeToXML
from nevow import rend
+
from allmydata import interfaces, uri, webish, dirnode
from allmydata.storage.shares import get_share_file
-from allmydata.storage_client import StorageFarmBroker
+from allmydata.storage_client import StorageFarmBroker, StubServer
from allmydata.immutable import upload
from allmydata.immutable.downloader.status import DownloadStatus
from allmydata.dirnode import DirectoryNode
@@ -33,6 +38,7 @@ from allmydata.test.no_network import GridTestMixin
from allmydata.test.common_web import HTTPClientGETFactory, \
HTTPClientHEADFactory
from allmydata.client import Client, SecretHolder
+from allmydata.introducer import IntroducerNode
# create a fake uploader/downloader, and a couple of fake dirnodes, then
# create a webserver that works against them
@@ -43,6 +49,9 @@ 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')
+FAVICON_MARKUP = ' '
+DIR_HTML_TAG = ''
+
class FakeStatsProvider:
def get_stats(self):
stats = {'stats': {}, 'counters': {}}
@@ -56,47 +65,55 @@ class FakeNodeMaker(NodeMaker):
'max_segment_size':128*1024 # 1024=KiB
}
def _create_lit(self, cap):
- return FakeCHKFileNode(cap)
+ return FakeCHKFileNode(cap, self.all_contents)
def _create_immutable(self, cap):
- return FakeCHKFileNode(cap)
+ return FakeCHKFileNode(cap, self.all_contents)
def _create_mutable(self, cap):
- return FakeMutableFileNode(None,
- None,
- self.encoding_params, None).init_from_cap(cap)
+ return FakeMutableFileNode(None, None,
+ self.encoding_params, None,
+ self.all_contents).init_from_cap(cap)
def create_mutable_file(self, contents="", keysize=None,
version=SDMF_VERSION):
- n = FakeMutableFileNode(None, None, self.encoding_params, None)
+ n = FakeMutableFileNode(None, None, self.encoding_params, None,
+ self.all_contents)
return n.create(contents, version=version)
class FakeUploader(service.Service):
name = "uploader"
- def upload(self, uploadable, history=None):
+ helper_furl = None
+ helper_connected = False
+
+ def upload(self, uploadable):
d = uploadable.get_size()
d.addCallback(lambda size: uploadable.read(size))
def _got_data(datav):
data = "".join(datav)
- n = create_chk_filenode(data)
- results = upload.UploadResults()
- results.uri = n.get_uri()
- return results
+ n = create_chk_filenode(data, self.all_contents)
+ ur = upload.UploadResults(file_size=len(data),
+ ciphertext_fetched=0,
+ preexisting_shares=0,
+ pushed_shares=10,
+ sharemap={},
+ servermap={},
+ timings={},
+ uri_extension_data={},
+ uri_extension_hash="fake",
+ verifycapstr="fakevcap")
+ ur.set_uri(n.get_uri())
+ return ur
d.addCallback(_got_data)
return d
+
def get_helper_info(self):
- return (None, False)
+ return (self.helper_furl, self.helper_connected)
-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])
+ serverA = StubServer(hashutil.tagged_hash("foo", "serverid_a")[:20])
+ serverB = StubServer(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)
@@ -154,27 +171,108 @@ class FakeHistory:
def list_all_helper_statuses(self):
return []
+class FakeDisplayableServer(StubServer):
+ def __init__(self, serverid, nickname, connected,
+ last_connect_time, last_loss_time, last_rx_time):
+ StubServer.__init__(self, serverid)
+ self.announcement = {"my-version": "allmydata-tahoe-fake",
+ "service-name": "storage",
+ "nickname": nickname}
+ self.connected = connected
+ self.last_loss_time = last_loss_time
+ self.last_rx_time = last_rx_time
+ self.last_connect_time = last_connect_time
+ def is_connected(self):
+ return self.connected
+ def get_permutation_seed(self):
+ return ""
+ def get_remote_host(self):
+ return ""
+ def get_last_loss_time(self):
+ return self.last_loss_time
+ def get_last_received_data_time(self):
+ return self.last_rx_time
+ def get_last_connect_time(self):
+ return self.last_connect_time
+ def get_announcement(self):
+ return self.announcement
+ def get_nickname(self):
+ return self.announcement["nickname"]
+ def get_available_space(self):
+ return 123456
+
+class FakeBucketCounter(object):
+ def get_state(self):
+ return {"last-complete-bucket-count": 0}
+ def get_progress(self):
+ return {"estimated-time-per-cycle": 0,
+ "cycle-in-progress": False,
+ "remaining-wait-time": 0}
+
+class FakeLeaseChecker(object):
+ def __init__(self):
+ self.expiration_enabled = False
+ self.mode = "age"
+ self.override_lease_duration = None
+ self.sharetypes_to_expire = {}
+ def get_state(self):
+ return {"history": None}
+ def get_progress(self):
+ return {"estimated-time-per-cycle": 0,
+ "cycle-in-progress": False,
+ "remaining-wait-time": 0}
+
+class FakeStorageServer(service.MultiService):
+ name = 'storage'
+ def __init__(self, nodeid, nickname):
+ service.MultiService.__init__(self)
+ self.my_nodeid = nodeid
+ self.nickname = nickname
+ self.bucket_counter = FakeBucketCounter()
+ self.lease_checker = FakeLeaseChecker()
+ def get_stats(self):
+ return {"storage_server.accepting_immutable_shares": False}
+
class FakeClient(Client):
def __init__(self):
# don't upcall to Client.__init__, since we only want to initialize a
# minimal subset
service.MultiService.__init__(self)
+ self.all_contents = {}
self.nodeid = "fake_nodeid"
- self.nickname = "fake_nickname"
+ self.nickname = u"fake_nickname \u263A"
self.introducer_furl = "None"
self.stats_provider = FakeStatsProvider()
self._secret_holder = SecretHolder("lease secret", "convergence secret")
self.helper = None
self.convergence = "some random string"
self.storage_broker = StorageFarmBroker(None, permute_peers=True)
+ # fake knowledge of another server
+ self.storage_broker.test_add_server("other_nodeid",
+ FakeDisplayableServer(
+ serverid="other_nodeid", nickname=u"other_nickname \u263B", connected = True,
+ last_connect_time = 10, last_loss_time = 20, last_rx_time = 30))
+ self.storage_broker.test_add_server("disconnected_nodeid",
+ FakeDisplayableServer(
+ serverid="other_nodeid", nickname=u"disconnected_nickname \u263B", connected = False,
+ last_connect_time = 15, last_loss_time = 25, last_rx_time = 35))
self.introducer_client = None
self.history = FakeHistory()
self.uploader = FakeUploader()
+ self.uploader.all_contents = self.all_contents
self.uploader.setServiceParent(self)
+ self.blacklist = None
self.nodemaker = FakeNodeMaker(None, self._secret_holder, None,
self.uploader, None,
- None, None)
+ None, None, None)
+ self.nodemaker.all_contents = self.all_contents
self.mutable_file_default = SDMF_VERSION
+ self.addService(FakeStorageServer(self.nodeid, self.nickname))
+
+ def get_long_nodeid(self):
+ return "v0-nodeid"
+ def get_long_tubid(self):
+ return "tubid"
def startService(self):
return service.MultiService.startService(self)
@@ -183,14 +281,16 @@ class FakeClient(Client):
MUTABLE_SIZELIMIT = FakeMutableFileNode.MUTABLE_SIZELIMIT
-class WebMixin(object):
+class WebMixin(testutil.TimezoneMixin):
def setUp(self):
+ self.setTimezone('UTC-13:00')
self.s = FakeClient()
self.s.startService()
self.staticdir = self.mktemp()
self.clock = Clock()
+ self.fakeTime = 86460 # 1d 0h 1m 0s
self.ws = webish.WebishServer(self.s, "0", staticdir=self.staticdir,
- clock=self.clock)
+ clock=self.clock, now_fn=lambda:self.fakeTime)
self.ws.setServiceParent(self.s)
self.webish_port = self.ws.getPortnum()
self.webish_url = self.ws.getURL()
@@ -236,22 +336,33 @@ class WebMixin(object):
self._sub_uri = sub_uri
foo.set_uri(u"sub", sub_uri, sub_uri)
sub = self.s.create_node_from_uri(sub_uri)
+ self._sub_node = sub
_ign, n, blocking_uri = self.makefile(1)
foo.set_uri(u"blockingfile", blocking_uri, blocking_uri)
+ # filenode to test for html encoding issues
+ self._htmlname_unicode = u"<&weirdly'named\"file>>>_.txt"
+ self._htmlname_raw = self._htmlname_unicode.encode('utf-8')
+ self._htmlname_urlencoded = urllib.quote(self._htmlname_raw, '')
+ self._htmlname_escaped = escapeToXML(self._htmlname_raw)
+ self._htmlname_escaped_attr = cgi.escape(self._htmlname_raw, quote=True)
+ self._htmlname_escaped_double = escapeToXML(cgi.escape(self._htmlname_raw, quote=True))
+ self.HTMLNAME_CONTENTS, n, self._htmlname_txt_uri = self.makefile(0)
+ foo.set_uri(self._htmlname_unicode, self._htmlname_txt_uri, self._htmlname_txt_uri)
+
unicode_filename = u"n\u00fc.txt" # n u-umlaut . t x t
# ok, unicode calls it LATIN SMALL LETTER U WITH DIAERESIS but I
# still think of it as an umlaut
foo.set_uri(unicode_filename, self._bar_txt_uri, self._bar_txt_uri)
- _ign, n, baz_file = self.makefile(2)
+ self.SUBBAZ_CONTENTS, n, baz_file = self.makefile(2)
self._baz_file_uri = baz_file
sub.set_uri(u"baz.txt", baz_file, baz_file)
_ign, n, self._bad_file_uri = self.makefile(3)
# this uri should not be downloadable
- del FakeCHKFileNode.all_contents[self._bad_file_uri]
+ del self.s.all_contents[self._bad_file_uri]
rodir = res[5][1]
self.public_root.set_uri(u"reedownlee", rodir.get_readonly_uri(),
@@ -264,6 +375,7 @@ class WebMixin(object):
# public/foo/baz.txt
# public/foo/quux.txt
# public/foo/blockingfile
+ # public/foo/<&weirdly'named\"file>>>_.txt
# public/foo/empty/
# public/foo/sub/
# public/foo/sub/baz.txt
@@ -278,14 +390,17 @@ class WebMixin(object):
d.addCallback(_got_metadata)
return d
+ def get_all_contents(self):
+ return self.s.all_contents
+
def makefile(self, number):
contents = "contents of file %s\n" % number
- n = create_chk_filenode(contents)
+ n = create_chk_filenode(contents, self.get_all_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)
+ n = create_mutable_filenode(contents, mdmf, self.s.all_contents)
return contents, n, n.get_uri(), n.get_readonly_uri()
def tearDown(self):
@@ -300,13 +415,16 @@ class WebMixin(object):
def failUnlessIsBazDotTxt(self, res):
self.failUnlessReallyEqual(res, self.BAZ_CONTENTS, res)
+ def failUnlessIsSubBazDotTxt(self, res):
+ self.failUnlessReallyEqual(res, self.SUBBAZ_CONTENTS, res)
+
def failUnlessIsBarJSON(self, res):
data = simplejson.loads(res)
self.failUnless(isinstance(data, list))
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.failIfIn("rw_uri", data[1]) # immutable
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))
@@ -322,11 +440,11 @@ class WebMixin(object):
def failUnlessIsQuuxDotTxtMetadata(self, metadata, readonly):
self.failUnless(metadata['mutable'])
if readonly:
- self.failIf("rw_uri" in metadata)
+ self.failIfIn("rw_uri", metadata)
else:
- self.failUnless("rw_uri" in metadata)
+ self.failUnlessIn("rw_uri", metadata)
self.failUnlessEqual(metadata['rw_uri'], self._quux_txt_uri)
- self.failUnless("ro_uri" in metadata)
+ self.failUnlessIn("ro_uri", metadata)
self.failUnlessEqual(metadata['ro_uri'], self._quux_txt_readonly_uri)
self.failUnlessReallyEqual(metadata['size'], len(self.QUUX_CONTENTS))
@@ -336,15 +454,15 @@ class WebMixin(object):
self.failUnlessEqual(data[0], "dirnode", res)
self.failUnless(isinstance(data[1], dict))
self.failUnless(data[1]["mutable"])
- self.failUnless("rw_uri" in data[1]) # mutable
+ self.failUnlessIn("rw_uri", data[1]) # mutable
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"baz.txt", u"blockingfile",
- u"empty", u"n\u00fc.txt", u"quux.txt", u"sub"])
+ [self._htmlname_unicode, 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()] )
@@ -366,9 +484,9 @@ class WebMixin(object):
self.failUnlessReallyEqual(to_str(kids[u"n\u00fc.txt"][1]["ro_uri"]),
self._bar_txt_uri)
self.failUnlessIn("quux.txt", kids)
- self.failUnlessReallyEqual(kids[u"quux.txt"][1]["rw_uri"],
+ self.failUnlessReallyEqual(to_str(kids[u"quux.txt"][1]["rw_uri"]),
self._quux_txt_uri)
- self.failUnlessReallyEqual(kids[u"quux.txt"][1]["ro_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,
@@ -449,13 +567,9 @@ class WebMixin(object):
if isinstance(res, failure.Failure):
res.trap(expected_failure)
if substring:
- self.failUnless(substring in str(res),
- "substring '%s' not in '%s'"
- % (substring, str(res)))
+ self.failUnlessIn(substring, str(res), which)
if response_substring:
- self.failUnless(response_substring in res.value.response,
- "response substring '%s' not in '%s'"
- % (response_substring, res.value.response))
+ self.failUnlessIn(response_substring, res.value.response, which)
else:
self.fail("%s was supposed to raise %s, not get '%s'" %
(which, expected_failure, res))
@@ -470,14 +584,16 @@ class WebMixin(object):
if isinstance(res, failure.Failure):
res.trap(expected_failure)
if substring:
- self.failUnless(substring in str(res),
- "%s: substring '%s' not in '%s'"
- % (which, substring, str(res)))
+ self.failUnlessIn(substring, str(res),
+ "'%s' not in '%s' (response is '%s') for test '%s'" % \
+ (substring, str(res),
+ getattr(res.value, "response", ""),
+ which))
if response_substring:
- self.failUnless(response_substring in res.value.response,
- "%s: response substring '%s' not in '%s'"
- % (which,
- response_substring, res.value.response))
+ self.failUnlessIn(response_substring, res.value.response,
+ "'%s' not in '%s' for test '%s'" % \
+ (response_substring, res.value.response,
+ which))
else:
self.fail("%s was supposed to raise %s, not get '%s'" %
(which, expected_failure, res))
@@ -498,8 +614,7 @@ class WebMixin(object):
self.failUnlessReallyEqual(res.value.status, "302")
else:
self.fail("%s was supposed to Error(302), not get '%s'" %
- (which, res))
-
+ (which, res))
class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixin, unittest.TestCase):
def test_create(self):
@@ -508,7 +623,24 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
def test_welcome(self):
d = self.GET("/")
def _check(res):
- self.failUnless('Welcome To Tahoe-LAFS' in res, res)
+ self.failUnlessIn('
Tahoe-LAFS - Welcome ', res)
+ self.failUnlessIn(FAVICON_MARKUP, res)
+ self.failUnlessIn('Recent and Active Operations ', res)
+ self.failUnlessIn('Operational Statistics ', res)
+ self.failUnless(re.search(' ',res), res)
+ self.failUnlessIn('Page rendered at', res)
+ self.failUnlessIn('Tahoe-LAFS code imported from:', res)
+ res_u = res.decode('utf-8')
+ self.failUnlessIn(u'fake_nickname \u263A ', res_u)
+ self.failUnlessIn(u'other_nickname \u263B
', res_u)
+ self.failUnlessIn(u'Connected to 1 \n of 2 known storage servers', res_u)
+ self.failUnless(re.search(u'\n 1d\u00A00h\u00A00m\u00A050s ', res_u), repr(res_u))
+ self.failUnless(re.search(u'\n 1d\u00A00h\u00A00m\u00A035s ', res_u), repr(res_u))
+ self.failUnless(re.search(u'1d\u00A00h\u00A00m\u00A030s ', res_u), repr(res_u))
+ self.failUnless(re.search(u'1d\u00A00h\u00A00m\u00A025s ', res_u), repr(res_u))
+ self.failUnlessIn(u'\u00A9 Tahoe-LAFS Software Foundation', res_u)
+ self.failUnlessIn(' Available ', res)
+ self.failUnlessIn('123.5kB', res)
self.s.basedir = 'web/test_welcome'
fileutil.make_dirs("web/test_welcome")
@@ -517,85 +649,102 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
d.addCallback(_check)
return d
- def test_provisioning(self):
- d = self.GET("/provisioning/")
- def _check(res):
- self.failUnless('Provisioning Tool' in res)
- fields = {'filled': True,
- "num_users": int(50e3),
- "files_per_user": 1000,
- "space_per_user": int(1e9),
- "sharing_ratio": 1.0,
- "encoding_parameters": "3-of-10-5",
- "num_servers": 30,
- "ownership_mode": "A",
- "download_rate": 100,
- "upload_rate": 10,
- "delete_rate": 10,
- "lease_timer": 7,
- }
- return self.POST("/provisioning/", **fields)
+ def test_introducer_status(self):
+ class MockIntroducerClient(object):
+ def __init__(self, connected):
+ self.connected = connected
+ def connected_to_introducer(self):
+ return self.connected
- d.addCallback(_check)
- def _check2(res):
- self.failUnless('Provisioning Tool' in res)
- self.failUnless("Share space consumed: 167.01TB" in res)
-
- fields = {'filled': True,
- "num_users": int(50e6),
- "files_per_user": 1000,
- "space_per_user": int(5e9),
- "sharing_ratio": 1.0,
- "encoding_parameters": "25-of-100-50",
- "num_servers": 30000,
- "ownership_mode": "E",
- "drive_failure_model": "U",
- "drive_size": 1000,
- "download_rate": 1000,
- "upload_rate": 100,
- "delete_rate": 100,
- "lease_timer": 7,
- }
- return self.POST("/provisioning/", **fields)
- d.addCallback(_check2)
- def _check3(res):
- self.failUnless("Share space consumed: huge!" in res)
- fields = {'filled': True}
- return self.POST("/provisioning/", **fields)
- d.addCallback(_check3)
- def _check4(res):
- self.failUnless("Share space consumed:" in res)
- d.addCallback(_check4)
+ d = defer.succeed(None)
+
+ # introducer not connected, unguessable furl
+ def _set_introducer_not_connected_unguessable(ign):
+ self.s.introducer_furl = "pb://someIntroducer/secret"
+ self.s.introducer_client = MockIntroducerClient(False)
+ return self.GET("/")
+ d.addCallback(_set_introducer_not_connected_unguessable)
+ def _check_introducer_not_connected_unguessable(res):
+ html = res.replace('\n', ' ')
+ self.failUnlessIn('pb://someIntroducer/[censored]
', html)
+ self.failIfIn('pb://someIntroducer/secret', html)
+ self.failUnless(re.search(' ', html), res)
+ d.addCallback(_check_introducer_not_connected_unguessable)
+
+ # introducer connected, unguessable furl
+ def _set_introducer_connected_unguessable(ign):
+ self.s.introducer_furl = "pb://someIntroducer/secret"
+ self.s.introducer_client = MockIntroducerClient(True)
+ return self.GET("/")
+ d.addCallback(_set_introducer_connected_unguessable)
+ def _check_introducer_connected_unguessable(res):
+ html = res.replace('\n', ' ')
+ self.failUnlessIn('pb://someIntroducer/[censored]
', html)
+ self.failIfIn('pb://someIntroducer/secret', html)
+ self.failUnless(re.search(' ', html), res)
+ d.addCallback(_check_introducer_connected_unguessable)
+
+ # introducer connected, guessable furl
+ def _set_introducer_connected_guessable(ign):
+ self.s.introducer_furl = "pb://someIntroducer/introducer"
+ self.s.introducer_client = MockIntroducerClient(True)
+ return self.GET("/")
+ d.addCallback(_set_introducer_connected_guessable)
+ def _check_introducer_connected_guessable(res):
+ html = res.replace('\n', ' ')
+ self.failUnlessIn('pb://someIntroducer/introducer
', html)
+ self.failUnless(re.search(' ', html), res)
+ d.addCallback(_check_introducer_connected_guessable)
return d
- def test_reliability_tool(self):
- try:
- from allmydata import reliability
- _hush_pyflakes = reliability
- del _hush_pyflakes
- except:
- raise unittest.SkipTest("reliability tool requires NumPy")
+ def test_helper_status(self):
+ d = defer.succeed(None)
- d = self.GET("/reliability/")
- def _check(res):
- self.failUnless('Reliability Tool' in res)
- fields = {'drive_lifetime': "8Y",
- "k": "3",
- "R": "7",
- "N": "10",
- "delta": "100000",
- "check_period": "1M",
- "report_period": "3M",
- "report_span": "5Y",
- }
- return self.POST("/reliability/", **fields)
+ # set helper furl to None
+ def _set_no_helper(ign):
+ self.s.uploader.helper_furl = None
+ return self.GET("/")
+ d.addCallback(_set_no_helper)
+ def _check_no_helper(res):
+ html = res.replace('\n', ' ')
+ self.failUnless(re.search(' ', html), res)
+ d.addCallback(_check_no_helper)
+
+ # enable helper, not connected
+ def _set_helper_not_connected(ign):
+ self.s.uploader.helper_furl = "pb://someHelper/secret"
+ self.s.uploader.helper_connected = False
+ return self.GET("/")
+ d.addCallback(_set_helper_not_connected)
+ def _check_helper_not_connected(res):
+ html = res.replace('\n', ' ')
+ self.failUnlessIn('pb://someHelper/[censored]
', html)
+ self.failIfIn('pb://someHelper/secret', html)
+ self.failUnless(re.search(' ', html), res)
+ d.addCallback(_check_helper_not_connected)
+
+ # enable helper, connected
+ def _set_helper_connected(ign):
+ self.s.uploader.helper_furl = "pb://someHelper/secret"
+ self.s.uploader.helper_connected = True
+ return self.GET("/")
+ d.addCallback(_set_helper_connected)
+ def _check_helper_connected(res):
+ html = res.replace('\n', ' ')
+ self.failUnlessIn('pb://someHelper/[censored]
', html)
+ self.failIfIn('pb://someHelper/secret', html)
+ self.failUnless(re.search(' ', html), res)
+ d.addCallback(_check_helper_connected)
+ return d
+ def test_storage(self):
+ d = self.GET("/storage")
+ def _check(res):
+ self.failUnlessIn('Storage Server Status', res)
+ self.failUnlessIn(FAVICON_MARKUP, res)
+ res_u = res.decode('utf-8')
+ self.failUnlessIn(u'Server Nickname: fake_nickname \u263A ', res_u)
d.addCallback(_check)
- def _check2(res):
- self.failUnless('Reliability Tool' in res)
- r = r'Probability of loss \(no maintenance\):\s+0.033591'
- self.failUnless(re.search(r, res), res)
- d.addCallback(_check2)
return d
def test_status(self):
@@ -607,12 +756,12 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
ret_num = h.list_all_retrieve_statuses()[0].get_counter()
d = self.GET("/status", followRedirect=True)
def _check(res):
- self.failUnless('Upload and Download Status' in res, res)
- self.failUnless('"down-%d"' % dl_num in res, res)
- self.failUnless('"up-%d"' % ul_num in res, res)
- self.failUnless('"mapupdate-%d"' % mu_num in res, res)
- self.failUnless('"publish-%d"' % pub_num in res, res)
- self.failUnless('"retrieve-%d"' % ret_num in res, res)
+ self.failUnlessIn('Recent and Active Operations', res)
+ self.failUnlessIn('"down-%d"' % dl_num, res)
+ self.failUnlessIn('"up-%d"' % ul_num, res)
+ self.failUnlessIn('"mapupdate-%d"' % mu_num, res)
+ self.failUnlessIn('"publish-%d"' % pub_num, res)
+ self.failUnlessIn('"retrieve-%d"' % ret_num, res)
d.addCallback(_check)
d.addCallback(lambda res: self.GET("/status/?t=json"))
def _check_json(res):
@@ -625,13 +774,13 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
d.addCallback(lambda res: self.GET("/status/down-%d" % dl_num))
def _check_dl(res):
- self.failUnless("File Download Status" in res, res)
+ self.failUnlessIn("File Download Status", 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.failUnlessIn("read", data)
self.failUnlessEqual(data["read"][0]["length"], 120)
self.failUnlessEqual(data["segment"][0]["segment_length"], 100)
self.failUnlessEqual(data["segment"][2]["segment_number"], 2)
@@ -640,28 +789,33 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
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)
+ self.failUnlessEqual(data["serverids"]["0"], "phwrsjte")
+ self.failUnless(data["serverids"].has_key("1"),
+ str(data["serverids"]))
+ self.failUnlessEqual(data["serverids"]["1"], "cmpuvkjm",
+ str(data["serverids"]))
+ self.failUnlessEqual(data["server_info"][phwr_id]["short"],
+ "phwrsjte")
+ self.failUnlessEqual(data["server_info"][cmpu_id]["short"],
+ "cmpuvkjm")
+ self.failUnlessIn("dyhb", data)
+ self.failUnlessIn("misc", 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)
+ self.failUnlessIn("File Upload Status", res)
d.addCallback(_check_ul)
d.addCallback(lambda res: self.GET("/status/mapupdate-%d" % mu_num))
def _check_mapupdate(res):
- self.failUnless("Mutable File Servermap Update Status" in res, res)
+ self.failUnlessIn("Mutable File Servermap Update Status", res)
d.addCallback(_check_mapupdate)
d.addCallback(lambda res: self.GET("/status/publish-%d" % pub_num))
def _check_publish(res):
- self.failUnless("Mutable File Publish Status" in res, res)
+ self.failUnlessIn("Mutable File Publish Status", res)
d.addCallback(_check_publish)
d.addCallback(lambda res: self.GET("/status/retrieve-%d" % ret_num))
def _check_retrieve(res):
- self.failUnless("Mutable File Retrieve Status" in res, res)
+ self.failUnlessIn("Mutable File Retrieve Status", res)
d.addCallback(_check_retrieve)
return d
@@ -892,22 +1046,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
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)
+ base = "/uri/%s" % urllib.quote("%s:RANDOMSTUFF" % self._quux_txt_uri)
d = self.GET(base)
d.addCallback(self.failUnlessIsQuuxDotTxt)
return d
@@ -949,7 +1088,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
return d
def test_PUT_FILE_URI_mdmf_extensions(self):
- base = "/uri/%s" % urllib.quote("%s:3:131073" % self._quux_txt_uri)
+ base = "/uri/%s" % urllib.quote("%s:EXTENSIONSTUFF" % self._quux_txt_uri)
self._quux_new_contents = "new_contents"
d = self.GET(base)
d.addCallback(lambda res: self.failUnlessIsQuuxDotTxt(res))
@@ -959,22 +1098,6 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
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
@@ -1000,6 +1123,90 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
self.PUT, base, "new_data"))
return d
+ def test_GET_etags(self):
+
+ def _check_etags(uri):
+ d1 = _get_etag(uri)
+ d2 = _get_etag(uri, 'json')
+ d = defer.DeferredList([d1, d2], consumeErrors=True)
+ def _check(results):
+ # All deferred must succeed
+ self.failUnless(all([r[0] for r in results]))
+ # the etag for the t=json form should be just like the etag
+ # fo the default t='' form, but with a 'json' suffix
+ self.failUnlessEqual(results[0][1] + 'json', results[1][1])
+ d.addCallback(_check)
+ return d
+
+ def _get_etag(uri, t=''):
+ targetbase = "/uri/%s?t=%s" % (urllib.quote(uri.strip()), t)
+ d = self.GET(targetbase, return_response=True, followRedirect=True)
+ def _just_the_etag(result):
+ data, response, headers = result
+ etag = headers['etag'][0]
+ if uri.startswith('URI:DIR'):
+ self.failUnless(etag.startswith('DIR:'), etag)
+ return etag
+ return d.addCallback(_just_the_etag)
+
+ # Check that etags work with immutable directories
+ (newkids, caps) = self._create_immutable_children()
+ d = self.POST2(self.public_url + "/foo/newdir?t=mkdir-immutable",
+ simplejson.dumps(newkids))
+ def _stash_immdir_uri(uri):
+ self._immdir_uri = uri
+ return uri
+ d.addCallback(_stash_immdir_uri)
+ d.addCallback(_check_etags)
+
+ # Check that etags work with immutable files
+ d.addCallback(lambda _: _check_etags(self._bar_txt_uri))
+
+ # use the ETag on GET
+ def _check_match(ign):
+ uri = "/uri/%s" % self._bar_txt_uri
+ d = self.GET(uri, return_response=True)
+ # extract the ETag
+ d.addCallback(lambda (data, code, headers):
+ headers['etag'][0])
+ # do a GET that's supposed to match the ETag
+ d.addCallback(lambda etag:
+ self.GET(uri, return_response=True,
+ headers={"If-None-Match": etag}))
+ # make sure it short-circuited (304 instead of 200)
+ d.addCallback(lambda (data, code, headers):
+ self.failUnlessEqual(int(code), http.NOT_MODIFIED))
+ return d
+ d.addCallback(_check_match)
+
+ def _no_etag(uri, t):
+ target = "/uri/%s?t=%s" % (uri, t)
+ d = self.GET(target, return_response=True, followRedirect=True)
+ d.addCallback(lambda (data, code, headers):
+ self.failIf("etag" in headers, target))
+ return d
+ def _yes_etag(uri, t):
+ target = "/uri/%s?t=%s" % (uri, t)
+ d = self.GET(target, return_response=True, followRedirect=True)
+ d.addCallback(lambda (data, code, headers):
+ self.failUnless("etag" in headers, target))
+ return d
+
+ d.addCallback(lambda ign: _yes_etag(self._bar_txt_uri, ""))
+ d.addCallback(lambda ign: _yes_etag(self._bar_txt_uri, "json"))
+ d.addCallback(lambda ign: _yes_etag(self._bar_txt_uri, "uri"))
+ d.addCallback(lambda ign: _yes_etag(self._bar_txt_uri, "readonly-uri"))
+ d.addCallback(lambda ign: _no_etag(self._bar_txt_uri, "info"))
+
+ d.addCallback(lambda ign: _yes_etag(self._immdir_uri, ""))
+ d.addCallback(lambda ign: _yes_etag(self._immdir_uri, "json"))
+ d.addCallback(lambda ign: _yes_etag(self._immdir_uri, "uri"))
+ d.addCallback(lambda ign: _yes_etag(self._immdir_uri, "readonly-uri"))
+ d.addCallback(lambda ign: _no_etag(self._immdir_uri, "info"))
+ d.addCallback(lambda ign: _no_etag(self._immdir_uri, "rename-form"))
+
+ 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",
@@ -1043,7 +1250,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
return d
def test_GET_FILEURL_info_mdmf_extensions(self):
- d = self.GET("/uri/%s:3:131073?t=info" % self._quux_txt_uri)
+ d = self.GET("/uri/%s:STUFF?t=info" % self._quux_txt_uri)
def _got(res):
self.failUnlessIn("mutable file (mdmf)", res)
self.failUnlessIn(self._quux_txt_uri, res)
@@ -1051,19 +1258,6 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
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)
@@ -1109,29 +1303,29 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
# 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",
+ d = self.PUT("/uri?format=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))
+ 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",
+ d = self.PUT("/uri?format=sdmf",
contents)
d.addCallback(lambda filecap: self.GET("/uri/%s?t=json" % filecap))
- d.addCallback(lambda json: self.failUnlessIn("sdmf", json))
+ d.addCallback(lambda json: self.failUnlessIn("SDMF", json))
return d
- def test_PUT_NEWFILEURL_unlinked_bad_mutable_type(self):
+ def test_PUT_NEWFILEURL_unlinked_bad_format(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",
+ return self.shouldHTTPError("PUT_NEWFILEURL_unlinked_bad_format",
+ 400, "Bad Request", "Unknown format: foo",
+ self.PUT, "/uri?format=foo",
contents)
def test_PUT_NEWFILEURL_range_bad(self):
@@ -1265,9 +1459,9 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
return d
def test_GET_FILEURL_json_mutable_type(self):
- # The JSON should include mutable-type, which says whether the
+ # The JSON should include format, which says whether the
# file is SDMF or MDMF
- d = self.PUT("/uri?mutable=true&mutable-type=mdmf",
+ d = self.PUT("/uri?format=mdmf",
self.NEWFILE_CONTENTS * 300000)
d.addCallback(lambda filecap: self.GET("/uri/%s?t=json" % filecap))
def _got_json(json, version):
@@ -1276,61 +1470,16 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
data = data[1]
assert isinstance(data, dict)
- self.failUnlessIn("mutable-type", data)
- self.failUnlessEqual(data['mutable-type'], version)
+ self.failUnlessIn("format", data)
+ self.failUnlessEqual(data["format"], version)
- d.addCallback(_got_json, "mdmf")
+ 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.PUT("/uri?format=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)
+ d.addCallback(_got_json, "SDMF")
return d
def test_GET_FILEURL_json_mdmf(self):
@@ -1364,79 +1513,65 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
return d
def test_CSS_FILE(self):
- d = self.GET("/tahoe_css", followRedirect=True)
+ 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 _check_upload_and_mkdir_forms(self, html):
+ # We should have a form to create a file, with radio buttons that allow
+ # the user to toggle whether it is a CHK/LIT (default), SDMF, or MDMF file.
+ self.failUnless(re.search(' ', html), html)
+ self.failUnless(re.search(' ', html), html)
+ self.failUnless(re.search('Return to Welcome page ',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)
+ def _check(html):
+ self.failUnlessIn('Return to Welcome page ', html)
+ self._check_upload_and_mkdir_forms(html)
+ self.failUnlessIn("quux", html)
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)
+ def test_GET_DIRECTORY_html_filenode_encoding(self):
+ d = self.GET(self.public_url + "/foo", followRedirect=True)
+ def _check(html):
+ # Check if encoded entries are there
+ self.failUnlessIn('@@named=/' + self._htmlname_urlencoded + '">'
+ + self._htmlname_escaped + '', html)
+ self.failUnlessIn('value="' + self._htmlname_escaped_attr + '"', html)
+ self.failIfIn(self._htmlname_escaped_double, html)
+ # Make sure that Nevow escaping actually works by checking for unsafe characters
+ # and that '&' is escaped.
+ for entity in '<>':
+ self.failUnlessIn(entity, self._htmlname_raw)
+ self.failIfIn(entity, self._htmlname_escaped)
+ self.failUnlessIn('&', re.sub(r'&(amp|lt|gt|quot|apos);', '', self._htmlname_raw))
+ self.failIfIn('&', re.sub(r'&(amp|lt|gt|quot|apos);', '', self._htmlname_escaped))
+ d.addCallback(_check)
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
-
+ def test_GET_root_html(self):
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")
+ d.addCallback(self._check_upload_and_mkdir_forms)
return d
def test_GET_DIRURL(self):
@@ -1445,8 +1580,8 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
ROOT = "../../.."
d = self.GET(self.public_url + "/foo", followRedirect=True)
def _check(res):
- self.failUnless(('Return to Welcome page' % ROOT)
- in res, res)
+ self.failUnlessIn(' Return to Welcome page' % ROOT, res)
+
# the FILE reference points to a URI, but it should end in bar.txt
bar_url = ("%s/file/%s/@@named=/bar.txt" %
(ROOT, urllib.quote(self._bar_txt_uri)))
@@ -1457,7 +1592,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
r'\s+ %d ' % len(self.BAR_CONTENTS),
])
self.failUnless(re.search(get_bar, res), res)
- for label in ['unlink', 'rename']:
+ for label in ['unlink', 'rename/relink']:
for line in res.split("\n"):
# find the line that contains the relevant button for bar.txt
if ("form action" in line and
@@ -1475,7 +1610,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
self.failUnlessIn('method="post"', line)
break
else:
- self.fail("unable to find '%s bar.txt' line" % (label,), res)
+ self.fail("unable to find '%s bar.txt' line" % (label,))
# the DIR reference just points to a URI
sub_url = ("%s/uri/%s/" % (ROOT, urllib.quote(self._sub_uri)))
@@ -1488,8 +1623,8 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
d.addCallback(lambda res:
self.GET(self.public_url + "/reedownlee", followRedirect=True))
def _check2(res):
- self.failUnless("(read-only)" in res, res)
- self.failIf("Upload a file" in res, res)
+ self.failUnlessIn("(read-only)", res)
+ self.failIfIn("Upload a file", res)
d.addCallback(_check2)
# and at a directory that contains a readonly directory
@@ -1503,8 +1638,8 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
# and an empty directory
d.addCallback(lambda res: self.GET(self.public_url + "/foo/empty/"))
def _check4(res):
- self.failUnless("directory is empty" in res, res)
- MKDIR_BUTTON_RE=re.compile(' .*Create a new directory in this directory .* ', re.I)
+ self.failUnlessIn("directory is empty", res)
+ MKDIR_BUTTON_RE=re.compile(' .*Create a new directory in this directory .* ', re.I)
self.failUnless(MKDIR_BUTTON_RE.search(res), res)
d.addCallback(_check4)
@@ -1513,7 +1648,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
d.addCallback(lambda res:
self.GET("/uri/" + tiny_litdir_uri + "/", followRedirect=True))
def _check5(res):
- self.failUnless('(immutable)' in res, res)
+ self.failUnlessIn('(immutable)', res)
self.failUnless(re.search('FILE '
r'\s+short ', res), res)
d.addCallback(_check5)
@@ -1532,13 +1667,13 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
d.addCallback(self.failUnlessIsFooJSON)
return d
- def test_GET_DIRURL_json_mutable_type(self):
+ def test_GET_DIRURL_json_format(self):
d = self.PUT(self.public_url + \
- "/foo/sdmf.txt?mutable=true&mutable-type=sdmf",
+ "/foo/sdmf.txt?format=sdmf",
self.NEWFILE_CONTENTS * 300000)
d.addCallback(lambda ignored:
self.PUT(self.public_url + \
- "/foo/mdmf.txt?mutable=true&mutable-type=mdmf",
+ "/foo/mdmf.txt?format=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.
@@ -1552,12 +1687,12 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
kids = data['children']
mdmf_data = kids['mdmf.txt'][1]
- self.failUnlessIn("mutable-type", mdmf_data)
- self.failUnlessEqual(mdmf_data['mutable-type'], "mdmf")
+ self.failUnlessIn("format", mdmf_data)
+ self.failUnlessEqual(mdmf_data["format"], "MDMF")
sdmf_data = kids['sdmf.txt'][1]
- self.failUnlessIn("mutable-type", sdmf_data)
- self.failUnlessEqual(sdmf_data['mutable-type'], "sdmf")
+ self.failUnlessIn("format", sdmf_data)
+ self.failUnlessEqual(sdmf_data["format"], "SDMF")
d.addCallback(_got_json)
return d
@@ -1580,10 +1715,11 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
return d
d.addCallback(getman, None)
def _got_html(manifest):
- self.failUnless("Manifest of SI=" in manifest)
- self.failUnless("sub " in manifest)
- self.failUnless(self._sub_uri in manifest)
- self.failUnless("sub/baz.txt " in manifest)
+ self.failUnlessIn("Manifest of SI=", manifest)
+ self.failUnlessIn("sub ", manifest)
+ self.failUnlessIn(self._sub_uri, manifest)
+ self.failUnlessIn("sub/baz.txt ", manifest)
+ self.failUnlessIn(FAVICON_MARKUP, manifest)
d.addCallback(_got_html)
# both t=status and unadorned GET should be identical
@@ -1594,8 +1730,8 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
d.addCallback(_got_html)
d.addCallback(getman, "text")
def _got_text(manifest):
- self.failUnless("\nsub " + self._sub_uri + "\n" in manifest)
- self.failUnless("\nsub/baz.txt URI:CHK:" in manifest)
+ self.failUnlessIn("\nsub " + self._sub_uri + "\n", manifest)
+ self.failUnlessIn("\nsub/baz.txt URI:CHK:", manifest)
d.addCallback(_got_text)
d.addCallback(getman, "JSON")
def _got_json(res):
@@ -1604,12 +1740,12 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
for (path_list, cap) in data:
got[tuple(path_list)] = cap
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)
- self.failUnless("storage-index" in res)
- self.failUnless("verifycaps" in res)
- self.failUnless("stats" in res)
+ self.failUnlessIn((u"sub", u"baz.txt"), got)
+ self.failUnlessIn("finished", res)
+ self.failUnlessIn("origin", res)
+ self.failUnlessIn("storage-index", res)
+ self.failUnlessIn("verifycaps", res)
+ self.failUnlessIn("stats", res)
d.addCallback(_got_json)
return d
@@ -1655,16 +1791,16 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
d.addCallback(self.wait_for_operation, "127")
d.addCallback(self.get_operation_results, "127", "json")
def _got_json(stats):
- expected = {"count-immutable-files": 3,
+ expected = {"count-immutable-files": 4,
"count-mutable-files": 2,
"count-literal-files": 0,
- "count-files": 5,
+ "count-files": 6,
"count-directories": 3,
- "size-immutable-files": 57,
+ "size-immutable-files": 76,
"size-literal-files": 0,
#"size-directories": 1912, # varies
#"largest-directory": 1590,
- "largest-directory-children": 7,
+ "largest-directory-children": 8,
"largest-immutable-file": 19,
}
for k,v in expected.iteritems():
@@ -1672,7 +1808,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
"stats[%s] was %s, not %s" %
(k, stats[k], v))
self.failUnlessReallyEqual(stats["size-files-histogram"],
- [ [11, 31, 3] ])
+ [ [11, 31, 4] ])
d.addCallback(_got_json)
return d
@@ -1681,7 +1817,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
def _check(res):
self.failUnless(res.endswith("\n"))
units = [simplejson.loads(t) for t in res[:-1].split("\n")]
- self.failUnlessReallyEqual(len(units), 9)
+ self.failUnlessReallyEqual(len(units), 10)
self.failUnlessEqual(units[-1]["type"], "stats")
first = units[0]
self.failUnlessEqual(first["path"], [])
@@ -1720,7 +1856,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
return d
def test_PUT_NEWDIRURL_mdmf(self):
- d = self.PUT(self.public_url + "/foo/newdir?t=mkdir&mutable-type=mdmf", "")
+ d = self.PUT(self.public_url + "/foo/newdir?t=mkdir&format=mdmf", "")
d.addCallback(lambda res:
self.failUnlessNodeHasChild(self._foo_node, u"newdir"))
d.addCallback(lambda res: self._foo_node.get(u"newdir"))
@@ -1729,7 +1865,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
return d
def test_PUT_NEWDIRURL_sdmf(self):
- d = self.PUT(self.public_url + "/foo/newdir?t=mkdir&mutable-type=sdmf",
+ d = self.PUT(self.public_url + "/foo/newdir?t=mkdir&format=sdmf",
"")
d.addCallback(lambda res:
self.failUnlessNodeHasChild(self._foo_node, u"newdir"))
@@ -1738,11 +1874,11 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
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_PUT_NEWDIRURL_bad_format(self):
+ return self.shouldHTTPError("PUT_NEWDIRURL_bad_format",
+ 400, "Bad Request", "Unknown format: foo",
+ self.PUT, self.public_url +
+ "/foo/newdir=?t=mkdir&format=foo", "")
def test_POST_NEWDIRURL(self):
d = self.POST2(self.public_url + "/foo/newdir?t=mkdir", "")
@@ -1753,7 +1889,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
return d
def test_POST_NEWDIRURL_mdmf(self):
- d = self.POST2(self.public_url + "/foo/newdir?t=mkdir&mutable-type=mdmf", "")
+ d = self.POST2(self.public_url + "/foo/newdir?t=mkdir&format=mdmf", "")
d.addCallback(lambda res:
self.failUnlessNodeHasChild(self._foo_node, u"newdir"))
d.addCallback(lambda res: self._foo_node.get(u"newdir"))
@@ -1762,7 +1898,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
return d
def test_POST_NEWDIRURL_sdmf(self):
- d = self.POST2(self.public_url + "/foo/newdir?t=mkdir&mutable-type=sdmf", "")
+ d = self.POST2(self.public_url + "/foo/newdir?t=mkdir&format=sdmf", "")
d.addCallback(lambda res:
self.failUnlessNodeHasChild(self._foo_node, u"newdir"))
d.addCallback(lambda res: self._foo_node.get(u"newdir"))
@@ -1770,15 +1906,15 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
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",
+ def test_POST_NEWDIRURL_bad_format(self):
+ return self.shouldHTTPError("POST_NEWDIRURL_bad_format",
+ 400, "Bad Request", "Unknown format: foo",
self.POST2, self.public_url + \
- "/foo/newdir?t=mkdir&mutable-type=foo", "")
+ "/foo/newdir?t=mkdir&format=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",
+ d = self.shouldFail2(error.Error, "POST_NEWDIRURL_emptyname",
"400 Bad Request",
"The webapi does not allow empty pathname components, i.e. a double slash",
self.POST, self.public_url + "//?t=mkdir")
@@ -1788,9 +1924,9 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
(newkids, caps) = self._create_initial_children()
query = "/foo/newdir?t=mkdir-with-children"
if version == MDMF_VERSION:
- query += "&mutable-type=mdmf"
+ query += "&format=mdmf"
elif version == SDMF_VERSION:
- query += "&mutable-type=sdmf"
+ query += "&format=sdmf"
else:
version = SDMF_VERSION # for later
d = self.POST2(self.public_url + query,
@@ -1845,12 +1981,12 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
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):
+ def test_POST_NEWDIRURL_initial_children_bad_format(self):
(newkids, caps) = self._create_initial_children()
- return self.shouldHTTPError("test bad mutable type",
- 400, "Bad Request", "Unknown type: foo",
+ return self.shouldHTTPError("POST_NEWDIRURL_initial_children_bad_format",
+ 400, "Bad Request", "Unknown format: foo",
self.POST2, self.public_url + \
- "/foo/newdir?t=mkdir-with-children&mutable-type=foo",
+ "/foo/newdir?t=mkdir-with-children&format=foo",
simplejson.dumps(newkids))
def test_POST_NEWDIRURL_immutable(self):
@@ -1923,25 +2059,6 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
d.addCallback(self.failUnlessNodeKeysAre, [u"baz.txt"])
return d
- def test_PUT_NEWDIRURL_mkdir_p(self):
- d = defer.succeed(None)
- d.addCallback(lambda res: self.POST(self.public_url + "/foo", t='mkdir', name='mkp'))
- d.addCallback(lambda res: self.failUnlessNodeHasChild(self._foo_node, u"mkp"))
- d.addCallback(lambda res: self._foo_node.get(u"mkp"))
- def mkdir_p(mkpnode):
- url = '/uri/%s?t=mkdir-p&path=/sub1/sub2' % urllib.quote(mkpnode.get_uri())
- 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.failUnlessReallyEqual(ssnode.get_uri(), ssuri))
- d = self.POST(url)
- d.addCallback(lambda uri2: self.failUnlessReallyEqual(uri2, ssuri))
- return d
- d.addCallback(made_subsub)
- return d
- d.addCallback(mkdir_p)
- return d
-
def test_PUT_NEWDIRURL_mkdirs(self):
d = self.PUT(self.public_url + "/foo/subdir/newdir?t=mkdir", "")
d.addCallback(lambda res:
@@ -1954,7 +2071,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
return d
def test_PUT_NEWDIRURL_mkdirs_mdmf(self):
- d = self.PUT(self.public_url + "/foo/subdir/newdir?t=mkdir&mutable-type=mdmf", "")
+ d = self.PUT(self.public_url + "/foo/subdir/newdir?t=mkdir&format=mdmf", "")
d.addCallback(lambda ignored:
self.failUnlessNodeHasChild(self._foo_node, u"subdir"))
d.addCallback(lambda ignored:
@@ -1972,7 +2089,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
return d
def test_PUT_NEWDIRURL_mkdirs_sdmf(self):
- d = self.PUT(self.public_url + "/foo/subdir/newdir?t=mkdir&mutable-type=sdmf", "")
+ d = self.PUT(self.public_url + "/foo/subdir/newdir?t=mkdir&format=sdmf", "")
d.addCallback(lambda ignored:
self.failUnlessNodeHasChild(self._foo_node, u"subdir"))
d.addCallback(lambda ignored:
@@ -1989,11 +2106,11 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
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",
+ def test_PUT_NEWDIRURL_mkdirs_bad_format(self):
+ return self.shouldHTTPError("PUT_NEWDIRURL_mkdirs_bad_format",
+ 400, "Bad Request", "Unknown format: foo",
self.PUT, self.public_url + \
- "/foo/subdir/newdir?t=mkdir&mutable-type=foo",
+ "/foo/subdir/newdir?t=mkdir&format=foo",
"")
def test_DELETE_DIRURL(self):
@@ -2034,14 +2151,14 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
assert isinstance(name, unicode)
d = node.list()
def _check(children):
- self.failUnless(name in children)
+ self.failUnlessIn(name, children)
d.addCallback(_check)
return d
def failIfNodeHasChild(self, node, name):
assert isinstance(name, unicode)
d = node.list()
def _check(children):
- self.failIf(name in children)
+ self.failIfIn(name, children)
d.addCallback(_check)
return d
@@ -2112,7 +2229,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
return d
def failUnlessCHKURIHasContents(self, got_uri, contents):
- self.failUnless(FakeCHKFileNode.all_contents[got_uri] == contents)
+ self.failUnless(self.get_all_contents()[got_uri] == contents)
def test_POST_upload(self):
d = self.POST(self.public_url + "/foo", t="upload",
@@ -2163,8 +2280,8 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
def _check_upload_results(page):
# this should be a page which describes the results of the upload
# that just finished.
- self.failUnless("Upload Results:" in page)
- self.failUnless("URI:" in page)
+ self.failUnlessIn("Upload Results:", page)
+ self.failUnlessIn("URI:", page)
uri_re = re.compile("URI: (.*) ")
mo = uri_re.search(page)
self.failUnless(mo, page)
@@ -2198,10 +2315,11 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
self.failUnlessReallyEqual(statuscode, str(http.FOUND))
self.failUnless(target.startswith(self.webish_url), target)
return client.getPage(target, method="GET")
+ # We encode "uri" as "%75ri" to exercise a case affected by ticket #1860.
d = self.shouldRedirect2("test_POST_upload_no_link_whendone_results",
check,
self.POST, "/uri", t="upload",
- when_done="/uri/%(uri)s",
+ when_done="/%75ri/%(uri)s",
file=("new.txt", self.NEWFILE_CONTENTS))
d.addCallback(lambda res:
self.failUnlessReallyEqual(res, self.NEWFILE_CONTENTS))
@@ -2215,7 +2333,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
self.failUnless(filecap.startswith("URI:SSK:"), filecap)
self.filecap = filecap
u = uri.WriteableSSKFileURI.init_from_string(filecap)
- self.failUnless(u.get_storage_index() in FakeMutableFileNode.all_contents)
+ self.failUnlessIn(u.get_storage_index(), self.get_all_contents())
n = self.s.create_node_from_uri(filecap)
return n.download_best_version()
d.addCallback(_check)
@@ -2241,69 +2359,79 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
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")
+ def test_POST_upload_format_unlinked(self):
+ def _check_upload_unlinked(ign, format, uri_prefix):
+ filename = format + ".txt"
+ d = self.POST("/uri?t=upload&format=" + format,
+ file=(filename, self.NEWFILE_CONTENTS * 300000))
+ def _got_results(results):
+ if format.upper() in ("SDMF", "MDMF"):
+ # webapi.rst says this returns a filecap
+ filecap = results
+ else:
+ # for immutable, it returns an "upload results page", and
+ # the filecap is buried inside
+ line = [l for l in results.split("\n") if "URI: " in l][0]
+ mo = re.search(r'([^<]+) ', line)
+ filecap = mo.group(1)
+ self.failUnless(filecap.startswith(uri_prefix),
+ (uri_prefix, filecap))
+ return self.GET("/uri/%s?t=json" % filecap)
+ d.addCallback(_got_results)
+ def _got_json(json):
+ data = simplejson.loads(json)
+ data = data[1]
+ self.failUnlessIn("format", data)
+ self.failUnlessEqual(data["format"], format.upper())
+ d.addCallback(_got_json)
+ return d
+ d = defer.succeed(None)
+ d.addCallback(_check_upload_unlinked, "chk", "URI:CHK")
+ d.addCallback(_check_upload_unlinked, "CHK", "URI:CHK")
+ d.addCallback(_check_upload_unlinked, "sdmf", "URI:SSK")
+ d.addCallback(_check_upload_unlinked, "mdmf", "URI: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",
+ def test_POST_upload_bad_format_unlinked(self):
+ return self.shouldHTTPError("POST_upload_bad_format_unlinked",
+ 400, "Bad Request", "Unknown format: foo",
self.POST,
- "/uri?5=upload&mutable=true&mutable-type=foo",
+ "/uri?t=upload&format=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]
+ def test_POST_upload_format(self):
+ def _check_upload(ign, format, uri_prefix, fn=None):
+ filename = format + ".txt"
+ d = self.POST(self.public_url +
+ "/foo?t=upload&format=" + format,
+ file=(filename, self.NEWFILE_CONTENTS * 300000))
+ def _got_filecap(filecap):
+ if fn is not None:
+ filenameu = unicode(filename)
+ self.failUnlessURIMatchesRWChild(filecap, fn, filenameu)
+ self.failUnless(filecap.startswith(uri_prefix))
+ return self.GET(self.public_url + "/foo/%s?t=json" % filename)
+ d.addCallback(_got_filecap)
+ def _got_json(json):
+ data = simplejson.loads(json)
+ data = data[1]
+ self.failUnlessIn("format", data)
+ self.failUnlessEqual(data["format"], format.upper())
+ d.addCallback(_got_json)
+ return d
- 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")
+ d = defer.succeed(None)
+ d.addCallback(_check_upload, "chk", "URI:CHK")
+ d.addCallback(_check_upload, "sdmf", "URI:SSK", self._foo_node)
+ d.addCallback(_check_upload, "mdmf", "URI:MDMF")
+ d.addCallback(_check_upload, "MDMF", "URI:MDMF")
return d
- def test_POST_upload_bad_mutable_type(self):
- return self.shouldHTTPError("test bad mutable type",
- 400, "Bad Request", "Unknown type: foo",
+ def test_POST_upload_bad_format(self):
+ return self.shouldHTTPError("POST_upload_bad_format",
+ 400, "Bad Request", "Unknown format: foo",
self.POST, self.public_url + \
- "/foo?t=upload&mutable=true&mutable-type=foo",
+ "/foo?t=upload&format=foo",
file=("foo.txt", self.NEWFILE_CONTENTS * 300000))
def test_POST_upload_mutable(self):
@@ -2359,7 +2487,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
followRedirect=True))
def _check_page(res):
# TODO: assert more about the contents
- self.failUnless("SSK" in res)
+ self.failUnlessIn("SSK", res)
return res
d.addCallback(_check_page)
@@ -2381,7 +2509,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
children = dict( [(unicode(name),value)
for (name,value)
in parsed[1]["children"].iteritems()] )
- self.failUnless(u"new.txt" in children)
+ self.failUnlessIn(u"new.txt", children)
new_json = children[u"new.txt"]
self.failUnlessEqual(new_json[0], "filenode")
self.failUnless(new_json[1]["mutable"])
@@ -2535,7 +2663,8 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
# make sure that nothing was added
d.addCallback(lambda res:
self.failUnlessNodeKeysAre(self._foo_node,
- [u"bar.txt", u"baz.txt", u"blockingfile",
+ [self._htmlname_unicode,
+ u"bar.txt", u"baz.txt", u"blockingfile",
u"empty", u"n\u00fc.txt", u"quux.txt",
u"sub"]))
return d
@@ -2544,7 +2673,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
bar_url = self.public_url + "/foo/bar.txt"
d = self.POST(bar_url, t="check")
def _check(res):
- self.failUnless("Healthy :" in res)
+ self.failUnlessIn("Healthy :", res)
d.addCallback(_check)
redir_url = "http://allmydata.org/TARGET"
def _check2(statuscode, target):
@@ -2559,16 +2688,16 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
d.addCallback(lambda res:
self.POST(bar_url, t="check", return_to=redir_url))
def _check3(res):
- self.failUnless("Healthy :" in res)
- self.failUnless("Return to file" in res)
- self.failUnless(redir_url in res)
+ self.failUnlessIn("Healthy :", res)
+ self.failUnlessIn("Return to file", res)
+ self.failUnlessIn(redir_url, res)
d.addCallback(_check3)
d.addCallback(lambda res:
self.POST(bar_url, t="check", output="JSON"))
def _check_json(res):
data = simplejson.loads(res)
- self.failUnless("storage-index" in data)
+ self.failUnlessIn("storage-index", data)
self.failUnless(data["results"]["healthy"])
d.addCallback(_check_json)
@@ -2578,7 +2707,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
bar_url = self.public_url + "/foo/bar.txt"
d = self.POST(bar_url, t="check", repair="true")
def _check(res):
- self.failUnless("Healthy :" in res)
+ self.failUnlessIn("Healthy :", res)
d.addCallback(_check)
redir_url = "http://allmydata.org/TARGET"
def _check2(statuscode, target):
@@ -2593,9 +2722,9 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
d.addCallback(lambda res:
self.POST(bar_url, t="check", return_to=redir_url))
def _check3(res):
- self.failUnless("Healthy :" in res)
- self.failUnless("Return to file" in res)
- self.failUnless(redir_url in res)
+ self.failUnlessIn("Healthy :", res)
+ self.failUnlessIn("Return to file", res)
+ self.failUnlessIn(redir_url, res)
d.addCallback(_check3)
return d
@@ -2603,7 +2732,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
foo_url = self.public_url + "/foo/"
d = self.POST(foo_url, t="check")
def _check(res):
- self.failUnless("Healthy :" in res, res)
+ self.failUnlessIn("Healthy :", res)
d.addCallback(_check)
redir_url = "http://allmydata.org/TARGET"
def _check2(statuscode, target):
@@ -2618,16 +2747,16 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
d.addCallback(lambda res:
self.POST(foo_url, t="check", return_to=redir_url))
def _check3(res):
- self.failUnless("Healthy :" in res, res)
- self.failUnless("Return to file/directory" in res)
- self.failUnless(redir_url in res)
+ self.failUnlessIn("Healthy :", res)
+ self.failUnlessIn("Return to file/directory", res)
+ self.failUnlessIn(redir_url, res)
d.addCallback(_check3)
d.addCallback(lambda res:
self.POST(foo_url, t="check", output="JSON"))
def _check_json(res):
data = simplejson.loads(res)
- self.failUnless("storage-index" in data)
+ self.failUnlessIn("storage-index", data)
self.failUnless(data["results"]["healthy"])
d.addCallback(_check_json)
@@ -2637,7 +2766,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
foo_url = self.public_url + "/foo/"
d = self.POST(foo_url, t="check", repair="true")
def _check(res):
- self.failUnless("Healthy :" in res, res)
+ self.failUnlessIn("Healthy :", res)
d.addCallback(_check)
redir_url = "http://allmydata.org/TARGET"
def _check2(statuscode, target):
@@ -2652,9 +2781,9 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
d.addCallback(lambda res:
self.POST(foo_url, t="check", return_to=redir_url))
def _check3(res):
- self.failUnless("Healthy :" in res)
- self.failUnless("Return to file/directory" in res)
- self.failUnless(redir_url in res)
+ self.failUnlessIn("Healthy :", res)
+ self.failUnlessIn("Return to file/directory", res)
+ self.failUnlessIn(redir_url, res)
d.addCallback(_check3)
return d
@@ -2666,7 +2795,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
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"))
+ self.POST(quux_extension_url, t="check"))
d.addCallback(_check)
return d
@@ -2676,10 +2805,9 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
def _check(res):
self.failUnlessIn("Healthy", res)
d.addCallback(_check)
- quux_extension_url = "/uri/%s" %\
- urllib.quote("%s:3:131073" % self._quux_txt_uri)
+ 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"))
+ self.POST(quux_extension_url, t="check", repair="true"))
d.addCallback(_check)
return d
@@ -2728,13 +2856,14 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
d.addCallback(self.wait_for_operation, "123")
def _check_json(data):
self.failUnlessReallyEqual(data["finished"], True)
- self.failUnlessReallyEqual(data["count-objects-checked"], 10)
- self.failUnlessReallyEqual(data["count-objects-healthy"], 10)
+ self.failUnlessReallyEqual(data["count-objects-checked"], 11)
+ self.failUnlessReallyEqual(data["count-objects-healthy"], 11)
d.addCallback(_check_json)
d.addCallback(self.get_operation_results, "123", "html")
def _check_html(res):
- self.failUnless("Objects Checked: 10 " in res)
- self.failUnless("Objects Healthy: 10 " in res)
+ self.failUnlessIn("Objects Checked: 11 ", res)
+ self.failUnlessIn("Objects Healthy: 11 ", res)
+ self.failUnlessIn(FAVICON_MARKUP, res)
d.addCallback(_check_html)
d.addCallback(lambda res:
@@ -2763,32 +2892,34 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
d.addCallback(self.wait_for_operation, "124")
def _check_json(data):
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-checked"], 11)
+ self.failUnlessReallyEqual(data["count-objects-healthy-pre-repair"], 11)
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-healthy-post-repair"], 11)
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: 10 " in res)
+ self.failUnlessIn("Objects Checked: 11 ", res)
- self.failUnless("Objects Healthy (before repair): 10 " in res)
- self.failUnless("Objects Unhealthy (before repair): 0 " in res)
- self.failUnless("Corrupt Shares (before repair): 0 " in res)
+ self.failUnlessIn("Objects Healthy (before repair): 11 ", res)
+ self.failUnlessIn("Objects Unhealthy (before repair): 0 ", res)
+ self.failUnlessIn("Corrupt Shares (before repair): 0 ", res)
- self.failUnless("Repairs Attempted: 0 " in res)
- self.failUnless("Repairs Successful: 0 " in res)
- self.failUnless("Repairs Unsuccessful: 0 " in res)
+ self.failUnlessIn("Repairs Attempted: 0 ", res)
+ self.failUnlessIn("Repairs Successful: 0 ", res)
+ self.failUnlessIn("Repairs Unsuccessful: 0 ", res)
- self.failUnless("Objects Healthy (after repair): 10 " in res)
- self.failUnless("Objects Unhealthy (after repair): 0 " in res)
- self.failUnless("Corrupt Shares (after repair): 0 " in res)
+ self.failUnlessIn("Objects Healthy (after repair): 11 ", res)
+ self.failUnlessIn("Objects Unhealthy (after repair): 0 ", res)
+ self.failUnlessIn("Corrupt Shares (after repair): 0 ", res)
+
+ self.failUnlessIn(FAVICON_MARKUP, res)
d.addCallback(_check_html)
return d
@@ -2806,24 +2937,24 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
return d
def test_POST_mkdir_mdmf(self):
- d = self.POST(self.public_url + "/foo?t=mkdir&name=newdir&mutable-type=mdmf")
+ d = self.POST(self.public_url + "/foo?t=mkdir&name=newdir&format=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 = self.POST(self.public_url + "/foo?t=mkdir&name=newdir&format=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_bad_format(self):
+ return self.shouldHTTPError("POST_mkdir_bad_format",
+ 400, "Bad Request", "Unknown format: foo",
+ self.POST, self.public_url +
+ "/foo?t=mkdir&name=newdir&format=foo")
def test_POST_mkdir_initial_children(self):
(newkids, caps) = self._create_initial_children()
@@ -2841,7 +2972,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
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",
+ "/foo?t=mkdir-with-children&name=newdir&format=mdmf",
simplejson.dumps(newkids))
d.addCallback(lambda res:
self.failUnlessNodeHasChild(self._foo_node, u"newdir"))
@@ -2857,7 +2988,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
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",
+ "/foo?t=mkdir-with-children&name=newdir&format=sdmf",
simplejson.dumps(newkids))
d.addCallback(lambda res:
self.failUnlessNodeHasChild(self._foo_node, u"newdir"))
@@ -2869,12 +3000,12 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
caps['filecap1'])
return d
- def test_POST_mkdir_initial_children_bad_mutable_type(self):
+ def test_POST_mkdir_initial_children_bad_format(self):
(newkids, caps) = self._create_initial_children()
- return self.shouldHTTPError("test bad mutable type",
- 400, "Bad Request", "Unknown type: foo",
+ return self.shouldHTTPError("POST_mkdir_initial_children_bad_format",
+ 400, "Bad Request", "Unknown format: foo",
self.POST, self.public_url + \
- "/foo?t=mkdir-with-children&name=newdir&mutable-type=foo",
+ "/foo?t=mkdir-with-children&name=newdir&format=foo",
simplejson.dumps(newkids))
def test_POST_mkdir_immutable(self):
@@ -2900,7 +3031,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
def test_POST_mkdir_immutable_bad(self):
(newkids, caps) = self._create_initial_children()
- d = self.shouldFail2(error.Error, "test_POST_mkdir_immutable_bad",
+ d = self.shouldFail2(error.Error, "POST_mkdir_immutable_bad",
"400 Bad Request",
"needed to be immutable but was not",
self.POST2,
@@ -2934,7 +3065,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
return d
def test_POST_mkdir_no_parentdir_noredirect_mdmf(self):
- d = self.POST("/uri?t=mkdir&mutable-type=mdmf")
+ d = self.POST("/uri?t=mkdir&format=mdmf")
def _after_mkdir(res):
u = uri.from_string(res)
# Check that this is an MDMF writecap
@@ -2943,18 +3074,18 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
return d
def test_POST_mkdir_no_parentdir_noredirect_sdmf(self):
- d = self.POST("/uri?t=mkdir&mutable-type=sdmf")
+ d = self.POST("/uri?t=mkdir&format=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_noredirect_bad_format(self):
+ return self.shouldHTTPError("POST_mkdir_no_parentdir_noredirect_bad_format",
+ 400, "Bad Request", "Unknown format: foo",
+ self.POST, self.public_url +
+ "/uri?t=mkdir&format=foo")
def test_POST_mkdir_no_parentdir_noredirect2(self):
# make sure form-based arguments (as on the welcome page) still work
@@ -3032,7 +3163,8 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
def _create_immutable_children(self):
contents, n, filecap1 = self.makefile(12)
md1 = {"metakey1": "metavalue1"}
- tnode = create_chk_filenode("immutable directory contents\n"*10)
+ tnode = create_chk_filenode("immutable directory contents\n"*10,
+ self.get_all_contents())
dnode = DirectoryNode(tnode, None, None)
assert not dnode.is_mutable()
immdircap = dnode.get_uri()
@@ -3087,7 +3219,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
# the regular /uri?t=mkdir operation is specified to ignore its body.
# Only t=mkdir-with-children pays attention to it.
(newkids, caps) = self._create_initial_children()
- d = self.shouldHTTPError("POST t=mkdir unexpected children",
+ d = self.shouldHTTPError("POST_mkdir_no_parentdir_unexpected_children",
400, "Bad Request",
"t=mkdir does not accept children=, "
"try t=mkdir-with-children instead",
@@ -3096,7 +3228,8 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
return d
def test_POST_noparent_bad(self):
- d = self.shouldHTTPError("POST /uri?t=bogus", 400, "Bad Request",
+ d = self.shouldHTTPError("POST_noparent_bad",
+ 400, "Bad Request",
"/uri accepts only PUT, PUT?t=mkdir, "
"POST?t=upload, and POST?t=mkdir",
self.POST, "/uri?t=bogus")
@@ -3144,12 +3277,13 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
d = self.GET("/")
def _after_get_welcome_page(res):
MKDIR_BUTTON_RE = re.compile(
- ''
- ' '
- ' ',
- re.I)
- mo = MKDIR_BUTTON_RE.search(res)
+ '