Пример #1
0
 def test_nested_msg(self):
     """
     message is logged when nested inside other effects
     """
     eff = Effect(Constant("foo")).on(lambda _: msg("yo", a='b')).on(
         lambda _: Effect(Constant("goo")))
     self.assertEqual(sync_perform(self.disp, eff), "goo")
     self.log.msg.assert_called_once_with("yo", f1='v', a='b')
Пример #2
0
 def test_nested_err(self):
     """
     error is logged when nested inside other effects
     """
     f = object()
     eff = Effect(Constant("foo")).on(lambda _: err(f, "yo", a='b')).on(
         lambda _: Effect(Constant("goo")))
     self.assertEqual(sync_perform(self.disp, eff), "goo")
     self.log.err.assert_called_once_with(f, "yo", f1='v', a='b')
Пример #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 test_boundfields(self):
     """
     When an effect is wrapped `BoundFields` then any logging effect
     inside is performed with fields setup in `BoundFields`
     """
     f = object()
     eff = Effect(Constant("foo")).on(lambda _: err(f, "yo", a='b')).on(
         lambda _: msg("foo", m='d')).on(lambda _: Effect(Constant("goo")))
     eff = with_log(eff, bf='new')
     self.assertEqual(sync_perform(self.disp, eff), "goo")
     self.log.msg.assert_called_once_with("foo", f1='v', bf='new', m='d')
     self.log.err.assert_called_once_with(f, "yo", f1='v', bf='new', a='b')
Пример #5
0
    def should_retry(e):
        if time() >= end_time:
            return Effect(Constant(False))
        else:
            retry_delay = should_retry.wait_secs.total_seconds()
            effect = Effect(Delay(retry_delay)).on(
                success=lambda x: Effect(Constant(True)))

            if backoff:
                should_retry.wait_secs *= 2

            return effect
Пример #6
0
 async def test_parallel(self, dispatcher):
     """
     'parallel' results in a list of results of the given effects, in the
     same order that they were passed to parallel.
     """
     d = await asyncio_perform(
         dispatcher,
         parallel([
             Effect(Constant('a')),
             Effect(
                 Delay(0.01)).on(success=lambda _: Effect(Constant('...'))),
             Effect(Constant('b'))
         ]))
     assert d == ['a', '...', 'b']
Пример #7
0
 def test_nested_boundfields(self):
     """
     BoundFields effects can be nested and the log effects internally
     will expand with all bound fields
     """
     eff = Effect(Constant("foo")).on(lambda _: msg("foo", m='d')).on(
         lambda _: Effect(Constant("goo")))
     e = Effect(Constant("abc")).on(lambda _: with_log(eff, i='a')).on(
         lambda _: Effect(Constant("def")))
     self.assertEqual(sync_perform(self.disp, with_log(e, o='f')), "def")
     self.log.msg.assert_called_once_with('foo',
                                          i='a',
                                          f1='v',
                                          m='d',
                                          o='f')
Пример #8
0
def prefetch_github(owner, repo, prefetch=True, rev=None):
    if isinstance(rev, str) and is_sha1_hash(rev):
        actual_rev = rev
    else:
        list_remote = yield Effect(GetListRemote(owner=owner, repo=repo))
        if rev is None:
            actual_rev = list_remote.branch(list_remote.symref("HEAD"))
        else:
            actual_rev = (list_remote.full_ref_name(rev)
                          or list_remote.branch(rev)
                          or list_remote.tag(f"{rev}^{{}}")
                          or list_remote.tag(rev))
            if actual_rev is None:
                yield Effect(
                    AbortWithErrorMessage(
                        message=revision_not_found_errormessage(
                            owner=owner, repo=repo, revision=rev)))
                return

    calculated_hash = yield Effect(
        CalculateSha256Sum(owner=owner, repo=repo, revision=actual_rev))
    if not calculated_hash:
        raise click.ClickException(
            ("Internal Error: Calculate hash value for sources "
             "in github repo {owner}/{repo}.").format(owner=owner, repo=repo))
    if prefetch:
        yield Effect(
            TryPrefetch(owner=owner,
                        repo=repo,
                        sha256=calculated_hash,
                        rev=actual_rev))
    return Effect(Constant({"rev": actual_rev, "sha256": calculated_hash}))
Пример #9
0
 def test_acquire_timeout(self):
     """
     acquire_eff creates child node and keeps checking if it is smallest and
     eventually gives up by raising `LockTimeout`. It deletes child node
     before returning.
     """
     seq = [(Constant(None), noop),
            (zk.CreateNode("/testlock"), const("/testlock")),
            (Func(uuid.uuid4), const("prefix")),
            (zk.CreateNode("/testlock/prefix",
                           value="id",
                           ephemeral=True,
                           sequence=True),
             const("/testlock/prefix0000000001")),
            (GetChildren("/testlock"),
             const(["prefix0000000000", "prefix0000000001"])),
            (Func(time.time), const(0)), (Delay(0.1), noop),
            (GetChildren("/testlock"),
             const(["prefix0000000000", "prefix0000000001"])),
            (Func(time.time), const(0.12)), (Delay(0.1), noop),
            (GetChildren("/testlock"),
             const(["prefix0000000000", "prefix0000000001"])),
            (Func(time.time), const(0.4)),
            (DeleteNode(path="/testlock/prefix0000000001",
                        version=-1), noop)]
     self.assertRaises(LockTimeout, perform_sequence, seq,
                       self.lock.acquire_eff(True, 0.3))
Пример #10
0
def fold_effect(f, initial, effects):
    """
    Fold over the results of effects, left-to-right.

    This is like :func:`functools.reduce`, but instead of acting on plain
    values, it acts on the results of effects.

    The function ``f`` will be called with the accumulator (starting with
    ``initial``) and a result of an effect repeatedly for each effect. The
    result of the previous call will be passed as the accumulator to the next
    call.

    For example, the following code evaluates to an Effect of 6::

        fold_effect(operator.add, 0, [Effect(Constant(1)),
                                      Effect(Constant(2)),
                                      Effect(Constant(3))])

    If no elements were in the list, Effect would result in 0.

    :param callable f: function of ``(accumulator, element) -> accumulator``
    :param initial: The value to be passed as the accumulator to the first
        invocation of ``f``.
    :param effects: sequence of Effects.
    """

    def failed(acc, e):
        raise FoldError(acc, e)

    def folder(acc, element):
        return acc.on(
            lambda r: element.on(lambda r2: f(r, r2), error=lambda e: failed(r, e))
        )

    return reduce(folder, effects, Effect(Constant(initial)))
Пример #11
0
 def test_perform_retry(self):
     """
     When the specified effect is successful, its result is propagated.
     """
     retry = Retry(effect=Effect(Constant('foo')),
                   should_retry=lambda e: 1 / 0)
     result = sync_perform(self.dispatcher, Effect(retry))
     self.assertEqual(result, 'foo')
Пример #12
0
 def test_tenant_scope(self):
     """The :obj:`TenantScope` performer passes through to child effects."""
     # This is not testing much, but at least that it calls
     # perform_tenant_scope in a vaguely working manner. There are
     # more specific TenantScope performer tests in otter.test.test_http
     dispatcher = get_full_dispatcher(*([None] * 8))
     scope = TenantScope(Effect(Constant('foo')), 1)
     eff = Effect(scope)
     self.assertEqual(sync_perform(dispatcher, eff), 'foo')
Пример #13
0
 def test_immediate_success(self):
     """
     If the wrapped effect succeeds at first, no delay or retry is done and
     the retry effect's result is the wrapped effect's result.
     """
     effect = Effect(Constant(1000))
     retrier = retry_effect_with_timeout(effect, 10, time=self.get_time())
     result = perform_sequence([], retrier)
     self.assertEqual(result, 1000)
Пример #14
0
 def acquire_eff(self, blocking, timeout):
     assert (self._behavior.acquired is LockBehavior.NOT_STARTED
             or (not self._behavior.acquired))
     assert (blocking, timeout) == self._behavior.acquire_call[:2]
     ret = self._behavior.acquire_call[-1]
     if isinstance(ret, Exception):
         self._behavior.acquired = False
         return Effect(Error(ret))
     else:
         self._behavior.acquired = ret
         return Effect(Constant(ret))
Пример #15
0
    def test_perform_throttle(self):
        """
        The bracket given to :obj:`_Throttle` is used to call the nested
        performer.
        """
        def bracket(f, *args, **kwargs):
            return f(*args, **kwargs).addCallback(lambda r: ('bracketed', r))

        throttle = _Throttle(bracket=bracket, effect=Effect(Constant('foo')))
        dispatcher = ComposedDispatcher(
            [TypeDispatcher({_Throttle: _perform_throttle}), base_dispatcher])
        result = sync_perform(dispatcher, Effect(throttle))
        self.assertEqual(result, ('bracketed', 'foo'))
Пример #16
0
    def should_retry(exc_info):
        # This is the wrong time to compute end_time.  It's a lot simpler to do
        # this than to hook into the effect being wrapped and record the time
        # it starts to run.  Perhaps implementing that would be a nice thing to
        # do later.
        #
        # Anyway, make note of when we want to be finished if we haven't yet
        # done so.
        if State.end_time is None:
            State.end_time = time() + timeout

        if time() >= State.end_time:
            return Effect(Constant(False))
        else:
            retry_delay = State.wait_time.total_seconds()
            effect = Effect(Delay(retry_delay)).on(
                success=lambda x: Effect(Constant(True)))

            if backoff:
                State.wait_time *= 2

            return effect
Пример #17
0
 def test_uses_step_request(self):
     """Steps are converted to requests."""
     steps = [
         TestStep(Effect(Constant((StepResult.SUCCESS, 'foo')))),
         TestStep(Effect(Error(RuntimeError('uh oh'))))
     ]
     effect = steps_to_effect(steps)
     self.assertIs(type(effect.intent), ParallelEffects)
     expected_exc_info = matches(MatchesException(RuntimeError('uh oh')))
     self.assertEqual(
         sync_perform(test_dispatcher(), effect),
         [(StepResult.SUCCESS, 'foo'),
          (StepResult.RETRY, [ErrorReason.Exception(expected_exc_info)])])
Пример #18
0
 def test_perform_srvreq_nested(self):
     """
     Concretizing of :obj:`ServiceRequest` effects happens even when they
     are not directly passed as the TenantScope's toplevel Effect, but also
     when they are returned from callbacks down the line.
     """
     ereq = service_request(ServiceType.CLOUD_SERVERS, 'GET', 'servers')
     eff = Effect(Constant("foo")).on(lambda r: ereq)
     tscope = TenantScope(eff, 1)
     self.assertEqual(
         sync_perform(self.dispatcher, Effect(tscope)),
         ('concretized', self.authenticator, self.log, self.service_configs,
          self.throttler, 1, ereq.intent))
Пример #19
0
    def release_eff(self):
        """
        Effect implementation of ``release``.

        :return: ``Effect`` of ``None``
        """
        def reset_node(_):
            self._node = None

        if self._node is not None:
            return Effect(DeleteNode(path=self._node, version=-1)).on(
                success=reset_node, error=catch(NoNodeError, reset_node))
        else:
            return Effect(Constant(None))
Пример #20
0
 def test_acquire_success(self):
     """
     acquire_eff creates child and gets lock as it is the smallest one
     """
     seq = [(Constant(None), noop),
            (zk.CreateNode("/testlock"), conste(NodeExistsError())),
            (Func(uuid.uuid4), const("prefix")),
            (zk.CreateNode("/testlock/prefix",
                           value="id",
                           ephemeral=True,
                           sequence=True),
             const("/testlock/prefix0000000000")),
            (GetChildren("/testlock"), const(["prefix0000000000"]))]
     self.assertTrue(
         perform_sequence(seq, self.lock.acquire_eff(False, None)))
Пример #21
0
 def test_acquire_create_path_success(self):
     """
     acquire_eff creates provided path if it doesn't exist
     """
     seq = [(Constant(None), noop),
            (zk.CreateNode("/testlock"), const("/testlock")),
            (Func(uuid.uuid4), const("prefix")),
            (zk.CreateNode("/testlock/prefix",
                           value="id",
                           ephemeral=True,
                           sequence=True),
             const("/testlock/prefix0000000000")),
            (GetChildren("/testlock"), const(["prefix0000000000"]))]
     self.assertTrue(
         perform_sequence(seq, self.lock.acquire_eff(False, None)))
Пример #22
0
 def test_acquire_other_error(self):
     """
     If acquire_eff internally raises any error then it tries to delete
     child node before returning.
     """
     seq = [(Constant(None), noop),
            (zk.CreateNode("/testlock"), const("/testlock")),
            (Func(uuid.uuid4), const("prefix")),
            (zk.CreateNode("/testlock/prefix",
                           value="id",
                           ephemeral=True,
                           sequence=True),
             const("/testlock/prefix0000000001")),
            (GetChildren("/testlock"), conste(SessionExpiredError())),
            (DeleteNode(path="/testlock/prefix0000000001",
                        version=-1), conste(SessionExpiredError()))]
     self.assertRaises(SessionExpiredError, perform_sequence, seq,
                       self.lock.acquire_eff(True, 0.3))
Пример #23
0
 def test_acquire_nonblocking_fails(self):
     """
     acquire_eff creates child and returns False immediately after finding
     its not the smallest child when blocking=False. It deletes child node
     before returning.
     """
     seq = [(Constant(None), noop),
            (zk.CreateNode("/testlock"), const("/testlock")),
            (Func(uuid.uuid4), const("prefix")),
            (zk.CreateNode("/testlock/prefix",
                           value="id",
                           ephemeral=True,
                           sequence=True),
             const("/testlock/prefix0000000001")),
            (GetChildren("/testlock"),
             const(["prefix0000000000", "prefix0000000001"])),
            (DeleteNode(path="/testlock/prefix0000000001",
                        version=-1), noop)]
     self.assertFalse(
         perform_sequence(seq, self.lock.acquire_eff(False, None)))
Пример #24
0
 def test_acquire_blocking_success(self):
     """
     acquire_eff creates child, realizes its not the smallest. Tries again
     every 0.01 seconds until it succeeds
     """
     seq = [(Constant(None), noop),
            (zk.CreateNode("/testlock"), const("/testlock")),
            (Func(uuid.uuid4), const("prefix")),
            (zk.CreateNode("/testlock/prefix",
                           value="id",
                           ephemeral=True,
                           sequence=True),
             const("/testlock/prefix0000000001")),
            (GetChildren("/testlock"),
             const(["prefix0000000000", "prefix0000000001"])),
            (Func(time.time), const(0)), (Delay(0.1), noop),
            (GetChildren("/testlock"),
             const(["prefix0000000000", "prefix0000000001"])),
            (Func(time.time), const(0.2)), (Delay(0.1), noop),
            (GetChildren("/testlock"), const(["prefix0000000001"]))]
     self.assertTrue(perform_sequence(seq, self.lock.acquire_eff(True, 1)))
Пример #25
0
 def test_acquire_blocking_no_timeout(self):
     """
     When acquire_eff is called without timeout, it creates child, realizes
     its not the smallest, tries again every 0.1 seconds without checking
     time and succeeds if its the smallest node
     """
     seq = [(Constant(None), noop),
            (zk.CreateNode("/testlock"), const("/testlock")),
            (Func(uuid.uuid4), const("prefix")),
            (zk.CreateNode("/testlock/prefix",
                           value="id",
                           ephemeral=True,
                           sequence=True),
             const("/testlock/prefix0000000001")),
            (GetChildren("/testlock"),
             const(["prefix0000000000", "prefix0000000001"])),
            (Func(time.time), const(0)), (Delay(0.1), noop),
            (GetChildren("/testlock"),
             const(["prefix0000000000", "prefix0000000001"])),
            (Delay(0.1), noop),
            (GetChildren("/testlock"), const(["prefix0000000001"]))]
     self.assertTrue(
         perform_sequence(seq, self.lock.acquire_eff(True, None)))
Пример #26
0
 def Continue():
     return Effect(Constant(None))
Пример #27
0
 def as_effect(self):
     """Return an effect that always results in failure."""
     return Effect(Constant((StepResult.FAILURE, list(self.reasons))))
Пример #28
0
 def as_effect(self):
     """
     Return an effect that always results in retry
     """
     result = StepResult.LIMITED_RETRY if self.limited else StepResult.RETRY
     return Effect(Constant((result, list(self.reasons))))
Пример #29
0
 def should_retry(exc_info):
     exc_type, exc_value, exc_traceback = exc_info
     failure = Failure(exc_value, exc_type, exc_traceback)
     return Effect(Constant(
         actual_retry_intent.should_retry.can_retry(failure)))
Пример #30
0
 def _game(groups, log, _print=False):
     self.assertEqual(log, "log")
     return [Effect(Constant(None)), Effect(Constant(['foo']))]