Project

General

Profile

0001-lingo-poll-backend-during-asynchronous-rendering-577.patch

Benjamin Dauvergne, 14 Oct 2021 11:43 AM

Download (7.48 KB)

View differences:

Subject: [PATCH] lingo: poll backend during asynchronous rendering (#57790)

 combo/apps/lingo/models.py  | 30 ++++++++++++++++---------
 tests/conftest.py           | 12 +++++++++-
 tests/test_lingo_payment.py | 44 ++++++++++++++++++++++++++++++++-----
 3 files changed, 69 insertions(+), 17 deletions(-)
combo/apps/lingo/models.py
638 638
        ordering = ['regie', 'extra_fee', 'subject']
639 639

  
640 640
    @classmethod
641
    def get_items_to_be_paid(cls, user):
641
    def get_items_to_be_paid(cls, user, poll=False, raise_on_poll=False):
642 642
        qs = cls.objects.filter(
643 643
            user=user, payment_date__isnull=True, waiting_date__isnull=True, cancellation_date__isnull=True
644 644
        )
645
        for transaction in Transaction.objects.filter(items__in=qs):
646
            if transaction.can_poll_backend():
647
                transaction.poll_backend()
645
        if poll:
646
            for transaction in Transaction.objects.filter(items__in=qs):
647
                if transaction.can_poll_backend():
648
                    if raise_on_poll:
649
                        raise NothingInCacheException
650
                    transaction.poll_backend()
648 651
        return qs
649 652

  
650 653
    def notify(self, status):
......
1087 1090

  
1088 1091
    def render(self, context):
1089 1092
        basket_template = template.loader.get_template('lingo/combo/basket.html')
1090
        items = BasketItem.get_items_to_be_paid(context['request'].user)
1093
        items = BasketItem.get_items_to_be_paid(
1094
            context['request'].user, poll=True, raise_on_poll=not context.get('synchronous')
1095
        )
1091 1096
        regies = {}
1092 1097
        for item in items:
1093 1098
            if not item.regie_id in regies:
......
1112 1117
    def is_enabled(cls):
1113 1118
        return Regie.objects.exists()
1114 1119

  
1115
    def get_transactions_queryset(self, context):
1120
    def get_transactions_queryset(self, context, poll=False):
1116 1121
        user = context['request'].user
1117 1122
        # list transactions :
1118 1123
        # * paid by the user
......
1120 1125
        qs = Transaction.objects.filter(models.Q(user=user) | models.Q(items__user=user)).filter(
1121 1126
            start_date__gte=timezone.now() - datetime.timedelta(days=7)
1122 1127
        )
1123
        for transaction in qs:
1124
            if transaction.can_poll_backend() and transaction.is_running():
1125
                transaction.poll_backend()
1128
        if poll:
1129
            for transaction in qs:
1130
                if transaction.can_poll_backend() and transaction.is_running():
1131
                    if not context.get('synchronous'):
1132
                        raise NothingInCacheException
1133
                    transaction.poll_backend()
1126 1134
        return qs
1127 1135

  
1128 1136
    def is_relevant(self, context):
......
1132 1140

  
1133 1141
    def render(self, context):
1134 1142
        recent_transactions_template = template.loader.get_template('lingo/combo/recent_transactions.html')
1135
        context['transactions'] = self.get_transactions_queryset(context).distinct().order_by('-start_date')
1143
        context['transactions'] = (
1144
            self.get_transactions_queryset(context, poll=True).distinct().order_by('-start_date')
1145
        )
1136 1146
        return recent_transactions_template.render(context)
1137 1147

  
1138 1148

  
tests/conftest.py
70 70

  
71 71
@pytest.fixture
72 72
def synchronous_cells(settings):
73
    settings.COMBO_TEST_ALWAYS_RENDER_CELLS_SYNCHRONOUSLY = True
73
    class M:
74
        @staticmethod
75
        def on():
76
            settings.COMBO_TEST_ALWAYS_RENDER_CELLS_SYNCHRONOUSLY = True
77

  
78
        @staticmethod
79
        def off():
80
            settings.COMBO_TEST_ALWAYS_RENDER_CELLS_SYNCHRONOUSLY = False
81

  
82
    M.on()
83
    return M
tests/test_lingo_payment.py
2153 2153
            self,
2154 2154
            payment_status,
2155 2155
            app,
2156
            user,
2157
            synchronous_cells,
2156 2158
        ):
2157 2159
            # Try to pay
2158 2160
            pay_resp = app.get('/test_basket_cell/')
......
2171 2173
                order_id=transaction.order_id,
2172 2174
            )
2173 2175

  
2174
            # Try to pay again
2176
            # check get_items_to_be_paid() does not poll anymore
2177
            BasketItem.get_items_to_be_paid(user)
2178
            assert payment_status.call_count == 0
2179

  
2180
            # Try to pay again, only with current information
2181
            synchronous_cells.off()
2175 2182
            resp = app.get('/test_basket_cell/')
2176
            assert 'foo item' not in resp
2177
            assert 'Pay' not in resp
2178
            assert 'Running' in resp
2183
            assert 'Loading' in resp.pyquery('.lingo-basket-cell').text()
2184
            assert 'Loading' in resp.pyquery('.lingo-recent-transactions-cell').text()
2179 2185
            resp = pay_resp.click('Pay').follow()
2180 2186
            assert 'Some items are already paid or' in resp
2181
            assert 'foo item' not in resp
2182
            assert 'Running' in resp
2187
            assert len(resp.pyquery('.lingo-basket-cell')) == 0
2188
            assert 'Loading' in resp.pyquery('.lingo-recent-transactions-cell').text()
2189
            assert payment_status.call_count == 1  # pay made a call to payfip backend
2190
            payment_status.reset_mock()
2191

  
2192
            # Make rendering synchronous and retry
2193
            synchronous_cells.on()
2194
            resp = app.get('/test_basket_cell/')
2195
            assert len(resp.pyquery('.lingo-basket-cell')) == 0
2196
            assert 'Running' in resp.pyquery('.lingo-recent-transactions-cell').text()
2197
            assert payment_status.call_count == 1  # transactions cell polled
2198
            payment_status.reset_mock()
2199

  
2200
            resp = pay_resp.click('Pay')
2201
            assert payment_status.call_count == 1  # pay polled
2202
            payment_status.reset_mock()
2203

  
2204
            resp = resp.follow()
2205
            assert 'Some items are already paid or' in resp
2206
            assert len(resp.pyquery('.lingo-basket-cell')) == 0
2207
            assert 'Running' in resp.pyquery('.lingo-recent-transactions-cell').text()
2208
            assert payment_status.call_count == 1  # transactions cell polled
2209
            payment_status.reset_mock()
2183 2210

  
2184 2211
            # Simulate paid status on polling
2185 2212
            payment_status.return_value = eopayment.common.PaymentResponse(
......
2193 2220
            assert 'foo item: 42.00' in resp
2194 2221
            assert 'Pay' not in resp
2195 2222
            assert 'Running' not in resp
2223
            assert len(resp.pyquery('.lingo-basket-cell')) == 0
2224
            assert '42.00' in resp.pyquery('.lingo-recent-transactions-cell').text()
2225
            assert payment_status.call_count == 1  # transactions cell polled
2226
            payment_status.reset_mock()
2196 2227

  
2197 2228
        @mock.patch('eopayment.payfip_ws.Payment.payment_status')
2198 2229
        def test_exception_during_polling(
2199 2230
            self,
2200 2231
            payment_status,
2201 2232
            app,
2233
            synchronous_cells,
2202 2234
            caplog,
2203 2235
        ):
2204 2236
            # Try to pay
2205
-