def test_composite_command_success(self):
        uc1 = UndoCommand(implementation=self.mocked_imp_succ,
                          var_context=self.mock_context,
                          id_=1)
        uc2 = UndoCommand(implementation=self.mocked_imp_succ,
                          var_context=self.mock_context,
                          id_=2)
        uc3 = UndoCommand(implementation=self.mocked_imp_succ,
                          var_context=self.mock_context,
                          id_=3)
        uc4 = UndoCommand(implementation=self.mocked_imp_succ,
                          var_context=self.mock_context,
                          id_=4)

        ccu1 = CompositeCommand({uc1: []}, stop_on_error=True)
        ccu2 = CompositeCommand({uc2: [uc3], uc3: [uc4]}, stop_on_error=True)

        c1 = Command(implementation=self.mocked_imp_succ,
                     var_context=self.mock_context,
                     undo_command=ccu1,
                     id_=5)
        c2 = Command(implementation=self.mocked_imp_succ,
                     var_context=self.mock_context,
                     undo_command=ccu2,
                     id_=6)

        cc = CompositeCommand({
            c1: [c2],
            c2: []
        },
                              stop_on_error=False,
                              stop_undo_on_error=False)

        res = cc.invoke()

        self.assertDictEqual(
            {
                5:
                CompletedProcess(success=True,
                                 stdout='stdout',
                                 stderr='stderr',
                                 rc=0,
                                 start_time=START,
                                 end_time=END),
                6:
                CompletedProcess(success=True,
                                 stdout='stdout',
                                 stderr='stderr',
                                 rc=0,
                                 start_time=START,
                                 end_time=END)
            }, cc.result)
        self.assertEqual(True, res)
        self.assertEqual(2, self.mocked_imp_succ.execute.call_count)
        self.assertEqual(0, self.mocked_imp_error.execute.call_count)
    def set_mocks(self, start=START, end=END):
        self.mocked_imp_succ = mock.Mock()
        self.mocked_imp_error = mock.Mock()

        self.mocked_imp_succ.execute.return_value = CompletedProcess(
            success=True,
            stdout='stdout',
            stderr='stderr',
            rc=0,
            start_time=start,
            end_time=end)

        self.mocked_imp_error.execute.return_value = CompletedProcess(
            success=False,
            stdout='stdout',
            stderr='stderr',
            rc=0,
            start_time=start,
            end_time=end)
    def test_check_output_variables(self):
        context = {}

        ic = UndoCommand(implementation=self.mocked_imp_succ,
                         var_context=context,
                         signature={'output': ['output', 'value']})
        ic._cp = CompletedProcess(True)

        ic.check_output_variables()

        self.assertFalse(ic._cp.success)
        self.assertEqual(f"Missing output values: output, value",
                         ic._cp.stderr)

        ic = UndoCommand(implementation=self.mocked_imp_succ,
                         var_context=context,
                         signature={"input": {}})
        ic._cp = CompletedProcess(True)

        ic.check_output_variables()

        self.assertTrue(ic._cp.success)
    def test_post_process(self):
        mock_context = mock.Mock()

        ic = UndoCommand(implementation=self.mocked_imp_succ,
                         var_context=mock_context,
                         post_process="vc.set('foo', 'bar')")
        ic.post_process()
        mock_context.set.assert_called_once_with('foo', 'bar')

        ic = UndoCommand(implementation=self.mocked_imp_succ,
                         var_context=mock_context,
                         post_process="raise KeyError('foo')")
        ic._cp = CompletedProcess()

        ic.post_process()
        self.assertFalse(ic._cp.success)
        self.assertIn("KeyError: 'foo'", ic._cp.stderr)
    def test_composite_command_error(self):
        uc1 = UndoCommand(implementation=self.mocked_imp_succ,
                          var_context=self.mock_context,
                          id_=1)
        uc2 = UndoCommand(implementation=self.mocked_imp_succ,
                          var_context=self.mock_context,
                          id_=2)
        uc3 = UndoCommand(implementation=self.mocked_imp_error,
                          var_context=self.mock_context,
                          id_=3)
        uc4 = UndoCommand(implementation=self.mocked_imp_succ,
                          var_context=self.mock_context,
                          id_=4)
        uc5 = UndoCommand(implementation=self.mocked_imp_succ,
                          var_context=self.mock_context,
                          id_=5)

        executor = ThreadPoolExecutor()
        ccu1 = CompositeCommand({uc1: []}, stop_on_error=True)
        ccu2 = CompositeCommand({uc2: [uc3, uc4]},
                                stop_on_error=True,
                                executor=executor)

        c6 = Command(implementation=self.mocked_imp_succ,
                     var_context=self.mock_context,
                     undo_command=ccu1,
                     id_=6)
        c7 = Command(implementation=self.mocked_imp_succ,
                     var_context=self.mock_context,
                     undo_command=ccu2,
                     id_=7)
        c8 = Command(implementation=self.mocked_imp_succ,
                     var_context=self.mock_context,
                     undo_command=uc5,
                     id_=8)

        cc = CompositeCommand({
            c6: [c7],
            c7: [c8]
        },
                              stop_on_error=False,
                              stop_undo_on_error=False,
                              executor=executor)

        res = cc.invoke()

        self.assertTrue(res)
        self.assertEqual(3, self.mocked_imp_succ.execute.call_count)
        self.assertEqual(0, self.mocked_imp_error.execute.call_count)

        res = cc.undo()

        self.assertFalse(res)
        self.assertEqual(7, self.mocked_imp_succ.execute.call_count)
        self.assertEqual(1, self.mocked_imp_error.execute.call_count)

        self.assertDictEqual(
            {
                1:
                CompletedProcess(success=True,
                                 stdout='stdout',
                                 stderr='stderr',
                                 rc=0,
                                 start_time=START,
                                 end_time=END),
                2:
                CompletedProcess(success=True,
                                 stdout='stdout',
                                 stderr='stderr',
                                 rc=0,
                                 start_time=START,
                                 end_time=END),
                3:
                CompletedProcess(success=False,
                                 stdout='stdout',
                                 stderr='stderr',
                                 rc=0,
                                 start_time=START,
                                 end_time=END),
                4:
                CompletedProcess(success=True,
                                 stdout='stdout',
                                 stderr='stderr',
                                 rc=0,
                                 start_time=START,
                                 end_time=END),
                5:
                CompletedProcess(success=True,
                                 stdout='stdout',
                                 stderr='stderr',
                                 rc=0,
                                 start_time=START,
                                 end_time=END),
                6:
                CompletedProcess(success=True,
                                 stdout='stdout',
                                 stderr='stderr',
                                 rc=0,
                                 start_time=START,
                                 end_time=END),
                7:
                CompletedProcess(success=True,
                                 stdout='stdout',
                                 stderr='stderr',
                                 rc=0,
                                 start_time=START,
                                 end_time=END),
                8:
                CompletedProcess(success=True,
                                 stdout='stdout',
                                 stderr='stderr',
                                 rc=0,
                                 start_time=START,
                                 end_time=END)
            }, cc.result)