// Copyright © 2015 HSL <https://www.hsl.fi> // This program is dual-licensed under the EUPL v1.2 and AGPLv3 licenses. package fi.hsl.parkandride.back.prediction; import fi.hsl.parkandride.back.AbstractDaoTest; import fi.hsl.parkandride.back.Dummies; import fi.hsl.parkandride.core.back.PredictorRepository; import fi.hsl.parkandride.core.domain.CapacityType; import fi.hsl.parkandride.core.domain.Usage; import fi.hsl.parkandride.core.domain.UtilizationKey; import fi.hsl.parkandride.core.domain.prediction.PredictorState; import fi.hsl.parkandride.core.service.ValidationException; import org.joda.time.DateTime; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import javax.inject.Inject; import static org.assertj.core.api.Assertions.assertThat; public class PredictorDaoTest extends AbstractDaoTest { @Rule public final ExpectedException thrown = ExpectedException.none(); @Inject Dummies dummies; @Inject PredictorRepository predictorRepository; private long facilityId; private UtilizationKey utilizationKey; @Before public void initTestData() { facilityId = dummies.createFacility(); utilizationKey = new UtilizationKey(facilityId, CapacityType.CAR, Usage.PARK_AND_RIDE); } // basics @Test public void creates_predictor_when_enabled_for_the_first_time() { assertThat(predictorRepository.findAllPredictors()).as("all predictors, before").isEmpty(); PredictorState state = enablePredictor("the-type", utilizationKey); assertThat(predictorRepository.findAllPredictors()).as("all predictors, after").containsOnly(state); // identifying fields: assertThat(state.predictorId).as("predictorId").isNotNull(); assertThat(state.predictorType).as("predictorType").isEqualTo("the-type"); assertThat(state.utilizationKey.facilityId).as("facilityId").isEqualTo(utilizationKey.facilityId); assertThat(state.utilizationKey.capacityType).as("capacityType").isEqualTo(utilizationKey.capacityType); assertThat(state.utilizationKey.usage).as("usage").isEqualTo(utilizationKey.usage); // default values: assertThat(state.latestUtilization).as("latestUtilization").isEqualTo(new DateTime(0)); // safe default: before all possible utilizations assertThat(state.moreUtilizations).as("moreUtilizations").isTrue(); // safe default: assume there are some utilizations to process assertThat(state.internalState).as("internalState").isEqualTo(""); // keep defaults in sync with Java code: PredictorState javaDefaults = new PredictorState(null, null, null); assertThat(javaDefaults.latestUtilization).as("javaDefaults.latestUtilization").isEqualTo(state.latestUtilization); assertThat(javaDefaults.moreUtilizations).as("javaDefaults.moreUtilizations").isEqualTo(state.moreUtilizations); assertThat(javaDefaults.internalState).as("javaDefaults.internalState").isEqualTo(state.internalState); } @Test public void returns_existing_predictor_when_enabled_for_the_second_time() { PredictorState state1 = enablePredictor("predictor-type", utilizationKey); PredictorState state2 = enablePredictor("predictor-type", utilizationKey); assertThat(state2.predictorId).as("state2.predictorId").isEqualTo(state1.predictorId); } @Test public void predictor_state_can_be_modified() { PredictorState expected = enablePredictor("type", utilizationKey); expected.latestUtilization = new DateTime(); expected.moreUtilizations = !expected.moreUtilizations; expected.internalState += "updated"; predictorRepository.save(expected); PredictorState actual = predictorRepository.getById(expected.predictorId); assertThat(actual).isNotNull(); assertThat(actual.latestUtilization).as("latestUtilization").isEqualTo(expected.latestUtilization); assertThat(actual.moreUtilizations).as("moreUtilizations").isEqualTo(expected.moreUtilizations); assertThat(actual.internalState).as("internalState").isEqualTo(expected.internalState); } @Test public void predictor_state_is_validated_before_saving() { PredictorState state = enablePredictor("type", utilizationKey); state.latestUtilization = null; state.internalState = null; thrown.expect(ValidationException.class); thrown.expectMessage("latestUtilization (NotNull)"); thrown.expectMessage("internalState (NotNull)"); predictorRepository.save(state); } // finding predictors with new utilizations /** * This can be useful if the database contains utilizations from before the predictor was created, * for example when starting to use a new type of predictor, or if predictors are not enabled automatically. */ @Test public void finds_recently_enabled_predictors_even_if_they_have_no_utilizations() { PredictorState state = enablePredictor("type", utilizationKey); assertThat(predictorRepository.findPredictorsNeedingUpdate()).containsExactly(state.predictorId); } @Test public void can_mark_predictors_to_have_processed_all_utilizations() { PredictorState state = enablePredictor("type", utilizationKey); state.moreUtilizations = false; predictorRepository.save(state); assertThat(predictorRepository.findPredictorsNeedingUpdate()).isEmpty(); } @Test public void can_mark_predictors_to_have_received_new_utilizations_to_be_processed() { PredictorState state = enablePredictor("type", utilizationKey); state.moreUtilizations = false; predictorRepository.save(state); predictorRepository.markPredictorsNeedAnUpdate(utilizationKey); state.moreUtilizations = true; assertThat(predictorRepository.findPredictorsNeedingUpdate()).containsExactly(state.predictorId); } // uniqueness @Test public void predictors_are_predictor_type_specific() { PredictorState state1 = enablePredictor("type1", utilizationKey); PredictorState state2 = enablePredictor("type2", utilizationKey); assertThat(state2.predictorId).as("state2.predictorId").isNotEqualTo(state1.predictorId); } @Test public void predictors_are_facility_specific() { long facilityId2 = dummies.createFacility(); PredictorState state1 = enablePredictor("predictor-type", new UtilizationKey(facilityId, CapacityType.CAR, Usage.PARK_AND_RIDE)); PredictorState state2 = enablePredictor("predictor-type", new UtilizationKey(facilityId2, CapacityType.CAR, Usage.PARK_AND_RIDE)); assertThat(state2.predictorId).as("state2.predictorId").isNotEqualTo(state1.predictorId); } @Test public void predictors_are_capacity_type_specific() { PredictorState state1 = enablePredictor("predictor-type", new UtilizationKey(facilityId, CapacityType.CAR, Usage.PARK_AND_RIDE)); PredictorState state2 = enablePredictor("predictor-type", new UtilizationKey(facilityId, CapacityType.ELECTRIC_CAR, Usage.PARK_AND_RIDE)); assertThat(state2.predictorId).as("state2.predictorId").isNotEqualTo(state1.predictorId); } @Test public void predictors_are_usage_specific() { PredictorState state1 = enablePredictor("predictor-type", new UtilizationKey(facilityId, CapacityType.CAR, Usage.PARK_AND_RIDE)); PredictorState state2 = enablePredictor("predictor-type", new UtilizationKey(facilityId, CapacityType.CAR, Usage.COMMERCIAL)); assertThat(state2.predictorId).as("state2.predictorId").isNotEqualTo(state1.predictorId); } @Test public void marking_predictors_is_facility_specific() { UtilizationKey key1 = new UtilizationKey(facilityId, CapacityType.CAR, Usage.PARK_AND_RIDE); UtilizationKey key2 = new UtilizationKey(dummies.createFacility(), CapacityType.CAR, Usage.PARK_AND_RIDE); createPredictorNotNeedingUpdate(key1); createPredictorNotNeedingUpdate(key2); predictorRepository.markPredictorsNeedAnUpdate(key1); assertThat(predictorRepository.findPredictorsNeedingUpdate()).hasSize(1); } @Test public void marking_predictors_is_capacity_type_specific() { UtilizationKey key1 = new UtilizationKey(facilityId, CapacityType.CAR, Usage.PARK_AND_RIDE); UtilizationKey key2 = new UtilizationKey(facilityId, CapacityType.ELECTRIC_CAR, Usage.PARK_AND_RIDE); createPredictorNotNeedingUpdate(key1); createPredictorNotNeedingUpdate(key2); predictorRepository.markPredictorsNeedAnUpdate(key1); assertThat(predictorRepository.findPredictorsNeedingUpdate()).hasSize(1); } @Test public void marking_predictors_is_usage_specific() { UtilizationKey key1 = new UtilizationKey(facilityId, CapacityType.CAR, Usage.PARK_AND_RIDE); UtilizationKey key2 = new UtilizationKey(facilityId, CapacityType.CAR, Usage.COMMERCIAL); createPredictorNotNeedingUpdate(key1); createPredictorNotNeedingUpdate(key2); predictorRepository.markPredictorsNeedAnUpdate(key1); assertThat(predictorRepository.findPredictorsNeedingUpdate()).hasSize(1); } private void createPredictorNotNeedingUpdate(UtilizationKey utilizationKey) { PredictorState state = enablePredictor("predictor-type", utilizationKey); state.moreUtilizations = false; predictorRepository.save(state); } private PredictorState enablePredictor(String predictorType, UtilizationKey utilizationKey) { Long predictorId = predictorRepository.enablePredictor(predictorType, utilizationKey); return predictorRepository.getById(predictorId); } }