1# This file is part of Buildbot.  Buildbot is free software: you can
2# redistribute it and/or modify it under the terms of the GNU General Public
3# License as published by the Free Software Foundation, version 2.
4#
5# This program is distributed in the hope that it will be useful, but WITHOUT
6# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
7# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
8# details.
9#
10# You should have received a copy of the GNU General Public License along with
11# this program; if not, write to the Free Software Foundation, Inc., 51
12# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
13#
14# Copyright Buildbot Team Members
15
16from parameterized import parameterized
17
18import mock
19
20from twisted.internet import defer
21from twisted.trial import unittest
22
23from buildbot.test.fake import fakemaster
24from buildbot.test.util.misc import TestReactorMixin
25from buildbot.util import service
26from buildbot.wamp import connector
27
28
29class FakeConfig:
30    def __init__(self, mq_dict):
31        self.mq = mq_dict
32
33
34class FakeService(service.AsyncMultiService):
35    name = "fakeWampService"
36    # Fake wamp service
37    # just call the maker on demand by the test
38
39    def __init__(self, url, realm, make, extra=None,
40                 debug=False, debug_wamp=False, debug_app=False):
41        super().__init__()
42        self.make = make
43        self.extra = extra
44
45    def gotConnection(self):
46        self.make(None)
47        r = self.make(self)
48        r.publish = mock.Mock(spec=r.publish)
49        r.register = mock.Mock(spec=r.register)
50        r.subscribe = mock.Mock(spec=r.subscribe)
51        r.onJoin(None)
52
53
54class TestedWampConnector(connector.WampConnector):
55    serviceClass = FakeService
56
57
58class WampConnector(TestReactorMixin, unittest.TestCase):
59
60    @defer.inlineCallbacks
61    def setUp(self):
62        self.setUpTestReactor()
63        master = fakemaster.make_master(self)
64        self.connector = TestedWampConnector()
65
66        config = FakeConfig({'type': 'wamp', 'router_url': "wss://foo", 'realm': "bb"})
67
68        yield self.connector.setServiceParent(master)
69        yield master.startService()
70        yield self.connector.reconfigServiceWithBuildbotConfig(config)
71
72    @defer.inlineCallbacks
73    def test_reconfig_same_config(self):
74        config = FakeConfig({'type': 'wamp', 'router_url': "wss://foo", 'realm': "bb"})
75        yield self.connector.reconfigServiceWithBuildbotConfig(config)
76
77    @parameterized.expand([
78        ('type', 'simple'),
79        ('router_url', 'wss://other-foo'),
80        ('realm', 'bb-other'),
81        ('wamp_debug_level', 'info'),
82    ])
83    @defer.inlineCallbacks
84    def test_reconfig_does_not_allow_config_change(self, attr_name, attr_value):
85        mq_dict = {'type': 'wamp', 'router_url': "wss://foo", 'realm': "bb"}
86        mq_dict[attr_name] = attr_value
87        with self.assertRaises(ValueError,
88                               msg="Cannot use different wamp settings when reconfiguring"):
89            yield self.connector.reconfigServiceWithBuildbotConfig(FakeConfig(mq_dict))
90
91    @defer.inlineCallbacks
92    def test_startup(self):
93        d = self.connector.getService()
94        self.connector.app.gotConnection()
95        yield d
96        # 824 is the hardcoded masterid of fakemaster
97        self.connector.service.publish.assert_called_with(
98            "org.buildbot.824.connected")
99
100    @defer.inlineCallbacks
101    def test_subscribe(self):
102        d = self.connector.subscribe('callback', 'topic', 'options')
103        self.connector.app.gotConnection()
104        yield d
105        self.connector.service.subscribe.assert_called_with(
106            'callback', 'topic', 'options')
107
108    @defer.inlineCallbacks
109    def test_publish(self):
110        d = self.connector.publish('topic', 'data', 'options')
111        self.connector.app.gotConnection()
112        yield d
113        self.connector.service.publish.assert_called_with(
114            'topic', 'data', options='options')
115
116    @defer.inlineCallbacks
117    def test_OnLeave(self):
118        d = self.connector.getService()
119        self.connector.app.gotConnection()
120        yield d
121        self.assertTrue(self.connector.master.running)
122        self.connector.service.onLeave(None)
123        self.assertFalse(self.connector.master.running)
124