Как написать модульный тест для гоночных условий для Django с использованием Python? - PullRequest
1 голос
/ 25 апреля 2019

Я реализовал API на основе инфраструктуры REST Django и Django и обнаружил, что у него возникли некоторые проблемы, когда он работает в условиях большого параллелизма.

Поэтому мне было интересно написать некоторый код тестирования для воспроизведения проблемы, иулучшите код, чтобы потом обеспечить его безопасность в потоке.

Я пробовал библиотеку before_after, и ее довольно сложно использовать, если занятая часть кода не является функцией или функцией, но содержитАргументы.

Я также пытался использовать ThreadPoolExecutor для генерации условия гонки, но оно вызывает django.db.utils.DatabaseError: DatabaseWrapper objects created in a thread can only be used in that same thread. The object with alias 'default' was created in thread id 4328317000 and this is thread id 4690485864.

Моя реализация выглядит так:

class TestOrderViewSet(APILiveServerTestCase, AuthRequestMixin):

    def test_replace_order_thread_safety(self):
        john_balance = self.john.wallet.balance
        jane_balance = self.jane.wallet.balance
        order_user_pairs = [(mommy.make_recipe('payments.tests.jane_order'), self.jane)]
        for i in range(10):
            order_user_pairs.append((mommy.make_recipe('payments.tests.jane_order'), self.jane))
            order_user_pairs.append((mommy.make_recipe('payments.tests.john_order'), self.john))
        random.shuffle(order_user_pairs)
        print(order_user_pairs)
        self.assertGreaterEqual(Order.objects.count(), 20)

        def replace_order(order, user, i):
            print(i, order.id)
            response = self.auth_post('order', {'pk': order.id}, user)
            print(i, user.wallet.balance)
            self.assertEqual(response.status_code, 200)
            user.wallet.refresh_from_db()
            print(i, user.wallet.balance)

        def count_done():
            return sum(int(r.done()) for r in results)

        with ThreadPoolExecutor(max_workers=4) as e:
            results = []
            for i in range(10):
                r = e.submit(replace_order, *order_user_pairs[i], i)
                results.append(r)
                r = e.submit(replace_order, *order_user_pairs[i], i)
                results.append(r)

            print('done', count_done())
        # e.shutdown(wait=True)
        print('done', count_done())

        self.john.wallet.refresh_from_db()
        self.jane.wallet.refresh_from_db()
        self.assertEqual(self.john.wallet.balance, john_balance + 1)
        self.assertEqual(self.jane.wallet.balance, jane_balance - 1)

Любые предложения приветствуются.Заранее спасибо.

...