def test_should_mark_products_as_compatible_via_isbn(self):
        product = ProductFactory(id=1,
                                 extraData={"isbn": "ABCDEFG"},
                                 isGcuCompatible=False)
        product_1 = ProductFactory(id=2,
                                   extraData={"isbn": "HIJKLMN"},
                                   isGcuCompatible=False)
        product_2 = ProductFactory(id=3,
                                   extraData={"isbn": "VWXYZ"},
                                   isGcuCompatible=False)
        product_3 = ProductFactory(id=4,
                                   extraData={"isbn": "HFGDS"},
                                   isGcuCompatible=False)

        isbns_list = ["ABCDEFG", "HIJKLMN", "OPQRSTU", "HFGDS"]

        queries = 2  # update; commit

        with assert_num_queries(queries):
            bulk_update_is_gcu_compatible_via_isbns(isbns_list,
                                                    4,
                                                    is_compatible=True)

        assert product.isGcuCompatible
        assert product_1.isGcuCompatible
        assert not product_2.isGcuCompatible
        assert product_3.isGcuCompatible
コード例 #2
0
    def test_get_subcategories(self, app):
        with assert_num_queries(0):
            response = TestClient(
                app.test_client()).get("/native/v1/subcategories")

        assert response.status_code == 200
        assert list(response.json.keys()) == [
            "subcategories", "searchGroups", "homepageLabels"
        ]
        assert len(response.json["subcategories"]) == len(
            subcategories.ALL_SUBCATEGORIES)
        assert len(response.json["searchGroups"]) == len(
            subcategories.SearchGroups)
        assert len(response.json["homepageLabels"]) == len(
            subcategories.HomepageLabels)
        assert all(
            list(subcategory_dict.keys()) == [
                "id",
                "categoryId",
                "appLabel",
                "searchGroupName",
                "homepageLabelName",
                "isEvent",
                "onlineOfflinePlatform",
            ] for subcategory_dict in response.json["subcategories"])
        assert all(
            list(search_group_dict.keys()) == [
                "name",
                "value",
            ] for search_group_dict in response.json["searchGroups"])
        assert all(
            list(homepage_label_dict.keys()) == [
                "name",
                "value",
            ] for homepage_label_dict in response.json["homepageLabels"])
    def test_should_mark_offers_and_products_as_incompatible_via_isbn(
            self, mocked_unindex_offer_ids):
        # Given
        product = ProductFactory(id=1, extraData={"isbn": "ABCDEFG"})
        product_1 = ProductFactory(id=2, extraData={"isbn": "HIJKLMN"})
        product_2 = ProductFactory(id=3, extraData={"isbn": "VWXYZ"})
        product_3 = ProductFactory(id=4, extraData={"isbn": "HFGDS"})
        offer = OfferFactory(id=1, product=product)
        offer_1 = OfferFactory(id=2, product=product_1)
        offer_2 = OfferFactory(id=3, product=product_2)
        offer_3 = OfferFactory(id=4, product=product_3)

        isbns_list = ["ABCDEFG", "HIJKLMN", "OPQRSTU", "HFGDS"]

        queries = 1  # update product
        queries += 1  # select offer
        queries += 2  # update offer; commit
        queries *= 2  # two batches

        # When
        with assert_num_queries(queries):
            bulk_update_is_gcu_compatible_via_isbns(isbns_list,
                                                    2,
                                                    is_compatible=False)

        # Then
        assert not product.isGcuCompatible
        assert not product_1.isGcuCompatible
        assert product_2.isGcuCompatible
        assert not product_3.isGcuCompatible
        assert not offer.isActive
        assert not offer_1.isActive
        assert offer_2.isActive
        assert not offer_3.isActive
        mocked_unindex_offer_ids.assert_has_calls([call([1, 2]), call([4])])
コード例 #4
0
    def test_report_offer_with_custom_reason(self, app):
        user, test_client = create_user_and_test_client(app)
        offer = OfferFactory()

        # expected queries:
        #   * select offer
        #   * get user
        #   * insert report
        #   * release savepoint
        #
        #   * reload user
        #   * select offer
        #   * insert email into db
        #   * release savepoint
        with assert_num_queries(8):
            data = {"reason": "OTHER", "customReason": "saynul"}
            response = test_client.post(f"/native/v1/offer/{offer.id}/report",
                                        json=data)
            assert response.status_code == 204

        assert OfferReport.query.count() == 1
        report = OfferReport.query.first()

        assert report.user == user
        assert report.offer == offer

        assert len(mails_testing.outbox) == 1

        email = mails_testing.outbox[0]
        assert email.sent_data["To"] == "*****@*****.**"
        assert email.sent_data["Vars"]["user_id"] == user.id
        assert email.sent_data["Vars"]["offer_id"] == offer.id
        assert "saynul" in email.sent_data["Vars"]["reason"]
        assert "offer_url" in email.sent_data["Vars"]
コード例 #5
0
    def test_send_offer_link_notification(self, app):
        """
        Test that a push notification to the user is send with a link to the
        offer.
        """
        # offer.id must be used before the assert_num_queries context manager
        # because it triggers a SQL query.
        offer = OfferFactory()
        offer_id = offer.id

        user, test_client = create_user_and_test_client(app)

        # expected queries:
        #   * get user
        #   * get offer
        #   * get FeatureToggle WEBAPP_V2_ENABLED (to build URL)
        with assert_num_queries(3):
            response = test_client.post(
                f"/native/v1/send_offer_link_by_push/{offer_id}")
            assert response.status_code == 204

        assert len(notifications_testing.requests) == 1

        notification = notifications_testing.requests[0]
        assert notification["user_ids"] == [user.id]

        assert offer.name in notification["message"]["title"]
        assert "deeplink" in notification
コード例 #6
0
    def when_requested_booking_period_dates_are_iso_format(self, app):
        booking_date = datetime(2020, 8, 12, 20, 00, tzinfo=timezone.utc)
        booking_period_beginning_date_iso = "2020-08-10"
        booking_period_ending_date_iso = "2020-08-12"
        booking = bookings_factories.BookingFactory(dateCreated=booking_date, token="AAAAAA")
        bookings_factories.BookingFactory(token="BBBBBB")
        pro_user = users_factories.ProFactory(email="*****@*****.**")
        offers_factories.UserOffererFactory(user=pro_user, offerer=booking.offerer)

        client = TestClient(app.test_client()).with_session_auth(pro_user.email)
        with assert_num_queries(
            testing.AUTHENTICATION_QUERIES
            + 2
            + 1  # TODO: query for feature flag, to be removed when IMPROVE_BOOKINGS_PERF is definitely adopted
        ):
            response = client.get(
                "/bookings/pro?bookingPeriodBeginningDate=%s&bookingPeriodEndingDate=%s"
                % (booking_period_beginning_date_iso, booking_period_ending_date_iso)
            )

        assert response.status_code == 200
        assert len(response.json["bookings_recap"]) == 1
        assert response.json["bookings_recap"][0]["booking_date"] == datetime.isoformat(
            utc_datetime_to_department_timezone(booking.dateCreated, booking.venue.departementCode)
        )
        assert response.json["page"] == 1
        assert response.json["pages"] == 1
        assert response.json["total"] == 1
コード例 #7
0
    def test_cancel_booking(self):
        stock = offers_factories.StockFactory(offer__bookingEmail="*****@*****.**")
        booking = booking_factories.IndividualBookingFactory.create_batch(20, stock=stock)[0]

        queries = 1  # select booking
        queries += 1  # select stock for update
        queries += 1  # refresh booking
        queries += 3  # update stock ; update booking ; release savepoint
        queries += 8  # (update batch attributes): select booking ; individualBooking ; user ; user.bookings ; deposit ; user_offerer ; favorites ; stock
        queries += 1  # select offer
        queries += 2  # insert email ; release savepoint
        queries += 4  # (TODO: optimize) select booking ; stock ; offer ; user
        queries += 1  # select bookings of same stock with users joinedloaded to avoid N+1 requests
        queries += 2  # select venue ; offerer
        queries += 2  # insert email ; release savepoint
        with assert_num_queries(queries):
            api.cancel_booking_by_beneficiary(booking.individualBooking.user, booking)

        # cancellation can trigger more than one request to Batch
        assert len(push_testing.requests) >= 1

        assert booking.isCancelled
        assert booking.status is BookingStatus.CANCELLED
        assert booking.cancellationReason == BookingCancellationReasons.BENEFICIARY
        assert len(mails_testing.outbox) == 2
        email_data1 = mails_testing.outbox[0].sent_data
        assert email_data1["Mj-TemplateID"] == 1091464  # to beneficiary
        email_data2 = mails_testing.outbox[1].sent_data
        assert email_data2["MJ-TemplateID"] == 780015  # to offerer
コード例 #8
0
def test_get_user_attributes():
    user = BeneficiaryGrant18Factory(deposit__version=1)
    offer = OfferFactory(product__id=list(TRACKED_PRODUCT_IDS.keys())[0])
    b1 = IndividualBookingFactory(individualBooking__user=user,
                                  amount=10,
                                  stock__offer=offer)
    b2 = IndividualBookingFactory(individualBooking__user=user,
                                  amount=10,
                                  dateUsed=datetime(2021, 5, 6),
                                  stock__offer=offer)
    IndividualBookingFactory(
        individualBooking__user=user,
        amount=100,
        status=BookingStatus.CANCELLED)  # should be ignored

    last_date_created = max(booking.dateCreated for booking in [b1, b2])

    n_query_get_user = 1
    n_query_get_bookings = 1
    n_query_get_deposit = 1
    n_query_is_pro = 1
    n_query_get_last_favorite = 1

    with assert_num_queries(n_query_get_user + n_query_get_bookings +
                            n_query_get_deposit + n_query_is_pro +
                            n_query_get_last_favorite):
        attributes = get_user_attributes(user)

    assert attributes == UserAttributes(
        domains_credit=DomainsCredit(
            all=Credit(initial=Decimal("500"), remaining=Decimal("480.00")),
            digital=Credit(initial=Decimal("200"), remaining=Decimal("200")),
            physical=Credit(initial=200, remaining=Decimal("180.00")),
        ),
        booking_categories=["FILM"],
        date_created=user.dateCreated,
        date_of_birth=user.dateOfBirth,
        departement_code="75",
        deposit_expiration_date=user.deposit_expiration_date,
        eligibility=EligibilityType.AGE18,
        first_name="Jeanne",
        is_beneficiary=True,
        is_pro=False,
        last_booking_date=last_date_created,
        last_name="Doux",
        marketing_push_subscription=True,
        postal_code=None,
        products_use_date={"product_brut_x_use": datetime(2021, 5, 6, 0, 0)},
        booking_count=2,
        booking_subcategories=["SUPPORT_PHYSIQUE_FILM"],
        deposit_activation_date=user.deposit_activation_date,
        has_completed_id_check=None,
        user_id=user.id,
        is_eligible=True,
        is_email_validated=True,
        last_favorite_creation_date=None,
        last_visit_date=None,
        marketing_email_subscription=True,
    )
コード例 #9
0
    def test_is_active_query_count_inside_request_context(self):
        feature = Feature.query.filter_by(
            name=FeatureToggle.WEBAPP_SIGNUP.name).first()
        feature.isActive = True
        repository.save(feature)

        with assert_num_queries(1):
            FeatureToggle.WEBAPP_SIGNUP.is_active()
            FeatureToggle.WEBAPP_SIGNUP.is_active()
            FeatureToggle.WEBAPP_SIGNUP.is_active()
コード例 #10
0
    def test_get_expired_offer(self, app):
        stock = EventStockFactory(beginningDatetime=datetime.utcnow() -
                                  timedelta(days=1))

        offer_id = stock.offer.id
        with assert_num_queries(1):
            response = TestClient(
                app.test_client()).get(f"/native/v1/offer/{offer_id}")

        assert response.json["isExpired"]
コード例 #11
0
def test_update_external_pro_user():
    user = ProFactory()

    n_query_get_user = 1
    n_query_is_pro = 1

    with assert_num_queries(n_query_get_user + n_query_is_pro):
        update_external_user(user)

    assert len(batch_testing.requests) == 0
    assert len(sendinblue_testing.sendinblue_requests) == 1
コード例 #12
0
    def test_send_offer_webapp_link_by_email_not_found(self, app):
        _, test_client = create_user_and_test_client(app)

        # expected queries:
        #   * get User
        #   * try to find Offer
        with assert_num_queries(2):
            response = test_client.post(
                "/native/v1/send_offer_webapp_link_by_email/98765432123456789")
            assert response.status_code == 404
        assert not mails_testing.outbox
コード例 #13
0
    def test_report_offer_unknown_reason(self, app, client):
        offer = OfferFactory()
        offer_id = offer.id

        with assert_num_queries(0):
            data = {"reason": "UNKNOWN"}
            response = client.post(f"/native/v1/offer/{offer_id}/report",
                                   json=data)
            assert response.status_code == 400
            assert response.json["reason"] == ["unknown reason"]

        assert OfferReport.query.count() == 0  # no new report
        assert not mails_testing.outbox
コード例 #14
0
    def test_send_offer_link_notification_not_found(self, app):
        """Test that no push notification is sent when offer is not found"""
        _, test_client = create_user_and_test_client(app)

        # expected queries:
        #   * get user
        #   * search for offer
        with assert_num_queries(2):
            response = test_client.post(
                "/native/v1/send_offer_link_by_push/9999999999")
            assert response.status_code == 404

        assert len(notifications_testing.requests) == 0
コード例 #15
0
 def test_check_user_has_access_to_offerer(self, app):
     pro = users_factories.UserFactory()
     offerer = offers_factories.OffererFactory()
     offers_factories.UserOffererFactory(user=pro, offerer=offerer)
     # fmt: off
     n_queries = (
         1  # select Offerer
         + 1  # select User
         + 1  # select UserOfferer
     )
     # fmt: on
     with assert_num_queries(n_queries):
         check_user_has_access_to_offerer(pro, offerer.id)
コード例 #16
0
    def test_list_beneficiaries(self, mocked_validate_csrf_token, app):
        users_factories.AdminFactory(email="*****@*****.**")
        users_factories.BeneficiaryGrant18Factory.create_batch(3)

        client = TestClient(
            app.test_client()).with_session_auth("*****@*****.**")
        n_queries = testing.AUTHENTICATION_QUERIES
        n_queries += 1  # select COUNT
        n_queries += 1  # select users
        with testing.assert_num_queries(n_queries):
            response = client.get("/pc/back-office/beneficiary_users")

        assert response.status_code == 200
コード例 #17
0
    def test_no_modifications(self, app) -> None:
        # given
        venue = offers_factories.VenueFactory()

        # when
        venue_data = {
            "departementCode": venue.departementCode,
            "city": venue.city,
            "motorDisabilityCompliant": venue.motorDisabilityCompliant,
        }

        # nothing has changed => nothing to save nor update
        with assert_num_queries(0):
            offerers_api.update_venue(venue, **venue_data)
コード例 #18
0
    def test_records_new_payment_lines_in_database(self):
        # Given
        cutoff = datetime.datetime.now()
        before_cutoff = cutoff - datetime.timedelta(days=1)

        beneficiary = users_factories.BeneficiaryGrant18Factory(
            email="*****@*****.**")
        offerer = offers_factories.OffererFactory()
        offer = offers_factories.ThingOfferFactory(
            venue__managingOfferer=offerer)
        paying_stock = offers_factories.ThingStockFactory(offer=offer)
        free_stock = offers_factories.ThingStockFactory(offer=offer, price=0)
        bookings_factories.UsedBookingFactory(user=beneficiary,
                                              stock=paying_stock,
                                              dateUsed=before_cutoff)
        bookings_factories.UsedBookingFactory(user=beneficiary,
                                              stock=paying_stock,
                                              dateUsed=before_cutoff)
        bookings_factories.UsedBookingFactory(user=beneficiary,
                                              stock=free_stock,
                                              dateUsed=before_cutoff)
        bookings_factories.UsedBookingFactory(user=beneficiary,
                                              stock=free_stock,
                                              dateUsed=before_cutoff)
        bookings_factories.UsedBookingFactory(user=beneficiary,
                                              stock=paying_stock,
                                              dateUsed=cutoff)

        payment_message = payments_factories.PaymentMessageFactory(
            name="ABCD123")
        payments_factories.PaymentFactory(paymentMessage=payment_message)

        initial_payment_count = Payment.query.count()

        # When
        n_queries = 1  # get_venue_ids_to_reimburse()
        n_queries += 1  # fetch custom reimbursement rules
        n_queries += 1  # find_bookings_eligible_for_payment_for_venue()
        n_queries += 1  # insert payments
        n_queries += 1  # release savepoint (commit)
        n_queries += 1  # insert PENDING payment statuses
        n_queries += 1  # release savepoint (commit)
        n_queries += 1  # insert NOT_PROCESSABLE payment statuses
        n_queries += 1  # release savepoint (commit)
        with assert_num_queries(n_queries):
            generate_new_payments(cutoff, batch_date=datetime.datetime.now())

        # Then
        assert Payment.query.count() - initial_payment_count == 2
コード例 #19
0
    def test_report_offer_custom_reason_too_long(self, app, client):
        offer = OfferFactory()
        offer_id = offer.id

        with assert_num_queries(0):
            data = {"reason": "OTHER", "customReason": "a" * 513}
            response = client.post(f"/native/v1/offer/{offer_id}/report",
                                   json=data)
            assert response.status_code == 400
            assert response.json["customReason"] == [
                "custom reason is too long"
            ]

        assert OfferReport.query.count() == 0  # no new report
        assert not mails_testing.outbox
コード例 #20
0
    def test_is_active_query_count_outside_request_context(self, app):
        feature = Feature.query.filter_by(
            name=FeatureToggle.WEBAPP_SIGNUP.name).first()
        feature.isActive = True
        repository.save(feature)
        context = flask._request_ctx_stack.pop()

        # we don't cache yet outside the scope of a request so it'll be 3 DB queries
        try:
            with assert_num_queries(3):
                FeatureToggle.WEBAPP_SIGNUP.is_active()
                FeatureToggle.WEBAPP_SIGNUP.is_active()
                FeatureToggle.WEBAPP_SIGNUP.is_active()

        finally:
            flask._request_ctx_stack.push(context)
コード例 #21
0
def test_update_external_user():
    user = BeneficiaryGrant18Factory()
    IndividualBookingFactory(individualBooking__user=user)

    n_query_get_user = 1
    n_query_get_bookings = 1
    n_query_get_deposit = 1
    n_query_is_pro = 1
    n_query_get_last_favorite = 1

    with assert_num_queries(n_query_get_user + n_query_get_bookings +
                            n_query_get_deposit + n_query_is_pro +
                            n_query_get_last_favorite):
        update_external_user(user)

    assert len(batch_testing.requests) == 1
    assert len(sendinblue_testing.sendinblue_requests) == 1
コード例 #22
0
def test_check_number_of_sql_queries():
    offer = offers_factories.OfferFactory()
    # FIXME (dbaty, 2021-07-05): we should put these `joinedload` in a
    # function, and call that function from `_reindex_offer_ids()`
    # where we fetch offers.
    offer = (offers_models.Offer.query.options(
        joinedload(offers_models.Offer.venue).joinedload(
            offerers_models.Venue.managingOfferer)).options(
                joinedload(offers_models.Offer.criteria)).options(
                    joinedload(offers_models.Offer.mediations)).options(
                        joinedload(offers_models.Offer.product)).options(
                            joinedload(offers_models.Offer.stocks)).one())

    # Make sure that the JOINs above are enough to avoid any extra SQL
    # query below where serializing an offer.
    with assert_num_queries(0):
        appsearch.AppSearchBackend().serialize_offer(offer)
コード例 #23
0
    def test_get_digital_offer_without_available_activation_code(self, app):
        # given
        stock = StockWithActivationCodesFactory(
            activationCodes__expirationDate=datetime(2000, 1, 1))
        offer_id = stock.offer.id

        queries = 1  # select offer
        queries += 1  # get available_activation_code for each offer.stocks

        # when
        with assert_num_queries(2):
            response = TestClient(
                app.test_client()).get(f"/native/v1/offer/{offer_id}")

        # then
        assert response.status_code == 200
        assert response.json["stocks"][0]["activationCode"] is None
コード例 #24
0
    def test_queries_performance(self, app) -> None:
        now = datetime.utcnow()
        two_months_ago = now - timedelta(days=60)
        book = ProductFactory(type=str(offer_type.ThingType.LIVRE_EDITION))
        user = UserFactory()
        BookingFactory.create_batch(size=10,
                                    stock__offer__product=book,
                                    dateCreated=two_months_ago,
                                    user=user)
        n_queries = (
            1  # select count
            + 1  # select initial ids
            + 1  # release savepoint/COMMIT
            + 4 * 3  # update, release savepoint/COMMIT, select next ids
        )

        with assert_num_queries(n_queries):
            handle_expired_bookings.cancel_expired_bookings(batch_size=3)
コード例 #25
0
    def test_report_offer_twice(self, app):
        user, test_client = create_user_and_test_client(app)
        offer = OfferFactory()

        OfferReportFactory(user=user, offer=offer)

        # expected queries:
        #   * get user
        #   * get offer
        #   * rollback
        with assert_num_queries(3):
            response = test_client.post(f"/native/v1/offer/{offer.id}/report",
                                        json={"reason": "PRICE_TOO_HIGH"})
            assert response.status_code == 400
            assert response.json["code"] == "OFFER_ALREADY_REPORTED"

        assert OfferReport.query.count() == 1  # no new report
        assert not mails_testing.outbox
コード例 #26
0
    def test_send_offer_webapp_link_by_email(self, app):
        offer_id = OfferFactory().id
        user, test_client = create_user_and_test_client(app)

        # expected queries:
        #   * get User
        #   * find Offer
        #   * find FeatureToggle WEBAPP_V2_ENABLED (to build URL)
        #   * save email to DB (testing backend)
        #   * release savepoint after saving email
        with assert_num_queries(5):
            response = test_client.post(
                f"/native/v1/send_offer_webapp_link_by_email/{offer_id}")
            assert response.status_code == 204

        assert len(mails_testing.outbox) == 1

        mail = mails_testing.outbox[0]
        assert mail.sent_data["To"] == user.email
コード例 #27
0
    def test_get_thing_offer(self, app):
        product = ProductFactory(thumbCount=1,
                                 subcategoryId=subcategories.ABO_MUSEE.id)
        offer = OfferFactory(product=product,
                             isEducational=True,
                             venue__isPermanent=True)
        ThingStockFactory(offer=offer, price=12.34)

        offer_id = offer.id
        with assert_num_queries(1):
            response = TestClient(
                app.test_client()).get(f"/native/v1/offer/{offer_id}")

        assert response.status_code == 200
        assert not response.json["stocks"][0]["beginningDatetime"]
        assert response.json["stocks"][0]["price"] == 1234
        assert response.json["subcategoryId"] == "ABO_MUSEE"
        assert response.json["isEducational"]
        assert not response.json["isExpired"]
        assert response.json["venue"]["isPermanent"]
コード例 #28
0
    def test_queries_performance_educational_bookings(self, app) -> None:
        now = datetime.utcnow()
        yesterday = now - timedelta(days=1)
        booking_factories.PendingEducationalBookingFactory.create_batch(
            size=10, educationalBooking__confirmationLimitDate=yesterday)
        n_queries = (
            +1  # select count
            + 1  # select initial booking ids
            + 1  # release savepoint/COMMIT
            + 4 * (
                1  # update
                + 1  # release savepoint/COMMIT
                + 1  # select stock
                + 1  # recompute dnBookedQuantity
                + 1  # select next ids
            ))

        with assert_num_queries(n_queries):
            handle_expired_bookings.cancel_expired_educational_bookings(
                batch_size=3)
コード例 #29
0
    def test_queries_performance_individual_bookings(self, app) -> None:
        now = datetime.utcnow()
        two_months_ago = now - timedelta(days=60)
        book = ProductFactory(subcategoryId=subcategories.LIVRE_PAPIER.id)
        booking_factories.IndividualBookingFactory.create_batch(
            size=10, stock__offer__product=book, dateCreated=two_months_ago)
        n_queries = (
            +1  # select count
            + 1  # select initial booking ids
            + 1  # release savepoint/COMMIT
            + 4 * (
                1  # update
                + 1  # release savepoint/COMMIT
                + 1  # select stock
                + 1  # recompute dnBookedQuantity
                + 1  # select next ids
            ))

        with assert_num_queries(n_queries):
            handle_expired_bookings.cancel_expired_individual_bookings(
                batch_size=3)
コード例 #30
0
def test_admin_call_num_queries(app):

    admin_user = users_factories.AdminFactory(email="*****@*****.**")

    user_offerers = offers_factories.UserOffererFactory.create_batch(3)

    offers_factories.VenueFactory(managingOfferer=user_offerers[0].offerer)
    offers_factories.VenueFactory(managingOfferer=user_offerers[1].offerer)
    offers_factories.VenueFactory(managingOfferer=user_offerers[2].offerer)

    client = TestClient(app.test_client()).with_session_auth(admin_user.email)

    # when
    n_queries = testing.AUTHENTICATION_QUERIES
    n_queries += 1  # get venues + offerers
    with assert_num_queries(n_queries):
        response = client.get("/venues")

    # then
    assert response.status_code == 200
    assert len(response.json["venues"]) == 3