def test_scenario_succeeds_when_rate_has_tolerated_drop(self, _logger):
        """
        ``write_request_load_scenario`` succeeds even if the rate drops,
        if it is within the tolerance percentage.

        Establish the requested rate by having the ``FakeFlockerClient``
        respond to all requests, then lower the rate by dropping
        alternate requests.
        """
        c = Clock()

        control_service = self.get_dropping_flocker_client_instance()
        cluster = self.make_cluster(control_service)
        sample_size = 5
        s = write_request_load_scenario(c, cluster, sample_size=sample_size,
                                        tolerance_percentage=0.6)
        cluster.get_control_service(c).drop_requests = True
        d = s.start()

        s.maintained().addBoth(lambda x: self.fail())
        d.addCallback(lambda ignored: s.stop())
        # Generate enough samples to finish the scenario
        c.pump(repeat(1, sample_size*s.request_rate))

        self.successResultOf(d)
class TestElecraftProtocol(unittest.TestCase):
    """Test _ElecraftClientProtocol and _ElecraftRadio.
    
    This test uses those implementation classes rather than the public interface because the public interface is hardcoded to attempt to open a serial device."""
    def setUp(self):
        self.clock = Clock()
        self.tr = StringTransport()
        self.protocol = _ElecraftClientProtocol(reactor=self.clock)
        self.proxy = self.protocol._proxy()
        self.protocol.makeConnection(self.tr)
        self.protocol.connectionMade()

    def test_state_smoke(self):
        state_smoke_test(self.proxy)

    def test_initial_send(self):
        self.assertIn('AI2;', self.tr.value())
        self.assertIn('K31;', self.tr.value())
        self.assertIn('IF;', self.tr.value())

    def test_simple_receive(self):
        self.protocol.dataReceived('FA00000000012;')
        self.assertEqual(12.0, self.proxy.get_rx_main().state()['freq'].get())

    def test_continues_after_bad_data(self):
        self.protocol.dataReceived('\x00\x00;;FA00000000012;')
        self.assertEqual(12.0, self.proxy.get_rx_main().state()['freq'].get())

    def test_not_too_much_polling(self):
        self.tr.clear()
        self.assertEqual('', self.tr.value())
        self.clock.pump([0.01] * 150)
        self.assertEqual('FA;', self.tr.value())
        self.clock.pump([0.01] * 500)
        self.assertEqual('FA;FA;FA;FA;FA;FA;', self.tr.value())
    def test_scenario_throws_exception_when_rate_drops(self):
        """
        ReadRequestLoadScenario raises RequestRateTooLow if rate
        drops below the requested rate.

        Establish the requested rate by having the FakeFlockerClient
        respond to all requests, then lower the rate by dropping
        alternate requests. This should result in RequestRateTooLow
        being raised.
        """
        c = Clock()

        cluster = self.make_cluster(RequestDroppingFakeFlockerClient)
        sample_size = 5
        s = ReadRequestLoadScenario(c, cluster, sample_size=sample_size)

        s.start()

        # Advance the clock by `sample_size` seconds to establish the
        # requested rate.
        c.pump(repeat(1, sample_size))

        cluster.get_control_service(c).drop_requests = True

        # Advance the clock by 2 seconds so that a request is dropped
        # and a new rate which is below the target can be established.
        c.advance(2)

        failure = self.failureResultOf(s.maintained())
        self.assertIsInstance(failure.value, RequestRateTooLow)
    def test_retry_on_failure(self, access_key_id, secret_key, bucket_name):
        """
        If bucket creation fails with an S3 error, the creation attempt is
        retried after a delay.
        """
        reactor = Clock()

        controller = MemoryS3()
        creds = AWSCredentials(access_key_id, secret_key)
        client, state = controller.client(creds=creds, endpoint=None)
        state.set_rate_limit_exceeded()

        d = create_user_bucket(reactor, client, bucket_name)
        # Let several minutes pass (in one second increments) while
        # the rate limit error is in place.
        reactor.pump([1] * 60 * 3)

        # It should still be retrying.
        self.assertNoResult(d)

        # Clear the rate limit error and let it try again.
        state.clear_rate_limit_exceeded()
        reactor.pump([1] * 60)

        # It should have met with success at this point.
        self.assertThat(self.successResultOf(d), Is(None))
    def test_scenario_throws_exception_when_rate_drops(self, _logger):
        """
        ``read_request_load_scenario`` raises ``RequestRateTooLow`` if rate
        drops below the requested rate.

        Establish the requested rate by having the ``FakeFlockerClient``
        respond to all requests, then lower the rate by dropping
        alternate requests. This should result in ``RequestRateTooLow``
        being raised.
        """
        c = Clock()

        cluster = self.make_cluster(self.get_error_response_client_instance(c))
        sample_size = 5
        cluster.get_control_service(c).delay = 0
        s = write_request_load_scenario(c, cluster, sample_size=sample_size,
                                        tolerance_percentage=0.0)
        s.start()

        # Advance the clock by `sample_size` seconds to establish the
        # requested rate.
        c.pump(repeat(1, sample_size))

        cluster.get_control_service(c).fail_requests = True

        # Advance the clock by 2 seconds so that a request is dropped
        # and a new rate which is below the target can be established.
        time_to_advance = s.tolerated_errors / sample_size
        c.pump(repeat(1, time_to_advance))

        failure = self.failureResultOf(s.maintained())

        _logger.flushTracebacks(FakeNetworkError)

        self.assertIsInstance(failure.value, RequestRateTooLow)
    def assert_mutate_function_retries_until_success(
            self, mutate_callable, expected_args, success_response,
            expected_result):
        """
        Assert that some CLB function that mutates the CLB will retry on
        pending update until the function succeeds.

        :param mutate_callable: a callable which takes a clb argument and
            a clock argument - this callable should call the CLB's mutate
            function with the required arguments and return the function's
            return value.  For example:
            ``lambda clb, clk: clb.update_node(..., clock=clk)``
        :param expected_args: What are the expected treq arguments?  This
            should be an array of
            [method, url, (expected args, expected kwargs)]
        :param success_response: a tuple of (Response, string response body)
            which should be the successful response back from the API
        :param expected_result: What is the expected successful result of the
            function that is called by ``mutate_callable``
        """
        clock = Clock()
        clb = self.get_clb(*(expected_args + pending_update_response))

        d = mutate_callable(clb, clock)

        self.assertNoResult(d)
        clock.pump([3])
        self.assertNoResult(d)

        clb.treq = get_fake_treq(
            *([self] + expected_args + [success_response]))

        clock.pump([3])
        self.assertEqual(self.successResultOf(d), expected_result)
Exemple #7
0
    def assert_mutate_function_retries_until_success(self, mutate_callable,
                                                     expected_args,
                                                     success_response,
                                                     expected_result):
        """
        Assert that some CLB function that mutates the CLB will retry on
        pending update until the function succeeds.

        :param mutate_callable: a callable which takes a clb argument and
            a clock argument - this callable should call the CLB's mutate
            function with the required arguments and return the function's
            return value.  For example:
            ``lambda clb, clk: clb.update_node(..., clock=clk)``
        :param expected_args: What are the expected treq arguments?  This
            should be an array of
            [method, url, (expected args, expected kwargs)]
        :param success_response: a tuple of (Response, string response body)
            which should be the successful response back from the API
        :param expected_result: What is the expected successful result of the
            function that is called by ``mutate_callable``
        """
        clock = Clock()
        clb = self.get_clb(*(expected_args + pending_update_response))

        d = mutate_callable(clb, clock)

        self.assertNoResult(d)
        clock.pump([3])
        self.assertNoResult(d)

        clb.treq = get_fake_treq(*([self] + expected_args +
                                   [success_response]))

        clock.pump([3])
        self.assertEqual(self.successResultOf(d), expected_result)
    def test_scenario_throws_exception_when_rate_drops(self, _logger):
        """
        ``read_request_load_scenario`` raises ``RequestRateTooLow`` if rate
        drops below the requested rate.

        Establish the requested rate by having the ``FakeFlockerClient``
        respond to all requests, then lower the rate by dropping
        alternate requests. This should result in ``RequestRateTooLow``
        being raised.
        """
        c = Clock()

        cluster = self.make_cluster(RequestDroppingFakeFlockerClient)
        sample_size = 5
        s = read_request_load_scenario(c,
                                       cluster,
                                       sample_size=sample_size,
                                       tolerance_percentage=0)

        s.start()

        # Advance the clock by `sample_size` seconds to establish the
        # requested rate.
        c.pump(repeat(1, sample_size))

        cluster.get_control_service(c).drop_requests = True

        # Advance the clock by 2 seconds so that a request is dropped
        # and a new rate which is below the target can be established.
        c.advance(2)

        failure = self.failureResultOf(s.maintained())
        self.assertIsInstance(failure.value, RequestRateTooLow)
    def test_scenario_succeeds_when_rate_has_tolerated_drop(self, _logger):
        """
        ``read_request_load_scenario`` succeeds even if the rate drops,
        if it is within the tolerance percentage.

        Establish the requested rate by having the ``FakeFlockerClient``
        respond to all requests, then lower the rate by dropping
        alternate requests.
        """
        c = Clock()

        cluster = self.make_cluster(RequestDroppingFakeFlockerClient)
        sample_size = 5
        s = read_request_load_scenario(c,
                                       cluster,
                                       sample_size=sample_size,
                                       tolerance_percentage=0.6)
        cluster.get_control_service(c).drop_requests = True
        d = s.start()
        s.maintained().addBoth(lambda x: self.fail())
        d.addCallback(lambda ignored: s.stop())
        # Generate enough samples to finish the scenario
        c.pump(repeat(1, sample_size * s.request_rate))

        self.successResultOf(d)
Exemple #10
0
    def test_glass_from_sand_on_wood_multiple(self):
        """
        Crafting two glass, from two sand, using ten saplings, should take
        20s and only use four saplings.
        """

        # Patch the clock.
        clock = Clock()
        self.tile.burning.clock = clock

        self.tile.inventory.fuel[0] = Slot(blocks['sapling'].slot, 0, 10)
        self.tile.inventory.crafting[0] = Slot(blocks['sand'].slot, 0, 2)
        self.tile.changed(self.factory, coords)

        # Pump the clock. Burn time is 20s.
        clock.pump([0.5] * 40)

        self.assertEqual(self.factory.world.chunk.states[0],
                         blocks["burning-furnace"].slot) # it was started...
        self.assertEqual(self.factory.world.chunk.states[1],
                         blocks["furnace"].slot) # ...and stopped at the end
        # 2 sands take 20s to smelt, only 4 saplings needed
        self.assertEqual(self.tile.inventory.fuel[0], (blocks['sapling'].slot, 0, 6))
        self.assertEqual(self.tile.inventory.crafting[0], None)
        self.assertEqual(self.tile.inventory.crafted[0], (blocks['glass'].slot, 0, 2))
    def test_read_request_load_succeeds(self, _logger):
        """
        ``read_request_load_scenario`` starts and stops without collapsing.
        """
        c = Clock()

        node1 = Node(uuid=uuid4(), public_address=IPAddress('10.0.0.1'))
        node2 = Node(uuid=uuid4(), public_address=IPAddress('10.0.0.2'))
        cluster = BenchmarkCluster(
            node1.public_address,
            lambda reactor: FakeFlockerClient([node1, node2]),
            {node1.public_address, node2.public_address},
            default_volume_size=DEFAULT_VOLUME_SIZE)

        sample_size = 5
        s = read_request_load_scenario(c, cluster, sample_size=sample_size)

        d = s.start()

        # Request rate samples are recorded every second and we need to
        # collect enough samples to establish the rate which is defined
        # by `sample_size`. Therefore, advance the clock by
        # `sample_size` seconds to obtain enough samples.
        c.pump(repeat(1, sample_size))
        s.maintained().addBoth(lambda x: self.fail())
        d.addCallback(lambda ignored: s.stop())
        c.pump(repeat(1, sample_size))
        self.successResultOf(d)
Exemple #12
0
    def assert_mutate_function_retries_until_timeout(self,
                                                     mutate_callable,
                                                     expected_args,
                                                     timeout=60):
        """
        Assert that some CLB function that mutates the CLB will retry on
        pending update until the function times out.

        :param mutate_callable: a callable which takes a clb argument and
            a clock argument - this callable should call the CLB's mutate
            function with the required arguments and return the function's
            return value.  For example:
            ``lambda clb, clk: clb.update_node(..., clock=clk)``
        :param expected_args: What are the expected treq arguments?  This
            should be an array of
            [method, url, (expected args, expected kwargs)]
        :param int timeout: When does your function time out retrying?
        """
        clock = Clock()
        clb = self.get_clb(*(expected_args + pending_update_response))

        d = mutate_callable(clb, clock)
        self.assertNoResult(d)

        for _ in range((timeout - 1) / 3):
            clock.pump([3])
            self.assertNoResult(d)

        clock.pump([3])
        self.failureResultOf(d, TimedOutError)
Exemple #13
0
    def test_glass_from_sand_on_wood_multiple(self):
        """
        Crafting two glass, from two sand, using ten saplings, should take
        20s and only use four saplings.
        """

        # Patch the clock.
        clock = Clock()
        self.tile.burning.clock = clock

        self.tile.inventory.fuel[0] = Slot(blocks['sapling'].slot, 0, 10)
        self.tile.inventory.crafting[0] = Slot(blocks['sand'].slot, 0, 2)
        self.tile.changed(self.factory, coords)

        # Pump the clock. Burn time is 20s.
        clock.pump([0.5] * 40)

        self.assertEqual(self.factory.world.chunk.states[0],
                         blocks["burning-furnace"].slot) # it was started...
        self.assertEqual(self.factory.world.chunk.states[1],
                         blocks["furnace"].slot) # ...and stopped at the end
        # 2 sands take 20s to smelt, only 4 saplings needed
        self.assertEqual(self.tile.inventory.fuel[0], (blocks['sapling'].slot, 0, 6))
        self.assertEqual(self.tile.inventory.crafting[0], None)
        self.assertEqual(self.tile.inventory.crafted[0], (blocks['glass'].slot, 0, 2))
    def test_read_request_load_succeeds(self):
        """
        ReadRequestLoadScenario starts and stops without collapsing.
        """
        c = Clock()

        node1 = Node(uuid=uuid4(), public_address=IPAddress('10.0.0.1'))
        node2 = Node(uuid=uuid4(), public_address=IPAddress('10.0.0.2'))
        cluster = BenchmarkCluster(
            node1.public_address,
            lambda reactor: FakeFlockerClient([node1, node2]),
            {node1.public_address, node2.public_address},
            default_volume_size=DEFAULT_VOLUME_SIZE
        )

        sample_size = 5
        s = ReadRequestLoadScenario(c, cluster, sample_size=sample_size)

        d = s.start()

        # Request rate samples are recorded every second and we need to
        # collect enough samples to establish the rate which is defined
        # by `sample_size`. Therefore, advance the clock by
        # `sample_size` seconds to obtain enough samples.
        c.pump(repeat(1, sample_size))
        s.maintained().addBoth(lambda x: self.fail())
        d.addCallback(lambda ignored: s.stop())
        self.successResultOf(d)
Exemple #15
0
    def test_scenario_throws_exception_when_rate_drops(self):
        """
        WriteRequestLoadScenario raises RequestRateTooLow if rate
        drops below the requested rate.

        Establish the requested rate by having the FakeFlockerClient
        respond to all requests, then lower the rate by dropping
        alternate requests. This should result in RequestRateTooLow
        being raised.
        """
        c = Clock()
        control_service = self.get_dropping_flocker_client_instance()
        cluster = self.make_cluster(control_service)
        sample_size = 5
        s = WriteRequestLoadScenario(c, cluster, sample_size=sample_size)

        s.start()

        # Advance the clock by `sample_size` seconds to establish the
        # requested rate.
        c.pump(repeat(1, sample_size))

        control_service.drop_requests = True

        # Advance the clock by 2 seconds so that a request is dropped
        # and a new rate which is below the target can be established.
        c.advance(2)

        failure = self.failureResultOf(s.maintained())
        self.assertIsInstance(failure.value, WRequestRateTooLow)
    def test_write_request_load_succeeds(self, _logger):
        """
        ``write_request_load_scenario`` starts and stops without collapsing.
        """
        c = Clock()
        cluster = self.make_cluster(self.get_fake_flocker_client_instance())
        sample_size = 5
        s = write_request_load_scenario(c, cluster, sample_size=sample_size)

        d = s.start()

        # Request rate samples are recorded every second and we need to
        # collect enough samples to establish the rate which is defined
        # by `sample_size`. Therefore, advance the clock by
        # `sample_size` seconds to obtain enough samples.
        c.pump(repeat(1, sample_size))
        s.maintained().addBoth(lambda x: self.fail())
        d.addCallback(lambda ignored: s.stop())

        def verify_scenario_returns_metrics(result):
            self.assertIsInstance(result, dict)

        d.addCallback(verify_scenario_returns_metrics)

        self.successResultOf(d)
    def assert_mutate_function_retries_until_timeout(
            self, mutate_callable, expected_args, timeout=60):
        """
        Assert that some CLB function that mutates the CLB will retry on
        pending update until the function times out.

        :param mutate_callable: a callable which takes a clb argument and
            a clock argument - this callable should call the CLB's mutate
            function with the required arguments and return the function's
            return value.  For example:
            ``lambda clb, clk: clb.update_node(..., clock=clk)``
        :param expected_args: What are the expected treq arguments?  This
            should be an array of
            [method, url, (expected args, expected kwargs)]
        :param int timeout: When does your function time out retrying?
        """
        clock = Clock()
        clb = self.get_clb(*(expected_args + pending_update_response))

        d = mutate_callable(clb, clock)
        self.assertNoResult(d)

        for _ in range((timeout - 1) / 3):
            clock.pump([3])
            self.assertNoResult(d)

        clock.pump([3])
        self.failureResultOf(d, TimedOutError)
Exemple #18
0
    def test_write_request_load_succeeds(self, _logger):
        """
        ``write_request_load_scenario`` starts and stops without collapsing.
        """
        c = Clock()
        cluster = self.make_cluster(self.get_fake_flocker_client_instance())
        sample_size = 5
        s = write_request_load_scenario(c, cluster, sample_size=sample_size)

        d = s.start()

        # Request rate samples are recorded every second and we need to
        # collect enough samples to establish the rate which is defined
        # by `sample_size`. Therefore, advance the clock by
        # `sample_size` seconds to obtain enough samples.
        c.pump(repeat(1, sample_size))
        s.maintained().addBoth(lambda x: self.fail())
        d.addCallback(lambda ignored: s.stop())

        def verify_scenario_returns_metrics(result):
            self.assertIsInstance(result, dict)

        d.addCallback(verify_scenario_returns_metrics)

        self.successResultOf(d)
Exemple #19
0
class RetryingAuthenticatorTests(SynchronousTestCase):
    """
    Tests for `RetryingAuthenticator`
    """
    def setUp(self):
        """
        Create RetryingAuthenticator
        """
        self.clock = Clock()
        self.mock_auth = iMock(IAuthenticator)
        self.authenticator = RetryingAuthenticator(self.clock,
                                                   self.mock_auth,
                                                   max_retries=3,
                                                   retry_interval=4)

    def test_delegates(self):
        """
        `RetryingAuthenticator` calls internal authenticator and returns its result
        """
        self.mock_auth.authenticate_tenant.return_value = succeed('result')
        d = self.authenticator.authenticate_tenant(23)
        self.assertEqual(self.successResultOf(d), 'result')
        self.mock_auth.authenticate_tenant.assert_called_once_with(23,
                                                                   log=None)

    def test_retries(self):
        """
        `RetryingAuthenticator` retries internal authenticator if it fails
        """
        self.mock_auth.authenticate_tenant.side_effect = lambda *a, **kw: fail(
            APIError(500, '2'))
        d = self.authenticator.authenticate_tenant(23)
        # mock_auth is called and there is no result
        self.assertNoResult(d)
        self.mock_auth.authenticate_tenant.assert_called_once_with(23,
                                                                   log=None)
        # Advance clock and mock_auth is called again
        self.clock.advance(4)
        self.assertEqual(self.mock_auth.authenticate_tenant.call_count, 2)
        self.assertNoResult(d)
        # advance clock and mock_auth's success return is propogated
        self.mock_auth.authenticate_tenant.side_effect = lambda *a, **kw: succeed(
            'result')
        self.clock.advance(4)
        self.assertEqual(self.successResultOf(d), 'result')

    def test_retries_times_out(self):
        """
        `RetryingAuthenticator` retries internal authenticator and times out if it
        keeps failing for certain period of time
        """
        self.mock_auth.authenticate_tenant.side_effect = lambda *a, **kw: fail(
            APIError(500, '2'))
        d = self.authenticator.authenticate_tenant(23)
        self.assertNoResult(d)
        self.clock.pump([4] * 4)
        f = self.failureResultOf(d, APIError)
        self.assertEqual(f.value.code, 500)
Exemple #20
0
class LocalOriginReadOptionNegotiation(unittest.TestCase):
    test_data = b"""line1
line2
anotherline"""
    port = 65466

    def setUp(self):
        self.clock = Clock()
        self.temp_dir = FilePath(tempfile.mkdtemp()).asBytesMode()
        self.target = self.temp_dir.child(b'foo')
        with self.target.open('wb') as temp_fd:
            temp_fd.write(self.test_data)
        self.reader = DelayedReader(self.target, _clock=self.clock, delay=2)
        self.transport = FakeTransport(hostAddress=('127.0.0.1', self.port))
        self.rs = LocalOriginReadSession(('127.0.0.1', 65465),
                                         self.reader,
                                         _clock=self.clock)
        self.wd = MockHandshakeWatchdog(4, self.rs.timedOut, _clock=self.clock)
        self.rs.timeout_watchdog = self.wd
        self.rs.transport = self.transport

    def test_option_normal(self):
        self.rs.startProtocol()
        self.rs.datagramReceived(
            OACKDatagram({
                b'blksize': b'9'
            }).to_wire(), ('127.0.0.1', 65465))
        self.clock.advance(0.1)
        self.assertEqual(self.rs.session.block_size, 9)
        self.clock.pump((1, ) * 3)
        self.assertEqual(self.transport.value(),
                         DATADatagram(1, self.test_data[:9]).to_wire())

        self.rs.datagramReceived(
            OACKDatagram({
                b'blksize': b'12'
            }).to_wire(), ('127.0.0.1', 65465))
        self.clock.advance(0.1)
        self.assertEqual(self.rs.session.block_size, 9)

        self.transport.clear()
        self.rs.datagramReceived(
            ACKDatagram(1).to_wire(), ('127.0.0.1', 65465))
        self.clock.pump((1, ) * 3)
        self.assertEqual(self.transport.value(),
                         DATADatagram(2, self.test_data[9:18]).to_wire())

        self.addCleanup(self.rs.cancel)

    def test_local_origin_read_option_timeout(self):
        self.rs.startProtocol()
        self.clock.advance(5)
        self.assertTrue(self.transport.disconnecting)

    def tearDown(self):
        self.temp_dir.remove()
class RemoteOriginReadOptionNegotiation(unittest.TestCase):
    test_data = """line1
line2
anotherline"""
    port = 65466

    def setUp(self):
        self.clock = Clock()
        self.tmp_dir_path = tempfile.mkdtemp()
        self.target = FilePath(self.tmp_dir_path).child('foo')
        with self.target.open('wb') as temp_fd:
            temp_fd.write(self.test_data)
        self.reader = DelayedReader(self.target, _clock=self.clock, delay=2)
        self.transport = FakeTransport(hostAddress=('127.0.0.1', self.port))
        self.rs = RemoteOriginReadSession(('127.0.0.1', 65465), self.reader,
                                          options={'blksize':'9'}, _clock=self.clock)
        self.rs.transport = self.transport

    def test_option_normal(self):
        self.rs.startProtocol()
        self.clock.advance(0.1)
        oack_datagram = OACKDatagram({'blksize':'9'}).to_wire()
        self.assertEqual(self.transport.value(), oack_datagram)
        self.clock.advance(3)
        self.assertEqual(self.transport.value(), oack_datagram * 2)

        self.transport.clear()
        self.rs.datagramReceived(ACKDatagram(0).to_wire(), ('127.0.0.1', 65465))
        self.clock.pump((1,)*3)
        self.assertEqual(self.transport.value(), DATADatagram(1, self.test_data[:9]).to_wire())

        self.addCleanup(self.rs.cancel)

    def test_option_timeout(self):
        self.rs.startProtocol()
        self.clock.advance(0.1)
        oack_datagram = OACKDatagram({'blksize':'9'}).to_wire()
        self.assertEqual(self.transport.value(), oack_datagram)
        self.failIf(self.transport.disconnecting)

        self.clock.advance(3)
        self.assertEqual(self.transport.value(), oack_datagram * 2)
        self.failIf(self.transport.disconnecting)

        self.clock.advance(2)
        self.assertEqual(self.transport.value(), oack_datagram * 3)
        self.failIf(self.transport.disconnecting)

        self.clock.advance(2)
        self.assertEqual(self.transport.value(), oack_datagram * 3)
        self.failUnless(self.transport.disconnecting)

    def tearDown(self):
        shutil.rmtree(self.tmp_dir_path)
Exemple #22
0
class BlocTests(SynchronousTestCase):
    """
    Tests for :obj:`Bloc`
    """
    def setUp(self):
        self.clock = Clock()
        self.b = Bloc(self.clock, 3, 10)
        self.b.startService()

    def test_get_index_settling(self):
        """
        `get_index` heartbeats and adds client to the group and returns settling
        json if group is settling
        """
        r = self.b.get_index(request_with_session('c'))
        self.assertIn("c", self.b._group)
        self.assertIn("c", self.b._clients)
        self.assertEqual(json.loads(r.decode("utf-8")), {'status': 'SETTLING'})

    def test_get_index_settled(self):
        """
        `get_index` heartbeats and adds client to the group and returns settled
        json with index and total if group has settled
        """
        for i in range(int(11 / 3) + 1):
            self.b.get_index(request_with_session('s'))
            self.clock.pump([1] * 3)
        r = self.b.get_index(request_with_session('s'))
        self.assertEqual(json.loads(r.decode("utf-8")), {
            'status': 'SETTLED',
            'index': 1,
            'total': 1
        })

    def test_disconnect(self):
        """
        Disconnects session by removing it
        """
        self.b.get_index(request_with_session('new'))
        r = self.b.cancel_session(request_with_session("new", "DELETE"))
        self.assertEqual(r.decode("utf-8"), "{}")
        self.assertNotIn('new', self.b._group)
        self.assertNotIn('new', self.b._clients)

    def test_timeout_removed(self):
        """
        On timeout HeartbeatingClients removes client from SettlingGroup
        """
        self.b.get_index(request_with_session('s'))
        self.clock.pump([1] * 4)
        self.assertNotIn("s", self.b._group)
        self.assertNotIn("s", self.b._clients)
Exemple #23
0
class RetryingAuthenticatorTests(TestCase):
    """
    Tests for `RetryingAuthenticator`
    """

    def setUp(self):
        """
        Create RetryingAuthenticator
        """
        self.clock = Clock()
        self.mock_auth = iMock(IAuthenticator)
        self.authenticator = RetryingAuthenticator(
            self.clock, self.mock_auth, max_retries=3, retry_interval=4)

    def test_delegates(self):
        """
        `RetryingAuthenticator` calls internal authenticator and returns its result
        """
        self.mock_auth.authenticate_tenant.return_value = succeed('result')
        d = self.authenticator.authenticate_tenant(23)
        self.assertEqual(self.successResultOf(d), 'result')
        self.mock_auth.authenticate_tenant.assert_called_once_with(23, log=None)

    def test_retries(self):
        """
        `RetryingAuthenticator` retries internal authenticator if it fails
        """
        self.mock_auth.authenticate_tenant.side_effect = lambda *a, **kw: fail(APIError(500, '2'))
        d = self.authenticator.authenticate_tenant(23)
        # mock_auth is called and there is no result
        self.assertNoResult(d)
        self.mock_auth.authenticate_tenant.assert_called_once_with(23, log=None)
        # Advance clock and mock_auth is called again
        self.clock.advance(4)
        self.assertEqual(self.mock_auth.authenticate_tenant.call_count, 2)
        self.assertNoResult(d)
        # advance clock and mock_auth's success return is propogated
        self.mock_auth.authenticate_tenant.side_effect = lambda *a, **kw: succeed('result')
        self.clock.advance(4)
        self.assertEqual(self.successResultOf(d), 'result')

    def test_retries_times_out(self):
        """
        `RetryingAuthenticator` retries internal authenticator and times out if it
        keeps failing for certain period of time
        """
        self.mock_auth.authenticate_tenant.side_effect = lambda *a, **kw: fail(APIError(500, '2'))
        d = self.authenticator.authenticate_tenant(23)
        self.assertNoResult(d)
        self.clock.pump([4] * 4)
        f = self.failureResultOf(d, APIError)
        self.assertEqual(f.value.code, 500)
Exemple #24
0
 def test_scenario_throws_exception_when_already_started(self, _logger):
     """
     start method in the ``RequestLoadScenario`` throws a
     ``RequestScenarioAlreadyStarted`` if the scenario is already started.
     """
     c = Clock()
     cluster = self.make_cluster(self.get_fake_flocker_client_instance())
     sample_size = 5
     s = write_request_load_scenario(c, cluster, sample_size=sample_size)
     # Start and stop
     s.start()
     c.pump(repeat(1, sample_size))
     self.assertRaises(RequestScenarioAlreadyStarted, s.start)
 def test_scenario_throws_exception_when_already_started(self, _logger):
     """
     start method in the ``RequestLoadScenario`` throws a
     ``RequestScenarioAlreadyStarted`` if the scenario is already started.
     """
     c = Clock()
     cluster = self.make_cluster(self.get_fake_flocker_client_instance())
     sample_size = 5
     s = write_request_load_scenario(c, cluster, sample_size=sample_size)
     # Start and stop
     s.start()
     c.pump(repeat(1, sample_size))
     self.assertRaises(RequestScenarioAlreadyStarted, s.start)
    def test_setup_timeout_when_datasat_not_created(self):
        """
        `WriteRequestLoadScenario` should timeout if the setup the dataset
        creation does not complete within the given time.
        """
        c = Clock()
        cluster = self.make_cluster(
            self.get_unresponsive_flocker_client_instance())
        s = WriteRequestLoadScenario(c, cluster, 5, sample_size=3)

        d = s.start()
        c.pump(repeat(1, s.timeout+1))

        failure = self.failureResultOf(d)
        self.assertIsInstance(failure.value, DatasetCreationTimeout)
Exemple #27
0
    def test_setup_timeout_when_datasat_not_created(self):
        """
        `WriteRequestLoadScenario` should timeout if the setup the dataset
        creation does not complete within the given time.
        """
        c = Clock()
        cluster = self.make_cluster(
            self.get_unresponsive_flocker_client_instance())
        s = WriteRequestLoadScenario(c, cluster, 5, sample_size=3)

        d = s.start()
        c.pump(repeat(1, s.timeout + 1))

        failure = self.failureResultOf(d)
        self.assertIsInstance(failure.value, DatasetCreationTimeout)
Exemple #28
0
class BootstrapLocalOriginWrite(unittest.TestCase):

    port = 65466

    def setUp(self):
        self.clock = Clock()
        self.temp_dir = FilePath(tempfile.mkdtemp()).asBytesMode()
        self.target = self.temp_dir.child(b'foo')
        self.writer = DelayedWriter(self.target, _clock=self.clock, delay=2)
        self.transport = FakeTransport(hostAddress=('127.0.0.1', self.port))
        self.ws = LocalOriginWriteSession(('127.0.0.1', 65465),
                                          self.writer,
                                          _clock=self.clock)
        self.wd = MockHandshakeWatchdog(4, self.ws.timedOut, _clock=self.clock)
        self.ws.timeout_watchdog = self.wd
        self.ws.transport = self.transport

    def test_invalid_tid(self):
        self.ws.startProtocol()
        bad_tid_dgram = ACKDatagram(123)
        self.ws.datagramReceived(bad_tid_dgram.to_wire(), ('127.0.0.1', 1111))

        err_dgram = TFTPDatagramFactory(*split_opcode(self.transport.value()))
        self.assertEqual(err_dgram.errorcode, ERR_TID_UNKNOWN)
        self.addCleanup(self.ws.cancel)

    #test_invalid_tid.skip = 'Will go to another test case'

    def test_local_origin_write_session_handshake_timeout(self):
        self.ws.startProtocol()
        self.clock.advance(5)
        self.assertFalse(self.transport.value())
        self.assertTrue(self.transport.disconnecting)

    def test_local_origin_write_session_handshake_success(self):
        self.ws.session.block_size = 6
        self.ws.startProtocol()
        self.clock.advance(1)
        data_datagram = DATADatagram(1, b'foobar')
        self.ws.datagramReceived(data_datagram.to_wire(), ('127.0.0.1', 65465))
        self.clock.pump((1, ) * 3)
        self.assertEqual(self.transport.value(), ACKDatagram(1).to_wire())
        self.assertFalse(self.transport.disconnecting)
        self.assertFalse(self.wd.active())
        self.addCleanup(self.ws.cancel)

    def tearDown(self):
        self.temp_dir.remove()
class BootstrapRemoteOriginRead(unittest.TestCase):
    test_data = """line1
line2
anotherline"""
    port = 65466

    def setUp(self):
        self.clock = Clock()
        self.tmp_dir_path = tempfile.mkdtemp()
        self.target = FilePath(self.tmp_dir_path).child('foo')
        with self.target.open('wb') as temp_fd:
            temp_fd.write(self.test_data)
        self.reader = DelayedReader(self.target, _clock=self.clock, delay=2)
        self.transport = FakeTransport(hostAddress=('127.0.0.1', self.port))
        self.rs = RemoteOriginReadSession(('127.0.0.1', 65465), self.reader, _clock=self.clock)
        self.rs.transport = self.transport

    @inlineCallbacks
    def test_invalid_tid(self):
        self.rs.startProtocol()
        data_datagram = DATADatagram(1, 'foobar')
        yield self.rs.datagramReceived(data_datagram, ('127.0.0.1', 11111))
        err_dgram = TFTPDatagramFactory(*split_opcode(self.transport.value()))
        self.assertEqual(err_dgram.errorcode, ERR_TID_UNKNOWN)
        self.addCleanup(self.rs.cancel)

    def test_remote_origin_read_bootstrap(self):
        # First datagram
        self.rs.session.block_size = 5
        self.rs.startProtocol()
        self.clock.pump((1,)*3)

        data_datagram_1 = DATADatagram(1, self.test_data[:5])

        self.assertEqual(self.transport.value(), data_datagram_1.to_wire())
        self.failIf(self.transport.disconnecting)

        # Normal exchange continues
        self.transport.clear()
        self.rs.datagramReceived(ACKDatagram(1).to_wire(), ('127.0.0.1', 65465))
        self.clock.pump((1,)*3)
        data_datagram_2 = DATADatagram(2, self.test_data[5:10])
        self.assertEqual(self.transport.value(), data_datagram_2.to_wire())
        self.failIf(self.transport.disconnecting)
        self.addCleanup(self.rs.cancel)

    def tearDown(self):
        shutil.rmtree(self.tmp_dir_path)
Exemple #30
0
class BootstrapRemoteOriginRead(unittest.TestCase):
    test_data = """line1
line2
anotherline"""
    port = 65466

    def setUp(self):
        self.clock = Clock()
        self.tmp_dir_path = tempfile.mkdtemp()
        self.target = FilePath(self.tmp_dir_path).child('foo')
        with self.target.open('wb') as temp_fd:
            temp_fd.write(self.test_data)
        self.reader = DelayedReader(self.target, _clock=self.clock, delay=2)
        self.transport = FakeTransport(hostAddress=('127.0.0.1', self.port))
        self.rs = RemoteOriginReadSession(('127.0.0.1', 65465), self.reader, _clock=self.clock)
        self.rs.transport = self.transport

    @inlineCallbacks
    def test_invalid_tid(self):
        self.rs.startProtocol()
        data_datagram = DATADatagram(1, 'foobar')
        yield self.rs.datagramReceived(data_datagram, ('127.0.0.1', 11111))
        err_dgram = TFTPDatagramFactory(*split_opcode(self.transport.value()))
        self.assertEqual(err_dgram.errorcode, ERR_TID_UNKNOWN)
        self.addCleanup(self.rs.cancel)

    def test_remote_origin_read_bootstrap(self):
        # First datagram
        self.rs.session.block_size = 5
        self.rs.startProtocol()
        self.clock.pump((1,)*3)

        data_datagram_1 = DATADatagram(1, self.test_data[:5])

        self.assertEqual(self.transport.value(), data_datagram_1.to_wire())
        self.failIf(self.transport.disconnecting)

        # Normal exchange continues
        self.transport.clear()
        self.rs.datagramReceived(ACKDatagram(1).to_wire(), ('127.0.0.1', 65465))
        self.clock.pump((1,)*3)
        data_datagram_2 = DATADatagram(2, self.test_data[5:10])
        self.assertEqual(self.transport.value(), data_datagram_2.to_wire())
        self.failIf(self.transport.disconnecting)
        self.addCleanup(self.rs.cancel)

    def tearDown(self):
        shutil.rmtree(self.tmp_dir_path)
class BootstrapLocalOriginWrite(unittest.TestCase):

    port = 65466

    def setUp(self):
        self.clock = Clock()
        self.tmp_dir_path = tempfile.mkdtemp()
        self.target = FilePath(self.tmp_dir_path).child("foo")
        self.writer = DelayedWriter(self.target, _clock=self.clock, delay=2)
        self.transport = FakeTransport(hostAddress=("127.0.0.1", self.port))
        self.ws = LocalOriginWriteSession(("127.0.0.1", 65465), self.writer, _clock=self.clock)
        self.wd = MockHandshakeWatchdog(4, self.ws.timedOut, _clock=self.clock)
        self.ws.timeout_watchdog = self.wd
        self.ws.transport = self.transport

    def test_invalid_tid(self):
        self.ws.startProtocol()
        bad_tid_dgram = ACKDatagram(123)
        self.ws.datagramReceived(bad_tid_dgram.to_wire(), ("127.0.0.1", 1111))

        err_dgram = TFTPDatagramFactory(*split_opcode(self.transport.value()))
        self.assertEqual(err_dgram.errorcode, ERR_TID_UNKNOWN)
        self.addCleanup(self.ws.cancel)

    # test_invalid_tid.skip = 'Will go to another test case'

    def test_local_origin_write_session_handshake_timeout(self):
        self.ws.startProtocol()
        self.clock.advance(5)
        self.failIf(self.transport.value())
        self.failUnless(self.transport.disconnecting)

    def test_local_origin_write_session_handshake_success(self):
        self.ws.session.block_size = 6
        self.ws.startProtocol()
        self.clock.advance(1)
        data_datagram = DATADatagram(1, "foobar")
        self.ws.datagramReceived(data_datagram.to_wire(), ("127.0.0.1", 65465))
        self.clock.pump((1,) * 3)
        self.assertEqual(self.transport.value(), ACKDatagram(1).to_wire())
        self.failIf(self.transport.disconnecting)
        self.failIf(self.wd.active())
        self.addCleanup(self.ws.cancel)

    def tearDown(self):
        shutil.rmtree(self.tmp_dir_path)
Exemple #32
0
class LocalOriginReadOptionNegotiation(unittest.TestCase):
    test_data = """line1
line2
anotherline"""
    port = 65466

    def setUp(self):
        self.clock = Clock()
        self.tmp_dir_path = tempfile.mkdtemp()
        self.target = FilePath(self.tmp_dir_path).child('foo')
        with self.target.open('wb') as temp_fd:
            temp_fd.write(self.test_data)
        self.reader = DelayedReader(self.target, _clock=self.clock, delay=2)
        self.transport = FakeTransport(hostAddress=('127.0.0.1', self.port))
        self.rs = LocalOriginReadSession(('127.0.0.1', 65465), self.reader, _clock=self.clock)
        self.wd = MockHandshakeWatchdog(4, self.rs.timedOut, _clock=self.clock)
        self.rs.timeout_watchdog = self.wd
        self.rs.transport = self.transport

    def test_option_normal(self):
        self.rs.startProtocol()
        self.rs.datagramReceived(OACKDatagram({'blksize':'9'}).to_wire(), ('127.0.0.1', 65465))
        self.clock.advance(0.1)
        self.assertEqual(self.rs.session.block_size, 9)
        self.clock.pump((1,)*3)
        self.assertEqual(self.transport.value(), DATADatagram(1, self.test_data[:9]).to_wire())

        self.rs.datagramReceived(OACKDatagram({'blksize':'12'}).to_wire(), ('127.0.0.1', 65465))
        self.clock.advance(0.1)
        self.assertEqual(self.rs.session.block_size, 9)

        self.transport.clear()
        self.rs.datagramReceived(ACKDatagram(1).to_wire(), ('127.0.0.1', 65465))
        self.clock.pump((1,)*3)
        self.assertEqual(self.transport.value(), DATADatagram(2, self.test_data[9:18]).to_wire())

        self.addCleanup(self.rs.cancel)

    def test_local_origin_read_option_timeout(self):
        self.rs.startProtocol()
        self.clock.advance(5)
        self.failUnless(self.transport.disconnecting)

    def tearDown(self):
        shutil.rmtree(self.tmp_dir_path)
class BootstrapLocalOriginWrite(unittest.TestCase):

    port = 65466

    def setUp(self):
        self.clock = Clock()
        self.temp_dir = FilePath(tempfile.mkdtemp()).asBytesMode()
        self.target = self.temp_dir.child(b'foo')
        self.writer = DelayedWriter(self.target, _clock=self.clock, delay=2)
        self.transport = FakeTransport(hostAddress=('127.0.0.1', self.port))
        self.ws = LocalOriginWriteSession(('127.0.0.1', 65465), self.writer, _clock=self.clock)
        self.wd = timedCaller([5], None, self.ws.timedOut, self.clock)
        self.ws.timeout_watchdog = self.wd
        self.ws.transport = self.transport

    def test_invalid_tid(self):
        self.ws.startProtocol()
        bad_tid_dgram = ACKDatagram(123)
        self.ws.datagramReceived(bad_tid_dgram.to_wire(), ('127.0.0.1', 1111))

        err_dgram = TFTPDatagramFactory(*split_opcode(self.transport.value()))
        self.assertEqual(err_dgram.errorcode, ERR_TID_UNKNOWN)
        self.addCleanup(self.ws.cancel)
    #test_invalid_tid.skip = 'Will go to another test case'

    def test_local_origin_write_session_handshake_timeout(self):
        self.ws.startProtocol()
        self.clock.advance(5)
        self.assertFalse(self.transport.value())
        self.assertTrue(self.transport.disconnecting)

    def test_local_origin_write_session_handshake_success(self):
        self.ws.session.block_size = 6
        self.ws.startProtocol()
        self.clock.advance(1)
        data_datagram = DATADatagram(1, b'foobar')
        self.ws.datagramReceived(data_datagram.to_wire(), ('127.0.0.1', 65465))
        self.clock.pump((1,)*3)
        self.assertEqual(self.transport.value(), ACKDatagram(1).to_wire())
        self.assertFalse(self.transport.disconnecting)
        self.addCleanup(self.ws.cancel)

    def tearDown(self):
        self.temp_dir.remove()
Exemple #34
0
    def test_scenario_stops_only_when_no_outstanding_requests(self, logger):
        """
        ``read_request_load_scenario`` should only be considered as stopped
        when all outstanding requests made by it have completed.
        """
        c = Clock()

        cluster = self.make_cluster(RequestErrorFakeFlockerClient)
        delay = 1

        control_service = cluster.get_control_service(c)

        control_service.delay = delay
        sample_size = 5
        s = read_request_load_scenario(c,
                                       cluster,
                                       request_rate=10,
                                       sample_size=sample_size)

        d = s.start()
        s.maintained().addBoth(lambda x: self.fail())

        # Advance the clock by `sample_size` seconds to establish the
        # requested rate.
        c.pump(repeat(1, sample_size))

        # Force the control service to fail requests for one second.
        # These requests will fail after the delay period set in the
        # control service.
        control_service.fail_requests = True
        c.advance(1)
        control_service.fail_requests = False

        d.addCallback(lambda ignored: s.stop())

        # The scenario should not successfully stop until after the
        # delay period for the failed requests.
        self.assertNoResult(d)
        c.advance(delay)

        # The scenario requests that failed will have been logged.
        logger.flushTracebacks(FakeNetworkError)

        self.successResultOf(d)
    def test_scenario_stops_only_when_no_outstanding_requests(self, logger):
        """
        ``read_request_load_scenario`` should only be considered as stopped
        when all outstanding requests made by it have completed.
        """
        c = Clock()

        cluster = self.make_cluster(RequestErrorFakeFlockerClient)
        delay = 1

        control_service = cluster.get_control_service(c)

        control_service.delay = delay
        sample_size = 5
        s = read_request_load_scenario(
            c, cluster, request_rate=10, sample_size=sample_size
        )

        d = s.start()
        s.maintained().addBoth(lambda x: self.fail())

        # Advance the clock by `sample_size` seconds to establish the
        # requested rate.
        c.pump(repeat(1, sample_size))

        # Force the control service to fail requests for one second.
        # These requests will fail after the delay period set in the
        # control service.
        control_service.fail_requests = True
        c.advance(1)
        control_service.fail_requests = False

        d.addCallback(lambda ignored: s.stop())

        # The scenario should not successfully stop until after the
        # delay period for the failed requests.
        self.assertNoResult(d)
        c.advance(delay)

        # The scenario requests that failed will have been logged.
        logger.flushTracebacks(FakeNetworkError)

        self.successResultOf(d)
Exemple #36
0
    def test_scenario_throws_exception_if_overloaded(self):
        """
        `WriteRequestLoadScenario` raises `RequestOverload` if the
        difference between sent requests and received requests exceeds
        the tolerated difference once we start monitoring the scenario.

        Note that, right now, the only way to make it fail is to generate
        this difference before we start monitoring the scenario.
        Once we implement some kind of tolerance, to allow fluctuations
        in the rate, we can update this tests to trigger the exception
        in a more realistic manner.
        """
        # XXX Update this test when we add tolerance for rate fluctuations.
        # See FLOC-3757.
        c = Clock()
        control_service = self.get_dropping_flocker_client_instance()
        cluster = self.make_cluster(control_service)
        target_rate = 10
        sample_size = 20
        s = WriteRequestLoadScenario(c,
                                     cluster,
                                     request_rate=target_rate,
                                     sample_size=sample_size)
        dropped_rate = target_rate / 2
        seconds_to_overload = s.max_outstanding / dropped_rate

        s.start()
        # Reach initial rate
        control_service.drop_requests = True
        # Initially, we generate enough dropped requests so that the scenario
        # is overloaded when we start monitoring.
        c.pump(repeat(1, seconds_to_overload + 1))
        # We stop dropping requests
        control_service.drop_requests = False
        # Now we generate the initial rate to start monitoring the scenario
        c.pump(repeat(1, sample_size))
        # We only need to advance one more second (first loop in the monitoring
        # loop) to trigger RequestOverload
        c.advance(1)

        failure = self.failureResultOf(s.maintained())
        self.assertIsInstance(failure.value, WRequestOverload)
    def test_delete_clb_retries_until_success(self):
        """
        Deleting a CLB will retry until the CLB is deleted (or in error or
        suspended mode, in which case it will give up).
        """
        self.clb_id = 12345

        success_treqs = [
            # All of these particular immutable states count as success.
            self.get_fake_treq_for_delete(
                Response(200, strbody=json.dumps(
                    {"loadBalancer": {"status": state}})),
                del_response=Response(400))
            for state in ("PENDING_DELETE", "DELETED", "ERROR", "SUSPENDED")
        ] + [
            # 404 from get-ting the server, meaning it's already gone.
            self.get_fake_treq_for_delete(
                Response(404, strbody=(
                    '{"message": "No such load balancer", "code": 404}')),
                del_response=Response(400))
        ]

        for success_treq in success_treqs:
            clock = Clock()
            _treq = self.get_fake_treq_for_delete(
                Response(
                    200,
                    strbody='{"loadBalancer": {"status": "PENDING_UPDATE"}}'),
                del_response=Response(400))

            clb = CloudLoadBalancer(pool=self.pool, treq=_treq)
            clb.clb_id = self.clb_id

            d = clb.delete(self.rcs, clock=clock)

            self.assertNoResult(d)
            clock.pump([3])
            self.assertNoResult(d)

            clb.treq = success_treq
            clock.pump([3])
            self.assertEqual(self.successResultOf(d), None)
Exemple #38
0
    def test_write_scenario_start_stop_start_succeeds(self, _logger):
        """
        ``write_request_load_scenario`` starts, stops and starts
        without collapsing.
        """
        c = Clock()
        cluster = self.make_cluster(self.get_fake_flocker_client_instance())
        sample_size = 5
        s = write_request_load_scenario(c, cluster, sample_size=sample_size)
        # Start and stop
        s.start()
        c.pump(repeat(1, sample_size))
        s.stop()

        # Start again and check it succeeds.
        d = s.start()
        c.pump(repeat(1, sample_size))
        s.maintained().addBoth(lambda x: self.fail())
        d.addCallback(lambda ignored: s.stop())
        self.successResultOf(d)
    def test_write_scenario_start_stop_start_succeeds(self, _logger):
        """
        ``write_request_load_scenario`` starts, stops and starts
        without collapsing.
        """
        c = Clock()
        cluster = self.make_cluster(self.get_fake_flocker_client_instance())
        sample_size = 5
        s = write_request_load_scenario(c, cluster, sample_size=sample_size)
        # Start and stop
        s.start()
        c.pump(repeat(1, sample_size))
        s.stop()

        # Start again and check it succeeds.
        d = s.start()
        c.pump(repeat(1, sample_size))
        s.maintained().addBoth(lambda x: self.fail())
        d.addCallback(lambda ignored: s.stop())
        self.successResultOf(d)
    def test_scenario_throws_exception_if_overloaded(self, __logger):
        """
        ``write_request_load_scenario`` raises ``RequestOverload`` if the
        difference between sent requests and received requests exceeds
        the tolerated difference once we start monitoring the scenario.

        Note that, right now, the only way to make it fail is to generate
        this difference before we start monitoring the scenario.
        Once we implement some kind of tolerance, to allow fluctuations
        in the rate, we can update this tests to trigger the exception
        in a more realistic manner.
        """
        # XXX Update this test when we add tolerance for rate fluctuations.
        # See FLOC-3757.
        c = Clock()
        control_service = self.get_dropping_flocker_client_instance()
        cluster = self.make_cluster(control_service)
        target_rate = 10
        sample_size = 20
        s = write_request_load_scenario(
            c, cluster, request_rate=target_rate, sample_size=sample_size
        )
        dropped_rate = target_rate / 2
        seconds_to_overload = s.max_outstanding / dropped_rate

        s.start()
        # Reach initial rate
        control_service.drop_requests = True
        # Initially, we generate enough dropped requests so that the scenario
        # is overloaded when we start monitoring.
        c.pump(repeat(1, seconds_to_overload+1))
        # We stop dropping requests
        control_service.drop_requests = False
        # Now we generate the initial rate to start monitoring the scenario
        c.pump(repeat(1, sample_size))
        # We only need to advance one more second (first loop in the monitoring
        # loop) to trigger RequestOverload
        c.advance(1)

        failure = self.failureResultOf(s.maintained())
        self.assertIsInstance(failure.value, RequestOverload)
Exemple #41
0
    def test_delete_clb_retries_until_success(self):
        """
        Deleting a CLB will retry until the CLB is deleted (or in error or
        suspended mode, in which case it will give up).
        """
        self.clb_id = 12345

        success_treqs = [
            # All of these particular immutable states count as success.
            self.get_fake_treq_for_delete(Response(
                200, strbody=json.dumps({"loadBalancer": {
                    "status": state
                }})),
                                          del_response=Response(400))
            for state in ("PENDING_DELETE", "DELETED", "ERROR", "SUSPENDED")
        ] + [
            # 404 from get-ting the server, meaning it's already gone.
            self.get_fake_treq_for_delete(Response(
                404,
                strbody=('{"message": "No such load balancer", "code": 404}')),
                                          del_response=Response(400))
        ]

        for success_treq in success_treqs:
            clock = Clock()
            _treq = self.get_fake_treq_for_delete(Response(
                200, strbody='{"loadBalancer": {"status": "PENDING_UPDATE"}}'),
                                                  del_response=Response(400))

            clb = CloudLoadBalancer(pool=self.pool, treq=_treq)
            clb.clb_id = self.clb_id

            d = clb.delete(self.rcs, clock=clock)

            self.assertNoResult(d)
            clock.pump([3])
            self.assertNoResult(d)

            clb.treq = success_treq
            clock.pump([3])
            self.assertEqual(self.successResultOf(d), None)
Exemple #42
0
    def test_glass_from_sand_on_wood_packets(self):
        """
        Crafting one glass, from one sand, using one wood, should generate
        some packets.
        """

        # Patch the clock.
        clock = Clock()
        self.tile.burning.clock = clock

        self.tile.inventory.fuel[0] = Slot(blocks['wood'].slot, 0, 1)
        self.tile.inventory.crafting[0] = Slot(blocks['sand'].slot, 0, 1)
        self.tile.changed(self.factory, coords)

        # Pump the clock. Burn time is 15s.
        clock.pump([0.5] * 30)

        self.assertEqual(len(self.protocol.write_packet_calls), 64)
        headers = [header[0] for header, params in self.protocol.write_packet_calls]
        self.assertEqual(headers.count('window-slot'), 3)
        self.assertEqual(headers.count('window-progress'), 61)
Exemple #43
0
    def test_glass_from_sand_on_wood_packets(self):
        """
        Crafting one glass, from one sand, using one wood, should generate
        some packets.
        """

        # Patch the clock.
        clock = Clock()
        self.tile.burning.clock = clock

        self.tile.inventory.fuel[0] = Slot(blocks['wood'].slot, 0, 1)
        self.tile.inventory.crafting[0] = Slot(blocks['sand'].slot, 0, 1)
        self.tile.changed(self.factory, coords)

        # Pump the clock. Burn time is 15s.
        clock.pump([0.5] * 30)

        self.assertEqual(len(self.protocol.write_packet_calls), 64)
        headers = [header[0] for header, params in self.protocol.write_packet_calls]
        self.assertEqual(headers.count('window-slot'), 3)
        self.assertEqual(headers.count('window-progress'), 61)
    def test_read_request_load_start_stop_start_succeeds(self, _logger):
        """
        ``read_request_load_scenario`` starts, stops and starts
        without collapsing.
        """
        c = Clock()

        node1 = Node(uuid=uuid4(), public_address=IPAddress('10.0.0.1'))
        node2 = Node(uuid=uuid4(), public_address=IPAddress('10.0.0.2'))
        cluster = BenchmarkCluster(
            node1.public_address,
            lambda reactor: FakeFlockerClient([node1, node2]),
            {node1.public_address, node2.public_address},
            default_volume_size=DEFAULT_VOLUME_SIZE)

        sample_size = 5
        s = read_request_load_scenario(c, cluster, sample_size=sample_size)
        # Start and stop
        s.start()
        c.pump(repeat(1, sample_size))
        s.stop()

        # Start again and verify the scenario succeeds
        d = s.start()
        c.pump(repeat(1, sample_size))
        s.maintained().addBoth(lambda x: self.fail())
        d.addCallback(lambda ignored: s.stop())
        c.pump(repeat(1, sample_size))
        self.successResultOf(d)
    def test_read_request_load_start_stop_start_succeeds(self, _logger):
        """
        ``read_request_load_scenario`` starts, stops and starts
        without collapsing.
        """
        c = Clock()

        node1 = Node(uuid=uuid4(), public_address=IPAddress('10.0.0.1'))
        node2 = Node(uuid=uuid4(), public_address=IPAddress('10.0.0.2'))
        cluster = BenchmarkCluster(
            node1.public_address,
            lambda reactor: FakeFlockerClient([node1, node2]),
            {node1.public_address, node2.public_address},
            default_volume_size=DEFAULT_VOLUME_SIZE
        )

        sample_size = 5
        s = read_request_load_scenario(c, cluster, sample_size=sample_size)
        # Start and stop
        s.start()
        c.pump(repeat(1, sample_size))
        s.stop()

        # Start again and verify the scenario succeeds
        d = s.start()
        c.pump(repeat(1, sample_size))
        s.maintained().addBoth(lambda x: self.fail())
        d.addCallback(lambda ignored: s.stop())
        c.pump(repeat(1, sample_size))
        self.successResultOf(d)
Exemple #46
0
    def test_scenario_timeouts_if_requests_not_completed(self):
        """
        `WriteRequestLoadScenario` should timeout if the outstanding
        requests for the scenarion do not complete within the specified
        time.
        """
        c = Clock()

        control_service = self.get_error_response_client(c)
        cluster = self.make_cluster(control_service)
        sample_size = 5
        s = WriteRequestLoadScenario(c,
                                     cluster,
                                     request_rate=10,
                                     sample_size=sample_size)

        # Set the delay for the requests to be longer than the scenario
        # timeout
        control_service.delay = s.timeout + 10

        d = s.start()
        s.maintained().addBoth(lambda x: self.fail())

        # Advance the clock by `sample_size` seconds to establish the
        # requested rate.
        c.pump(repeat(1, sample_size))

        control_service.fail_requests = True
        c.advance(1)
        control_service.fail_requests = False

        d.addCallback(lambda ignored: s.stop())

        # Advance the clock by the timeout value so it is triggered
        # before the requests complete.
        self.assertNoResult(d)
        c.advance(s.timeout + 1)
        self.assertTrue(s.rate_measurer.outstanding() > 0)
        self.successResultOf(d)
Exemple #47
0
    def test_scenario_stops_only_when_no_outstanding_requests(self):
        """
        `WriteRequestLoadScenario` should only be considered as stopped
        when all outstanding requests made by it have completed.
        """
        c = Clock()

        control_service = self.get_error_response_client(c)
        cluster = self.make_cluster(control_service)
        delay = 1

        control_service.delay = delay
        sample_size = 5
        s = WriteRequestLoadScenario(c,
                                     cluster,
                                     request_rate=10,
                                     sample_size=sample_size)

        d = s.start()
        s.maintained().addBoth(lambda x: self.fail())

        # Advance the clock by `sample_size` seconds to establish the
        # requested rate.
        c.pump(repeat(1, sample_size))

        # Force the control service to fail requests for one second.
        # These requests will fail after the delay period set in the
        # control service.
        control_service.fail_requests = True
        c.advance(1)
        control_service.fail_requests = False

        d.addCallback(lambda ignored: s.stop())

        # The scenario should not successfully stop until after the
        # delay period for the failed requests.
        self.assertNoResult(d)
        c.advance(delay)
        self.successResultOf(d)
Exemple #48
0
    def test_delete_clb_retries_until_timeout(self):
        """
        Deleting a CLB will retry if the state wonky until it times out.
        """
        clock = Clock()
        self.clb_id = 12345
        _treq = self.get_fake_treq_for_delete(Response(
            200, strbody='{"loadBalancer": {"status": "PENDING_UPDATE"}}'),
                                              del_response=Response(400))

        clb = CloudLoadBalancer(pool=self.pool, treq=_treq)
        clb.clb_id = self.clb_id
        d = clb.delete(self.rcs, clock=clock)
        self.assertNoResult(d)

        timeout = 60
        for _ in range((timeout - 1) / 3):
            clock.pump([3])
            self.assertNoResult(d)

        clock.pump([3])
        self.failureResultOf(d, TimedOutError)
    def test_scenario_stops_only_when_no_outstanding_requests(self):
        """
        `WriteRequestLoadScenario` should only be considered as stopped
        when all outstanding requests made by it have completed.
        """
        c = Clock()

        control_service = self.get_error_response_client(c)
        cluster = self.make_cluster(control_service)
        delay = 1

        control_service.delay = delay
        sample_size = 5
        s = WriteRequestLoadScenario(
            c, cluster, request_rate=10, sample_size=sample_size
        )

        d = s.start()
        s.maintained().addBoth(lambda x: self.fail())

        # Advance the clock by `sample_size` seconds to establish the
        # requested rate.
        c.pump(repeat(1, sample_size))

        # Force the control service to fail requests for one second.
        # These requests will fail after the delay period set in the
        # control service.
        control_service.fail_requests = True
        c.advance(1)
        control_service.fail_requests = False

        d.addCallback(lambda ignored: s.stop())

        # The scenario should not successfully stop until after the
        # delay period for the failed requests.
        self.assertNoResult(d)
        c.advance(delay)
        self.successResultOf(d)
class RemoteOriginWriteOptionNegotiation(unittest.TestCase):

    port = 65466

    def setUp(self):
        self.clock = Clock()
        self.tmp_dir_path = tempfile.mkdtemp()
        self.target = FilePath(self.tmp_dir_path).child('foo')
        self.writer = DelayedWriter(self.target, _clock=self.clock, delay=2)
        self.transport = FakeTransport(hostAddress=('127.0.0.1', self.port))
        self.ws = RemoteOriginWriteSession(('127.0.0.1', 65465), self.writer,
                                           options={'blksize':'9'}, _clock=self.clock)
        self.ws.transport = self.transport

    def test_option_normal(self):
        self.ws.startProtocol()
        self.clock.advance(0.1)
        oack_datagram = OACKDatagram({'blksize':'9'}).to_wire()
        self.assertEqual(self.transport.value(), oack_datagram)
        self.clock.advance(3)
        self.assertEqual(self.transport.value(), oack_datagram * 2)

        self.transport.clear()
        self.ws.datagramReceived(DATADatagram(1, 'foobarbaz').to_wire(), ('127.0.0.1', 65465))
        self.clock.pump((1,)*3)
        self.assertEqual(self.transport.value(), ACKDatagram(1).to_wire())
        self.assertEqual(self.ws.session.block_size, 9)

        self.transport.clear()
        self.ws.datagramReceived(DATADatagram(2, 'smthng').to_wire(), ('127.0.0.1', 65465))
        self.clock.pump((1,)*3)
        self.assertEqual(self.transport.value(), ACKDatagram(2).to_wire())
        self.clock.pump((1,)*10)
        self.writer.finish()
        self.assertEqual(self.writer.file_path.open('r').read(), 'foobarbazsmthng')
        self.failUnless(self.transport.disconnecting)

    def test_option_timeout(self):
        self.ws.startProtocol()
        self.clock.advance(0.1)
        oack_datagram = OACKDatagram({'blksize':'9'}).to_wire()
        self.assertEqual(self.transport.value(), oack_datagram)
        self.failIf(self.transport.disconnecting)

        self.clock.advance(3)
        self.assertEqual(self.transport.value(), oack_datagram * 2)
        self.failIf(self.transport.disconnecting)

        self.clock.advance(2)
        self.assertEqual(self.transport.value(), oack_datagram * 3)
        self.failIf(self.transport.disconnecting)

        self.clock.advance(2)
        self.assertEqual(self.transport.value(), oack_datagram * 3)
        self.failUnless(self.transport.disconnecting)

    def tearDown(self):
        shutil.rmtree(self.tmp_dir_path)
    def test_scenario_timeouts_if_requests_not_completed(self):
        """
        `WriteRequestLoadScenario` should timeout if the outstanding
        requests for the scenarion do not complete within the specified
        time.
        """
        c = Clock()

        control_service = self.get_error_response_client(c)
        cluster = self.make_cluster(control_service)
        sample_size = 5
        s = WriteRequestLoadScenario(
            c, cluster, request_rate=10, sample_size=sample_size
        )

        # Set the delay for the requests to be longer than the scenario
        # timeout
        control_service.delay = s.timeout + 10

        d = s.start()
        s.maintained().addBoth(lambda x: self.fail())

        # Advance the clock by `sample_size` seconds to establish the
        # requested rate.
        c.pump(repeat(1, sample_size))

        control_service.fail_requests = True
        c.advance(1)
        control_service.fail_requests = False

        d.addCallback(lambda ignored: s.stop())

        # Advance the clock by the timeout value so it is triggered
        # before the requests complete.
        self.assertNoResult(d)
        c.advance(s.timeout + 1)
        self.assertTrue(s.rate_measurer.outstanding() > 0)
        self.successResultOf(d)
Exemple #52
0
    def test_glass_from_sand_on_wood(self):
        """
        Crafting one glass, from one sand, using one wood, should take 15s.
        """

        # Patch the clock.
        clock = Clock()
        self.tile.burning.clock = clock

        self.tile.inventory.fuel[0] = Slot(blocks['wood'].slot, 0, 1)
        self.tile.inventory.crafting[0] = Slot(blocks['sand'].slot, 0, 1)
        self.tile.changed(self.factory, coords)

        # Pump the clock. Burn time is 15s.
        clock.pump([0.5] * 30)

        self.assertEqual(self.factory.world.chunk.states[0],
                         blocks["burning-furnace"].slot) # it was started...
        self.assertEqual(self.factory.world.chunk.states[1],
                         blocks["furnace"].slot) # ...and stopped at the end
        self.assertEqual(self.tile.inventory.fuel[0], None)
        self.assertEqual(self.tile.inventory.crafting[0], None)
        self.assertEqual(self.tile.inventory.crafted[0], (blocks['glass'].slot, 0, 1))
Exemple #53
0
    def test_glass_from_sand_on_wood(self):
        """
        Crafting one glass, from one sand, using one wood, should take 15s.
        """

        # Patch the clock.
        clock = Clock()
        self.tile.burning.clock = clock

        self.tile.inventory.fuel[0] = Slot(blocks['wood'].slot, 0, 1)
        self.tile.inventory.crafting[0] = Slot(blocks['sand'].slot, 0, 1)
        self.tile.changed(self.factory, coords)

        # Pump the clock. Burn time is 15s.
        clock.pump([0.5] * 30)

        self.assertEqual(self.factory.world.chunk.states[0],
                         blocks["burning-furnace"].slot) # it was started...
        self.assertEqual(self.factory.world.chunk.states[1],
                         blocks["furnace"].slot) # ...and stopped at the end
        self.assertEqual(self.tile.inventory.fuel[0], None)
        self.assertEqual(self.tile.inventory.crafting[0], None)
        self.assertEqual(self.tile.inventory.crafted[0], (blocks['glass'].slot, 0, 1))
Exemple #54
0
class TestElecraftProtocol(unittest.TestCase):
    """Test _ElecraftClientProtocol and _ElecraftRadio.
    
    This test uses those implementation classes rather than the public interface because the public interface is hardcoded to attempt to open a serial device."""
    
    def setUp(self):
        self.clock = Clock()
        self.tr = StringTransport()
        self.protocol = _ElecraftClientProtocol(reactor=self.clock)
        self.proxy = self.protocol._proxy()
        self.protocol.makeConnection(self.tr)
        self.protocol.connectionMade()
    
    def test_state_smoke(self):
        state_smoke_test(self.proxy)
    
    def test_initial_send(self):
        self.assertIn(b'AI2;', self.tr.value())
        self.assertIn(b'K31;', self.tr.value())
        self.assertIn(b'IF;', self.tr.value())
    
    def test_simple_receive(self):
        self.protocol.dataReceived(b'FA00000000012;')
        self.assertEqual(12.0, self.proxy.get_rx_main().state()['freq'].get())
    
    def test_continues_after_bad_data(self):
        self.protocol.dataReceived(b'\x00\x00;;FA00000000012;')
        self.assertEqual(12.0, self.proxy.get_rx_main().state()['freq'].get())
    
    def test_not_too_much_polling(self):
        self.tr.clear()
        self.assertEqual(b'', self.tr.value())
        self.clock.pump([0.01] * 150)
        self.assertEqual(b'FA;', self.tr.value())
        self.clock.pump([0.01] * 500)
        self.assertEqual(b'FA;FA;FA;FA;FA;FA;', self.tr.value())
    def test_delete_clb_retries_until_timeout(self):
        """
        Deleting a CLB will retry if the state wonky until it times out.
        """
        clock = Clock()
        self.clb_id = 12345
        _treq = self.get_fake_treq_for_delete(
            Response(
                200,
                strbody='{"loadBalancer": {"status": "PENDING_UPDATE"}}'),
            del_response=Response(400))

        clb = CloudLoadBalancer(pool=self.pool, treq=_treq)
        clb.clb_id = self.clb_id
        d = clb.delete(self.rcs, clock=clock)
        self.assertNoResult(d)

        timeout = 60
        for _ in range((timeout - 1) / 3):
            clock.pump([3])
            self.assertNoResult(d)

        clock.pump([3])
        self.failureResultOf(d, TimedOutError)
Exemple #56
0
    def test_glass_from_sand_on_wood_multiple_packets(self):
        """
        Crafting two glass, from two sand, using ten saplings, should make
        some packets.
        """

        # Patch the clock.
        clock = Clock()
        self.tile.burning.clock = clock

        self.tile.inventory.fuel[0] = Slot(blocks['sapling'].slot, 0, 10)
        self.tile.inventory.crafting[0] = Slot(blocks['sand'].slot, 0, 2)
        self.tile.changed(self.factory, coords)

        # Pump the clock. Burn time is 20s.
        clock.pump([0.5] * 40)

        self.assertEqual(len(self.protocol.write_packet_calls), 89)
        headers = [header[0] for header, params in self.protocol.write_packet_calls]
        # 4 updates for fuel slot (4 saplings burned)
        # 2 updates for crafting slot (2 sand blocks melted)
        # 2 updates for crafted slot (2 glass blocks crafted)
        self.assertEqual(headers.count('window-slot'), 8)
        self.assertEqual(headers.count('window-progress'), 81)
Exemple #57
0
    def test_glass_from_sand_on_wood_multiple_packets(self):
        """
        Crafting two glass, from two sand, using ten saplings, should make
        some packets.
        """

        # Patch the clock.
        clock = Clock()
        self.tile.burning.clock = clock

        self.tile.inventory.fuel[0] = Slot(blocks['sapling'].slot, 0, 10)
        self.tile.inventory.crafting[0] = Slot(blocks['sand'].slot, 0, 2)
        self.tile.changed(self.factory, coords)

        # Pump the clock. Burn time is 20s.
        clock.pump([0.5] * 40)

        self.assertEqual(len(self.protocol.write_packet_calls), 89)
        headers = [header[0] for header, params in self.protocol.write_packet_calls]
        # 4 updates for fuel slot (4 saplings burned)
        # 2 updates for crafting slot (2 sand blocks melted)
        # 2 updates for crafted slot (2 glass blocks crafted)
        self.assertEqual(headers.count('window-slot'), 8)
        self.assertEqual(headers.count('window-progress'), 81)
Exemple #58
0
class HeartbeatingClientsTests(SynchronousTestCase):
    """
    Tests for :obj:`HeartbeatingClients`
    """
    def setUp(self):
        self.clock = Clock()
        self.removed_clients = set()
        self.c = HeartbeatingClients(self.clock, 5, 1,
                                     self.removed_clients.add)

    def test_all(self):
        """
        Only clients that has not hearbeat will be removed. Others will remain
        """
        self.c.startService()
        self.c.heartbeat("c1")
        self.c.heartbeat("c2")
        self.clock.advance(1)
        self.c.heartbeat("c3")
        self.clock.pump([1] * 4)
        self.c.heartbeat("c3")
        self.clock.pump([1] * 2)
        self.assertNotIn("c1", self.c)
        self.assertNotIn("c2", self.c)
        self.assertEqual(self.removed_clients, set(["c1", "c2"]))

    def test_remove(self):
        """
        Client removed via `self.remove` is not checked anymore
        """
        self.c.startService()
        self.c.heartbeat("c1")
        self.c.heartbeat("c2")
        self.c.remove("c1")
        self.assertNotIn("c1", self.c)
        self.clock.pump([1] * 6)
        self.assertNotIn("c1", self.removed_clients)
class SchedTest:
    def tearDown(self):
        return IService(self.siteStore).stopService()


    def setUp(self):
        self.clock = Clock()

        scheduler = IScheduler(self.siteStore)
        self.stubTime(scheduler)
        IService(self.siteStore).startService()


    def now(self):
        return Time.fromPOSIXTimestamp(self.clock.seconds())


    def stubTime(self, scheduler):
        scheduler.callLater = self.clock.callLater
        scheduler.now = self.now


    def test_implementsSchedulerInterface(self):
        """
        Verify that IScheduler is declared as implemented.
        """
        self.failUnless(IScheduler.providedBy(IScheduler(self.store)))


    def test_scheduler(self):
        """
        Test that the ordering and timing of scheduled calls is correct.
        """
        # create 3 timed events.  the first one fires.  the second one fires,
        # then reschedules itself.  the third one should never fire because the
        # reactor is shut down first.  assert that the first and second fire
        # only once, and that the third never fires.
        s = self.store

        t1 = TestEvent(testCase=self,
                       name=u't1',
                       store=s, runAgain=None)
        t2 = TestEvent(testCase=self,
                       name=u't2',
                       store=s, runAgain=2)
        t3 = TestEvent(testCase=self,
                       name=u't3',
                       store=s, runAgain=None)

        now = self.now()
        self.ts = [t1, t2, t3]

        S = IScheduler(s)

        # Schedule them out of order to make sure behavior doesn't
        # depend on tasks arriving in soonest-to-latest order.
        S.schedule(t2, now + timedelta(seconds=3))
        S.schedule(t1, now + timedelta(seconds=1))
        S.schedule(t3, now + timedelta(seconds=100))

        self.clock.pump([2, 2, 2])
        self.assertEqual(t1.runCount, 1)
        self.assertEqual(t2.runCount, 2)
        self.assertEqual(t3.runCount, 0)


    def test_unscheduling(self):
        """
        Test the unscheduleFirst method of the scheduler.
        """
        sch = IScheduler(self.store)
        t1 = TestEvent(testCase=self, name=u't1', store=self.store)
        t2 = TestEvent(testCase=self, name=u't2', store=self.store, runAgain=None)

        sch.schedule(t1, self.now() + timedelta(seconds=1))
        sch.schedule(t2, self.now() + timedelta(seconds=2))
        sch.unscheduleFirst(t1)
        self.clock.advance(3)
        self.assertEquals(t1.runCount, 0)
        self.assertEquals(t2.runCount, 1)


    def test_inspection(self):
        """
        Test that the L{scheduledTimes} method returns an iterable of all the
        times at which a particular item is scheduled to run.
        """
        now = self.now() + timedelta(seconds=1)
        off = timedelta(seconds=3)
        sch = IScheduler(self.store)
        runnable = TestEvent(store=self.store, name=u'Only event')
        sch.schedule(runnable, now)
        sch.schedule(runnable, now + off)
        sch.schedule(runnable, now + off + off)

        self.assertEquals(
            list(sch.scheduledTimes(runnable)),
            [now, now + off, now + off + off])


    def test_scheduledTimesDuringRun(self):
        """
        L{Scheduler.scheduledTimes} should not include scheduled times that have
        already triggered.
        """
        futureTimes = []
        scheduler = IScheduler(self.store)
        runner = HookRunner(
            store=self.store,
            hook=lambda self: futureTimes.append(
                list(scheduler.scheduledTimes(self))))

        then = self.now() + timedelta(seconds=1)
        scheduler.schedule(runner, self.now())
        scheduler.schedule(runner, then)
        self.clock.advance(1)
        self.assertEquals(futureTimes, [[then], []])


    def test_deletedRunnable(self):
        """
        Verify that if a scheduled item is deleted,
        L{TimedEvent.invokeRunnable} just deletes the L{TimedEvent} without
        raising an exception.
        """
        now = self.now()
        scheduler = IScheduler(self.store)
        runnable = TestEvent(store=self.store, name=u'Only event')
        scheduler.schedule(runnable, now)

        runnable.deleteFromStore()

        # Invoke it manually to avoid timing complexity.
        timedEvent = self.store.findUnique(
            TimedEvent, TimedEvent.runnable == runnable)
        timedEvent.invokeRunnable()

        self.assertEqual(
            self.store.findUnique(
                TimedEvent,
                TimedEvent.runnable == runnable,
                default=None),
            None)