예제 #1
0
class TestPanoptesPollingPluginRunner(unittest.TestCase):
    @patch('redis.StrictRedis', panoptes_mock_redis_strict_client)
    @patch('kazoo.client.KazooClient', panoptes_mock_kazoo_client)
    def setUp(self):

        self.my_dir, self.panoptes_test_conf_file = get_test_conf_file()
        self._panoptes_resource = PanoptesResource(
            resource_site="test",
            resource_class="test",
            resource_subclass="test",
            resource_type="test",
            resource_id="test",
            resource_endpoint="test",
            resource_creation_timestamp=_TIMESTAMP,
            resource_plugin="test")

        self._panoptes_context = PanoptesContext(
            self.panoptes_test_conf_file,
            key_value_store_class_list=[
                PanoptesTestKeyValueStore, PanoptesResourcesKeyValueStore,
                PanoptesPollingPluginKeyValueStore, PanoptesSecretsStore,
                PanoptesPollingPluginAgentKeyValueStore,
                PanoptesDiscoveryPluginAgentKeyValueStore,
                PanoptesDiscoveryPluginKeyValueStore
            ],
            create_message_producer=False,
            async_message_producer=False,
            create_zookeeper_client=True)
        self._runner_class = PanoptesPluginWithEnrichmentRunner

        self._log_capture = LogCapture(
            attributes=TestPanoptesPluginRunner.extract)

    def tearDown(self):
        self._log_capture.uninstall()

    def tearDown(self):
        self._log_capture.uninstall()

    @patch('yahoo_panoptes.framework.metrics.time')
    @patch(
        'yahoo_panoptes.framework.context.PanoptesContext._get_message_producer'
    )
    @patch('yahoo_panoptes.framework.context.PanoptesContext.message_producer',
           new_callable=PropertyMock)
    @patch(
        'yahoo_panoptes.polling.polling_plugin_agent.PanoptesPollingTaskContext'
    )
    @patch(
        'yahoo_panoptes.framework.resources.PanoptesResourceStore.get_resource'
    )
    def test_polling_plugin_agent(self, resource, panoptes_context,
                                  message_producer, message_producer_property,
                                  time):

        producer = MockPanoptesMessageProducer()
        time.return_value = 1
        message_producer.return_value = producer
        message_producer_property.return_value = producer
        resource.return_value = self._panoptes_resource
        panoptes_context.return_value = self._panoptes_context

        polling_plugin_task('Test Polling Plugin', 'polling')

        log_prefix = '[Test Polling Plugin] [plugin|test|site|test|class|test|' \
                     'subclass|test|type|test|id|test|endpoint|test]'

        self._log_capture.check_present(
            ('panoptes.tests.test_runner', 'INFO',
             'Attempting to execute plugin "Test Polling Plugin"'),
            ('panoptes.tests.test_runner', 'DEBUG',
             'Loaded plugin "Test Polling Plugin", '
             'version "0.1" of type "polling", category "polling"'),
            ('panoptes.tests.test_runner', 'DEBUG',
             'Loaded plugin "Test Polling Plugin 2", '
             'version "0.1" of type "polling", category "polling"'),
            ('panoptes.tests.test_runner', 'ERROR',
             'No enrichment data found on KV store for plugin Test'
             ' Polling Plugin resource test namespace test using key test'),
            ('panoptes.tests.test_runner', 'DEBUG',
             'Successfully created PanoptesEnrichmentCache enrichment_data '
             '{} for plugin Test Polling Plugin'),
            ('panoptes.tests.test_runner', 'DEBUG',
             'Attempting to get lock for plugin "Test Polling Plugin", '
             'with lock path and identifier in seconds'),
            ('panoptes.tests.test_runner', 'INFO',
             '{} Acquired lock'.format(log_prefix)),
            ('panoptes.tests.test_runner', 'INFO',
             '{} Plugin returned a result set with 1 members'.format(
                 log_prefix)),
            ('panoptes.tests.test_runner', 'INFO',
             '{} Callback function ran in seconds'.format(log_prefix)),
            ('panoptes.tests.test_runner', 'INFO',
             '{} Ran in seconds'.format(log_prefix)),
            ('panoptes.tests.test_runner', 'INFO',
             '{} Released lock'.format(log_prefix)),
            ('panoptes.tests.test_runner', 'INFO',
             '{} GC took seconds. There are garbage objects.'.format(
                 log_prefix)),
            ('panoptes.tests.test_runner', 'DEBUG',
             'Deleting module: yapsy_loaded_plugin_Test_Polling_Plugin'),
            ('panoptes.tests.test_runner', 'DEBUG',
             'Deleting module: yapsy_loaded_plugin_Test_Polling_Plugin'),
            ('panoptes.tests.test_runner', 'DEBUG', 'Deleting module: '
             'yapsy_loaded_plugin_Test_Polling_Plugin_Second_Instance'),
            order_matters=False)

        kafka_push_log = {
            "metrics_group_type":
            "Test",
            "metrics_group_interval":
            60,
            "metrics_group_creation_timestamp":
            1,
            "metrics_group_schema_version":
            "0.2",
            "resource": {
                "resource_site": "test",
                "resource_class": "test",
                "resource_subclass": "test",
                "resource_type": "test",
                "resource_id": "test",
                "resource_endpoint": "test",
                "resource_metadata": {
                    "_resource_ttl": "604800"
                },
                "resource_creation_timestamp": 1.0,
                "resource_plugin": "test"
            },
            "metrics": [{
                "metric_creation_timestamp": 1,
                "metric_name": "test",
                "metric_value": 0.0,
                "metric_type": "gauge"
            }],
            "dimensions": []
        }

        # Timestamps need to be removed to check Panoptes Metrics
        metric_groups_seen = 0
        for line in self._log_capture.actual():

            _, _, log = line

            if 'resource_creation_timestamp' in log:
                log = re.sub(r"resource_creation_timestamp\": \d+\.\d+,",
                             "resource_creation_timestamp\": 1.0,", log)
                resource_match = re.search(r'{.*}', log)

                if resource_match is not None:
                    self.assertEqual(
                        ordered(json.loads(resource_match.group(0))),
                        ordered(kafka_push_log))

            if log.startswith('Sent metric group'):
                metric_groups_seen += 1

            if log.startswith('Going to send metric group'):
                metric_groups_seen += 1

        self.assertEqual(metric_groups_seen, 2)
예제 #2
0
 def check_contain(log_capture: LogCapture, expected: tuple) -> bool:
     return expected in set(log_capture.actual())
예제 #3
0
class TestProcessPayments(CacheResetMixin, TestCase):
    """Test process_payments command."""
    def setUp(self):
        super().setUp()
        self.tempdir = TempDirectory()
        self.account = BankAccount(account_number='123456/7890',
                                   currency='CZK')
        self.account.save()
        payment = get_payment(identifier='PAYMENT_1',
                              account=self.account,
                              state=PaymentState.READY_TO_PROCESS)
        payment.save()
        self.log_handler = LogCapture(
            'django_pain.management.commands.process_payments',
            propagate=False)

    def tearDown(self):
        self.log_handler.uninstall()
        self.tempdir.cleanup()

    def _test_non_existing_account(self, param_name):
        """
        Test non existing account.

        param_name should contain either '--include-accounts' or '--exclude-accounts'
        """
        BankAccount.objects.create(account_number='987654/3210',
                                   currency='CZK')
        with override_settings(PAIN_PROCESS_PAYMENTS_LOCK_FILE=os.path.join(
                self.tempdir.path, 'test.lock')):
            out = StringIO()
            err = StringIO()
            with self.assertRaises(CommandError):
                call_command('process_payments',
                             param_name,
                             'xxxxxx/xxxx,yyyyyy/yyyy,987654/3210',
                             stdout=out,
                             stderr=err)

            self.assertEqual(out.getvalue(), '')
            self.assertEqual(err.getvalue(), '')
            self.log_handler.check(
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Command process_payments started.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Lock acquired.'),
                ('django_pain.management.commands.process_payments', 'ERROR',
                 'Following accounts do not exist: xxxxxx/xxxx, yyyyyy/yyyy. Terminating.'
                 ),
            )

    @override_settings(
        PAIN_PROCESSORS={
            'dummy':
            'django_pain.tests.commands.test_process_payments.DummyTruePaymentProcessor'
        })
    def test_payments_processed(self):
        """Test processed payments."""
        with override_settings(PAIN_PROCESS_PAYMENTS_LOCK_FILE=os.path.join(
                self.tempdir.path, 'test.lock')):
            call_command('process_payments')

            self.assertQuerysetEqual(BankPayment.objects.values_list(
                'identifier', 'account', 'state', 'processor'),
                                     [('PAYMENT_1', self.account.pk,
                                       PaymentState.PROCESSED, 'dummy')],
                                     transform=tuple,
                                     ordered=False)
            self.assertEqual(BankPayment.objects.first().objective,
                             'True objective')
            self.log_handler.check(
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Command process_payments started.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Lock acquired.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing 1 unprocessed payments.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing payments with processor dummy.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Marking 0 unprocessed payments as DEFERRED.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Command process_payments finished.'),
            )

    @override_settings(
        PAIN_PROCESSORS={
            'dummy':
            'django_pain.tests.commands.test_process_payments.DummyFalsePaymentProcessor'
        })
    def test_payments_deferred(self):
        """Test deferred payments."""
        with override_settings(PAIN_PROCESS_PAYMENTS_LOCK_FILE=os.path.join(
                self.tempdir.path, 'test.lock')):
            call_command('process_payments')

            self.assertQuerysetEqual(
                BankPayment.objects.values_list('identifier', 'account',
                                                'state', 'processor'),
                [('PAYMENT_1', self.account.pk, PaymentState.DEFERRED, '')],
                transform=tuple,
                ordered=False)
            self.assertEqual(BankPayment.objects.first().objective, '')
            self.log_handler.check(
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Command process_payments started.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Lock acquired.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing 1 unprocessed payments.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing payments with processor dummy.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Marking 1 unprocessed payments as DEFERRED.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Command process_payments finished.'),
            )

    @override_settings(
        PAIN_PROCESSORS={
            'dummy':
            'django_pain.tests.commands.test_process_payments.DummyTrueErrorPaymentProcessor'
        })
    def test_payments_processed_with_error(self):
        """Test processed payments with processing error."""
        with override_settings(PAIN_PROCESS_PAYMENTS_LOCK_FILE=os.path.join(
                self.tempdir.path, 'test.lock')):
            call_command('process_payments')

            self.assertQuerysetEqual(
                BankPayment.objects.values_list('identifier', 'account',
                                                'state', 'processor',
                                                'processing_error'),
                [('PAYMENT_1', self.account.pk, PaymentState.PROCESSED,
                  'dummy', PaymentProcessingError.DUPLICITY)],
                transform=tuple,
                ordered=False)
            self.assertEqual(BankPayment.objects.first().objective,
                             'Dummy objective')
            self.log_handler.check(
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Command process_payments started.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Lock acquired.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing 1 unprocessed payments.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing payments with processor dummy.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Marking 0 unprocessed payments as DEFERRED.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Command process_payments finished.'),
            )

    @override_settings(
        PAIN_PROCESSORS={
            'dummy':
            'django_pain.tests.commands.test_process_payments.DummyFalseErrorPaymentProcessor'
        })
    def test_payments_deferred_with_error(self):
        """Test deferred payments with processing error."""
        with override_settings(PAIN_PROCESS_PAYMENTS_LOCK_FILE=os.path.join(
                self.tempdir.path, 'test.lock')):
            call_command('process_payments')

            self.assertQuerysetEqual(
                BankPayment.objects.values_list('identifier', 'account',
                                                'state', 'processor',
                                                'processing_error'),
                [('PAYMENT_1', self.account.pk, PaymentState.DEFERRED, 'dummy',
                  PaymentProcessingError.DUPLICITY)],
                transform=tuple,
                ordered=False)
            self.assertEqual(BankPayment.objects.first().objective,
                             'Dummy objective')
            self.log_handler.check(
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Command process_payments started.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Lock acquired.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing 1 unprocessed payments.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing payments with processor dummy.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Saving payment %s as DEFERRED with error PaymentProcessingError.DUPLICITY.'
                 % BankPayment.objects.first().uuid),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Marking 0 unprocessed payments as DEFERRED.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Command process_payments finished.'),
            )

    @override_settings(PAIN_PROCESSORS=OrderedDict([
        ('dummy_false',
         'django_pain.tests.commands.test_process_payments.DummyFalsePaymentProcessor'
         ),
        ('dummy_true',
         'django_pain.tests.commands.test_process_payments.DummyTruePaymentProcessor'
         ),
    ]))
    def test_payments_from_to(self):
        """Test processed payments."""
        with override_settings(PAIN_PROCESS_PAYMENTS_LOCK_FILE=os.path.join(
                self.tempdir.path, 'test.lock')):
            call_command('process_payments', '--from', '2017-01-01 00:00',
                         '--to', '2017-01-02 00:00')

            self.assertQuerysetEqual(BankPayment.objects.values_list(
                'identifier', 'account', 'state', 'processor'),
                                     [('PAYMENT_1', self.account.pk,
                                       PaymentState.READY_TO_PROCESS, '')],
                                     transform=tuple,
                                     ordered=False)
            self.assertEqual(BankPayment.objects.first().objective, '')

    def test_invalid_date_raises_exception(self):
        with override_settings(PAIN_PROCESS_PAYMENTS_LOCK_FILE=os.path.join(
                self.tempdir.path, 'test.lock')):
            with self.assertRaises(CommandError):
                call_command('process_payments', '--from', '2017-01-32 00:00',
                             '--to', '2017-02-01 00:00')
            with self.assertRaises(CommandError):
                call_command('process_payments', '--from', 'not a date',
                             '--to', '2017-02-01 00:00')
            with self.assertRaises(CommandError):
                call_command('process_payments', '--from', '2017-01-01 00:00',
                             '--to', '2017-01-32 00:00')
            with self.assertRaises(CommandError):
                call_command('process_payments', '--from', '2017-01-01 00:00',
                             '--to', 'not a date')

    def test_lock(self):
        """Test process payments lock."""
        with override_settings(PAIN_PROCESS_PAYMENTS_LOCK_FILE=os.path.join(
                self.tempdir.path, 'test.lock')):
            lock = open(SETTINGS.process_payments_lock_file, 'a')
            fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)
            out = StringIO()
            err = StringIO()
            call_command('process_payments',
                         '--no-color',
                         stdout=out,
                         stderr=err)
            self.assertEqual(out.getvalue(), '')
            self.assertEqual(
                err.getvalue(),
                'Command process_payments is already running. Terminating.\n')
            self.assertQuerysetEqual(BankPayment.objects.values_list(
                'identifier', 'account', 'state', 'processor'),
                                     [('PAYMENT_1', self.account.pk,
                                       PaymentState.READY_TO_PROCESS, '')],
                                     transform=tuple,
                                     ordered=False)
            self.log_handler.check(
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Command process_payments started.'),
                ('django_pain.management.commands.process_payments', 'WARNING',
                 'Command already running. Terminating.'))

    def test_invalid_lock(self):
        """Test process payments with invalid lock file."""
        with override_settings(PAIN_PROCESS_PAYMENTS_LOCK_FILE=os.path.join(
                self.tempdir.path, 'test.lock')):
            os.mkdir(SETTINGS.process_payments_lock_file, mode=0o0)
            out = StringIO()
            err = StringIO()
            with self.assertRaisesRegexp(
                    CommandError,
                    r'^Error occured while opening lockfile .*/test.lock:.*Is a '
                    r'directory: .*\. Terminating\.$'):
                call_command('process_payments',
                             '--no-color',
                             stdout=out,
                             stderr=err)
            self.assertEqual(out.getvalue(), '')
            self.assertEqual(err.getvalue(), '')
            self.assertEqual(len(self.log_handler.actual()), 2)
            self.assertEqual(
                self.log_handler.actual()[0],
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Command process_payments started.'),
            )
            self.assertEqual(
                self.log_handler.actual()[1][:2],
                ('django_pain.management.commands.process_payments', 'ERROR'))
            self.assertRegex(
                self.log_handler.actual()[1][2],
                r'^Error occured while opening lockfile .*/test.lock:.*Is a directory.*Terminating\.$'
            )
            os.chmod(SETTINGS.process_payments_lock_file, 0o755)

    @override_settings(
        PAIN_PROCESSORS={
            'dummy':
            'django_pain.tests.commands.test_process_payments.DummyTruePaymentProcessor'
        })
    def test_exclusion_in_payment_processing(self):
        """Test excluding accounts from payment processing"""
        account2 = BankAccount(account_number='987654/3210', currency='CZK')
        account2.save()
        get_payment(identifier='PAYMENT_2',
                    account=self.account,
                    state=PaymentState.READY_TO_PROCESS).save()
        get_payment(identifier='PAYMENT_3',
                    account=account2,
                    state=PaymentState.READY_TO_PROCESS).save()
        with override_settings(PAIN_PROCESS_PAYMENTS_LOCK_FILE=os.path.join(
                self.tempdir.path, 'test.lock')):
            out = StringIO()
            err = StringIO()
            call_command('process_payments',
                         '--exclude-accounts',
                         '987654/3210',
                         stdout=out,
                         stderr=err)

            self.assertEqual(out.getvalue(), '')
            self.assertEqual(err.getvalue(), '')
            self.log_handler.check(
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Command process_payments started.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Lock acquired.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing 2 unprocessed payments.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing payments with processor dummy.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Marking 0 unprocessed payments as DEFERRED.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Command process_payments finished.'),
            )

    @override_settings(
        PAIN_PROCESSORS={
            'dummy':
            'django_pain.tests.commands.test_process_payments.DummyTruePaymentProcessor'
        })
    def test_exclusion_of_non_existing_account_in_payment_processing(self):
        """Test excluding non-existing accounts from payment processing"""
        self._test_non_existing_account('--exclude-accounts')

    @override_settings(
        PAIN_PROCESSORS={
            'dummy':
            'django_pain.tests.commands.test_process_payments.DummyTruePaymentProcessor'
        })
    def test_inclusion_in_payment_processing(self):
        """Test including accounts from payment processing"""
        account2 = BankAccount(account_number='987654/3210', currency='CZK')
        account2.save()
        get_payment(identifier='PAYMENT_2',
                    account=self.account,
                    state=PaymentState.READY_TO_PROCESS).save()
        get_payment(identifier='PAYMENT_3',
                    account=account2,
                    state=PaymentState.READY_TO_PROCESS).save()
        with override_settings(PAIN_PROCESS_PAYMENTS_LOCK_FILE=os.path.join(
                self.tempdir.path, 'test.lock')):
            out = StringIO()
            err = StringIO()
            call_command('process_payments',
                         '--include-accounts',
                         '123456/7890',
                         stdout=out,
                         stderr=err)

            self.assertEqual(out.getvalue(), '')
            self.assertEqual(err.getvalue(), '')
            self.log_handler.check(
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Command process_payments started.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Lock acquired.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing 2 unprocessed payments.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing payments with processor dummy.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Marking 0 unprocessed payments as DEFERRED.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Command process_payments finished.'),
            )

    @override_settings(
        PAIN_PROCESSORS={
            'dummy':
            'django_pain.tests.commands.test_process_payments.DummyTruePaymentProcessor'
        })
    def test_inclusion_of_non_existing_account_in_payment_processing(self):
        """Test including non-existing accounts from payment processing"""
        self._test_non_existing_account('--include-accounts')

    @override_settings(
        PAIN_PROCESSORS={
            'dummy':
            'django_pain.tests.commands.test_process_payments.DummyTruePaymentProcessor'
        })
    def test_card_payments_processed(self):
        get_payment(identifier='PAYMENT_2',
                    account=self.account,
                    state=PaymentState.READY_TO_PROCESS,
                    payment_type=PaymentType.CARD_PAYMENT,
                    counter_account_number='',
                    processor='dummy').save()
        get_payment(identifier='PAYMENT_3',
                    account=self.account,
                    state=PaymentState.READY_TO_PROCESS,
                    payment_type=PaymentType.CARD_PAYMENT,
                    counter_account_number='',
                    processor='dummy').save()
        with override_settings(PAIN_PROCESS_PAYMENTS_LOCK_FILE=os.path.join(
                self.tempdir.path, 'test.lock')):
            call_command('process_payments')
            self.assertQuerysetEqual(BankPayment.objects.values_list(
                'identifier', 'state',
                'processor'), [('PAYMENT_1', PaymentState.PROCESSED, 'dummy'),
                               ('PAYMENT_2', PaymentState.PROCESSED, 'dummy'),
                               ('PAYMENT_3', PaymentState.PROCESSED, 'dummy')],
                                     transform=tuple,
                                     ordered=False)
            self.assertEqual(BankPayment.objects.first().objective,
                             'True objective')
            self.log_handler.check(
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Command process_payments started.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Lock acquired.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing 3 unprocessed payments.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing card payments.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing card payments with processor dummy.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing payments with processor dummy.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Marking 0 unprocessed payments as DEFERRED.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Command process_payments finished.'),
            )

    @override_settings(PAIN_PROCESSORS=OrderedDict([
        ('dummy',
         'django_pain.tests.commands.test_process_payments.DummyTruePaymentProcessor'
         ),
        ('dummy_false',
         'django_pain.tests.commands.test_process_payments.DummyFalsePaymentProcessor'
         ),
    ]))
    def test_card_payments_unprocessed(self):
        get_payment(identifier='PAYMENT_2',
                    account=self.account,
                    state=PaymentState.READY_TO_PROCESS,
                    payment_type=PaymentType.CARD_PAYMENT,
                    counter_account_number='',
                    processor='dummy_false',
                    transaction_date=date(2018, 5, 10)).save()
        get_payment(identifier='PAYMENT_3',
                    account=self.account,
                    state=PaymentState.READY_TO_PROCESS,
                    payment_type=PaymentType.CARD_PAYMENT,
                    counter_account_number='',
                    processor='dummy',
                    transaction_date=date(2018, 5, 11)).save()
        with override_settings(PAIN_PROCESS_PAYMENTS_LOCK_FILE=os.path.join(
                self.tempdir.path, 'test.lock')):
            call_command('process_payments')
            self.assertQuerysetEqual(
                BankPayment.objects.values_list('identifier', 'state',
                                                'processor'),
                [('PAYMENT_1', PaymentState.PROCESSED, 'dummy'),
                 ('PAYMENT_2', PaymentState.DEFERRED, 'dummy_false'),
                 ('PAYMENT_3', PaymentState.PROCESSED, 'dummy')],
                transform=tuple,
                ordered=False)
            self.assertEqual(BankPayment.objects.first().objective,
                             'True objective')
            self.log_handler.check(
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Command process_payments started.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Lock acquired.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing 3 unprocessed payments.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing card payments.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing card payments with processor dummy.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing card payments with processor dummy_false.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Saving payment %s as DEFERRED with error None.' %
                 BankPayment.objects.get(identifier='PAYMENT_2').uuid),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing payments with processor dummy.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Marking 0 unprocessed payments as DEFERRED.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Command process_payments finished.'),
            )

    @override_settings(PAIN_PROCESSORS=OrderedDict([
        ('dummy',
         'django_pain.tests.commands.test_process_payments.DummyTruePaymentProcessor'
         ),
        ('dummy_error',
         'django_pain.tests.commands.test_process_payments.DummyFalseErrorPaymentProcessor'
         ),
    ]))
    def test_card_payments_defferred(self):
        get_payment(identifier='PAYMENT_2',
                    account=self.account,
                    state=PaymentState.READY_TO_PROCESS,
                    payment_type=PaymentType.CARD_PAYMENT,
                    counter_account_number='',
                    processor='dummy_error',
                    transaction_date=date(2018, 5, 10)).save()
        get_payment(identifier='PAYMENT_3',
                    account=self.account,
                    state=PaymentState.READY_TO_PROCESS,
                    payment_type=PaymentType.CARD_PAYMENT,
                    counter_account_number='',
                    processor='dummy',
                    transaction_date=date(2018, 5, 11)).save()
        with override_settings(PAIN_PROCESS_PAYMENTS_LOCK_FILE=os.path.join(
                self.tempdir.path, 'test.lock')):
            call_command('process_payments')
            self.assertQuerysetEqual(
                BankPayment.objects.values_list('identifier', 'state',
                                                'processor'),
                [('PAYMENT_1', PaymentState.PROCESSED, 'dummy'),
                 ('PAYMENT_2', PaymentState.DEFERRED, 'dummy_error'),
                 ('PAYMENT_3', PaymentState.PROCESSED, 'dummy')],
                transform=tuple,
                ordered=False)
            self.assertEqual(BankPayment.objects.first().objective,
                             'True objective')
            self.log_handler.check(
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Command process_payments started.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Lock acquired.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing 3 unprocessed payments.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing card payments.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing card payments with processor dummy.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing card payments with processor dummy_error.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Saving payment %s as DEFERRED with error PaymentProcessingError.DUPLICITY.'
                 % BankPayment.objects.get(identifier='PAYMENT_2').uuid),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Processing payments with processor dummy.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Marking 0 unprocessed payments as DEFERRED.'),
                ('django_pain.management.commands.process_payments', 'INFO',
                 'Command process_payments finished.'),
            )