From ed6a397b891cd3f67fa30e820457915120372184 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 19 Jan 2023 14:28:43 +0100 Subject: [PATCH] (test) test places cache --- .../api/slots_reservations_controller.rb | 2 +- app/models/slots_reservation.rb | 24 +++- app/services/slots/places_cache_service.rb | 2 +- test/fixtures/slots_reservations.yml | 2 + .../reservations/reserve_machine_test.rb | 10 +- .../reservations/reserve_space_test.rb | 10 +- .../reservations/reserve_training_test.rb | 10 +- .../reservations/space_seats_test.rb | 26 ++++- test/integration/slots_reservations_test.rb | 103 ++++++++++++++++++ 9 files changed, 176 insertions(+), 13 deletions(-) create mode 100644 test/integration/slots_reservations_test.rb diff --git a/app/controllers/api/slots_reservations_controller.rb b/app/controllers/api/slots_reservations_controller.rb index 0613ebab1..18a1534af 100644 --- a/app/controllers/api/slots_reservations_controller.rb +++ b/app/controllers/api/slots_reservations_controller.rb @@ -12,7 +12,7 @@ class API::SlotsReservationsController < API::ApiController authorize @slot_reservation if @slot_reservation.update(slot_params) SubscriptionExtensionAfterReservation.new(@slot_reservation.reservation).extend_subscription_if_eligible - render :show, status: :created, location: @slot_reservation + render :show, status: :ok, location: @slot_reservation else render json: @slot_reservation.errors, status: :unprocessable_entity end diff --git a/app/models/slots_reservation.rb b/app/models/slots_reservation.rb index 8e8d6f7e5..030eb55ff 100644 --- a/app/models/slots_reservation.rb +++ b/app/models/slots_reservation.rb @@ -10,6 +10,7 @@ class SlotsReservation < ApplicationRecord after_create :add_to_places_cache after_update :set_ex_start_end_dates_attrs, if: :slot_changed? after_update :notify_member_and_admin_slot_is_modified, if: :slot_changed? + after_update :switch_places_cache, if: :slot_changed? after_update :notify_member_and_admin_slot_is_canceled, if: :canceled? after_update :update_event_nb_free_places, if: :canceled? @@ -41,26 +42,37 @@ class SlotsReservation < ApplicationRecord reservation.update_event_nb_free_places end + def switch_places_cache + old_slot_id = saved_change_to_slot_id[0] + remove_from_places_cache(Slot.find(old_slot_id)) + add_to_places_cache + end + def add_to_places_cache update_places_cache(:+) Slots::PlacesCacheService.add_users(slot, reservation.reservable_type, reservation.reservable_id, [reservation.statistic_profile.user_id]) end - def remove_from_places_cache - update_places_cache(:-) - Slots::PlacesCacheService.remove_users(slot, reservation.reservable_type, reservation.reservable_id, [reservation.statistic_profile.user_id]) + # @param target_slot [Slot] + def remove_from_places_cache(target_slot = slot) + update_places_cache(:-, target_slot) + Slots::PlacesCacheService.remove_users(target_slot, + reservation.reservable_type, + reservation.reservable_id, + [reservation.statistic_profile.user_id]) end # @param operation [Symbol] :+ or :- - def update_places_cache(operation) + # @param target_slot [Slot] + def update_places_cache(operation, target_slot = slot) if reservation.reservable_type == 'Event' - Slots::PlacesCacheService.change_places(slot, + Slots::PlacesCacheService.change_places(target_slot, reservation.reservable_type, reservation.reservable_id, reservation.total_booked_seats, operation) else - Slots::PlacesCacheService.change_places(slot, reservation.reservable_type, reservation.reservable_id, 1, operation) + Slots::PlacesCacheService.change_places(target_slot, reservation.reservable_type, reservation.reservable_id, 1, operation) end end diff --git a/app/services/slots/places_cache_service.rb b/app/services/slots/places_cache_service.rb index 57ba953b7..d063aafc8 100644 --- a/app/services/slots/places_cache_service.rb +++ b/app/services/slots/places_cache_service.rb @@ -85,7 +85,7 @@ class Slots::PlacesCacheService all_users as ( select (ids.id)::text::int as all_ids from users - ,jsonb_array_elements(users.user_ids) with ordinality ids(id, index) + ,jsonb_array_elements(users.user_ids::jsonb) with ordinality ids(id, index) ), remaining_users as ( SELECT array_to_json(array(SELECT unnest(array_agg(all_users.all_ids)) EXCEPT SELECT unnest('{#{user_ids.to_s.gsub(/\]| |\[|/, '')}}'::int[])))::jsonb as ids diff --git a/test/fixtures/slots_reservations.yml b/test/fixtures/slots_reservations.yml index 038302da9..fe37369d7 100644 --- a/test/fixtures/slots_reservations.yml +++ b/test/fixtures/slots_reservations.yml @@ -1,6 +1,7 @@ # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html one: + id: 1 slot_id: 1 reservation_id: 1 ex_start_at: @@ -9,6 +10,7 @@ one: offered: two: + id: 2 slot_id: 2 reservation_id: 2 ex_start_at: diff --git a/test/integration/reservations/reserve_machine_test.rb b/test/integration/reservations/reserve_machine_test.rb index f115fa76f..ba4df59b1 100644 --- a/test/integration/reservations/reserve_machine_test.rb +++ b/test/integration/reservations/reserve_machine_test.rb @@ -14,6 +14,7 @@ class Reservations::ReserveMachineTest < ActionDispatch::IntegrationTest machine = Machine.find(6) availability = Availability.find(4) + slot = availability.slots.first reservations_count = Reservation.count invoice_count = Invoice.count @@ -33,7 +34,7 @@ class Reservations::ReserveMachineTest < ActionDispatch::IntegrationTest reservable_type: machine.class.name, slots_reservations_attributes: [ { - slot_id: availability.slots.first.id + slot_id: slot.id } ] } @@ -79,6 +80,13 @@ class Reservations::ReserveMachineTest < ActionDispatch::IntegrationTest # notification assert_not_empty Notification.where(attached_object: reservation) + + # place cache + slot.reload + cached = slot.places.detect { |p| p['reservable_id'] == machine.id && p['reservable_type'] == machine.class.name } + assert_not_nil cached + assert_equal 1, cached['reserved_places'] + assert_includes cached['user_ids'], @user_without_subscription.id end test 'user without subscription reserves a machine with error' do diff --git a/test/integration/reservations/reserve_space_test.rb b/test/integration/reservations/reserve_space_test.rb index d54f71c89..7e8885f81 100644 --- a/test/integration/reservations/reserve_space_test.rb +++ b/test/integration/reservations/reserve_space_test.rb @@ -14,6 +14,7 @@ class Reservations::ReserveSpaceTest < ActionDispatch::IntegrationTest space = Space.first availability = space.availabilities.first + slot = availability.slots.first reservations_count = Reservation.count invoice_count = Invoice.count @@ -33,7 +34,7 @@ class Reservations::ReserveSpaceTest < ActionDispatch::IntegrationTest reservable_type: space.class.name, slots_reservations_attributes: [ { - slot_id: availability.slots.first.id + slot_id: slot.id } ] } @@ -79,5 +80,12 @@ class Reservations::ReserveSpaceTest < ActionDispatch::IntegrationTest # notification assert_not_empty Notification.where(attached_object: reservation) + + # place cache + slot.reload + cached = slot.places.detect { |p| p['reservable_id'] == space.id && p['reservable_type'] == space.class.name } + assert_not_nil cached + assert_equal 1, cached['reserved_places'] + assert_includes cached['user_ids'], @user_without_subscription.id end end diff --git a/test/integration/reservations/reserve_training_test.rb b/test/integration/reservations/reserve_training_test.rb index 7ad91c2e6..1cefca105 100644 --- a/test/integration/reservations/reserve_training_test.rb +++ b/test/integration/reservations/reserve_training_test.rb @@ -14,6 +14,7 @@ class Reservations::ReserveTrainingTest < ActionDispatch::IntegrationTest training = Training.first availability = training.availabilities.first + slot = availability.slots.first reservations_count = Reservation.count invoice_count = Invoice.count @@ -31,7 +32,7 @@ class Reservations::ReserveTrainingTest < ActionDispatch::IntegrationTest reservable_type: training.class.name, slots_reservations_attributes: [ { - slot_id: availability.slots.first.id + slot_id: slot.id } ] } @@ -75,6 +76,13 @@ class Reservations::ReserveTrainingTest < ActionDispatch::IntegrationTest # notification assert_not_empty Notification.where(attached_object: reservation) + + # place cache + slot.reload + cached = slot.places.detect { |p| p['reservable_id'] == training.id && p['reservable_type'] == training.class.name } + assert_not_nil cached + assert_equal 1, cached['reserved_places'] + assert_includes cached['user_ids'], @user_without_subscription.id end test 'user reserves a training with an expired coupon with error' do diff --git a/test/integration/reservations/space_seats_test.rb b/test/integration/reservations/space_seats_test.rb index 6afeff6b1..75f330c5b 100644 --- a/test/integration/reservations/space_seats_test.rb +++ b/test/integration/reservations/space_seats_test.rb @@ -31,7 +31,8 @@ class Reservations::SpaceSeatsTest < ActionDispatch::IntegrationTest space_ids: [space.id], nb_total_places: 2, occurrences: [ - { start_at: date.iso8601, end_at: (date + 1.hour).iso8601 }] + { start_at: date.iso8601, end_at: (date + 1.hour).iso8601 } + ] } } @@ -42,6 +43,7 @@ class Reservations::SpaceSeatsTest < ActionDispatch::IntegrationTest # Check the availability res = json_response(response.body) availability = Availability.find(res[:id]) + slot = availability.slots.first ### FIRST RESERVATION @@ -61,7 +63,7 @@ class Reservations::SpaceSeatsTest < ActionDispatch::IntegrationTest reservable_type: space.class.name, slots_reservations_attributes: [ { - slot_id: availability.slots.first.id + slot_id: slot.id } ] } @@ -106,6 +108,12 @@ class Reservations::SpaceSeatsTest < ActionDispatch::IntegrationTest # notification assert_not_empty Notification.where(attached_object: reservation) + # place cache + slot.reload + cached = slot.places.detect { |p| p['reservable_id'] == space.id && p['reservable_type'] == space.class.name } + assert_not_nil cached + assert_equal 1, cached['reserved_places'] + assert_includes cached['user_ids'], @user1.id ### SECOND RESERVATION login_as(@user2, scope: :user) @@ -169,6 +177,13 @@ class Reservations::SpaceSeatsTest < ActionDispatch::IntegrationTest # notification assert_not_empty Notification.where(attached_object: reservation) + # place cache + slot.reload + cached = slot.places.detect { |p| p['reservable_id'] == space.id && p['reservable_type'] == space.class.name } + assert_not_nil cached + assert_equal 2, cached['reserved_places'] + assert_includes cached['user_ids'], @user2.id + ### THIRD RESERVATION login_as(@user3, scope: :user) @@ -214,5 +229,12 @@ class Reservations::SpaceSeatsTest < ActionDispatch::IntegrationTest assert_not_equal reservation.user.id, @user3.id assert_not_equal invoice.user.id, @user3.id assert_not_equal space.prices.find_by(group_id: @user3.group_id, plan_id: nil).amount, invoice_item.amount + + # place cache + slot.reload + cached = slot.places.detect { |p| p['reservable_id'] == space.id && p['reservable_type'] == space.class.name } + assert_not_nil cached + assert_equal 2, cached['reserved_places'] + assert_not_includes cached['user_ids'], @user3.id end end diff --git a/test/integration/slots_reservations_test.rb b/test/integration/slots_reservations_test.rb new file mode 100644 index 000000000..c538345e1 --- /dev/null +++ b/test/integration/slots_reservations_test.rb @@ -0,0 +1,103 @@ +# frozen_string_literal: true + +require 'test_helper' + +class SlotsReservationsTest < ActionDispatch::IntegrationTest + def setup + @admin = User.find_by(username: 'admin') + @user = User.members.without_subscription.first + login_as(@admin, scope: :user) + end + + test 'cancel a reservation' do + put '/api/slots_reservations/1/cancel' + + # Check response format & status + assert_equal 200, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the reservation was correctly canceled + slots_reservation = SlotsReservation.find(1) + assert_not_nil slots_reservation + assert_not_nil slots_reservation.canceled_at + + # place cache + slot = slots_reservation.slot + cached = slot.places.detect do |p| + p['reservable_id'] == slots_reservation.reservation.reservable_id && p['reservable_type'] == slots_reservation.reservation.reservable_type + end + assert_not_nil cached + assert_equal 0, cached['reserved_places'] + assert_not_includes cached['user_ids'], slots_reservation.reservation.statistic_profile.user_id + end + + test 'update a reservation' do + machine = Machine.find(6) + availability = machine.availabilities.first + slot = availability.slots.first + + post '/api/local_payment/confirm_payment', params: { + customer_id: @user.id, + items: [ + { + reservation: { + reservable_id: machine.id, + reservable_type: machine.class.name, + slots_reservations_attributes: [ + { + slot_id: slot.id + } + ] + } + } + ] + }.to_json, headers: default_headers + + # general assertions about creation + assert_equal 201, response.status + slots_reservation = SlotsReservation.last + assert_equal slot.id, slots_reservation.slot_id + + # place cache + slot.reload + cached = slot.places.detect { |p| p['reservable_id'] == machine.id && p['reservable_type'] == machine.class.name } + assert_not_nil cached + assert_equal 1, cached['reserved_places'] + assert_includes cached['user_ids'], @user.id + + # update the reservation to another slot + new_slot = availability.slots.last + + patch "/api/slots_reservations/#{slots_reservation.id}", + params: { + slots_reservation: { + slot_id: new_slot.id + } + } + + # Check response format & status + assert_equal 200, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the reservation was correctly moved + slots_reservation.reload + assert_equal new_slot.id, slots_reservation.slot_id + + # old place cache + slot.reload + cached = slot.places.detect do |p| + p['reservable_id'] == machine.id && p['reservable_type'] == machine.class.name + end + assert_not_nil cached + assert_equal 0, cached['reserved_places'] + assert_not_includes cached['user_ids'], @user.id + # new cache place + new_slot.reload + cached = new_slot.places.detect do |p| + p['reservable_id'] == slots_reservation.reservation.reservable_id && p['reservable_type'] == slots_reservation.reservation.reservable_type + end + assert_not_nil cached + assert_equal 1, cached['reserved_places'] + assert_includes cached['user_ids'], @user.id + end +end