def test_asynchronous_send_email_task(self, uwsgi):
        import mtp_common.tasks

        if b'send_email' not in spooler._registry:
            # other tests had already loaded the module and then cleared the registry
            importlib.reload(mtp_common.tasks)

        self.assertIn(b'send_email', spooler._registry)

        email_args = ('*****@*****.**', 'dummy-email.txt', '890')
        email_kwargs = dict(context={'abc': '321'}, html_template='dummy-email.html')
        job = {
            spooler.identifier: b'send_email',
            b'args': pickle.dumps(email_args),
            b'kwargs': pickle.dumps(email_kwargs),
        }

        # schedule call
        self.assertIsNone(mtp_common.tasks.send_email(*email_args, **email_kwargs))
        self.assertEqual(len(mail.outbox), 0)
        call_args, _ = uwsgi.spool.call_args
        self.assertDictEqual(call_args[0], job)

        # simulate call
        self.assertEqual(spooler(job), uwsgi.SPOOL_OK)
        self.assertEqual(len(mail.outbox), 1)
        email = mail.outbox[0]
        self.assertEqual(email.subject, '890')
        self.assertEqual(email.body, 'EMAIL-321')
        self.assertSequenceEqual(email.recipients(), ['*****@*****.**'])
    def test_asynchronous_precondition(self, uwsgi):
        state = {'runs': 0}

        @spoolable(pre_condition=True)
        def async_task(context: Context):
            self.assertTrue(context.spooled)
            state['runs'] += 1

        @spoolable(pre_condition=False)
        def sync_task(context: Context):
            self.assertFalse(context.spooled)
            state['runs'] += 1

        async_task()
        sync_task()
        self.assertEqual(len(uwsgi.spool.call_args_list), 1)
        spooler({spooler.identifier: b'async_task'})
        self.assertEqual(state['runs'], 2)
    def test_asynchronous_run(self, uwsgi):
        state = {'run': False}

        @spoolable()
        def func(a, b, context: Context):
            self.assertEqual(a, 1)
            self.assertEqual(b, 2)
            self.assertTrue(context.spooled)
            state['run'] = True
            return 321

        self.assertIsNone(func(1, 2), 'spooler tasks cannot return values')
        self.assertFalse(state['run'], 'spooler task ran synchronously')
        self.assertTrue(uwsgi.spool.called)
        # simulate spooler:
        self.assertEqual(spooler({
            spooler.identifier: b'func',
            b'args': pickle.dumps((1,)),
            b'kwargs': pickle.dumps({'b': 2}),
        }), uwsgi.SPOOL_OK)
        self.assertTrue(state['run'], 'spooler task did not run')
 def test_asynchronous_missing(self, uwsgi, logger):
     self.assertEqual(spooler({
         spooler.identifier: b'func',
     }), uwsgi.SPOOL_IGNORE)
     self.assertTrue(logger.error.called, True)
 def test_asynchronous_fallback(self, uwsgi, fallback):
     fallback.return_value = uwsgi.SPOOL_OK
     self.assertEqual(spooler({
         b'ud_spool_func': b'func',
     }), uwsgi.SPOOL_OK)
     self.assertTrue(fallback.called)