/* * The MIT License * * Copyright 2013 Sony Mobile Communications Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.sonyericsson.jenkins.plugins.bfa.db; import com.sonyericsson.jenkins.plugins.bfa.PluginImpl; import com.sonyericsson.jenkins.plugins.bfa.graphs.FailureCauseTimeInterval; import com.sonyericsson.jenkins.plugins.bfa.graphs.GraphFilterBuilder; import com.sonyericsson.jenkins.plugins.bfa.model.FailureCause; import com.sonyericsson.jenkins.plugins.bfa.model.FailureCauseModification; import com.sonyericsson.jenkins.plugins.bfa.statistics.FailureCauseStatistics; import com.sonyericsson.jenkins.plugins.bfa.statistics.Statistics; import com.sonyericsson.jenkins.plugins.bfa.statistics.Statistics.UpstreamCause; import com.sonyericsson.jenkins.plugins.bfa.utils.ObjectCountPair; import org.jfree.data.time.Day; import org.jfree.data.time.Hour; import org.jfree.data.time.TimePeriod; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PowerMockIgnore; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import org.powermock.reflect.Whitebox; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import static org.hamcrest.CoreMatchers.anyOf; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.lessThan; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.powermock.api.mockito.PowerMockito.mockStatic; import static org.powermock.api.mockito.PowerMockito.when; /** * Test class for statistics fetching using Embedded MongoDB. * * @author Fredrik Persson <fredrik6.persson@sonymobile.com> * */ @RunWith(PowerMockRunner.class) @PrepareForTest(PluginImpl.class) @PowerMockIgnore("javax.management.*") //Solves PowerMock issue 277 public class EmbeddedMongoStatisticsTest extends EmbeddedMongoTest { // CS IGNORE MagicNumber FOR NEXT 600 LINES. REASON: Test data. private static final String ID1 = "111111111111111111111111"; private static final String ID2 = "222222222222222222222222"; private static final String CAT1 = "CAT1"; private static final String CAT2 = "CAT2"; private static final String PROJECT_A = "Project A"; private static final String PROJECT_B = "Project B"; private static final String PROJECT_C = "Project C"; private static final String MASTER_A = "Master A"; private static final String MASTER_B = "Master B"; private static final String MASTER_C = "Master C"; private static final String SUCCESS = "SUCCESS"; private static final String ABORTED = "ABORTED"; private static final String UNSTABLE = "UNSTABLE"; private static final int BUILD_NR = 54321; private static Date lastHour; private static Date now; private TimePeriod hourPeriod1; private TimePeriod hourPeriod2; private GraphFilterBuilder filter1; private GraphFilterBuilder filter2; @Override @Before public void setUp() throws IOException { super.setUp(); Calendar lastHourCalendar = Calendar.getInstance(); lastHourCalendar.add(Calendar.HOUR_OF_DAY, -1); lastHour = lastHourCalendar.getTime(); now = new Date(); hourPeriod1 = new Hour(lastHour); hourPeriod2 = new Hour(); filter1 = new GraphFilterBuilder(); filter2 = new GraphFilterBuilder(); PluginImpl plugin = new PluginImpl(); mockStatic(PluginImpl.class); when(PluginImpl.getInstance()).thenReturn(plugin); Whitebox.setInternalState(plugin, "knowledgeBase", knowledgeBase); } /** * Sets up the knowledgebase with two failure causes. * @throws Exception if something goes wrong */ private void setUpTwoCauses() throws Exception { FailureCauseStatistics statCause1 = new FailureCauseStatistics(ID1, null); FailureCauseStatistics statCause2 = new FailureCauseStatistics(ID2, null); FailureCause cause1 = new FailureCause(ID1, null, null, null, null, CAT1, null, null); FailureCause cause2 = new FailureCause(ID2, null, null, null, null, CAT2, null, null); knowledgeBase.addCause(cause1); knowledgeBase.addCause(cause2); List<FailureCauseStatistics> failureList1 = new ArrayList<FailureCauseStatistics>(); failureList1.add(statCause1); failureList1.add(statCause2); List<FailureCauseStatistics> failureList2 = new ArrayList<FailureCauseStatistics>(); failureList2.add(statCause1); List<FailureCauseStatistics> failureList3 = new ArrayList<FailureCauseStatistics>(); Statistics statistics1 = new Statistics(PROJECT_A, 1, "", lastHour, 1L, null, null, MASTER_A, 0, UNSTABLE, null, failureList1); Statistics statistics2 = new Statistics(PROJECT_B, 2, "", now, 1L, null, null, MASTER_B, 0, ABORTED, null, failureList2); Statistics statistics3 = new Statistics(PROJECT_C, 3, "", now, 1L, null, null, MASTER_C, 0, SUCCESS, null, failureList3); knowledgeBase.saveStatistics(statistics1); knowledgeBase.saveStatistics(statistics2); knowledgeBase.saveStatistics(statistics3); } /** * Tests {@link MongoDBKnowledgeBase#getLatestFailureForCause(String)}. * @throws Exception if something goes wrong */ @Test public void testGetLatestFailureForCause() throws Exception { setUpTwoCauses(); assertEquals(now, knowledgeBase.getLatestFailureForCause(ID1)); assertEquals(lastHour, knowledgeBase.getLatestFailureForCause(ID2)); } /** * Tests {@link MongoDBKnowledgeBase#updateLastSeen(List, Date)}. * @throws Exception if something goes wrong */ @Test public void testUpdateLastSeen() throws Exception { setUpTwoCauses(); List<String> ids = Arrays.asList(ID1, ID2); knowledgeBase.updateLastSeen(ids, now); assertEquals(now, knowledgeBase.getCause(ID1).getLastOccurred()); assertEquals(now, knowledgeBase.getCause(ID2).getLastOccurred()); } /** * Tests {@link MongoDBKnowledgeBase#getCreationDateForCause(String)} by saving * a dummy {@link FailureCause} and verifying it was created recently. * @throws Exception if something goes wrong */ @Test public void testGetCreationDateForCause() throws Exception { FailureCause emptyCause = new FailureCause(null, null, null, null, null, "", null, null); String id = knowledgeBase.addCause(emptyCause).getId(); Date creationDate = knowledgeBase.getCreationDateForCause(id); long createdMillisAgo = System.currentTimeMillis() - creationDate.getTime(); int createdSecondsAgo = (int)TimeUnit.SECONDS.convert(createdMillisAgo, TimeUnit.MILLISECONDS); assertThat(createdSecondsAgo, is(lessThan(2))); } /** * Tests {@link MongoDBKnowledgeBase#getNbrOfNullFailureCauses * (com.sonyericsson.jenkins.plugins.bfa.graphs.GraphFilterBuilder)}. * @throws Exception if something goes wrong */ @Test public void testGetNbrOfNullFailureCauses() throws Exception { assertEquals(0, knowledgeBase.getNbrOfNullFailureCauses(null)); Statistics nullStatistics = new Statistics(null, 1, null, null, 1L, null, null, null, 1, null, null, null); knowledgeBase.saveStatistics(nullStatistics); assertEquals(1, knowledgeBase.getNbrOfNullFailureCauses(null)); } /** * Test for {@link FailureCause#initModifications()}. Verifies that the creation date * is taken as latest modification date if no saved modifications are present. * @throws Exception if something goes wrong */ @Test public void testInitModifications() throws Exception { FailureCause cause = knowledgeBase.addCause(new FailureCause()); List<FailureCauseModification> mods = cause.getAndInitiateModifications(); assertFalse("Should have creation date after initiation", mods.isEmpty()); long createdMillisAgo = System.currentTimeMillis() - mods.get(0).getTime().getTime(); int createdSecondsAgo = (int)TimeUnit.SECONDS.convert(createdMillisAgo, TimeUnit.MILLISECONDS); assertThat(createdSecondsAgo, is(lessThan(2))); } /** * Tests {@link MongoDBKnowledgeBase#getNbrOfFailureCausesPerId * (com.sonyericsson.jenkins.plugins.bfa.graphs.GraphFilterBuilder, int)}. * @throws Exception if something goes wrong */ @Test public void testGetNbrOfFailureCausesPerId() throws Exception { setUpTwoCauses(); List<ObjectCountPair<String>> result = knowledgeBase.getNbrOfFailureCausesPerId(null, 0); assertEquals(2, result.size()); assertEquals(2, result.get(0).getCount()); assertEquals(1, result.get(1).getCount()); assertEquals(ID1, result.get(0).getObject()); assertEquals(ID2, result.get(1).getObject()); } /** * Tests {@link MongoDBKnowledgeBase#getNbrOfFailureCauses * (com.sonyericsson.jenkins.plugins.bfa.graphs.GraphFilterBuilder)}. * @throws Exception if something goes wrong */ @Test public void testGetNbrOfFailureCauses() throws Exception { setUpTwoCauses(); List<ObjectCountPair<FailureCause>> result = knowledgeBase.getNbrOfFailureCauses(null); assertEquals(2, result.size()); assertEquals(2, result.get(0).getCount()); assertEquals(1, result.get(1).getCount()); assertEquals(ID1, result.get(0).getObject().getId()); assertEquals(ID2, result.get(1).getObject().getId()); } /** * Tests that {@link MongoDBKnowledgeBase#getStatistics * (com.sonyericsson.jenkins.plugins.bfa.graphs.GraphFilterBuilder)} with upstream cause.gets stored correctly. * @throws Exception if something goes wrong */ @Test public void testStatisticsWithUpstreamCauses() throws Exception { Statistics.UpstreamCause uc = new UpstreamCause(PROJECT_B, BUILD_NR); Statistics s = new Statistics(PROJECT_A, 1, null, null, 1L, null, null, MASTER_A, 0, UNSTABLE, uc, null); knowledgeBase.saveStatistics(s); List<Statistics> fetchedStatistics = knowledgeBase.getStatistics(null, -1); assertNotNull("The fetched statistics should not be null", fetchedStatistics); assertFalse("The fetched statistics list should not be empty", fetchedStatistics.isEmpty()); Statistics.UpstreamCause fetchedUC = fetchedStatistics.get(0).getUpstreamCause(); assertEquals(fetchedUC.getUpstreamBuild(), uc.getUpstreamBuild()); assertEquals(fetchedUC.getUpstreamProject(), uc.getUpstreamProject()); } /** * Tests that {@link MongoDBKnowledgeBase#getStatistics * (com.sonyericsson.jenkins.plugins.bfa.graphs.GraphFilterBuilder)} with no upstream cause works correctly. * @throws Exception if something goes wrong */ @Test public void testStatisticsWithNoUpstreamCauses() throws Exception { Statistics s = new Statistics(PROJECT_A, 1, null, null, 1L, null, null, MASTER_A, 0, UNSTABLE, null, null); knowledgeBase.saveStatistics(s); List<Statistics> fetchedStatistics = knowledgeBase.getStatistics(null, -1); assertNotNull("The fetched statistics should not be null", fetchedStatistics); assertFalse("The fetched statistics list should not be empty", fetchedStatistics.isEmpty()); Statistics.UpstreamCause fetchedUC = fetchedStatistics.get(0).getUpstreamCause(); assertTrue("The fetched upstream cause should be null", fetchedUC == null); } /** * Tests {@link MongoDBKnowledgeBase#getFailureCausesPerBuild(GraphFilterBuilder)}. * @throws Exception if something goes wrong */ @Test public void testGetFailureCausesPerBuild() throws Exception { setUpTwoCauses(); Map<Integer, List<FailureCause>> result = knowledgeBase.getFailureCausesPerBuild(null); // We have two build numbers: assertEquals(2, result.entrySet().size()); // We have two FailureCauses for build #1: assertEquals(2, result.get(1).size()); // We have one FailureCause for build #2: assertEquals(1, result.get(2).size()); // For build #1, we have both failure causes: List<FailureCause> firstBuildFailureCauses = result.get(1); assertThat(firstBuildFailureCauses.get(0).getId(), anyOf(equalTo(ID1), equalTo(ID2))); assertThat(firstBuildFailureCauses.get(1).getId(), anyOf(equalTo(ID1), equalTo(ID2))); assertFalse("The ids should not be equal", firstBuildFailureCauses.get(0).equals(firstBuildFailureCauses.get(1))); // For build #2, we have only failure cause with id1: assertEquals(ID1, result.get(2).get(0).getId()); } /** * Tests {@link MongoDBKnowledgeBase#getFailureCausesPerTime(int, GraphFilterBuilder, boolean)}. * Fetches failure causes per time in hour intervals and does not group by categories. * @throws Exception if something goes wrong */ @Test public void testGetFailureCausesPerTimeNonCategories() throws Exception { setUpTwoCauses(); List<FailureCauseTimeInterval> result = knowledgeBase.getFailureCausesPerTime(Calendar.HOUR_OF_DAY, null, false); // We expect 3 FailureCauseIntervals: assertEquals(3, result.size()); boolean firstFound = false; boolean secondFound = false; boolean thirdFound = false; for (FailureCauseTimeInterval timeInterval : result) { if (timeInterval.getId().equals(ID1) && timeInterval.getPeriod().equals(hourPeriod2) && timeInterval.getNumber() == 1) { firstFound = true; } else if (timeInterval.getId().equals(ID2) && timeInterval.getPeriod().equals(hourPeriod1) && timeInterval.getNumber() == 1) { secondFound = true; } else if (timeInterval.getId().equals(ID1) && timeInterval.getPeriod().equals(hourPeriod1) && timeInterval.getNumber() == 1) { thirdFound = true; } } assertTrue(firstFound); assertTrue(secondFound); assertTrue(thirdFound); } /** * Tests {@link MongoDBKnowledgeBase#getFailureCausesPerTime(int, GraphFilterBuilder, boolean)}. * Fetches failure causes per time in hour intervals and groups by categories. * @throws Exception if something goes wrong */ @Test public void testGetFailureCausesPerTimeWithCategories() throws Exception { setUpTwoCauses(); List<FailureCauseTimeInterval> result = knowledgeBase.getFailureCausesPerTime(Calendar.HOUR_OF_DAY, null, true); // We expect 3 FailureCauseIntervals: assertEquals(3, result.size()); boolean firstFound = false; boolean secondFound = false; boolean thirdFound = false; for (FailureCauseTimeInterval timeInterval : result) { if (timeInterval.getName().equals(CAT1) && timeInterval.getPeriod().equals(hourPeriod2) && timeInterval.getNumber() == 1) { firstFound = true; } else if (timeInterval.getName().equals(CAT2) && timeInterval.getPeriod().equals(hourPeriod1) && timeInterval.getNumber() == 1) { secondFound = true; } else if (timeInterval.getName().equals(CAT1) && timeInterval.getPeriod().equals(hourPeriod1) && timeInterval.getNumber() == 1) { thirdFound = true; } } assertTrue(firstFound); assertTrue(secondFound); assertTrue(thirdFound); } /** * Tests {@link MongoDBKnowledgeBase#getFailureCausesPerTime(int, GraphFilterBuilder, boolean)}. * Fetches failure causes per time in day intervals and does not group by categories. * @throws Exception if something goes wrong */ @Test public void testGetFailureCausesPerTimeDayPeriod() throws Exception { setUpTwoCauses(); List<FailureCauseTimeInterval> result = knowledgeBase.getFailureCausesPerTime(Calendar.DATE, null, false); // We expect 2 FailureCauseIntervals: assertEquals(2, result.size()); assertEquals(ID2, result.get(0).getId()); assertEquals(new Day(), result.get(0).getPeriod()); assertEquals(1, result.get(0).getNumber()); assertEquals(ID1, result.get(1).getId()); assertEquals(new Day(), result.get(1).getPeriod()); assertEquals(2, result.get(1).getNumber()); } /** * Tests {@link MongoDBKnowledgeBase#getUnknownFailureCauseQuotaPerTime(int, GraphFilterBuilder)}. * Sets up statistics for one day where 50% are without failure causes. * @throws Exception if something goes wrong */ @Test public void testGetUnknownFailureCauseQuotaPerTimeOneDay() throws Exception { FailureCause cause = new FailureCause(ID1, null, null, null, null, CAT1, null, null); knowledgeBase.saveCause(cause); FailureCauseStatistics causeStats = new FailureCauseStatistics(ID1, null); List<FailureCauseStatistics> statList = new ArrayList<FailureCauseStatistics>(); statList.add(causeStats); Statistics statistics1 = new Statistics(null, 1, null, new Date(), 1L, null, null, null, 0, null, null, statList); Statistics statistics2 = new Statistics(null, 2, null, new Date(), 1L, null, null, null, 0, null, null, null); knowledgeBase.saveStatistics(statistics1); knowledgeBase.saveStatistics(statistics2); TimePeriod today = new Day(); Map<TimePeriod, Double> result = knowledgeBase.getUnknownFailureCauseQuotaPerTime(Calendar.DATE, null); assertEquals(1, result.keySet().size()); assertEquals(0, Double.compare(result.values().iterator().next(), 0.5)); assertEquals(today, result.keySet().iterator().next()); } /** * Test for filtering statistics by project. * @throws Exception if something goes wrong */ @Test public void testFilterOnProject() throws Exception { setUpTwoCauses(); filter1.setProjectName(PROJECT_A); filter2.setProjectName(PROJECT_B); doFilterAssert(); } /** * Test for filtering statistics by build number. * @throws Exception if something goes wrong */ @Test public void testFilterOnBuildNumber() throws Exception { setUpTwoCauses(); filter1.setBuildNumbers(Arrays.asList(1)); filter2.setBuildNumbers(Arrays.asList(2)); doFilterAssert(); } /** * Test for filtering statistics by master. * @throws Exception if something goes wrong */ @Test public void testFilterOnMaster() throws Exception { setUpTwoCauses(); filter1.setMasterName(MASTER_A); filter2.setMasterName(MASTER_B); doFilterAssert(); } /** * Test for filtering statistics by build started. * @throws Exception if something goes wrong */ @Test public void testFilterOnBuildStarted() throws Exception { setUpTwoCauses(); Calendar fewMinutesAgo = Calendar.getInstance(); fewMinutesAgo.add(Calendar.MINUTE, -5); Calendar moreThanAnHourAgo = Calendar.getInstance(); moreThanAnHourAgo.add(Calendar.MINUTE, -65); filter1.setSince(moreThanAnHourAgo.getTime()); filter2.setSince(fewMinutesAgo.getTime()); doFilterAssert(); } /** * Test for filtering statistics by result. * @throws Exception if something goes wrong */ @Test public void testFilterOnResult() throws Exception { setUpTwoCauses(); filter1.setResult(SUCCESS); filter2.setResult(ABORTED); doFilterAssert(2, 2); } /** * Test for filtering statistics by excluded result. * @throws Exception if something goes wrong */ @Test public void testFilterOnExcludeResult() throws Exception { setUpTwoCauses(); filter1.setExcludeResult(ABORTED); filter2.setExcludeResult(SUCCESS); doFilterAssert(2, 2); } /** * Shortcut for the filter assert helper with default parameters. */ private void doFilterAssert() { doFilterAssert(2, 1); } /** * Helper for the filter tests. Verifies that the correct result is returned since * most filter tests have the same expected result. * * @param firstSize the expected result size from {@link #filter1}. * @param secondSize the expected result size from {@link #filter2}. */ private void doFilterAssert(int firstSize, int secondSize) { List<ObjectCountPair<FailureCause>> result1 = knowledgeBase.getNbrOfFailureCauses(filter1); List<ObjectCountPair<FailureCause>> result2 = knowledgeBase.getNbrOfFailureCauses(filter2); assertEquals(firstSize, result1.size()); String resultId1 = result1.get(0).getObject().getId(); String resultId2 = result1.get(1).getObject().getId(); assertThat(resultId1, anyOf(equalTo(ID1), equalTo(ID2))); assertThat(resultId2, anyOf(equalTo(ID1), equalTo(ID2))); assertFalse("Both ids should not be equal", resultId1.equals(resultId2)); assertEquals(secondSize, result2.size()); assertEquals(ID1, result2.get(0).getObject().getId()); } }