예제 #1
0
 def setUp(self):
     super(ComponentConnectorTest, self).setUp()
     self.reactor = FakeReactor()
     # XXX this should be dropped once the FakeReactor doesn't use the
     # real reactor anymore under the hood.
     self.reactor._reactor = Clock()
     self.config = Configuration()
     self.config.data_path = self.makeDir()
     self.makeDir(path=self.config.sockets_path)
     self.connector = TestComponentConnector(self.reactor, self.config)
예제 #2
0
 def setUp(self):
     super(PackageTaskHandlerTest, self).setUp()
     self.config = PackageTaskHandlerConfiguration()
     self.store = PackageStore(self.makeFile())
     self.reactor = FakeReactor()
     self.handler = PackageTaskHandler(self.store, self.facade, self.remote,
                                       self.config, self.reactor)
예제 #3
0
 def set_up(self, test_case):
     super(BrokerClientHelper, self).set_up(test_case)
     # The client needs its own reactor to avoid infinite loops
     # when the broker broadcasts and event
     test_case.client_reactor = FakeReactor()
     test_case.client = BrokerClient(test_case.client_reactor)
     test_case.client.broker = test_case.remote
예제 #4
0
 def set_up(self, test_case):
     super(ManagerHelper, self).set_up(test_case)
     test_case.config = ManagerConfiguration()
     test_case.config.load(["-c", test_case.config_filename])
     test_case.reactor = FakeReactor()
     test_case.manager = Manager(test_case.reactor, test_case.config)
     test_case.manager.broker = test_case.remote
예제 #5
0
 def setUp(self):
     super(LandscapeServiceTest, self).setUp()
     self.config = Configuration()
     self.config.data_path = self.makeDir()
     self.makeDir(path=self.config.sockets_path)
     self.reactor = FakeReactor()
     signal.signal(signal.SIGUSR1, signal.SIG_DFL)
예제 #6
0
 def set_up(self, test_case):
     super(BrokerServiceHelper, self).set_up(test_case)
     test_case.broker_service.startService()
     # Use different reactor to simulate separate processes
     self._connector = RemoteBrokerConnector(
         FakeReactor(), test_case.broker_service.config)
     deferred = self._connector.connect()
     test_case.remote = test_case.successResultOf(deferred)
예제 #7
0
 def set_up(self, test_case):
     super(BrokerClientHelper, self).set_up(test_case)
     # The client needs its own reactor to avoid infinite loops
     # when the broker broadcasts and event
     test_case.client_reactor = FakeReactor()
     config = BrokerConfiguration()
     config.stagger_launch = 0  # let's keep tests deterministic
     test_case.client = BrokerClient(test_case.client_reactor, config)
     test_case.client.broker = test_case.remote
예제 #8
0
 def set_up(self, test_case):
     super(MonitorHelper, self).set_up(test_case)
     persist = Persist()
     persist_filename = test_case.makePersistFile()
     test_case.config = MonitorConfiguration()
     test_case.config.load(["-c", test_case.config_filename])
     test_case.reactor = FakeReactor()
     test_case.monitor = Monitor(test_case.reactor, test_case.config,
                                 persist, persist_filename)
     test_case.monitor.broker = test_case.remote
     test_case.mstore = test_case.broker_service.message_store
예제 #9
0
    def setUp(self):
        super(ComponentPublisherTest, self).setUp()
        reactor = FakeReactor()
        config = Configuration()
        config.data_path = self.makeDir()
        self.makeDir(path=config.sockets_path)
        self.component = TestComponent()
        self.publisher = ComponentPublisher(self.component, reactor, config)
        self.publisher.start()

        self.connector = TestComponentConnector(reactor, config)
        connected = self.connector.connect()
        connected.addCallback(lambda remote: setattr(self, "remote", remote))
        return connected
예제 #10
0
 def set_up(self, test_case):
     super(ExchangeHelper, self).set_up(test_case)
     test_case.persist_filename = test_case.makePersistFile()
     test_case.persist = Persist(filename=test_case.persist_filename)
     test_case.mstore = get_default_message_store(
         test_case.persist, test_case.config.message_store_path)
     test_case.identity = Identity(test_case.config, test_case.persist)
     test_case.transport = FakeTransport(None, test_case.config.url,
                                         test_case.config.ssl_public_key)
     test_case.reactor = FakeReactor()
     test_case.exchange_store = ExchangeStore(
         test_case.config.exchange_store_path)
     test_case.exchanger = MessageExchange(
         test_case.reactor, test_case.mstore, test_case.transport,
         test_case.identity, test_case.exchange_store, test_case.config)
예제 #11
0
    def test_wb_is_lazy(self):
        """
        The L{LazyRemoteBroker} class doesn't initialize the actual remote
        broker until one of its attributes gets actually accessed.
        """
        reactor = FakeReactor()
        connector = RemoteBrokerConnector(reactor, self.broker_service.config)
        self.broker = LazyRemoteBroker(connector)
        self.assertIs(self.broker._remote, None)

        def close_connection(result):
            self.assertTrue(result)
            connector.disconnect()

        result = self.broker.ping()
        return result.addCallback(close_connection)
예제 #12
0
    def test_errors_are_printed_and_exit_program(self, init_logging_mock):
        class MyException(Exception):
            pass

        self.log_helper.ignore_errors(MyException)

        class HandlerMock(PackageTaskHandler):
            def run(self):
                return fail(MyException("Hey error"))

        # Ok now for some real stuff

        def assert_log(ignored):
            self.assertIn("MyException", self.logfile.getvalue())
            init_logging_mock.assert_called_once_with(ANY, "handler-mock")

        result = run_task_handler(HandlerMock, ["-c", self.config_filename],
                                  reactor=FakeReactor())

        return result.addCallback(assert_log)
예제 #13
0
    def test_start_stop(self):
        """
        The L{BrokerService.startService} method makes the process start
        listening to the broker socket, and starts the L{Exchanger} and
        the L{Pinger} as well.
        """
        self.service.exchanger.start = Mock()
        self.service.pinger.start = Mock()
        self.service.exchanger.stop = Mock()

        self.service.startService()
        reactor = FakeReactor()
        connector = RemoteBrokerConnector(reactor, self.config)
        connected = connector.connect()
        connected.addCallback(lambda remote: remote.get_server_uuid())
        connected.addCallback(lambda x: connector.disconnect())
        connected.addCallback(lambda x: self.service.stopService())

        self.service.exchanger.start.assert_called_with()
        self.service.pinger.start.assert_called_with()
        self.service.exchanger.stop.assert_called_with()
예제 #14
0
 def get_reactor(self):
     return FakeReactor()
예제 #15
0
class ComponentConnectorTest(LandscapeTest):
    def setUp(self):
        super(ComponentConnectorTest, self).setUp()
        self.reactor = FakeReactor()
        # XXX this should be dropped once the FakeReactor doesn't use the
        # real reactor anymore under the hood.
        self.reactor._reactor = Clock()
        self.config = Configuration()
        self.config.data_path = self.makeDir()
        self.makeDir(path=self.config.sockets_path)
        self.connector = TestComponentConnector(self.reactor, self.config)

    def test_connect_with_max_retries(self):
        """
        If C{max_retries} is passed to L{RemoteObjectConnector.connect},
        then it will give up trying to connect after that amount of times.
        """
        self.log_helper.ignore_errors("Error while connecting to test")
        deferred = self.connector.connect(max_retries=2)
        self.assertNoResult(deferred)
        return
        self.failureResultOf(deferred).trap(ConnectError)

    def test_connect_logs_errors(self):
        """
        Connection errors are logged.
        """
        self.log_helper.ignore_errors("Error while connecting to test")

        def assert_log(ignored):
            self.assertIn("Error while connecting to test",
                          self.logfile.getvalue())

        result = self.connector.connect(max_retries=0)
        self.assertFailure(result, ConnectError)
        return result.addCallback(assert_log)

    def test_connect_with_quiet(self):
        """
        If the C{quiet} option is passed, no errors will be logged.
        """
        result = self.connector.connect(max_retries=0, quiet=True)
        return self.assertFailure(result, ConnectError)

    def test_reconnect_fires_event(self):
        """
        An event is fired whenever the connection is established again after
        it has been lost.
        """
        reconnects = []
        self.reactor.call_on("test-reconnect", lambda: reconnects.append(True))

        component = TestComponent()
        publisher = ComponentPublisher(component, self.reactor, self.config)
        publisher.start()
        deferred = self.connector.connect()
        self.successResultOf(deferred)
        self.connector._connector.disconnect()  # Simulate a disconnection
        self.assertEqual([], reconnects)
        self.reactor._reactor.advance(10)
        self.assertEqual([True], reconnects)

    def test_connect_with_factor(self):
        """
        If C{factor} is passed to the L{ComponentConnector.connect} method,
        then the associated protocol factory will be set to that value.
        """
        component = TestComponent()
        publisher = ComponentPublisher(component, self.reactor, self.config)
        publisher.start()
        deferred = self.connector.connect(factor=1.0)
        remote = self.successResultOf(deferred)
        self.assertEqual(1.0, remote._factory.factor)

    def test_disconnect(self):
        """
        It is possible to call L{ComponentConnector.disconnect} multiple times,
        even if the connection has been already closed.
        """
        component = TestComponent()
        publisher = ComponentPublisher(component, self.reactor, self.config)
        publisher.start()
        self.connector.connect()
        self.connector.disconnect()
        self.connector.disconnect()

    def test_disconnect_without_connect(self):
        """
        It is possible to call L{ComponentConnector.disconnect} even if the
        connection was never established. In that case the method is
        effectively a no-op.
        """
        self.connector.disconnect()

    @mock.patch("twisted.python.lockfile.kill")
    def test_stale_locks_with_dead_pid(self, mock_kill):
        """Publisher starts with stale lock."""
        mock_kill.side_effect = [OSError(errno.ESRCH, "No such process")]
        sock_path = os.path.join(self.config.sockets_path, u"test.sock")
        lock_path = u"{}.lock".format(sock_path)
        # fake a PID which does not exist
        os.symlink("-1", lock_path)

        component = TestComponent()
        # Test the actual Unix reactor implementation. Fakes won't do.
        reactor = LandscapeReactor()
        publisher = ComponentPublisher(component, reactor, self.config)

        # Shouldn't raise the exception.
        publisher.start()

        # ensure stale lock was replaced
        self.assertNotEqual("-1", os.readlink(lock_path))
        mock_kill.assert_called_with(-1, 0)

        publisher.stop()
        reactor._cleanup()

    @mock.patch("twisted.python.lockfile.kill")
    def test_stale_locks_recycled_pid(self, mock_kill):
        """Publisher starts with stale lock pointing to recycled process."""
        mock_kill.side_effect = [
            OSError(errno.EPERM, "Operation not permitted")
        ]
        sock_path = os.path.join(self.config.sockets_path, u"test.sock")
        lock_path = u"{}.lock".format(sock_path)
        # fake a PID recycled by a known process which isn't landscape (init)
        os.symlink("1", lock_path)

        component = TestComponent()
        # Test the actual Unix reactor implementation. Fakes won't do.
        reactor = LandscapeReactor()
        publisher = ComponentPublisher(component, reactor, self.config)

        # Shouldn't raise the exception.
        publisher.start()

        # ensure stale lock was replaced
        self.assertNotEqual("1", os.readlink(lock_path))
        mock_kill.assert_not_called()
        self.assertFalse(publisher._port.lockFile.clean)

        publisher.stop()
        reactor._cleanup()

    @mock.patch("twisted.python.lockfile.kill")
    def test_with_valid_lock(self, mock_kill):
        """Publisher raises lock error if a valid lock is held."""
        sock_path = os.path.join(self.config.sockets_path, u"test.sock")
        lock_path = u"{}.lock".format(sock_path)
        # fake a landscape process
        app = self.makeFile(textwrap.dedent("""\
            #!/usr/bin/python3
            import time
            time.sleep(10)
        """),
                            basename="landscape-manager")
        os.chmod(app, 0o755)
        call = subprocess.Popen([app])
        self.addCleanup(call.terminate)
        os.symlink(str(call.pid), lock_path)

        component = TestComponent()
        # Test the actual Unix reactor implementation. Fakes won't do.
        reactor = LandscapeReactor()
        publisher = ComponentPublisher(component, reactor, self.config)

        with self.assertRaises(CannotListenError):
            publisher.start()

        # ensure lock was not replaced
        self.assertEqual(str(call.pid), os.readlink(lock_path))
        mock_kill.assert_called_with(call.pid, 0)
        reactor._cleanup()
예제 #16
0
 def setUp(self):
     super(PingClientTest, self).setUp()
     self.reactor = FakeReactor()
예제 #17
0
class ComponentConnectorTest(LandscapeTest):
    def setUp(self):
        super(ComponentConnectorTest, self).setUp()
        self.reactor = FakeReactor()
        # XXX this should be dropped once the FakeReactor doesn't use the
        # real reactor anymore under the hood.
        self.reactor._reactor = Clock()
        self.config = Configuration()
        self.config.data_path = self.makeDir()
        self.makeDir(path=self.config.sockets_path)
        self.connector = TestComponentConnector(self.reactor, self.config)

    def test_connect_with_max_retries(self):
        """
        If C{max_retries} is passed to L{RemoteObjectConnector.connect},
        then it will give up trying to connect after that amount of times.
        """
        self.log_helper.ignore_errors("Error while connecting to test")
        deferred = self.connector.connect(max_retries=2)
        self.assertNoResult(deferred)
        return
        self.failureResultOf(deferred).trap(ConnectError)

    def test_connect_logs_errors(self):
        """
        Connection errors are logged.
        """
        self.log_helper.ignore_errors("Error while connecting to test")

        def assert_log(ignored):
            self.assertIn("Error while connecting to test",
                          self.logfile.getvalue())

        result = self.connector.connect(max_retries=0)
        self.assertFailure(result, ConnectError)
        return result.addCallback(assert_log)

    def test_connect_with_quiet(self):
        """
        If the C{quiet} option is passed, no errors will be logged.
        """
        result = self.connector.connect(max_retries=0, quiet=True)
        return self.assertFailure(result, ConnectError)

    def test_reconnect_fires_event(self):
        """
        An event is fired whenever the connection is established again after
        it has been lost.
        """
        reconnects = []
        self.reactor.call_on("test-reconnect", lambda: reconnects.append(True))

        component = TestComponent()
        publisher = ComponentPublisher(component, self.reactor, self.config)
        publisher.start()
        deferred = self.connector.connect()
        self.successResultOf(deferred)
        self.connector._connector.disconnect()  # Simulate a disconnection
        self.assertEqual([], reconnects)
        self.reactor._reactor.advance(10)
        self.assertEqual([True], reconnects)

    def test_connect_with_factor(self):
        """
        If C{factor} is passed to the L{ComponentConnector.connect} method,
        then the associated protocol factory will be set to that value.
        """
        component = TestComponent()
        publisher = ComponentPublisher(component, self.reactor, self.config)
        publisher.start()
        deferred = self.connector.connect(factor=1.0)
        remote = self.successResultOf(deferred)
        self.assertEqual(1.0, remote._factory.factor)

    def test_disconnect(self):
        """
        It is possible to call L{ComponentConnector.disconnect} multiple times,
        even if the connection has been already closed.
        """
        component = TestComponent()
        publisher = ComponentPublisher(component, self.reactor, self.config)
        publisher.start()
        self.connector.connect()
        self.connector.disconnect()
        self.connector.disconnect()

    def test_disconnect_without_connect(self):
        """
        It is possible to call L{ComponentConnector.disconnect} even if the
        connection was never established. In that case the method is
        effectively a no-op.
        """
        self.connector.disconnect()