objective.taskboard.followup.FollowUpDataRepositoryByFileTest.java Source code

Java tutorial

Introduction

Here is the source code for objective.taskboard.followup.FollowUpDataRepositoryByFileTest.java

Source

/*-
 * [LICENSE]
 * Taskboard
 * ---
 * Copyright (C) 2015 - 2017 Objective Solutions
 * ---
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * [/LICENSE]
 */

package objective.taskboard.followup;

import static java.nio.file.Files.copy;
import static java.nio.file.Files.createDirectories;
import static java.nio.file.Files.createTempDirectory;
import static java.nio.file.Files.exists;
import static java.nio.file.Files.size;
import static objective.taskboard.followup.FollowUpDataRepositoryByFile.EXTENSION_JSON;
import static objective.taskboard.followup.FollowUpDataRepositoryByFile.EXTENSION_ZIP;
import static objective.taskboard.followup.FollowUpDataRepositoryByFile.FILE_NAME_FORMATTER;
import static objective.taskboard.followup.FollowUpHelper.assertFollowUpDataV0;
import static objective.taskboard.followup.FollowUpHelper.followupEmptyV2;
import static objective.taskboard.followup.FollowUpHelper.followupExpectedV2;
import static objective.taskboard.followup.FollowUpHelper.followupWithExtraFieldsV2;
import static objective.taskboard.followup.FollowUpHelper.getDefaultFollowupData;
import static objective.taskboard.followup.FollowUpHelper.getDefaultFollowupDataWithExtraFields;
import static objective.taskboard.followup.FollowUpHelper.getEmptyFollowupData;
import static objective.taskboard.utils.IOUtilities.ENCODE_UTF_8;
import static objective.taskboard.utils.IOUtilities.asResource;
import static objective.taskboard.utils.ZipUtils.unzip;
import static objective.taskboard.utils.ZipUtils.zip;
import static org.apache.commons.io.FileUtils.deleteQuietly;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.greaterThan;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;

import objective.taskboard.database.directory.DataBaseDirectory;
import objective.taskboard.rules.TimeZoneRule;
import objective.taskboard.utils.DateTimeUtils;

public class FollowUpDataRepositoryByFileTest {
    private static final ZoneId TIMEZONE = ZoneId.systemDefault();
    private static final String PROJECT_TEST = "PROJECT TEST";
    private static final String PROJECT_TEST_2 = "PROJECT TEST 2";
    private static final LocalDate TODAY_DATE = LocalDate.now();
    private static final LocalDate TODAY = TODAY_DATE;
    private static final LocalDate YESTERDAY = TODAY_DATE.minusDays(1);

    private Path dataPath;
    private FollowUpDataRepository subject;

    @Rule
    public TimeZoneRule timeZoneRule = new TimeZoneRule("America/Sao_Paulo");

    @Before
    public void before() throws IOException {
        dataPath = createTempDirectory(getClass().getSimpleName());

        DataBaseDirectory dataBaseDirectory = mock(DataBaseDirectory.class);
        when(dataBaseDirectory.path(anyString())).thenReturn(dataPath);

        subject = new FollowUpDataRepositoryByFile(dataBaseDirectory);
    }

    @After
    public void after() {
        deleteQuietly(dataPath.toFile());
    }

    @Test
    public void whenSaveOneProject_thenOneFileShouldBeGenerated() throws IOException {
        subject.save(PROJECT_TEST, TODAY_DATE, getDefaultFollowupData());

        assertGeneratedFile(PROJECT_TEST, followupExpectedV2());
    }

    @Test
    public void whenSaveEmptyData_thenNoDataShouldBeGenerated() throws IOException {
        subject.save(PROJECT_TEST, TODAY_DATE, getEmptyFollowupData());

        assertGeneratedFile(PROJECT_TEST, followupEmptyV2());
    }

    @Test
    public void whenSaveTwoProjects_thenTwoFilesShouldBeGenerated() throws IOException {
        subject.save(PROJECT_TEST, TODAY_DATE, getDefaultFollowupData());
        subject.save(PROJECT_TEST_2, TODAY_DATE, getDefaultFollowupData());

        assertGeneratedFile(PROJECT_TEST, followupExpectedV2());
        assertGeneratedFile(PROJECT_TEST_2, followupExpectedV2());
    }

    @Test
    public void givenProjectWithNoHistory_whenGetHistoryGivenProjects_thenReturnNoData() {
        List<LocalDate> history = subject.getHistoryByProject(PROJECT_TEST);
        assertTrue("History should be empty", history.isEmpty());
    }

    @Test
    public void givenProjectWithTodaysHistory_whenGetHistoryGivenProjects_thenReturnNoData() {
        createProjectZip(PROJECT_TEST, TODAY);

        List<LocalDate> history = subject.getHistoryByProject(PROJECT_TEST);
        assertTrue("History should be empty", history.isEmpty());
    }

    @Test
    public void givenProjectWithYesterdaysHistory_whenGetHistoryGivenProjects_thenReturnData() {
        createProjectZip(PROJECT_TEST, YESTERDAY);

        List<LocalDate> history = subject.getHistoryByProject(PROJECT_TEST);
        assertEquals("History size", 1, history.size());
        assertEquals("First history", YESTERDAY, history.get(0));
    }

    @Test
    public void whenHasDataHistory_GetShouldReturnSomeData() {
        createProjectZipV0(PROJECT_TEST);

        List<FromJiraDataRow> jiraData = subject.get(YESTERDAY, TIMEZONE, PROJECT_TEST).fromJiraDs.rows;

        assertEquals("Jira data size", jiraData.size(), 1);
        assertFollowUpDataV0(jiraData.get(0));
    }

    @Test
    public void whenDoesNotHaveDataHistory_GetShouldThrowAnIllegalStateException() {
        try {
            subject.get(YESTERDAY, TIMEZONE, PROJECT_TEST);
            fail("Should have thrown IllegalStateException");
        } catch (IllegalStateException e) {
            assertNotNull("IllegalStateException shouldn't be null", e);
        }
    }

    @Test
    public void whenHasInvalidDataHistory_GetShouldThrowAnIllegalStateException() throws URISyntaxException {
        try {
            Path pathJSON = Paths.get(getClass().getResource("impl/V1_followUpDataHistoryExpected.json").toURI());
            Path zipFile = dataPath.resolve(PROJECT_TEST).resolve(YESTERDAY + EXTENSION_JSON + EXTENSION_ZIP);
            zip(pathJSON, zipFile);

            subject.get(YESTERDAY, TIMEZONE, PROJECT_TEST);
            fail("Should have thrown IllegalStateException");
        } catch (IllegalStateException e) {
            assertNotNull("IllegalStateException shouldn't be null", e);
        }
    }

    @Test
    public void whenHasDataHistoryWithCfd_GetShouldRestoreSyntheticsDataSources() {
        // given
        createProjectZipV2(PROJECT_TEST);

        // when
        FollowUpData data = subject.get(YESTERDAY, TIMEZONE, PROJECT_TEST);

        // then
        assertThat(data).isEqualToComparingFieldByFieldRecursively(getDefaultFollowupData());
    }

    @Test
    public void testVersion2() {
        // given
        createProjectZipV2(PROJECT_TEST);

        // when
        FollowUpData data = subject.get(YESTERDAY, TIMEZONE, PROJECT_TEST);

        // then
        assertThat(data).isEqualToComparingFieldByFieldRecursively(getDefaultFollowupData());
    }

    @Test
    public void whenHasDataHistoryWithCfdAndPassesZoneId_GetShouldRecalculateAnalyticsAndSynthetics() {
        // given
        createProjectZipV1(PROJECT_TEST);
        ZoneId saoPauloTZ = ZoneId.of("America/Sao_Paulo"); // -03:00, no conversion
        ZoneId torontoTZ = ZoneId.of("America/Toronto"); // -04:00, changes date and hours
        ZoneId sydneyTZ = ZoneId.of("Australia/Sydney"); // +10:00, same day, different hours

        // when
        FollowUpData dataSaoPaulo = subject.get(YESTERDAY, saoPauloTZ, PROJECT_TEST);
        FollowUpData dataToronto = subject.get(YESTERDAY, torontoTZ, PROJECT_TEST);
        FollowUpData dataSydney = subject.get(YESTERDAY, sydneyTZ, PROJECT_TEST);

        // then
        List<ZonedDateTime> saoPauloAnalyticsDates = dataSaoPaulo.analyticsTransitionsDsList.get(0).rows
                .get(0).transitionsDates;
        assertEquals(saoPauloAnalyticsDates.get(0),
                DateTimeUtils.parseDateTime("2017-09-27", "00:00:00", saoPauloTZ));
        assertEquals(saoPauloAnalyticsDates.get(1),
                DateTimeUtils.parseDateTime("2017-09-26", "00:00:00", saoPauloTZ));
        assertEquals(saoPauloAnalyticsDates.get(2),
                DateTimeUtils.parseDateTime("2017-09-25", "00:00:00", saoPauloTZ));

        List<ZonedDateTime> torontoAnalyticsDates = dataToronto.analyticsTransitionsDsList.get(0).rows
                .get(0).transitionsDates;
        assertEquals(torontoAnalyticsDates.get(0),
                DateTimeUtils.parseDateTime("2017-09-26", "23:00:00", torontoTZ));
        assertEquals(torontoAnalyticsDates.get(1),
                DateTimeUtils.parseDateTime("2017-09-25", "23:00:00", torontoTZ));
        assertEquals(torontoAnalyticsDates.get(2),
                DateTimeUtils.parseDateTime("2017-09-24", "23:00:00", torontoTZ));

        List<ZonedDateTime> sydneyAnalyticsDates = dataSydney.analyticsTransitionsDsList.get(0).rows
                .get(0).transitionsDates;
        assertEquals(sydneyAnalyticsDates.get(0), DateTimeUtils.parseDateTime("2017-09-27", "13:00:00", sydneyTZ));
        assertEquals(sydneyAnalyticsDates.get(1), DateTimeUtils.parseDateTime("2017-09-26", "13:00:00", sydneyTZ));
        assertEquals(sydneyAnalyticsDates.get(2), DateTimeUtils.parseDateTime("2017-09-25", "13:00:00", sydneyTZ));

        List<SyntheticTransitionsDataRow> saoPauloSyntheticRows = dataSaoPaulo.syntheticsTransitionsDsList
                .get(0).rows;
        assertEquals(saoPauloSyntheticRows.get(0).date,
                DateTimeUtils.parseDateTime("2017-09-25", "00:00:00", saoPauloTZ));
        assertEquals(saoPauloSyntheticRows.get(1).date,
                DateTimeUtils.parseDateTime("2017-09-25", "00:00:00", saoPauloTZ));
        assertEquals(saoPauloSyntheticRows.get(2).date,
                DateTimeUtils.parseDateTime("2017-09-26", "00:00:00", saoPauloTZ));
        assertEquals(saoPauloSyntheticRows.get(3).date,
                DateTimeUtils.parseDateTime("2017-09-26", "00:00:00", saoPauloTZ));
        assertEquals(saoPauloSyntheticRows.get(4).date,
                DateTimeUtils.parseDateTime("2017-09-27", "00:00:00", saoPauloTZ));
        assertEquals(saoPauloSyntheticRows.get(5).date,
                DateTimeUtils.parseDateTime("2017-09-27", "00:00:00", saoPauloTZ));

        List<SyntheticTransitionsDataRow> torontoSyntheticRows = dataToronto.syntheticsTransitionsDsList
                .get(0).rows;
        assertEquals(torontoSyntheticRows.get(0).date,
                DateTimeUtils.parseDateTime("2017-09-24", "00:00:00", torontoTZ));
        assertEquals(torontoSyntheticRows.get(1).date,
                DateTimeUtils.parseDateTime("2017-09-24", "00:00:00", torontoTZ));
        assertEquals(torontoSyntheticRows.get(2).date,
                DateTimeUtils.parseDateTime("2017-09-25", "00:00:00", torontoTZ));
        assertEquals(torontoSyntheticRows.get(3).date,
                DateTimeUtils.parseDateTime("2017-09-25", "00:00:00", torontoTZ));
        assertEquals(torontoSyntheticRows.get(4).date,
                DateTimeUtils.parseDateTime("2017-09-26", "00:00:00", torontoTZ));
        assertEquals(torontoSyntheticRows.get(5).date,
                DateTimeUtils.parseDateTime("2017-09-26", "00:00:00", torontoTZ));

        List<SyntheticTransitionsDataRow> sydneySyntheticsRows = dataSydney.syntheticsTransitionsDsList.get(0).rows;
        assertEquals(sydneySyntheticsRows.get(0).date,
                DateTimeUtils.parseDateTime("2017-09-25", "00:00:00", sydneyTZ));
        assertEquals(sydneySyntheticsRows.get(1).date,
                DateTimeUtils.parseDateTime("2017-09-25", "00:00:00", sydneyTZ));
        assertEquals(sydneySyntheticsRows.get(2).date,
                DateTimeUtils.parseDateTime("2017-09-26", "00:00:00", sydneyTZ));
        assertEquals(sydneySyntheticsRows.get(3).date,
                DateTimeUtils.parseDateTime("2017-09-26", "00:00:00", sydneyTZ));
        assertEquals(sydneySyntheticsRows.get(4).date,
                DateTimeUtils.parseDateTime("2017-09-27", "00:00:00", sydneyTZ));
        assertEquals(sydneySyntheticsRows.get(5).date,
                DateTimeUtils.parseDateTime("2017-09-27", "00:00:00", sydneyTZ));
    }

    @Test
    public void whenSaveExtraFieldsData_thenExtraFieldsDataShouldBeGenerated() throws IOException {
        subject.save(PROJECT_TEST, TODAY_DATE, getDefaultFollowupDataWithExtraFields());

        assertGeneratedFile(PROJECT_TEST, followupWithExtraFieldsV2());
    }

    private void assertGeneratedFile(String project, String dataHistoryExpected) throws IOException {
        String dateString = TODAY.format(FILE_NAME_FORMATTER);
        Path source = dataPath.resolve(project).resolve(dateString + EXTENSION_JSON + EXTENSION_ZIP);

        assertTrue("File should be exist", exists(source));
        assertThat(size(source), greaterThan(0L));

        Path destiny = createTempDirectory("FollowUpDataHistoryAssertTest");
        try {
            unzip(source.toFile(), destiny);
            Path pathJSON = destiny.resolve(dateString + EXTENSION_JSON);
            String actual = IOUtils.toString(asResource(pathJSON).getInputStream(), ENCODE_UTF_8);

            assertEquals("Follow Up data history", dataHistoryExpected, actual);
        } finally {
            deleteQuietly(destiny.toFile());
        }
    }

    private Path createProjectZipV0(String project) {
        return createProjectZip(project, YESTERDAY, "impl/V0_followUpDataHistoryExpected.json");
    }

    private Path createProjectZipV1(String project) {
        return createProjectZip(project, YESTERDAY, "impl/V1_followUpDataHistoryExpected.json");
    }

    private Path createProjectZipV2(String project) {
        return createProjectZip(project, YESTERDAY, "impl/V2_followUpDataHistoryExpected.json");
    }

    private Path createProjectZip(String project, LocalDate date) {
        return createProjectZip(project, date, "impl/V2_followUpDataHistoryExpected.json");
    }

    private Path createProjectZip(String projectKey, LocalDate date, String file) {
        try {
            Path pathProject = dataPath.resolve(projectKey);
            createDirectories(pathProject);

            Path pathInputJSON = Paths.get(getClass().getResource(file).toURI());
            Path pathOutputJSON = pathProject.resolve(date.format(FILE_NAME_FORMATTER) + EXTENSION_JSON);
            copy(pathInputJSON, pathOutputJSON);

            Path zipFile = Paths.get(pathOutputJSON.toString() + EXTENSION_ZIP);
            zip(pathOutputJSON, zipFile);
            return pathProject;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}