X-Git-Url: https://git.rkrishnan.org/?a=blobdiff_plain;f=src%2Fallmydata%2Ftest%2Ftest_web.py;h=18514a3a57b012bbebf4cbe3d35b9a9e9d3571cf;hb=e1285d27b9b3203c1e968720177a46ae0a696983;hp=300c19a56f55bd3f688bcc6a6be9cfb1190ea042;hpb=062ae99372d73a02ff376fc3ef66d16dba6be9d7;p=tahoe-lafs%2Ftahoe-lafs.git
diff --git a/src/allmydata/test/test_web.py b/src/allmydata/test/test_web.py
index 300c19a5..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
@@ -6,7 +6,7 @@ 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, html
+from twisted.web import client, error, http
from twisted.python import failure, log
from foolscap.api import fireEventually, flushEventualQueue
@@ -50,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):
@@ -172,25 +172,34 @@ class FakeHistory:
return []
class FakeDisplayableServer(StubServer):
- def __init__(self, serverid, nickname):
+ 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 True
+ return self.connected
def get_permutation_seed(self):
return ""
def get_remote_host(self):
return ""
def get_last_loss_time(self):
- return None
- def get_announcement_time(self):
- return None
+ 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):
@@ -240,7 +249,13 @@ class FakeClient(Client):
self.storage_broker = StorageFarmBroker(None, permute_peers=True)
# fake knowledge of another server
self.storage_broker.test_add_server("other_nodeid",
- FakeDisplayableServer("other_nodeid", u"other_nickname \u263B"))
+ 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()
@@ -254,6 +269,11 @@ class FakeClient(Client):
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)
def stopService(self):
@@ -261,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()
@@ -324,8 +346,8 @@ class WebMixin(object):
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 = html.escape(self._htmlname_raw)
- self._htmlname_escaped_double = escapeToXML(html.escape(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)
@@ -563,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'" % \
@@ -592,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
@@ -600,12 +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'My nickname: fake_nickname \u263A ', res_u)
+ 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")
@@ -614,6 +649,54 @@ 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)
@@ -622,26 +705,36 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
self.s.uploader.helper_furl = None
return self.GET("/")
d.addCallback(_set_no_helper)
- d.addCallback(lambda res:
- self.failUnlessIn('Connected to helper?: not configured ', res))
+ 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"
+ self.s.uploader.helper_furl = "pb://someHelper/secret"
self.s.uploader.helper_connected = False
return self.GET("/")
d.addCallback(_set_helper_not_connected)
- d.addCallback(lambda res:
- self.failUnlessIn('Connected to helper?: no ', res))
+ 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"
+ self.s.uploader.helper_furl = "pb://someHelper/secret"
self.s.uploader.helper_connected = True
return self.GET("/")
d.addCallback(_set_helper_connected)
- d.addCallback(lambda res:
- self.failUnlessIn('Connected to helper?: yes ', res))
+ 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):
@@ -663,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)
@@ -1435,24 +1528,24 @@ 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)
@@ -1499,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
@@ -1546,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(' .*Create a new directory in this directory .* ', re.I)
+ 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)
@@ -3184,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)
+ '