Ejemplo n.º 1
0
    def test_sequence(self):
        """Prove the sequence of events on a transaction-decorated method.

        We expect it to look like:
        lock
        get the wrapper if necessary
        invoke the method
        while the method raises etag error, refresh the wrapper and re-invoke
        unlock
        """
        txfx = self.useFixture(fx.WrapperTaskFx(self.dwrap))

        @tx.entry_transaction
        def blacklist_this(wrapper_or_getter):
            # Always converted by now
            self.assertIsInstance(wrapper_or_getter, ewrap.EntryWrapper)
            return self.retry_twice(wrapper_or_getter, self.tracker, txfx)

        # With an EntryWrapperGetter, get() is invoked
        self.assertEqual(self.dwrap, blacklist_this(self.getter))
        self.assertEqual([
            'lock', 'get', 'update 1', 'refresh', 'update 2', 'refresh',
            'update 3', 'unlock'
        ], txfx.get_log())

        # With an EntryWrapper, get() is not invoked
        self.tracker.counter = 0
        txfx.reset_log()
        self.assertEqual(self.dwrap, blacklist_this(self.dwrap))
        self.assertEqual([
            'lock', 'update 1', 'refresh', 'update 2', 'refresh', 'update 3',
            'unlock'
        ], txfx.get_log())
Ejemplo n.º 2
0
 def test_flag_update(self):
     """flag_update=False avoids update even if Subtask returns True."""
     txfx = self.useFixture(fx.WrapperTaskFx(self.dwrap))
     tx1 = tx.WrapperTask('tx1', self.getter)
     tx1.add_functor_subtask(lambda x: True, flag_update=False)
     tx1.execute()
     self.assertEqual(0, txfx.patchers['update'].mock.call_count)
     # But if there's another Subtask that returns True without
     # flag_update=False, it does trigger an update.
     tx1.add_functor_subtask(lambda x: True)
     tx1.execute()
     self.assertEqual(1, txfx.patchers['update'].mock.call_count)
Ejemplo n.º 3
0
    def test_logspec(self):
        txfx = self.useFixture(fx.WrapperTaskFx(self.dwrap))
        tx1 = tx.WrapperTask('tx1', self.getter)
        mock_log = mock.Mock()
        mock_log.side_effect = lambda *args: txfx.log('log')

        def functor(wrp):
            txfx.log('functor')

        # "False" logspec ignored
        tx1.add_functor_subtask(functor, logspec=[])
        # logspec must have at least two args
        self.assertRaises(ValueError,
                          tx1.add_functor_subtask,
                          functor,
                          logspec=[1])
        # First arg must be callable
        self.assertRaises(ValueError,
                          tx1.add_functor_subtask,
                          functor,
                          logspec=[1, 2])
        # Valid call with just a string
        tx1.add_functor_subtask(functor, logspec=[mock_log, "string"])
        # Valid call with a format string and args
        tx1.add_functor_subtask(functor,
                                logspec=[mock_log, "one %s two %s", 1, 2])
        # Valid call with named args
        tx1.add_functor_subtask(functor,
                                logspec=[
                                    mock_log, "three %(three)s four %(four)s",
                                    {
                                        'three': 3,
                                        'four': 4
                                    }
                                ])

        tx1.execute()
        self.assertEqual([
            'lock', 'get', 'functor', 'log', 'functor', 'log', 'functor',
            'log', 'functor', 'unlock'
        ], txfx.get_log())
        mock_log.assert_has_calls([
            mock.call("string"),
            mock.call("one %s two %s", 1, 2),
            mock.call("three %(three)s four %(four)s", {
                'three': 3,
                'four': 4
            })
        ])
Ejemplo n.º 4
0
    def test_wrapper_task2(self):
        # Now:
        # o Fake like update forces retry
        # o Test add_functor_subtask, including chaining
        # o Ensure GET is deferred when .wrapper() is not called ahead of time.
        # o Make sure subtask args are getting to the subtask.
        txfx = fx.WrapperTaskFx(self.dwrap)

        def _update_retries_twice(timeout=-1):
            self.assertEqual(123, timeout)
            return self.retry_twice(self.dwrap, self.tracker, txfx)

        txfx.patchers['update'].side_effect = _update_retries_twice

        self.useFixture(txfx)

        def functor(wrapper, arg1, arg2, kwarg3=None, kwarg4=None):
            txfx.log('functor')
            # Make sure args are getting here
            self.assertEqual(['arg', 1], arg1)
            self.assertEqual('arg2', arg2)
            self.assertIsNone(kwarg3)
            self.assertEqual('kwarg4', kwarg4)
            return wrapper, True

        # Instantiate-add-execute chain
        tx.WrapperTask(
            'tx2', self.getter,
            update_timeout=123).add_functor_subtask(functor, ['arg', 1],
                                                    'arg2',
                                                    kwarg4='kwarg4').execute()
        # Check the overall order.  Update should have been called thrice (two
        # retries)
        self.assertEqual(3, txfx.patchers['update'].mock.call_count)
        self.assertEqual([
            'lock', 'get', 'functor', 'update 1', 'refresh', 'functor',
            'update 2', 'refresh', 'functor', 'update 3', 'unlock'
        ], txfx.get_log())
Ejemplo n.º 5
0
    def test_subtask_provides(self):
        self.useFixture(fx.WrapperTaskFx(self.dwrap))
        test_case = self

        class ChainSubtask(tx.Subtask):
            def __init__(self, val, *args, **kwargs):
                self.val = val
                super(ChainSubtask, self).__init__(*args, **kwargs)

            def execute(self, *args, **kwargs):
                test_case.assertEqual(test_case.dwrap, args[0])
                # If execute accepts **kwargs, 'provided' is provided.
                test_case.assertIn('provided', kwargs)
                test_case.assertEqual(kwargs['expected_provided'],
                                      kwargs['provided'])
                return self.val

        class ChainSubtask2(tx.Subtask):
            def execute(self, wrp, provided, expected_provided):
                test_case.assertEqual(test_case.dwrap, wrp)
                # Able to get 'provided' as a named parameter
                test_case.assertEqual(expected_provided, provided)

        wtsk = tx.WrapperTask('name', self.getter)
        wtsk.add_subtask(ChainSubtask(1, provides='one', expected_provided={}))
        # Can't add another Subtask with the same 'provides'
        self.assertRaises(ValueError, wtsk.add_subtask,
                          ChainSubtask(2, provides='one'))
        # Next subtask should see the result from the first.
        wtsk.add_subtask(
            ChainSubtask(2, provides='two', expected_provided={'one': 1}))
        # Add one that doesn't provide.  Its return shouldn't show up in
        # 'provided'.
        wtsk.add_subtask(
            ChainSubtask(3, expected_provided={
                'one': 1,
                'two': 2
            }))
        # 'provided' works implicitly when it's a named parameter on execute
        wtsk.add_subtask(ChainSubtask2(expected_provided={'one': 1, 'two': 2}))
        # Even when execute doesn't return anything, we 'provide' that None
        wtsk.add_subtask(
            ChainSubtask2(provides='four',
                          expected_provided={
                              'one': 1,
                              'two': 2
                          }))

        # Make sure the same stuff works for functors
        def ret_val_kwargs(*args, **kwargs):
            self.assertEqual(self.dwrap, args[0])
            self.assertIn('provided', kwargs)
            self.assertEqual(kwargs['expected_provided'], kwargs['provided'])
            return args[1]

        def ret_val_explicit(wrp, val, provided, expected_provided):
            self.assertEqual(self.dwrap, wrp)
            self.assertEqual(expected_provided, provided)
            return val

        self.assertRaises(ValueError,
                          wtsk.add_functor_subtask,
                          int,
                          provides='one')
        wtsk.add_functor_subtask(ret_val_kwargs,
                                 5,
                                 provides='five',
                                 expected_provided={
                                     'one': 1,
                                     'two': 2,
                                     'four': None
                                 })
        wtsk.add_functor_subtask(ret_val_kwargs,
                                 6,
                                 expected_provided={
                                     'one': 1,
                                     'two': 2,
                                     'four': None,
                                     'five': 5
                                 })
        wtsk.add_functor_subtask(ret_val_explicit,
                                 7,
                                 provides='seven',
                                 expected_provided={
                                     'one': 1,
                                     'two': 2,
                                     'four': None,
                                     'five': 5
                                 })
        wtsk.add_functor_subtask(ret_val_explicit,
                                 8,
                                 expected_provided={
                                     'one': 1,
                                     'two': 2,
                                     'four': None,
                                     'five': 5,
                                     'seven': 7
                                 })

        # Execute the WrapperTask, verifying assertions in ChainSubtask[2] and
        # ret_val_{kwargs|explicit)
        wrapper, subtask_rets = wtsk.execute()
        self.assertEqual(self.dwrap, wrapper)
        # Verify final form of subtask_rets returned from WrapperTask.execute()
        self.assertEqual(
            {
                'one': 1,
                'two': 2,
                'four': None,
                'five': 5,
                'seven': 7
            }, subtask_rets)
Ejemplo n.º 6
0
    def test_wrapper_task1(self):
        txfx = self.useFixture(fx.WrapperTaskFx(self.dwrap))

        # Must supply a wrapper or getter to instantiate
        self.assertRaises(ValueError, tx.WrapperTask, 'foo', 'bar')

        # Create a valid WrapperTask
        tx1 = tx.WrapperTask('tx1', self.getter)
        self.assertEqual('tx1', tx1.name)
        self.assertIn('wrapper_getter_uuid', tx1.provides)
        self.assertIn('subtask_rets_getter_uuid', tx1.provides)
        # Nothing has been run yet
        self.assertEqual([], txfx.get_log())
        # Try running with no subtasks
        self.assertRaises(ex.WrapperTaskNoSubtasks, tx1.execute)
        # Try adding something that isn't a Subtask
        self.assertRaises(ValueError, tx1.add_subtask, 'Not a Subtask')
        # Error paths don't run anything.
        self.assertEqual([], txfx.get_log())

        # Add a subtask that doesn't change anything
        tx1.add_subtask(
            self.LparNameAndMem('z3-9-5-126-127-00000001', logger=txfx))
        # Adding a subtask does not run anything
        self.assertEqual([], txfx.get_log())

        # Get the wrapper - this should invoke GET, but *not* under lock
        self.assertEqual(self.dwrap, tx1.wrapper)
        self.assertEqual(['get'], txfx.get_log())

        # Run the transaction
        lwrap, subtask_rets = tx1.execute()
        # The name should be unchanged
        self.assertEqual('z3-9-5-126-127-00000001', lwrap.name)
        # And update should not have been called, which should be reflected in
        # the log.  Note that 'get' is NOT called a second time.
        self.assertEqual([
            'get', 'lock', 'LparNameAndMem_z3-9-5-126-127-00000001', 'unlock'
        ], txfx.get_log())
        self.assertEqual({}, subtask_rets)

        txfx.reset_log()
        # These subtasks do change the name.
        tx1.add_subtask(self.LparNameAndMem('new_name', logger=txfx))
        tx1.add_subtask(self.LparNameAndMem('newer_name', logger=txfx))
        # But this one doesn't.  We're making sure the last 'no update needed'
        # doesn't make the overall update_needed status False.
        tx1.add_subtask(self.LparNameAndMem('newer_name', logger=txfx))
        # Get the wrapper - this should *not* reinvoke GET
        self.assertEqual(self.dwrap, tx1.wrapper)
        self.assertEqual([], txfx.get_log())
        # Now execute the transaction
        lwrap, subtask_rets = tx1.execute()
        # The last change should be the one that stuck
        self.assertEqual('newer_name', lwrap.name)
        # Check the overall order.  Update was called.
        self.assertEqual([
            'lock', 'LparNameAndMem_z3-9-5-126-127-00000001',
            'LparNameAndMem_new_name', 'LparNameAndMem_newer_name',
            'LparNameAndMem_newer_name', 'update', 'unlock'
        ], txfx.get_log())
        self.assertEqual({}, subtask_rets)

        # Test 'cloning' the subtask list
        txfx.reset_log()
        tx2 = tx.WrapperTask('tx2', self.getter, subtasks=tx1.subtasks)
        # Add another one to make sure it goes at the end
        tx2.add_subtask(self.LparNameAndMem('newest_name', logger=txfx))
        # Add one to the original transaction to make sure it doesn't affect
        # this one.
        tx1.add_subtask(self.LparNameAndMem('bogus_name', logger=txfx))
        lwrap, subtask_rets = tx2.execute()
        # The last change should be the one that stuck
        self.assertEqual('newest_name', lwrap.name)
        # Check the overall order.  This one GETs under lock.  Update called.
        self.assertEqual([
            'lock', 'get', 'LparNameAndMem_z3-9-5-126-127-00000001',
            'LparNameAndMem_new_name', 'LparNameAndMem_newer_name',
            'LparNameAndMem_newer_name', 'LparNameAndMem_newest_name',
            'update', 'unlock'
        ], txfx.get_log())
        self.assertEqual({}, subtask_rets)