Merge pull request #1167 from meejah/3852.json-welcome-page

3852.json welcome page
This commit is contained in:
meejah 2022-01-07 11:49:04 -07:00 committed by GitHub
commit 451d79af83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 136 additions and 27 deletions

View File

@ -0,0 +1 @@

View File

@ -11,6 +11,7 @@ if PY2:
from future.builtins import filter, map, zip, ascii, chr, hex, input, next, oct, open, pow, round, super, bytes, dict, list, object, range, str, max, min # noqa: F401 from future.builtins import filter, map, zip, ascii, chr, hex, input, next, oct, open, pow, round, super, bytes, dict, list, object, range, str, max, min # noqa: F401
import time import time
import json
from urllib.parse import ( from urllib.parse import (
quote, quote,
@ -24,14 +25,23 @@ from twisted.web.template import Tag
from twisted.web.test.requesthelper import DummyRequest from twisted.web.test.requesthelper import DummyRequest
from twisted.application import service from twisted.application import service
from testtools.twistedsupport import succeeded from testtools.twistedsupport import succeeded
from twisted.internet.defer import inlineCallbacks from twisted.internet.defer import (
inlineCallbacks,
succeed,
)
from ...storage_client import ( from ...storage_client import (
NativeStorageServer, NativeStorageServer,
StorageFarmBroker, StorageFarmBroker,
) )
from ...web.root import RootElement from ...web.root import (
RootElement,
Root,
)
from ...util.connection_status import ConnectionStatus from ...util.connection_status import ConnectionStatus
from ...crypto.ed25519 import (
create_signing_keypair,
)
from allmydata.web.root import URIHandler from allmydata.web.root import URIHandler
from allmydata.client import _Client from allmydata.client import _Client
@ -47,6 +57,7 @@ from ..common import (
from ..common import ( from ..common import (
SyncTestCase, SyncTestCase,
AsyncTestCase,
) )
from testtools.matchers import ( from testtools.matchers import (
@ -138,3 +149,94 @@ class RenderServiceRow(SyncTestCase):
self.assertThat(item.slotData.get("version"), Equals("")) self.assertThat(item.slotData.get("version"), Equals(""))
self.assertThat(item.slotData.get("nickname"), Equals("")) self.assertThat(item.slotData.get("nickname"), Equals(""))
class RenderRoot(AsyncTestCase):
@inlineCallbacks
def test_root_json(self):
"""
The 'welcome' / root page renders properly with ?t=json when some
servers show None for available_space while others show a
valid int
See also https://tahoe-lafs.org/trac/tahoe-lafs/ticket/3852
"""
ann = {
"anonymous-storage-FURL": "pb://w2hqnbaa25yw4qgcvghl5psa3srpfgw3@tcp:127.0.0.1:51309/vucto2z4fxment3vfxbqecblbf6zyp6x",
"permutation-seed-base32": "w2hqnbaa25yw4qgcvghl5psa3srpfgw3",
}
srv0 = NativeStorageServer(b"server_id0", ann, None, {}, EMPTY_CLIENT_CONFIG)
srv0.get_connection_status = lambda: ConnectionStatus(False, "summary0", {}, 0, 0)
srv1 = NativeStorageServer(b"server_id1", ann, None, {}, EMPTY_CLIENT_CONFIG)
srv1.get_connection_status = lambda: ConnectionStatus(False, "summary1", {}, 0, 0)
# arrange for this server to have some valid available space
srv1.get_available_space = lambda: 12345
class FakeClient(_Client):
history = []
stats_provider = object()
nickname = ""
nodeid = b"asdf"
_node_public_key = create_signing_keypair()[1]
introducer_clients = []
helper = None
def __init__(self):
service.MultiService.__init__(self)
self.storage_broker = StorageFarmBroker(
permute_peers=True,
tub_maker=None,
node_config=EMPTY_CLIENT_CONFIG,
)
self.storage_broker.test_add_server(b"test-srv0", srv0)
self.storage_broker.test_add_server(b"test-srv1", srv1)
root = Root(FakeClient(), now_fn=time.time)
lines = []
req = DummyRequest(b"")
req.fields = {}
req.args = {
b"t": [b"json"],
}
# for some reason, DummyRequest is already finished when we
# try to add a notifyFinish handler, so override that
# behavior.
def nop():
return succeed(None)
req.notifyFinish = nop
req.write = lines.append
yield root.render(req)
raw_js = b"".join(lines).decode("utf8")
js = json.loads(raw_js)
servers = js["servers"]
self.assertEquals(len(servers), 2)
self.assertIn(
{
"connection_status": "summary0",
"nodeid": "server_id0",
"last_received_data": 0,
"version": None,
"available_space": None,
"nickname": ""
},
servers
)
self.assertIn(
{
"connection_status": "summary1",
"nodeid": "server_id1",
"last_received_data": 0,
"version": None,
"available_space": 12345,
"nickname": ""
},
servers
)

View File

@ -820,29 +820,37 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
""" """
d = self.GET("/?t=json") d = self.GET("/?t=json")
def _check(res): def _check(res):
"""
Check that the results are correct.
We can't depend on the order of servers in the output
"""
decoded = json.loads(res) decoded = json.loads(res)
expected = { self.assertEqual(decoded['introducers'], {u'statuses': []})
u'introducers': { actual_servers = decoded[u"servers"]
u'statuses': [], self.assertEquals(len(actual_servers), 2)
self.assertIn(
{
u"nodeid": u'other_nodeid',
u'available_space': 123456,
u'connection_status': u'summary',
u'last_received_data': 30,
u'nickname': u'other_nickname \u263b',
u'version': u'1.0',
}, },
u'servers': sorted([ actual_servers
{u"nodeid": u'other_nodeid', )
u'available_space': 123456, self.assertIn(
u'connection_status': u'summary', {
u'last_received_data': 30, u"nodeid": u'disconnected_nodeid',
u'nickname': u'other_nickname \u263b', u'available_space': 123456,
u'version': u'1.0', u'connection_status': u'summary',
}, u'last_received_data': 35,
{u"nodeid": u'disconnected_nodeid', u'nickname': u'disconnected_nickname \u263b',
u'available_space': 123456, u'version': u'1.0',
u'connection_status': u'summary', },
u'last_received_data': 35, actual_servers
u'nickname': u'disconnected_nickname \u263b', )
u'version': u'1.0',
},
], key=lambda o: sorted(o.items())),
}
self.assertEqual(expected, decoded)
d.addCallback(_check) d.addCallback(_check)
return d return d

View File

@ -297,14 +297,12 @@ class Root(MultiFormatResource):
} }
return json.dumps(result, indent=1) + "\n" return json.dumps(result, indent=1) + "\n"
def _describe_known_servers(self, broker): def _describe_known_servers(self, broker):
return sorted(list( return list(
self._describe_server(server) self._describe_server(server)
for server for server
in broker.get_known_servers() in broker.get_known_servers()
), key=lambda o: sorted(o.items())) )
def _describe_server(self, server): def _describe_server(self, server):
status = server.get_connection_status() status = server.get_connection_status()