alfio.manager.system.DataMigratorIntegrationTest.java Source code

Java tutorial

Introduction

Here is the source code for alfio.manager.system.DataMigratorIntegrationTest.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.system;

import alfio.TestConfiguration;
import alfio.config.DataSourceConfiguration;
import alfio.config.Initializer;
import alfio.config.RepositoryConfiguration;
import alfio.controller.form.UpdateTicketOwnerForm;
import alfio.controller.support.TemplateProcessor;
import alfio.manager.EventManager;
import alfio.manager.FileUploadManager;
import alfio.manager.TicketReservationManager;
import alfio.manager.support.PartialTicketPDFGenerator;
import alfio.manager.user.UserManager;
import alfio.model.*;
import alfio.model.modification.*;
import alfio.model.modification.support.LocationDescriptor;
import alfio.model.system.EventMigration;
import alfio.model.transaction.PaymentProxy;
import alfio.model.user.Organization;
import alfio.model.user.Role;
import alfio.model.user.User;
import alfio.repository.EventRepository;
import alfio.repository.TicketCategoryRepository;
import alfio.repository.TicketRepository;
import alfio.repository.TicketReservationRepository;
import alfio.repository.plugin.PluginConfigurationRepository;
import alfio.repository.system.EventMigrationRepository;
import alfio.repository.user.OrganizationRepository;
import alfio.test.util.IntegrationTestUtil;
import alfio.util.TemplateManager;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

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

import static org.junit.Assert.*;

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

    private static final int AVAILABLE_SEATS = 20;
    private static final Map<String, String> DESCRIPTION = Collections.singletonMap("en", "desc");

    @Autowired
    private EventManager eventManager;
    @Autowired
    private EventRepository eventRepository;
    @Autowired
    private OrganizationRepository organizationRepository;
    @Autowired
    private UserManager userManager;
    @Autowired
    private TicketRepository ticketRepository;
    @Autowired
    private DataMigrator dataMigrator;
    @Autowired
    private EventMigrationRepository eventMigrationRepository;
    @Autowired
    private TicketReservationManager ticketReservationManager;
    @Autowired
    private TicketCategoryRepository ticketCategoryRepository;
    @Autowired
    private TemplateManager templateManager;
    @Autowired
    private FileUploadManager fileUploadManager;
    @Autowired
    private PluginConfigurationRepository pluginConfigurationRepository;
    @Autowired
    private TicketReservationRepository ticketReservationRepository;
    @Value("${alfio.version}")
    private String currentVersion;
    @Value("${alfio.build-ts}")
    private String buildTimestamp;

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

    private Pair<Event, String> initEvent(List<TicketCategoryModification> categories) {
        return initEvent(categories, "display name");
    }

    private Pair<Event, String> initEvent(List<TicketCategoryModification> categories, String displayName) {
        String organizationName = UUID.randomUUID().toString();
        String username = UUID.randomUUID().toString();
        String eventName = UUID.randomUUID().toString();

        organizationRepository.create(organizationName, "org", "email@example.com");
        Organization organization = organizationRepository.findByName(organizationName).get();
        userManager.insertUser(organization.getId(), username, "test", "test", "test@example.com", Role.OPERATOR,
                User.Type.INTERNAL);

        Map<String, String> desc = new HashMap<>();
        desc.put("en", "muh description");
        desc.put("it", "muh description");
        desc.put("de", "muh description");

        EventModification em = new EventModification(null, Event.EventType.INTERNAL, "url", "url", "url", null,
                null, eventName, displayName, organization.getId(), "muh location", "0.0", "0.0",
                ZoneId.systemDefault().getId(), desc,
                new DateTimeModification(LocalDate.now().plusDays(5), LocalTime.now()),
                new DateTimeModification(LocalDate.now().plusDays(5), LocalTime.now().plusHours(1)), BigDecimal.TEN,
                "CHF", AVAILABLE_SEATS, BigDecimal.ONE, true, null, categories, false,
                new LocationDescriptor("", "", "", ""), 7, null, null);
        eventManager.createEvent(em);
        return Pair.of(eventManager.getSingleEvent(eventName, username), username);
    }

    @Test
    public void testMigration() {
        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));
        Pair<Event, String> eventUsername = initEvent(categories);
        Event event = eventUsername.getKey();

        try {
            eventRepository.updatePrices("CHF", 40, false, BigDecimal.ONE, "STRIPE", event.getId(),
                    PriceContainer.VatStatus.NOT_INCLUDED, 1000);

            dataMigrator.migrateEventsToCurrentVersion();
            EventMigration eventMigration = eventMigrationRepository.loadEventMigration(event.getId());
            assertNotNull(eventMigration);
            //assertEquals(buildTimestamp, eventMigration.getBuildTimestamp().toString());
            assertEquals(currentVersion, eventMigration.getCurrentVersion());

            List<Ticket> tickets = ticketRepository.findFreeByEventId(event.getId());
            assertNotNull(tickets);
            assertFalse(tickets.isEmpty());
            assertEquals(AVAILABLE_SEATS, tickets.size());
            assertTrue(tickets.stream().allMatch(t -> t.getCategoryId() == null));
        } finally {
            eventManager.deleteEvent(event.getId(), eventUsername.getValue());
        }
    }

    @Test
    public void testMigrationWithExistingRecord() {
        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));
        Pair<Event, String> eventUsername = initEvent(categories);
        Event event = eventUsername.getKey();

        try {
            eventMigrationRepository.insertMigrationData(event.getId(), "1.4",
                    ZonedDateTime.now(ZoneId.of("UTC")).minusDays(1), EventMigration.Status.COMPLETE.toString());
            eventRepository.updatePrices("CHF", 40, false, BigDecimal.ONE, "STRIPE", event.getId(),
                    PriceContainer.VatStatus.NOT_INCLUDED, 1000);
            dataMigrator.migrateEventsToCurrentVersion();
            EventMigration eventMigration = eventMigrationRepository.loadEventMigration(event.getId());
            assertNotNull(eventMigration);
            //assertEquals(buildTimestamp, eventMigration.getBuildTimestamp().toString());
            assertEquals(currentVersion, eventMigration.getCurrentVersion());

            List<Ticket> tickets = ticketRepository.findFreeByEventId(event.getId());
            assertNotNull(tickets);
            assertFalse(tickets.isEmpty());
            assertEquals(20, tickets.size());
            assertTrue(tickets.stream().allMatch(t -> t.getCategoryId() == null));
        } finally {
            eventManager.deleteEvent(event.getId(), eventUsername.getValue());
        }
    }

    @Test
    public void testAlreadyMigratedEvent() {
        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));
        Pair<Event, String> eventUsername = initEvent(categories);
        Event event = eventUsername.getKey();

        try {
            ZonedDateTime migrationTs = ZonedDateTime.now(ZoneId.of("UTC"));
            eventMigrationRepository.insertMigrationData(event.getId(), currentVersion, migrationTs,
                    EventMigration.Status.COMPLETE.toString());
            eventRepository.updatePrices("CHF", 40, false, BigDecimal.ONE, "STRIPE", event.getId(),
                    PriceContainer.VatStatus.NOT_INCLUDED, 1000);
            dataMigrator.migrateEventsToCurrentVersion();
            EventMigration eventMigration = eventMigrationRepository.loadEventMigration(event.getId());
            assertNotNull(eventMigration);
            //assertEquals(migrationTs.toString(), eventMigration.getBuildTimestamp().toString());
            assertEquals(currentVersion, eventMigration.getCurrentVersion());

            List<Ticket> tickets = ticketRepository.findFreeByEventId(event.getId());
            assertNotNull(tickets);
            assertFalse(tickets.isEmpty());
            assertEquals(AVAILABLE_SEATS, tickets.size());//<-- the migration has not been done
            assertTrue(tickets.stream().allMatch(t -> t.getCategoryId() == null));
        } finally {
            eventManager.deleteEvent(event.getId(), eventUsername.getValue());
        }
    }

    @Test
    public void testUpdateDisplayName() {
        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));
        Pair<Event, String> eventUsername = initEvent(categories, null);
        Event event = eventUsername.getKey();

        try {
            dataMigrator.migrateEventsToCurrentVersion();
            EventMigration eventMigration = eventMigrationRepository.loadEventMigration(event.getId());
            assertNotNull(eventMigration);
            //assertEquals(buildTimestamp, eventMigration.getBuildTimestamp().toString());
            assertEquals(currentVersion, eventMigration.getCurrentVersion());

            Event withDescription = eventRepository.findById(event.getId());
            assertNotNull(withDescription.getDisplayName());
            assertEquals(event.getShortName(), withDescription.getShortName());
            assertEquals(event.getShortName(), withDescription.getDisplayName());
        } finally {
            eventManager.deleteEvent(event.getId(), eventUsername.getValue());
        }
    }

    @Test
    public void testUpdateTicketReservation() {
        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));
        Pair<Event, String> eventUsername = initEvent(categories);
        Event event = eventUsername.getKey();
        try {
            TicketReservationModification trm = new TicketReservationModification();
            trm.setAmount(1);
            trm.setTicketCategoryId(eventManager.loadTicketCategories(event).get(0).getId());
            TicketReservationWithOptionalCodeModification r = new TicketReservationWithOptionalCodeModification(trm,
                    Optional.empty());
            Date expiration = DateUtils.addDays(new Date(), 1);
            String reservationId = ticketReservationManager.createTicketReservation(event,
                    Collections.singletonList(r), Collections.emptyList(), expiration, Optional.empty(),
                    Optional.empty(), Locale.ENGLISH, false);
            dataMigrator.fillReservationsLanguage();
            TicketReservation ticketReservation = ticketReservationManager.findById(reservationId).get();
            assertEquals("en", ticketReservation.getUserLanguage());
        } finally {
            eventManager.deleteEvent(event.getId(), eventUsername.getValue());
        }
    }

    @Test
    public void testUpdateGender() {
        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));
        Pair<Event, String> eventUsername = initEvent(categories);
        Event event = eventUsername.getKey();
        try {
            TicketReservationModification trm = new TicketReservationModification();
            trm.setAmount(2);
            trm.setTicketCategoryId(eventManager.loadTicketCategories(event).get(0).getId());
            TicketReservationWithOptionalCodeModification r = new TicketReservationWithOptionalCodeModification(trm,
                    Optional.empty());
            Date expiration = DateUtils.addDays(new Date(), 1);
            String reservationId = ticketReservationManager.createTicketReservation(event,
                    Collections.singletonList(r), Collections.emptyList(), expiration, Optional.empty(),
                    Optional.empty(), Locale.ENGLISH, false);
            ticketReservationManager.confirm("TOKEN", null, event, reservationId, "email@email.ch",
                    new CustomerName("Full Name", "Full", "Name", event), Locale.ENGLISH, null,
                    new TotalPrice(1000, 10, 0, 0), Optional.empty(), Optional.of(PaymentProxy.ON_SITE), false,
                    null, null, null);
            List<Ticket> tickets = ticketRepository.findTicketsInReservation(reservationId);
            UpdateTicketOwnerForm first = new UpdateTicketOwnerForm();
            first.setEmail("email@email.ch");
            //first.setTShirtSize("SMALL");
            //first.setGender("F");
            first.setFirstName("Full");
            first.setLastName("Name");
            UpdateTicketOwnerForm second = new UpdateTicketOwnerForm();
            //second.setTShirtSize("SMALL-F");
            second.setEmail("email@email.ch");
            second.setFirstName("Full");
            second.setLastName("Name");
            PartialTicketPDFGenerator generator = TemplateProcessor.buildPartialPDFTicket(Locale.ITALIAN, event,
                    ticketReservationManager.findById(reservationId).get(),
                    ticketCategoryRepository.getByIdAndActive(tickets.get(0).getCategoryId(), event.getId()),
                    organizationRepository.getById(event.getOrganizationId()), templateManager, fileUploadManager,
                    "");
            ticketReservationManager.updateTicketOwner(tickets.get(0), Locale.ITALIAN, event, first, (t) -> "",
                    (t) -> "", Optional.empty());
            ticketReservationManager.updateTicketOwner(tickets.get(1), Locale.ITALIAN, event, second, (t) -> "",
                    (t) -> "", Optional.empty());
            //FIXME
            //dataMigrator.fillTicketsGender();
            //ticketRepository.findTicketsInReservation(reservationId).forEach(t -> assertEquals("F", t.getGender()));
        } finally {
            eventManager.deleteEvent(event.getId(), eventUsername.getValue());
        }
    }

    @Test
    public void testFixCategoriesSize() {
        List<TicketCategoryModification> categories = Arrays.asList(
                new TicketCategoryModification(null, "default", AVAILABLE_SEATS - 1,
                        new DateTimeModification(LocalDate.now(), LocalTime.now()),
                        new DateTimeModification(LocalDate.now(), LocalTime.now()), DESCRIPTION, BigDecimal.TEN,
                        false, "", true, null, null, null, null, null),
                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> eventUsername = initEvent(categories);
        Event event = eventUsername.getKey();
        TicketCategory firstCategory = ticketCategoryRepository.findByEventId(event.getId()).stream()
                .filter(TicketCategory::isBounded).findFirst().orElseThrow(IllegalStateException::new);
        int firstCategoryID = firstCategory.getId();
        ticketCategoryRepository.updateSeatsAvailability(firstCategoryID, AVAILABLE_SEATS + 1);
        dataMigrator.fixCategoriesSize(event);
        assertEquals(AVAILABLE_SEATS - 1, ticketRepository.countAllocatedTicketsForEvent(event.getId()).intValue());
        assertEquals(1, ticketRepository.countFreeTicketsForUnbounded(event.getId()).intValue());
        assertEquals(AVAILABLE_SEATS - 1,
                ticketRepository.countFreeTickets(event.getId(), firstCategoryID).intValue());
        assertEquals(AVAILABLE_SEATS - 1, firstCategory.getMaxTickets());
    }

    @Test
    public void testFixStuckTickets() {
        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));
        Pair<Event, String> eventUsername = initEvent(categories);
        Event event = eventUsername.getKey();
        TicketReservationModification trm = new TicketReservationModification();
        trm.setAmount(1);
        trm.setTicketCategoryId(eventManager.loadTicketCategories(event).get(0).getId());
        TicketReservationWithOptionalCodeModification r = new TicketReservationWithOptionalCodeModification(trm,
                Optional.empty());
        Date expiration = DateUtils.addDays(new Date(), 1);
        String reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(r),
                Collections.emptyList(), expiration, Optional.empty(), Optional.empty(), Locale.ENGLISH, false);
        //simulate the effect of a reservation cancellation after #392, as described in #391
        ticketReservationRepository.updateReservationStatus(reservationId,
                TicketReservation.TicketReservationStatus.CANCELLED.name());
        List<Ticket> ticketsInReservation = ticketRepository.findTicketsInReservation(reservationId);
        assertEquals(1, ticketsInReservation.size());
        String uuid = ticketsInReservation.get(0).getUuid();
        assertTrue(ticketsInReservation.stream().allMatch(t -> t.getStatus() == Ticket.TicketStatus.PENDING));
        dataMigrator.fixStuckTickets(event.getId());
        assertTrue(ticketRepository.findByUUID(uuid).getStatus() == Ticket.TicketStatus.RELEASED);
    }
}