Example #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')
Example #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')
Example #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)),
    ]
Example #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')
Example #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
Example #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']
Example #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')
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}))
Example #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))
Example #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)))
Example #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')
Example #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')
Example #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)
Example #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))
Example #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'))
Example #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
Example #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)])])
Example #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))
Example #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))
Example #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)))
Example #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)))
Example #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))
Example #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)))
Example #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)))
Example #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)))
Example #26
0
 def Continue():
     return Effect(Constant(None))
Example #27
0
 def as_effect(self):
     """Return an effect that always results in failure."""
     return Effect(Constant((StepResult.FAILURE, list(self.reasons))))
Example #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))))
Example #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)))
Example #30
0
 def _game(groups, log, _print=False):
     self.assertEqual(log, "log")
     return [Effect(Constant(None)), Effect(Constant(['foo']))]