source: trunk/src/allmydata/test/web/test_introducer.py

Last change on this file was 1cfe843d, checked in by Alexandre Detiste <alexandre.detiste@…>, at 2024-02-22T23:40:25Z

more python2 removal

  • Property mode set to 100644
File size: 7.0 KB
Line 
1"""
2Ported to Python 3.
3"""
4
5import json
6from os.path import join
7
8from bs4 import BeautifulSoup
9
10from twisted.internet import reactor
11from twisted.internet import defer
12from testtools.twistedsupport import succeeded
13
14from ..common import (
15    SyncTestCase,
16    AsyncTestCase,
17)
18
19from foolscap.api import (
20    fireEventually,
21    flushEventualQueue,
22    Tub,
23)
24
25import allmydata
26from allmydata.introducer import (
27    create_introducer,
28)
29from allmydata.introducer.server import (
30    _IntroducerNode,
31)
32from allmydata.web.introweb import (
33    IntroducerRoot,
34)
35
36from allmydata import node
37from .common import (
38    assert_soup_has_favicon,
39    assert_soup_has_text,
40    assert_soup_has_tag_with_attributes,
41)
42from ..common import (
43    SameProcessStreamEndpointAssigner,
44)
45from ..common_util import (
46    FakeCanary,
47)
48from ..common_web import (
49    do_http,
50    render,
51)
52
53from testtools.matchers import (
54    Equals,
55    AfterPreprocessing,
56)
57
58
59@defer.inlineCallbacks
60def create_introducer_webish(reactor, port_assigner, basedir):
61    """
62    Create and start an introducer node and return it and its ``WebishServer``
63    service.
64
65    :param reactor: The reactor to use to allow the introducer node to use to
66        listen for connections.
67
68    :param SameProcessStreamEndpointAssigner port_assigner: The assigner to
69        use to assign a listening port for the introducer node.
70
71    :param bytes basedir: A non-existant path where the introducer node will
72        be created.
73
74    :return Deferred[(_IntroducerNode, WebishServer)]: A Deferred that fires
75        with the node and its webish service.
76    """
77    node.create_node_dir(basedir, "testing")
78    main_tub_location, main_tub_endpoint = port_assigner.assign(reactor)
79    _, web_port_endpoint = port_assigner.assign(reactor)
80    with open(join(basedir, "tahoe.cfg"), "w") as f:
81        f.write(
82            "[node]\n"
83            "tub.port = {main_tub_endpoint}\n"
84            "tub.location = {main_tub_location}\n"
85            "web.port = {web_port_endpoint}\n".format(
86                main_tub_endpoint=main_tub_endpoint,
87                main_tub_location=main_tub_location,
88                web_port_endpoint=web_port_endpoint,
89            )
90        )
91
92    intro_node = yield create_introducer(basedir)
93    ws = intro_node.getServiceNamed("webish")
94
95    yield fireEventually(None)
96    intro_node.startService()
97    defer.returnValue((intro_node, ws))
98
99
100class IntroducerWeb(AsyncTestCase):
101    """
102    Tests for web-facing functionality of an introducer node.
103    """
104    def setUp(self):
105        self.node = None
106        self.port_assigner = SameProcessStreamEndpointAssigner()
107        self.port_assigner.setUp()
108        self.addCleanup(self.port_assigner.tearDown)
109        # Anything using Foolscap leaves some timer trash in the reactor that
110        # we have to arrange to have cleaned up.
111        self.addCleanup(lambda: flushEventualQueue(None))
112        return super(IntroducerWeb, self).setUp()
113
114    @defer.inlineCallbacks
115    def test_welcome(self):
116        node, ws = yield create_introducer_webish(
117            reactor,
118            self.port_assigner,
119            self.mktemp(),
120        )
121        self.addCleanup(node.stopService)
122
123        url = "http://localhost:%d/" % (ws.getPortnum(),)
124        res = yield do_http("get", url)
125        soup = BeautifulSoup(res, 'html5lib')
126        assert_soup_has_text(self, soup, u'Welcome to the Tahoe-LAFS Introducer')
127        assert_soup_has_favicon(self, soup)
128        assert_soup_has_text(self, soup, u'Page rendered at')
129        assert_soup_has_text(self, soup, u'Tahoe-LAFS code imported from:')
130
131    @defer.inlineCallbacks
132    def test_basic_information(self):
133        """
134        The introducer web page includes the software version and several other
135        simple pieces of information.
136        """
137        node, ws = yield create_introducer_webish(
138            reactor,
139            self.port_assigner,
140            self.mktemp(),
141        )
142        self.addCleanup(node.stopService)
143
144        url = "http://localhost:%d/" % (ws.getPortnum(),)
145        res = yield do_http("get", url)
146        soup = BeautifulSoup(res, 'html5lib')
147        assert_soup_has_text(
148            self,
149            soup,
150            allmydata.__full_version__,
151        )
152        assert_soup_has_text(self, soup, u"no peers!")
153        assert_soup_has_text(self, soup, u"subscribers!")
154        assert_soup_has_tag_with_attributes(
155            self,
156            soup,
157            "link",
158            {"href": "/tahoe.css"},
159        )
160
161    @defer.inlineCallbacks
162    def test_tahoe_css(self):
163        """
164        The introducer serves the css.
165        """
166        node, ws = yield create_introducer_webish(
167            reactor,
168            self.port_assigner,
169            self.mktemp(),
170        )
171        self.addCleanup(node.stopService)
172
173        url = "http://localhost:%d/tahoe.css" % (ws.getPortnum(),)
174
175        # Just don't return an error.  If it does, do_http will raise
176        # something.
177        yield do_http("get", url)
178
179    @defer.inlineCallbacks
180    def test_json_front_page(self):
181        """
182        The front page can be served as json.
183        """
184        node, ws = yield create_introducer_webish(
185            reactor,
186            self.port_assigner,
187            self.mktemp(),
188        )
189        self.addCleanup(node.stopService)
190
191        url = "http://localhost:%d/?t=json" % (ws.getPortnum(),)
192        res = yield do_http("get", url)
193        data = json.loads(res)
194        self.assertEqual(data["subscription_summary"], {})
195        self.assertEqual(data["announcement_summary"], {})
196
197
198class IntroducerRootTests(SyncTestCase):
199    """
200    Tests for ``IntroducerRoot``.
201    """
202    def test_json(self):
203        """
204        The JSON response includes totals for the number of subscriptions and
205        announcements of each service type.
206        """
207        config = node.config_from_string(self.mktemp(), "", "")
208        config.get_private_path = lambda ignored: self.mktemp()
209        main_tub = Tub()
210        main_tub.listenOn(b"tcp:0")
211        main_tub.setLocation(b"tcp:127.0.0.1:1")
212        introducer_node = _IntroducerNode(config, main_tub, None, None)
213
214        introducer_service = introducer_node.getServiceNamed("introducer")
215        for n in range(2):
216            introducer_service.add_subscriber(
217                FakeCanary(),
218                "arbitrary",
219                {"info": "info"},
220            )
221
222        # It would be nice to use the publish method but then we have to
223        # generate a correctly signed message which I don't feel like doing.
224        ann_t = ("msg", "sig", "key")
225        ann = {"service-name": "arbitrary"}
226        introducer_service._announcements[("arbitrary", "key")] = (
227            ann_t,
228            FakeCanary(),
229            ann,
230            0,
231        )
232
233        resource = IntroducerRoot(introducer_node)
234        response = render(resource, {b"t": [b"json"]})
235        expected = {
236            u"subscription_summary": {"arbitrary": 2},
237            u"announcement_summary": {"arbitrary": 1},
238        }
239        self.assertThat(
240            response,
241            succeeded(AfterPreprocessing(json.loads, Equals(expected))))
Note: See TracBrowser for help on using the repository browser.