alfio.manager.AdminReservationManagerIntegrationTest.java Source code

Java tutorial

Introduction

Here is the source code for alfio.manager.AdminReservationManagerIntegrationTest.java

Source

/**
 * This file is part of alf.io.
 *
 * alf.io is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * alf.io is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with alf.io.  If not, see <http://www.gnu.org/licenses/>.
 */
package alfio.manager;

import alfio.TestConfiguration;
import alfio.config.DataSourceConfiguration;
import alfio.config.Initializer;
import alfio.config.RepositoryConfiguration;
import alfio.manager.user.UserManager;
import alfio.model.*;
import alfio.model.modification.*;
import alfio.model.modification.AdminReservationModification.Attendee;
import alfio.model.modification.AdminReservationModification.Category;
import alfio.model.modification.AdminReservationModification.CustomerData;
import alfio.model.modification.AdminReservationModification.TicketsInfo;
import alfio.model.result.Result;
import alfio.repository.*;
import alfio.repository.user.OrganizationRepository;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.stream.IntStream;

import static alfio.test.util.IntegrationTestUtil.*;
import static java.util.stream.Collectors.toList;
import static org.junit.Assert.*;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { RepositoryConfiguration.class, DataSourceConfiguration.class,
        TestConfiguration.class })
@ActiveProfiles({ Initializer.PROFILE_DEV, Initializer.PROFILE_DISABLE_JOBS })
@Transactional
public class AdminReservationManagerIntegrationTest {

    @BeforeClass
    public static void initEnv() {
        initSystemProperties();
    }

    @Autowired
    private AdminReservationManager adminReservationManager;
    @Autowired
    private EventManager eventManager;
    @Autowired
    private OrganizationRepository organizationRepository;
    @Autowired
    private UserManager userManager;
    @Autowired
    private TicketCategoryRepository ticketCategoryRepository;
    @Autowired
    private TicketRepository ticketRepository;
    @Autowired
    private EmailMessageRepository emailMessageRepository;
    @Autowired
    private TicketReservationManager ticketReservationManager;
    @Autowired
    private SpecialPriceRepository specialPriceRepository;
    @Autowired
    private EventRepository eventRepository;

    @Test
    public void testReserveFromExistingCategory() throws Exception {
        List<TicketCategoryModification> categories = Collections.singletonList(new TicketCategoryModification(null,
                "default", AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(), LocalTime.now()),
                new DateTimeModification(LocalDate.now(), LocalTime.now()), DESCRIPTION, BigDecimal.TEN, false, "",
                false, null, null, null, null, null));
        performExistingCategoryTest(categories, false, Collections.singletonList(1), false, true, 0,
                AVAILABLE_SEATS);
    }

    @Test
    public void testReserveFromExistingMultipleCategories() throws Exception {
        List<TicketCategoryModification> categories = Arrays.asList(
                new TicketCategoryModification(null, "default", 10,
                        new DateTimeModification(LocalDate.now(), LocalTime.now()),
                        new DateTimeModification(LocalDate.now(), LocalTime.now()), DESCRIPTION, BigDecimal.TEN,
                        false, "", false, null, null, null, null, null),
                new TicketCategoryModification(null, "2nd", 10,
                        new DateTimeModification(LocalDate.now(), LocalTime.now()),
                        new DateTimeModification(LocalDate.now(), LocalTime.now()), DESCRIPTION, BigDecimal.TEN,
                        false, "", false, null, null, null, null, null));
        performExistingCategoryTest(categories, false, Arrays.asList(10, 10), false, true, 0, AVAILABLE_SEATS);
    }

    @Test
    public void testReserveFromExistingCategoryNotEnoughSeatsNotBounded() throws Exception {
        List<TicketCategoryModification> categories = Collections.singletonList(new TicketCategoryModification(null,
                "default", 1, new DateTimeModification(LocalDate.now(), LocalTime.now()),
                new DateTimeModification(LocalDate.now(), LocalTime.now()), DESCRIPTION, BigDecimal.TEN, false, "",
                false, null, null, null, null, null));
        performExistingCategoryTest(categories, false, Collections.singletonList(1), false, true, 0,
                AVAILABLE_SEATS);
    }

    @Test
    public void testReserveExistingCategoryNotEnoughSeatsNotBoundedSoldOut() throws Exception {
        List<TicketCategoryModification> categories = Collections.singletonList(new TicketCategoryModification(null,
                "default", 1, new DateTimeModification(LocalDate.now(), LocalTime.now()),
                new DateTimeModification(LocalDate.now(), LocalTime.now()), DESCRIPTION, BigDecimal.TEN, false, "",
                false, null, null, null, null, null));
        performExistingCategoryTest(categories, false, Collections.singletonList(1), true, true, AVAILABLE_SEATS,
                AVAILABLE_SEATS + 1);
    }

    @Test
    public void testReserveFromExistingCategoryNotEnoughSeatsBounded() throws Exception {
        List<TicketCategoryModification> categories = Collections.singletonList(new TicketCategoryModification(null,
                "default", 1, new DateTimeModification(LocalDate.now(), LocalTime.now()),
                new DateTimeModification(LocalDate.now(), LocalTime.now()), DESCRIPTION, BigDecimal.TEN, false, "",
                true, null, null, null, null, null));
        performExistingCategoryTest(categories, true, Collections.singletonList(2), false, true, 0,
                AVAILABLE_SEATS);
    }

    @Test
    public void testReserveFromExistingCategoryNotEnoughSeatsNoExtensionAllowedBounded() throws Exception {
        List<TicketCategoryModification> categories = Collections.singletonList(new TicketCategoryModification(null,
                "default", AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(), LocalTime.now()),
                new DateTimeModification(LocalDate.now(), LocalTime.now()), DESCRIPTION, BigDecimal.TEN, false, "",
                true, null, null, null, null, null));
        performExistingCategoryTest(categories, true, Collections.singletonList(AVAILABLE_SEATS + 1), false, false,
                0, AVAILABLE_SEATS);
    }

    @Test
    public void testReserveFromExistingCategoryNotEnoughSeatsNoExtensionAllowedNotBounded() throws Exception {
        List<TicketCategoryModification> categories = Collections.singletonList(new TicketCategoryModification(null,
                "default", AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(), LocalTime.now()),
                new DateTimeModification(LocalDate.now(), LocalTime.now()), DESCRIPTION, BigDecimal.TEN, false, "",
                false, null, null, null, null, null));
        performExistingCategoryTest(categories, true, Collections.singletonList(AVAILABLE_SEATS + 1), false, false,
                0, AVAILABLE_SEATS);
    }

    @Test
    public void testReserveFromNewCategory() throws Exception {
        List<TicketCategoryModification> categories = Collections.singletonList(new TicketCategoryModification(null,
                "default", 1, new DateTimeModification(LocalDate.now(), LocalTime.now()),
                new DateTimeModification(LocalDate.now(), LocalTime.now()), DESCRIPTION, BigDecimal.TEN, false, "",
                true, null, null, null, null, null));
        Pair<Event, String> eventWithUsername = initEvent(categories, organizationRepository, userManager,
                eventManager, eventRepository);
        Event event = eventWithUsername.getKey();
        String username = eventWithUsername.getValue();
        DateTimeModification expiration = DateTimeModification.fromZonedDateTime(ZonedDateTime.now().plusDays(1));
        CustomerData customerData = new CustomerData("Integration", "Test", "integration-test@test.ch",
                "Billing Address", "en");
        Category category = new Category(null, "name", new BigDecimal("100.00"));
        int attendees = AVAILABLE_SEATS;
        List<TicketsInfo> ticketsInfoList = Collections
                .singletonList(new TicketsInfo(category, generateAttendees(attendees), true, false));
        AdminReservationModification modification = new AdminReservationModification(expiration, customerData,
                ticketsInfoList, "en", false, null);
        Result<Pair<TicketReservation, List<Ticket>>> result = adminReservationManager
                .createReservation(modification, event.getShortName(), username);
        assertTrue(result.isSuccess());
        Pair<TicketReservation, List<Ticket>> data = result.getData();
        List<Ticket> tickets = data.getRight();
        assertTrue(tickets.size() == attendees);
        assertNotNull(data.getLeft());
        int categoryId = tickets.get(0).getCategoryId();
        Event modified = eventManager.getSingleEvent(event.getShortName(), username);
        assertEquals(attendees + 1, eventRepository.countExistingTickets(event.getId()).intValue());
        assertEquals(attendees,
                ticketRepository.findPendingTicketsInCategories(Collections.singletonList(categoryId)).size());
        TicketCategory categoryModified = ticketCategoryRepository.getByIdAndActive(categoryId, event.getId());
        assertEquals(categoryModified.getMaxTickets(), attendees);
        ticketCategoryRepository.findByEventId(event.getId())
                .forEach(tc -> assertTrue(specialPriceRepository.findAllByCategoryId(tc.getId()).stream()
                        .allMatch(sp -> sp.getStatus() == SpecialPrice.Status.PENDING)));
        adminReservationManager.confirmReservation(event.getShortName(), data.getLeft().getId(), username);
        ticketCategoryRepository.findByEventId(event.getId())
                .forEach(tc -> assertTrue(specialPriceRepository.findAllByCategoryId(tc.getId()).stream()
                        .allMatch(sp -> sp.getStatus() == SpecialPrice.Status.TAKEN)));
        assertFalse(ticketRepository.findAllReservationsConfirmedButNotAssigned(event.getId())
                .contains(data.getLeft().getId()));
    }

    @Test
    public void testReserveMixed() throws Exception {
        List<TicketCategoryModification> categories = Collections.singletonList(new TicketCategoryModification(null,
                "default", 1, new DateTimeModification(LocalDate.now(), LocalTime.now()),
                new DateTimeModification(LocalDate.now(), LocalTime.now()), DESCRIPTION, BigDecimal.TEN, false, "",
                false, null, null, null, null, null));
        Pair<Event, String> eventWithUsername = initEvent(categories, organizationRepository, userManager,
                eventManager, eventRepository);
        Event event = eventWithUsername.getKey();
        String username = eventWithUsername.getValue();
        DateTimeModification expiration = DateTimeModification.fromZonedDateTime(ZonedDateTime.now().plusDays(1));
        CustomerData customerData = new CustomerData("Integration", "Test", "integration-test@test.ch",
                "Billing Address", "en");

        TicketCategory existingCategory = ticketCategoryRepository.findByEventId(event.getId()).get(0);

        Category resExistingCategory = new Category(existingCategory.getId(), "", existingCategory.getPrice());
        Category resNewCategory = new Category(null, "name", new BigDecimal("100.00"));
        int attendees = 1;
        List<TicketsInfo> ticketsInfoList = Arrays.asList(
                new TicketsInfo(resExistingCategory, generateAttendees(attendees), false, false),
                new TicketsInfo(resNewCategory, generateAttendees(attendees), false, false),
                new TicketsInfo(resExistingCategory, generateAttendees(attendees), false, false));
        AdminReservationModification modification = new AdminReservationModification(expiration, customerData,
                ticketsInfoList, "en", false, null);
        Result<Pair<TicketReservation, List<Ticket>>> result = adminReservationManager
                .createReservation(modification, event.getShortName(), username);
        assertTrue(result.isSuccess());
        Pair<TicketReservation, List<Ticket>> data = result.getData();
        List<Ticket> tickets = data.getRight();
        assertTrue(tickets.size() == 3);
        assertNotNull(data.getLeft());
        assertTrue(tickets.stream().allMatch(t -> t.getTicketsReservationId().equals(data.getKey().getId())));
        int resExistingCategoryId = tickets.get(0).getCategoryId();
        int resNewCategoryId = tickets.get(2).getCategoryId();

        Event modified = eventManager.getSingleEvent(event.getShortName(), username);
        assertEquals(AVAILABLE_SEATS, eventRepository.countExistingTickets(event.getId()).intValue());
        assertEquals(3, ticketRepository
                .findPendingTicketsInCategories(Arrays.asList(resExistingCategoryId, resNewCategoryId)).size());
        assertEquals(3, ticketRepository.findTicketsInReservation(data.getLeft().getId()).size());

        String reservationId = data.getLeft().getId();
        assertEquals(ticketRepository.findTicketsInReservation(reservationId).stream().findFirst().get().getId(),
                ticketRepository.findFirstTicketInReservation(reservationId).get().getId());

        ticketCategoryRepository.findByEventId(event.getId())
                .forEach(tc -> assertTrue(specialPriceRepository.findAllByCategoryId(tc.getId()).stream()
                        .allMatch(sp -> sp.getStatus() == SpecialPrice.Status.PENDING)));
        adminReservationManager.confirmReservation(event.getShortName(), data.getLeft().getId(), username);
        ticketCategoryRepository.findByEventId(event.getId())
                .forEach(tc -> assertTrue(specialPriceRepository.findAllByCategoryId(tc.getId()).stream()
                        .allMatch(sp -> sp.getStatus() == SpecialPrice.Status.TAKEN)));
        assertFalse(ticketRepository.findAllReservationsConfirmedButNotAssigned(event.getId())
                .contains(data.getLeft().getId()));
    }

    @Test
    public void testConfirmReservation() throws Exception {
        List<TicketCategoryModification> categories = Collections.singletonList(new TicketCategoryModification(null,
                "default", 1, new DateTimeModification(LocalDate.now(), LocalTime.now()),
                new DateTimeModification(LocalDate.now(), LocalTime.now()), DESCRIPTION, BigDecimal.TEN, false, "",
                true, null, null, null, null, null));
        Triple<Event, String, TicketReservation> testResult = performExistingCategoryTest(categories, true,
                Collections.singletonList(2), false, true, 0, AVAILABLE_SEATS);
        assertNotNull(testResult);
        Result<Triple<TicketReservation, List<Ticket>, Event>> result = adminReservationManager.confirmReservation(
                testResult.getLeft().getShortName(), testResult.getRight().getId(), testResult.getMiddle());
        assertTrue(result.isSuccess());
        Triple<TicketReservation, List<Ticket>, Event> triple = result.getData();
        assertEquals(TicketReservation.TicketReservationStatus.COMPLETE, triple.getLeft().getStatus());
        triple.getMiddle().forEach(t -> assertEquals(Ticket.TicketStatus.ACQUIRED, t.getStatus()));
        assertTrue(emailMessageRepository.findByEventId(triple.getRight().getId(), 0, 50, null).isEmpty());
        ticketCategoryRepository.findByEventId(triple.getRight().getId())
                .forEach(tc -> assertTrue(specialPriceRepository.findAllByCategoryId(tc.getId()).stream()
                        .allMatch(sp -> sp.getStatus() == SpecialPrice.Status.TAKEN)));
        assertFalse(ticketRepository.findAllReservationsConfirmedButNotAssigned(triple.getRight().getId())
                .contains(triple.getLeft().getId()));
    }

    private Triple<Event, String, TicketReservation> performExistingCategoryTest(
            List<TicketCategoryModification> categories, boolean bounded, List<Integer> attendeesNr,
            boolean addSeatsIfNotAvailable, boolean expectSuccess, int reservedTickets, int expectedEventSeats) {
        assertEquals("Test error: categories' size must be equal to attendees' size", categories.size(),
                attendeesNr.size());
        Pair<Event, String> eventWithUsername = initEvent(categories, organizationRepository, userManager,
                eventManager, eventRepository);
        Event event = eventWithUsername.getKey();
        String username = eventWithUsername.getValue();
        DateTimeModification expiration = DateTimeModification.fromZonedDateTime(ZonedDateTime.now().plusDays(1));
        CustomerData customerData = new CustomerData("Integration", "Test", "integration-test@test.ch",
                "Billing Address", "en");
        Iterator<Integer> attendeesIterator = attendeesNr.iterator();
        List<TicketCategory> existingCategories = ticketCategoryRepository.findByEventId(event.getId());
        List<Attendee> allAttendees = new ArrayList<>();
        List<TicketsInfo> ticketsInfoList = existingCategories.stream().map(existingCategory -> {
            Category category = new Category(existingCategory.getId(), existingCategory.getName(),
                    existingCategory.getPrice());
            List<Attendee> attendees = generateAttendees(attendeesIterator.next());
            allAttendees.addAll(attendees);
            return new TicketsInfo(category, attendees, addSeatsIfNotAvailable, false);
        }).collect(toList());
        AdminReservationModification modification = new AdminReservationModification(expiration, customerData,
                ticketsInfoList, "en", false, null);

        if (reservedTickets > 0) {
            TicketReservationModification trm = new TicketReservationModification();
            trm.setAmount(reservedTickets);
            trm.setTicketCategoryId(existingCategories.get(0).getId());
            TicketReservationWithOptionalCodeModification r = new TicketReservationWithOptionalCodeModification(trm,
                    Optional.empty());
            ticketReservationManager.createTicketReservation(event, Collections.singletonList(r),
                    Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.empty(),
                    Locale.ENGLISH, false);
        }

        Result<Pair<TicketReservation, List<Ticket>>> result = adminReservationManager
                .createReservation(modification, event.getShortName(), username);
        if (expectSuccess) {
            validateSuccess(bounded, attendeesNr, event, username, existingCategories, result, allAttendees,
                    expectedEventSeats, reservedTickets);
        } else {
            assertFalse(result.isSuccess());
            return null;
        }
        return Triple.of(eventWithUsername.getLeft(), eventWithUsername.getRight(), result.getData().getKey());
    }

    private void validateSuccess(boolean bounded, List<Integer> attendeesNr, Event event, String username,
            List<TicketCategory> existingCategories, Result<Pair<TicketReservation, List<Ticket>>> result,
            List<Attendee> allAttendees, int expectedEventSeats, int reservedTickets) {

        assertTrue(result.isSuccess());
        Pair<TicketReservation, List<Ticket>> data = result.getData();
        assertTrue(data.getRight().size() == attendeesNr.stream().mapToInt(i -> i).sum());
        assertNotNull(data.getLeft());
        Event modified = eventManager.getSingleEvent(event.getShortName(), username);
        assertEquals(expectedEventSeats, eventRepository.countExistingTickets(event.getId()).intValue());
        List<Ticket> tickets = ticketRepository.findPendingTicketsInCategories(
                existingCategories.stream().map(TicketCategory::getId).collect(toList()));
        assertEquals(attendeesNr.stream().mapToInt(i -> i).sum(), tickets.size() - reservedTickets);
        if (bounded) {
            final Iterator<Integer> iterator = attendeesNr.iterator();
            existingCategories.forEach(existingCategory -> {
                TicketCategory categoryModified = ticketCategoryRepository
                        .getByIdAndActive(existingCategory.getId(), event.getId());
                assertEquals(categoryModified.getMaxTickets(), iterator.next().intValue());
            });
        }
        for (int i = 0; i < tickets.size() - reservedTickets; i++) {
            Attendee attendee = allAttendees.get(i);
            if (!attendee.isEmpty()) {
                Ticket ticket = data.getRight().get(i);
                assertTrue(ticket.getAssigned());
                assertNotNull(ticket.getFullName());
                assertEquals(attendee.getFullName(), ticket.getFullName());
                assertEquals(attendee.getEmailAddress(), ticket.getEmail());
                assertEquals(Ticket.TicketStatus.PENDING, ticket.getStatus());
                assertEquals(data.getLeft().getId(), ticket.getTicketsReservationId());
            }
        }
        ticketCategoryRepository.findByEventId(modified.getId())
                .forEach(tc -> assertTrue(specialPriceRepository.findAllByCategoryId(tc.getId()).stream()
                        .allMatch(sp -> sp.getStatus() == SpecialPrice.Status.PENDING)));
        assertFalse(ticketRepository.findAllReservationsConfirmedButNotAssigned(event.getId())
                .contains(data.getLeft().getId()));
    }

    private List<Attendee> generateAttendees(int count) {
        return IntStream.range(0, count).mapToObj(i -> new Attendee(null, "Attendee " + i, "Test" + i,
                "attendee" + i + "@test.ch", "en", false, null, Collections.emptyMap())).collect(toList());
    }
}