/**
* 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.system.ConfigurationManager;
import alfio.manager.user.UserManager;
import alfio.model.Event;
import alfio.model.TicketCategory;
import alfio.model.modification.ConfigurationModification;
import alfio.model.modification.DateTimeModification;
import alfio.model.modification.EventModification;
import alfio.model.modification.TicketCategoryModification;
import alfio.model.modification.support.LocationDescriptor;
import alfio.model.system.Configuration;
import alfio.model.system.ConfigurationKeys;
import alfio.model.system.ConfigurationPathLevel;
import alfio.model.user.Organization;
import alfio.model.user.Role;
import alfio.repository.TicketCategoryRepository;
import alfio.repository.system.ConfigurationRepository;
import alfio.repository.user.OrganizationRepository;
import alfio.test.util.IntegrationTestUtil;
import alfio.util.OptionalWrapper;
import org.junit.Before;
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.util.*;
import java.util.stream.Collectors;
import static alfio.model.system.ConfigurationKeys.*;
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 ConfigurationManagerIntegrationTest {
public static final String USERNAME = "test";
@BeforeClass
public static void initEnv() {
IntegrationTestUtil.initSystemProperties();
}
Event event;
TicketCategory ticketCategory;
@Autowired
private ConfigurationManager configurationManager;
@Autowired
private ConfigurationRepository configurationRepository;
@Autowired
private EventManager eventManager;
@Autowired
private OrganizationRepository organizationRepository;
@Autowired
private UserManager userManager;
@Autowired
private TicketCategoryRepository ticketCategoryRepository;
@Before
public void prepareEnv() {
//setup...
organizationRepository.create("org", "org", "email@example.com");
Organization organization = organizationRepository.findByName("org").get(0);
userManager.insertUser(organization.getId(), USERNAME, "test", "test", "test@example.com", Role.OWNER);
Map<String, String> desc = new HashMap<>();
desc.put("en", "muh description");
desc.put("it", "muh description");
desc.put("de", "muh description");
List<TicketCategoryModification> ticketsCategory = Collections.singletonList(
new TicketCategoryModification(null, "default", 20,
new DateTimeModification(LocalDate.now(), LocalTime.now()),
new DateTimeModification(LocalDate.now(), LocalTime.now()),
Collections.singletonMap("en", "desc"), BigDecimal.TEN, false, "", false));
EventModification em = new EventModification(null, Event.EventType.INTERNAL, "url", "url", "url", null, null,
"eventShortName", "displayName", organization.getId(),
"muh location", desc,
new DateTimeModification(LocalDate.now(), LocalTime.now()),
new DateTimeModification(LocalDate.now(), LocalTime.now()),
BigDecimal.TEN, "CHF", 20, BigDecimal.ONE, true, null, ticketsCategory, false, new LocationDescriptor("","","",""), 7, null, null);
eventManager.createEvent(em);
event = eventManager.getSingleEvent("eventShortName", "test");
ticketCategory = ticketCategoryRepository.findAllTicketCategories(event.getId()).get(0);
}
@Test
public void testPresentStringConfigValue() {
assertEquals(Optional.of("5"), configurationManager.getStringConfigValue(Configuration.from(event.getOrganizationId(), event.getId(), MAX_AMOUNT_OF_TICKETS_BY_RESERVATION)));
}
@Test
public void testEmptyStringConfigValue() {
assertEquals(Optional.empty(), configurationManager.getStringConfigValue(Configuration.from(event.getOrganizationId(), event.getId(), SMTP_PASSWORD)));
}
@Test
public void testStringValueWithDefault() {
assertEquals("5", configurationManager.getStringConfigValue(Configuration.from(event.getOrganizationId(), event.getId(), MAX_AMOUNT_OF_TICKETS_BY_RESERVATION), "-1"));
assertEquals("-1", configurationManager.getStringConfigValue(Configuration.from(event.getOrganizationId(), event.getId(), SMTP_PASSWORD), "-1"));
}
@Test(expected = IllegalArgumentException.class)
public void testMissingConfigValue() {
configurationManager.getRequiredValue(Configuration.from(event.getOrganizationId(), event.getId(), SMTP_PASSWORD));
}
@Test
public void testRequiredValue() {
assertEquals("5", configurationManager.getRequiredValue(Configuration.from(event.getOrganizationId(), event.getId(), MAX_AMOUNT_OF_TICKETS_BY_RESERVATION)));
}
@Test
public void testIntValue() {
assertEquals(5, configurationManager.getIntConfigValue(Configuration.from(event.getOrganizationId(), event.getId(), MAX_AMOUNT_OF_TICKETS_BY_RESERVATION), -1));
//missing value
assertEquals(-1, configurationManager.getIntConfigValue(Configuration.from(event.getOrganizationId(), event.getId(), ASSIGNMENT_REMINDER_INTERVAL), -1));
configurationManager.saveSystemConfiguration(ConfigurationKeys.BASE_URL, "blabla");
assertEquals("blabla", configurationManager.getRequiredValue(Configuration.from(event.getOrganizationId(), event.getId(), ConfigurationKeys.BASE_URL)));
//not a number
assertEquals(-1, configurationManager.getIntConfigValue(Configuration.from(event.getOrganizationId(), event.getId(), ConfigurationKeys.BASE_URL), -1));
}
@Test
public void testBooleanValue() {
//missing value
assertFalse(configurationManager.getBooleanConfigValue(Configuration.from(event.getOrganizationId(), event.getId(), ticketCategory.getId(), ALLOW_FREE_TICKETS_CANCELLATION), false));
//false value
configurationManager.saveSystemConfiguration(ConfigurationKeys.ALLOW_FREE_TICKETS_CANCELLATION, "false");
assertFalse(configurationManager.getBooleanConfigValue(Configuration.from(event.getOrganizationId(), event.getId(), ticketCategory.getId(), ALLOW_FREE_TICKETS_CANCELLATION), true));
//true value
configurationManager.saveSystemConfiguration(ConfigurationKeys.ALLOW_FREE_TICKETS_CANCELLATION, "true");
assertTrue(configurationManager.getBooleanConfigValue(Configuration.from(event.getOrganizationId(), event.getId(), ticketCategory.getId(), ALLOW_FREE_TICKETS_CANCELLATION), false));
}
@Test
public void testOverrideMechanism() {
Organization organization = organizationRepository.findByName("org").get(0);
Event event = eventManager.getSingleEvent("eventShortName", "test");
TicketCategory tc = eventManager.loadTicketCategories(event).get(0);
//
//check override level up to event level
assertEquals(5, configurationManager.getIntConfigValue(Configuration.from(event.getOrganizationId(), event.getId(), MAX_AMOUNT_OF_TICKETS_BY_RESERVATION), -1));
configurationRepository.insertOrganizationLevel(organization.getId(), MAX_AMOUNT_OF_TICKETS_BY_RESERVATION.getValue(), "6", "desc");
assertEquals(6, configurationManager.getIntConfigValue(Configuration.from(event.getOrganizationId(), event.getId(), MAX_AMOUNT_OF_TICKETS_BY_RESERVATION), -1));
configurationRepository.insertEventLevel(organization.getId(), event.getId(), MAX_AMOUNT_OF_TICKETS_BY_RESERVATION.getValue(), "7", "desc");
assertEquals(7, configurationManager.getIntConfigValue(Configuration.from(event.getOrganizationId(), event.getId(), MAX_AMOUNT_OF_TICKETS_BY_RESERVATION), -1));
configurationRepository.insertTicketCategoryLevel(organization.getId(), event.getId(), tc.getId(), MAX_AMOUNT_OF_TICKETS_BY_RESERVATION.getValue(), "8", "desc");
assertEquals(7, configurationManager.getIntConfigValue(Configuration.from(event.getOrganizationId(), event.getId(), MAX_AMOUNT_OF_TICKETS_BY_RESERVATION), -1));
}
@Test
public void testBasicConfigurationNotNeeded() {
configurationRepository.deleteByKey(ConfigurationKeys.BASE_URL.getValue());
configurationRepository.deleteByKey(ConfigurationKeys.SUPPORTED_LANGUAGES.getValue());
configurationRepository.insert(ConfigurationKeys.BASE_URL.getValue(), "http://localhost:8080", "");
configurationRepository.insert(ConfigurationKeys.SUPPORTED_LANGUAGES.getValue(), "7", "");
configurationRepository.insert(ConfigurationKeys.MAPS_SERVER_API_KEY.getValue(), "MAPS_SERVER_API_KEY", "");
configurationRepository.insert(ConfigurationKeys.MAPS_CLIENT_API_KEY.getValue(), "MAPS_CLIENT_API_KEY", "");
configurationRepository.insert(ConfigurationKeys.MAILER_TYPE.getValue(), "smtp", "");
assertFalse(configurationManager.isBasicConfigurationNeeded());
}
@Test
public void testSaveOnlyExistingConfiguration() {
configurationRepository.insertOrganizationLevel(event.getOrganizationId(), ConfigurationKeys.BANK_ACCOUNT_NR.getValue(), "MY-ACCOUNT_NUMBER", "empty");
Configuration existing = configurationRepository.findByKeyAtOrganizationLevel(event.getOrganizationId(), ConfigurationKeys.BANK_ACCOUNT_NR.getValue()).orElseThrow(IllegalStateException::new);
Map<ConfigurationKeys.SettingCategory, List<Configuration>> all = configurationManager.loadOrganizationConfig(event.getOrganizationId(), USERNAME);
List<Configuration> flatten = all.entrySet().stream().flatMap(e -> e.getValue().stream()).collect(Collectors.toList());
List<ConfigurationModification> modified = flatten.stream().filter(c -> !c.getKey().equals(ConfigurationKeys.BANK_ACCOUNT_NR.getValue())).map(ConfigurationModification::fromConfiguration).collect(Collectors.toList());
modified.add(new ConfigurationModification(existing.getId(), existing.getKey(), "NEW-NUMBER"));
configurationManager.saveAllOrganizationConfiguration(event.getOrganizationId(), modified, USERNAME);
List<Configuration> organizationConfiguration = configurationRepository.findOrganizationConfiguration(event.getOrganizationId());
assertEquals(1, organizationConfiguration.size());
Optional<Configuration> result = configurationRepository.findByKeyAtOrganizationLevel(event.getOrganizationId(), ConfigurationKeys.BANK_ACCOUNT_NR.getValue());
assertTrue(result.isPresent());
Configuration configuration = result.get();
assertEquals(ConfigurationKeys.BANK_ACCOUNT_NR, configuration.getConfigurationKey());
assertEquals("NEW-NUMBER", configuration.getValue());
}
@Test
public void testSaveOnlyValidConfiguration() {
configurationRepository.insertOrganizationLevel(event.getOrganizationId(), ConfigurationKeys.BANK_ACCOUNT_NR.getValue(), "MY-ACCOUNT_NUMBER", "empty");
Configuration existing = configurationRepository.findByKeyAtOrganizationLevel(event.getOrganizationId(), ConfigurationKeys.BANK_ACCOUNT_NR.getValue()).orElseThrow(IllegalStateException::new);
Map<ConfigurationKeys.SettingCategory, List<Configuration>> all = configurationManager.loadOrganizationConfig(event.getOrganizationId(), USERNAME);
List<Configuration> flatten = all.entrySet().stream().flatMap(e -> e.getValue().stream()).collect(Collectors.toList());
List<ConfigurationModification> modified = flatten.stream().filter(c -> !c.getKey().equals(ConfigurationKeys.BANK_ACCOUNT_NR.getValue()) && !c.getKey().equals(ConfigurationKeys.PARTIAL_RESERVATION_ID_LENGTH.getValue())).map(ConfigurationModification::fromConfiguration).collect(Collectors.toList());
modified.add(new ConfigurationModification(existing.getId(), existing.getKey(), "NEW-NUMBER"));
modified.add(new ConfigurationModification(-1, ConfigurationKeys.PARTIAL_RESERVATION_ID_LENGTH.getValue(), "9"));
configurationManager.saveAllOrganizationConfiguration(event.getOrganizationId(), modified, USERNAME);
List<Configuration> organizationConfiguration = configurationRepository.findOrganizationConfiguration(event.getOrganizationId());
assertEquals(2, organizationConfiguration.size());
Optional<Configuration> result = configurationRepository.findByKeyAtOrganizationLevel(event.getOrganizationId(), ConfigurationKeys.BANK_ACCOUNT_NR.getValue());
assertTrue(result.isPresent());
Configuration configuration = result.get();
assertEquals(ConfigurationKeys.BANK_ACCOUNT_NR, configuration.getConfigurationKey());
assertEquals("NEW-NUMBER", configuration.getValue());
result = configurationRepository.findByKeyAtOrganizationLevel(event.getOrganizationId(), ConfigurationKeys.PARTIAL_RESERVATION_ID_LENGTH.getValue());
assertTrue(result.isPresent());
configuration = result.get();
assertEquals(ConfigurationKeys.PARTIAL_RESERVATION_ID_LENGTH, configuration.getConfigurationKey());
assertEquals("9", configuration.getValue());
}
@Test
public void testLoadOrganizationConfiguration() {
Map<ConfigurationKeys.SettingCategory, List<Configuration>> orgConf = configurationManager.loadOrganizationConfig(event.getOrganizationId(), USERNAME);
assertEquals(6, orgConf.size());
assertEquals(ConfigurationKeys.byPathLevel(ConfigurationPathLevel.ORGANIZATION).size(), orgConf.values().stream().flatMap(Collection::stream).count());
String value = "MY-ACCOUNT_NUMBER";
configurationRepository.insertOrganizationLevel(event.getOrganizationId(), ConfigurationKeys.BANK_ACCOUNT_NR.getValue(), value, "empty");
orgConf = configurationManager.loadOrganizationConfig(event.getOrganizationId(), USERNAME);
assertEquals(6, orgConf.size());
assertEquals(ConfigurationKeys.byPathLevel(ConfigurationPathLevel.ORGANIZATION).size(), orgConf.values().stream().flatMap(Collection::stream).count());
assertEquals(value, orgConf.get(SettingCategory.PAYMENT_OFFLINE).stream().filter(c -> c.getConfigurationKey() == ConfigurationKeys.BANK_ACCOUNT_NR).findFirst().orElseThrow(IllegalStateException::new).getValue());
}
@Test
public void testBasicConfigurationNeeded() {
configurationRepository.deleteByKey(ConfigurationKeys.BASE_URL.getValue());
assertTrue(configurationManager.isBasicConfigurationNeeded());
}
@Test
public void testSaveBooleanOptions() {
String ftcKey = ALLOW_FREE_TICKETS_CANCELLATION.getValue();
configurationRepository.insert(ftcKey, "false", "this should be updated to true");
ConfigurationModification ftc = new ConfigurationModification(configurationRepository.findByKey(ftcKey).getId(), ftcKey, "true");
String prKey = ENABLE_PRE_REGISTRATION.getValue();
configurationRepository.insert(prKey, "true", "this should be updated to false");
ConfigurationModification pr = new ConfigurationModification(configurationRepository.findByKey(prKey).getId(), prKey, "false");
ConfigurationModification newTrue = new ConfigurationModification(-1, ENABLE_WAITING_QUEUE.getValue(), "true");
ConfigurationModification newFalse = new ConfigurationModification(-1, ENABLE_WAITING_QUEUE_NOTIFICATION.getValue(), "false");
ConfigurationModification newNull = new ConfigurationModification(-1, GOOGLE_ANALYTICS_ANONYMOUS_MODE.getValue(), null);
configurationManager.saveAllSystemConfiguration(Arrays.asList(ftc, pr, newTrue, newFalse, newNull));
Configuration cFtc = configurationRepository.findByKey(ftcKey);
assertNotNull(ftc);
assertEquals("true", cFtc.getValue());
Configuration cPr = configurationRepository.findByKey(prKey);
assertNotNull(cPr);
assertEquals("false", cPr.getValue());
Configuration nTrue = configurationRepository.findByKey(ENABLE_WAITING_QUEUE.getValue());
assertNotNull(nTrue);
assertEquals("true", nTrue.getValue());
Configuration nFalse = configurationRepository.findByKey(ENABLE_WAITING_QUEUE_NOTIFICATION.getValue());
assertNotNull(nFalse);
assertEquals("false", nFalse.getValue());
Optional<Configuration> opt = OptionalWrapper.optionally(() -> configurationRepository.findByKey(GOOGLE_ANALYTICS_ANONYMOUS_MODE.getValue()));
assertFalse(opt.isPresent());
}
}