X-Git-Url: https://git.rkrishnan.org/?a=blobdiff_plain;f=src%2Fallmydata%2Ftest%2Ftest_web.py;h=18514a3a57b012bbebf4cbe3d35b9a9e9d3571cf;hb=e1285d27b9b3203c1e968720177a46ae0a696983;hp=841bedc16e72c34de750de56bb9309d566c033b4;hpb=8f630a76fe009394e4666ac8761cbcbe04aa6a29;p=tahoe-lafs%2Ftahoe-lafs.git
diff --git a/src/allmydata/test/test_web.py b/src/allmydata/test/test_web.py
index 841bedc1..18514a3a 100644
--- a/src/allmydata/test/test_web.py
+++ b/src/allmydata/test/test_web.py
@@ -1,4 +1,4 @@
-import os.path, re, urllib, time
+import os.path, re, urllib, time, cgi
import simplejson
from StringIO import StringIO
@@ -11,11 +11,12 @@ 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
@@ -49,7 +50,7 @@ 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):
@@ -64,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"
+ 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)
@@ -162,28 +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)
+ 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)
@@ -192,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()
@@ -250,6 +341,16 @@ class WebMixin(object):
_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
@@ -261,7 +362,7 @@ class WebMixin(object):
_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(),
@@ -274,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
@@ -288,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):
@@ -356,8 +461,8 @@ class WebMixin(object):
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()] )
@@ -480,8 +585,10 @@ class WebMixin(object):
res.trap(expected_failure)
if substring:
self.failUnlessIn(substring, str(res),
- "'%s' not in '%s' for test '%s'" % \
- (substring, str(res), which))
+ "'%s' not in '%s' (response is '%s') for test '%s'" % \
+ (substring, str(res),
+ getattr(res.value, "response", ""),
+ which))
if response_substring:
self.failUnlessIn(response_substring, res.value.response,
"'%s' not in '%s' for test '%s'" % \
@@ -509,7 +616,6 @@ class WebMixin(object):
self.fail("%s was supposed to Error(302), not get '%s'" %
(which, res))
-
class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixin, unittest.TestCase):
def test_create(self):
pass
@@ -517,9 +623,24 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
def test_welcome(self):
d = self.GET("/")
def _check(res):
- self.failUnlessIn('Welcome to Tahoe-LAFS', res)
+ self.failUnlessIn('
Tahoe-LAFS - Welcome', res)
self.failUnlessIn(FAVICON_MARKUP, res)
- self.failUnlessIn('href="https://tahoe-lafs.org/"', 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")
@@ -528,6 +649,104 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
d.addCallback(_check)
return d
+ def test_introducer_status(self):
+ class MockIntroducerClient(object):
+ def __init__(self, connected):
+ self.connected = connected
+ def connected_to_introducer(self):
+ return self.connected
+
+ 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_helper_status(self):
+ d = defer.succeed(None)
+
+ # 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)
+ return d
+
def test_status(self):
h = self.s.get_history()
dl_num = h.list_all_download_statuses()[0].get_counter()
@@ -537,7 +756,7 @@ 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.failUnlessIn('Upload and Download Status', 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)
@@ -570,11 +789,15 @@ 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.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)
@@ -1305,29 +1528,47 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
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.failUnlessIn('name="t" value="upload"', html)
- self.failUnlessIn('input checked="checked" type="radio" id="upload-chk" value="chk" name="format"', html)
- self.failUnlessIn('input type="radio" id="upload-sdmf" value="sdmf" name="format"', html)
- self.failUnlessIn('input type="radio" id="upload-mdmf" value="mdmf" name="format"', html)
+ self.failUnless(re.search('', html), html)
+ self.failUnless(re.search('', html), html)
+ self.failUnless(re.search('Return to Welcome page', 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_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_GET_root_html(self):
d = self.GET("/")
d.addCallback(self._check_upload_and_mkdir_forms)
@@ -1351,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/move']:
+ 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
@@ -1398,7 +1639,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
d.addCallback(lambda res: self.GET(self.public_url + "/foo/empty/"))
def _check4(res):
self.failUnlessIn("directory is empty", res)
- MKDIR_BUTTON_RE=re.compile('.*.*', re.I)
+ MKDIR_BUTTON_RE=re.compile('.*.*', re.I)
self.failUnless(MKDIR_BUTTON_RE.search(res), res)
d.addCallback(_check4)
@@ -1550,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():
@@ -1567,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
@@ -1576,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"], [])
@@ -1988,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",
@@ -2074,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))
@@ -2091,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.failUnlessIn(u.get_storage_index(), 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)
@@ -2421,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
@@ -2613,13 +2856,13 @@ 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.failUnlessIn("Objects Checked: 10", res)
- self.failUnlessIn("Objects Healthy: 10", res)
+ self.failUnlessIn("Objects Checked: 11", res)
+ self.failUnlessIn("Objects Healthy: 11", res)
self.failUnlessIn(FAVICON_MARKUP, res)
d.addCallback(_check_html)
@@ -2649,22 +2892,22 @@ 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.failUnlessIn("Objects Checked: 10", res)
+ self.failUnlessIn("Objects Checked: 11", res)
- self.failUnlessIn("Objects Healthy (before repair): 10", 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)
@@ -2672,7 +2915,7 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
self.failUnlessIn("Repairs Successful: 0", res)
self.failUnlessIn("Repairs Unsuccessful: 0", res)
- self.failUnlessIn("Objects Healthy (after repair): 10", 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)
@@ -2920,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()
@@ -3033,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)
+ '