示例#1
0
class NonConcurrentlyTests(SynchronousTestCase):
    """Tests for :func:`non_concurrently`."""

    def setUp(self):
        self.locks = Reference(pset())

    def _get_locks(self):
        """Get the locks set."""
        return sync_perform(_get_dispatcher(), self.locks.read())

    def _add_lock(self, value):
        """Add an item to the locks set."""
        return sync_perform(_get_dispatcher(),
                            self.locks.modify(lambda cc: cc.add(value)))

    def test_success(self):
        """
        :func:`non_concurrently` returns the result of the passed effect, and
        adds the ``key`` to the ``locks`` while executing.
        """
        dispatcher = _get_dispatcher()

        def execute_stuff():
            self.assertEqual(self._get_locks(), pset(['the-key']))
            return 'foo'

        eff = Effect(Func(execute_stuff))

        non_c_eff = non_concurrently(self.locks, 'the-key', eff)
        self.assertEqual(sync_perform(dispatcher, non_c_eff), 'foo')
        # after the effect completes, its lock is released
        self.assertEqual(self._get_locks(), pset([]))

    def test_refuses_concurrency(self):
        """
        :func:`non_concurrently` raises :obj:`ConcurrentError` when the key is
        already locked.
        """
        self._add_lock('the-key')
        eff = Effect(Error(RuntimeError('foo')))
        non_c_eff = non_concurrently(self.locks, 'the-key', eff)
        self.assertRaises(
            ConcurrentError,
            sync_perform, _get_dispatcher(), non_c_eff)
        self.assertEqual(self._get_locks(), pset(['the-key']))

    def test_cleans_up_on_exception(self):
        """
        When the effect results in error, the key is still removed from the
        locked set.
        """
        dispatcher = _get_dispatcher()
        eff = Effect(Error(RuntimeError('foo!')))
        non_c_eff = non_concurrently(self.locks, 'the-key', eff)
        e = self.assertRaises(RuntimeError, sync_perform, dispatcher,
                              non_c_eff)
        self.assertEqual(str(e), 'foo!')
        self.assertEqual(self._get_locks(), pset([]))
示例#2
0
    def __init__(self,
                 log,
                 dispatcher,
                 num_buckets,
                 partitioner_factory,
                 build_timeout,
                 interval,
                 limited_retry_iterations,
                 step_limits,
                 converge_all_groups=converge_all_groups):
        """
        :param log: a bound log
        :param dispatcher: The dispatcher to use to perform effects.
        :param int buckets: the number of logical `buckets` which are be
            shared between all Otter nodes running this service. The buckets
            will be partitioned up between nodes to detirmine which nodes
            should work on which groups.
        :param partitioner_factory: Callable of (all_buckets, log, callback)
            which should create an :obj:`Partitioner` to distribute the
            buckets.
        :param number build_timeout: number of seconds to wait for servers to
            be in building before it's is timed out and deleted
        :param interval: Interval between convergence steps, per group.
        :param callable converge_all_groups: like :func:`converge_all_groups`,
            to be used for test injection only
        :param int limited_retry_iterations: number of iterations to wait for
            LIMITED_RETRY steps
        :param dict step_limits: Mapping of step name to number of executions
            allowed in a convergence cycle
        """
        MultiService.__init__(self)
        self.log = log.bind(otter_service='converger')
        self._dispatcher = dispatcher
        self._buckets = range(num_buckets)
        self.partitioner = partitioner_factory(
            buckets=self._buckets,
            log=self.log,
            got_buckets=self.buckets_acquired)
        self.partitioner.setServiceParent(self)
        self.build_timeout = build_timeout
        self._converge_all_groups = converge_all_groups
        self.interval = interval
        self.limited_retry_iterations = limited_retry_iterations
        self.step_limits = get_step_limits_from_conf(step_limits)

        # ephemeral mutable state
        self.currently_converging = Reference(pset())
        self.recently_converged = Reference(pmap())
        # Groups we're waiting on temporarily, and may give up on.
        self.waiting = Reference(pmap())  # {group_id: num_iterations_waited}
示例#3
0
def simple_intents():
    return [
        Authenticate(None, None, None),
        InvalidateToken(None, None),
        Request(method='GET', url='http://example.com/'),
        Retry(effect=Effect(Constant(None)), should_retry=lambda e: False),
        Delay(0),
        Constant(None),
        ReadReference(ref=Reference(None)),
    ]
示例#4
0
 def setUp(self):
     self.locks = Reference(pset())