Skip to content
Permalink
Browse files
Compacted history for tests: byte array introduced instead of objects…
… with primitives, caching constants compactor IDs to reduce map get count, unit tests fixed - Fixes #147.

Signed-off-by: Dmitriy Pavlov <dpavlov@apache.org>
  • Loading branch information
dspavlov committed Aug 9, 2019
1 parent d5c757b commit a96c97db4c04f6121061ba43e2d79298436f3957
Showing 21 changed files with 706 additions and 428 deletions.
@@ -26,7 +26,9 @@
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.ignite.ci.teamcity.ignited.BuildRefCompacted;
import org.apache.ignite.tcbot.engine.chain.*;
import org.apache.ignite.tcignited.build.TestCompactedV2;
import org.apache.ignite.tcignited.buildlog.IBuildLogProcessor;
import org.apache.ignite.tcservice.ITeamcity;
import org.apache.ignite.tcservice.model.hist.BuildRef;
@@ -39,6 +41,7 @@
import org.apache.ignite.ci.teamcity.ignited.TeamcityIgnitedMock;
import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
import org.jetbrains.annotations.NotNull;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;

@@ -69,6 +72,12 @@ public class BuildChainProcessorTest {
}
});

@Before
public void resetCaches() {
BuildRefCompacted.resetCached();
TestCompactedV2.resetCached();
TestCompactedMult.resetCached();
}
/**
*
*/
@@ -21,25 +21,24 @@
import com.google.common.collect.Lists;
import com.google.inject.Guice;
import com.google.inject.Injector;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.OptionalInt;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
import org.apache.ignite.tcservice.ITeamcity;
import org.apache.ignite.ci.tcbot.chain.MockBasedTcBotModule;
import org.apache.ignite.ci.teamcity.ignited.TeamcityIgnitedProviderMock;
import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
import org.apache.ignite.ci.user.ITcBotUserCreds;
import org.apache.ignite.tcbot.engine.conf.BranchTracked;
import org.apache.ignite.tcbot.engine.conf.ChainAtServerTracked;
import org.apache.ignite.ci.tcbot.chain.MockBasedTcBotModule;
import org.apache.ignite.tcbot.engine.conf.TcBotJsonConfig;
import org.apache.ignite.tcservice.model.result.tests.TestOccurrenceFull;
import org.apache.ignite.tcbot.persistence.IStringCompactor;
import org.apache.ignite.tcignited.ITeamcityIgnitedProvider;
import org.apache.ignite.tcignited.TeamcityIgnitedImpl;
import org.apache.ignite.ci.teamcity.ignited.TeamcityIgnitedProviderMock;
import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
import org.apache.ignite.ci.user.ITcBotUserCreds;
import org.apache.ignite.tcservice.ITeamcity;
import org.apache.ignite.tcservice.model.result.tests.TestOccurrenceFull;
import org.jetbrains.annotations.NotNull;
import org.junit.Before;
import org.junit.Test;
@@ -57,6 +56,8 @@
public class IssueDetectorTest {
/** Server id. */
public static final String SRV_ID = "apacheTest";
public static final String PDS_1 = "PDS1";
public static final String PDS_2 = "PDS2_noChanges";

/** Builds emulated storage. */
private Map<Integer, FatBuildCompacted> apacheBuilds = new ConcurrentHashMap<>();
@@ -144,33 +145,42 @@ public void emulateHistory(String chainId,
IStringCompactor c,
Map<String, String> pds1Hist,
Map<String, String> buildWoChanges) {
Map<Integer, FatBuildCompacted> builds = apacheBuilds;

emulateHistory(builds, chainId, c, PDS_1, pds1Hist, PDS_2, buildWoChanges);
}

public static void emulateHistory(Map<Integer, FatBuildCompacted> builds,
String chainId, IStringCompactor c,
String pds1, Map<String, String> pds1Hist,
String pds2, Map<String, String> buildWoChanges) {
OptionalInt longestHist = Stream.concat(pds1Hist.values().stream(),
buildWoChanges.values().stream()).mapToInt(String::length).max();
Preconditions.checkState(longestHist.isPresent());
int histLen = longestHist.getAsInt();

for (int i = 0; i < histLen; i++) {
FatBuildCompacted pds1Build
= createFatBuild(c, "PDS1", ITeamcity.DEFAULT, 1100 + i, 100 * i, false)
= createFatBuild(c, pds1, ITeamcity.DEFAULT, 1100 + i, 100 * i, false)
.addTests(c, testsMapToXmlModel(pds1Hist, histLen, i), null)
.changes(new int[] {i});

apacheBuilds.put(pds1Build.id(), pds1Build);
builds.put(pds1Build.id(), pds1Build);

FatBuildCompacted pds2Build
= createFatBuild(c, "PDS2_noChanges", ITeamcity.DEFAULT, 1200 + i, 100 * i, false)
= createFatBuild(c, pds2, ITeamcity.DEFAULT, 1200 + i, 100 * i, false)
.addTests(c, testsMapToXmlModel(buildWoChanges, histLen, i), null);

apacheBuilds.put(pds2Build.id(), pds2Build);
builds.put(pds2Build.id(), pds2Build);

FatBuildCompacted chainBuild = createFatBuild(c, chainId, ITeamcity.DEFAULT, 1000 + i, 100 * i, false)
.snapshotDependencies(new int[] {pds1Build.id(), pds2Build.id()});
apacheBuilds.put(chainBuild.id(), chainBuild);
builds.put(chainBuild.id(), chainBuild);
}
}

@NotNull
public List<TestOccurrenceFull> testsMapToXmlModel(
public static List<TestOccurrenceFull> testsMapToXmlModel(
Map<String, String> pds1Hist,
int histLen,
int idx) {
@@ -184,9 +194,15 @@ public List<TestOccurrenceFull> testsMapToXmlModel(

char chState = stat.charAt(locIdx);
boolean ok = '0' == chState;
boolean failed = '1' == chState;
if (ok || failed)
page.add(createTest(name.hashCode(), name, ok));
boolean failed = '1' == chState || '6' == chState;
boolean muted = '6' == chState;
if (ok || failed) {
TestOccurrenceFull test = createTest(name.hashCode(), name, ok);
if (muted)
test.muted = true;

page.add(test);
}
});

return page;
@@ -20,7 +20,7 @@
import com.google.common.base.Preconditions;
import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
import org.apache.ignite.ci.teamcity.ignited.runhist.Invocation;
import org.apache.ignite.ci.teamcity.ignited.runhist.RunHistCompacted;
import org.apache.ignite.tcignited.history.RunHistCompacted;
import org.apache.ignite.ci.teamcity.ignited.runhist.RunHistKey;
import org.apache.ignite.tcbot.common.TcBotConst;
import org.apache.ignite.tcbot.common.conf.ITcServerConfig;
@@ -29,11 +29,14 @@
import java.io.InputStreamReader;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -50,6 +53,7 @@
import org.apache.ignite.Ignition;
import org.apache.ignite.ci.db.TcHelperDb;
import org.apache.ignite.ci.tcbot.chain.PrChainsProcessorTest;
import org.apache.ignite.ci.tcbot.issue.IssueDetectorTest;
import org.apache.ignite.ci.teamcity.ignited.BuildRefCompacted;
import org.apache.ignite.ci.teamcity.ignited.buildtype.BuildTypeRefCompacted;
import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
@@ -62,20 +66,25 @@
import org.apache.ignite.tcbot.common.conf.ITcServerConfig;
import org.apache.ignite.tcbot.common.interceptor.GuavaCachedModule;
import org.apache.ignite.tcbot.common.util.FutureUtil;
import org.apache.ignite.tcbot.engine.chain.TestCompactedMult;
import org.apache.ignite.tcbot.engine.conf.ITcBotConfig;
import org.apache.ignite.tcbot.engine.conf.TcBotJsonConfig;
import org.apache.ignite.tcbot.engine.issue.EventTemplates;
import org.apache.ignite.tcbot.persistence.IStringCompactor;
import org.apache.ignite.tcbot.persistence.IgniteStringCompactor;
import org.apache.ignite.tcbot.persistence.TcBotPersistenceModule;
import org.apache.ignite.tcbot.persistence.scheduler.DirectExecNoWaitScheduler;
import org.apache.ignite.tcbot.persistence.scheduler.IScheduler;
import org.apache.ignite.tcignited.build.FatBuildDao;
import org.apache.ignite.tcignited.build.ProactiveFatBuildSync;
import org.apache.ignite.tcignited.build.TestCompactedV2;
import org.apache.ignite.tcignited.buildlog.ILogProductSpecific;
import org.apache.ignite.tcignited.buildref.BuildRefDao;
import org.apache.ignite.tcignited.history.BuildStartTimeStorage;
import org.apache.ignite.tcignited.history.HistoryCollector;
import org.apache.ignite.tcignited.history.IRunHistory;
import org.apache.ignite.tcignited.history.ISuiteRunHistory;
import org.apache.ignite.tcignited.history.SuiteInvocationHistoryDao;
import org.apache.ignite.tcservice.ITeamcity;
import org.apache.ignite.tcservice.TeamcityServiceConnection;
import org.apache.ignite.tcservice.http.ITeamcityHttpConnection;
@@ -108,6 +117,7 @@
import static junit.framework.TestCase.assertNotNull;
import static junit.framework.TestCase.assertNull;
import static junit.framework.TestCase.assertTrue;
import static org.apache.ignite.ci.tcbot.issue.IssueDetectorTest.SRV_ID;
import static org.apache.ignite.tcbot.common.conf.TcBotWorkDir.ensureDirExist;
import static org.apache.ignite.tcbot.persistence.IgniteStringCompactor.STRINGS_CACHE;
import static org.mockito.ArgumentMatchers.anyString;
@@ -161,6 +171,10 @@ public static void stopIgnite() {
public void clearIgniteCaches() {
clearCache(BuildRefDao.TEAMCITY_BUILD_CACHE_NAME);
clearCache(FatBuildDao.TEAMCITY_FAT_BUILD_CACHE_NAME);

BuildRefCompacted.resetCached();
TestCompactedV2.resetCached();
TestCompactedMult.resetCached();
}

/**
@@ -810,7 +824,76 @@ public void testCachesInvalidation() {

FutureUtil.getResults(futures);
svc.shutdown();
}

@Test
public void testTestHistoryPropagation() {
TeamcityIgnitedModule module = new TeamcityIgnitedModule();

Injector injector = Guice.createInjector(module, new GuavaCachedModule(), new IgniteAndSchedulerTestModule());

String chainId = TeamcityIgnitedImpl.DEFAULT_PROJECT_ID;
IStringCompactor c = injector.getInstance(IStringCompactor.class);

String testUnmuted = "testUnmuted";
Map<String, String> pds1Hist = new TreeMap<String, String>() {
{
put(testUnmuted, "66666611111");
put("testOk", " 0000");
}
};
String testFlakyStableFailure = "testFlakyStableFailure";

Map<String, String> pds2Hist = new TreeMap<String, String>() {
{
put("testFailedShoudlBeConsideredAsFlaky", "0000011111");
put(testFlakyStableFailure, "0000011111111111");
}
};

Map<Integer, FatBuildCompacted> builds = new HashMap<>();
String suite1 = IssueDetectorTest.PDS_1;
String suite2 = IssueDetectorTest.PDS_2;
IssueDetectorTest.emulateHistory(builds, chainId, c, suite1, pds1Hist, suite2, pds2Hist);

BuildRefDao buildRefDao = injector.getInstance(BuildRefDao.class).init();

FatBuildDao fatBuildDao = injector.getInstance(FatBuildDao.class).init();

injector.getInstance(SuiteInvocationHistoryDao.class).init();
injector.getInstance(BuildStartTimeStorage.class).init();

int srvId = ITeamcityIgnited.serverIdToInt(IssueDetectorTest.SRV_ID);
builds.forEach((k, v) -> {
buildRefDao.save(srvId, new BuildRefCompacted(v));
fatBuildDao.putFatBuild(srvId, k, v);
});

HistoryCollector histCollector = injector.getInstance(HistoryCollector.class);

IRunHistory hist = histCollector.getTestRunHist(SRV_ID,
c.getStringId(testUnmuted),
c.getStringId(suite1),
c.getStringId(ITeamcity.DEFAULT));

assertNotNull(hist);

assertEquals(Arrays.asList(4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1, 1), hist.getLatestRunResults());

assertEquals(0, hist.getCriticalFailuresCount());

assertFalse(hist.isFlaky());
assertEquals(1.0, hist.getFailRate(), 0.05);

IRunHistory histFailedFlaky = histCollector.getTestRunHist(SRV_ID,
c.getStringId(testFlakyStableFailure),
c.getStringId(suite2),
c.getStringId(ITeamcity.DEFAULT));

assertTrue(histFailedFlaky.isFlaky());

Integer integer = histFailedFlaky.detectTemplate(EventTemplates.newFailureForFlakyTest);
assertNotNull(integer);
}

/**
@@ -697,14 +697,14 @@ ISuiteRunHistory suiteHist(ITeamcityIgnited tcIgn,
return null;

try {
ISuiteRunHistory suiteRunHistory = histCacheMap.get(baseBranchId,
ISuiteRunHistory suiteRunHist = histCacheMap.get(baseBranchId,
() -> Optional.ofNullable(tcIgn.getSuiteRunHist(buildTypeIdId, baseBranchId)))
.orElse(null);

if (suiteRunHistory != null && requireParameters != null && !requireParameters.isEmpty())
return suiteRunHistory.filter(requireParameters);
if (suiteRunHist != null && requireParameters != null && !requireParameters.isEmpty())
return suiteRunHist.filter(requireParameters);

return suiteRunHistory;
return suiteRunHist;
}
catch (ExecutionException e) {
throw ExceptionUtil.propagateException(e);
@@ -28,9 +28,7 @@
import org.apache.ignite.tcbot.persistence.IStringCompactor;
import org.apache.ignite.tcignited.ITeamcityIgnited;
import org.apache.ignite.tcignited.build.ITest;
import org.apache.ignite.tcignited.history.IRunHistSummary;
import org.apache.ignite.tcignited.history.IRunHistory;
import org.apache.ignite.tcignited.history.IRunStat;
import org.apache.ignite.tcignited.history.ISuiteRunHistory;
import org.apache.ignite.tcservice.model.result.tests.TestOccurrence;

@@ -44,15 +42,19 @@ public class TestCompactedMult {
private long avgDuration = -1;

/** Status success. */
private static volatile int STATUS_SUCCESS = -1;
private static volatile int STATUS_SUCCESS_CID = -1;

public TestCompactedMult(IStringCompactor compactor, MultBuildRunCtx ctx) {
this.compactor = compactor;
this.ctx = ctx;

//Each time compactor should give same result
if (STATUS_SUCCESS == -1)
STATUS_SUCCESS = compactor.getStringId(TestOccurrence.STATUS_SUCCESS);
if (STATUS_SUCCESS_CID == -1)
STATUS_SUCCESS_CID = compactor.getStringId(TestOccurrence.STATUS_SUCCESS);
}

public static void resetCached() {
STATUS_SUCCESS_CID = -1;
}

@Nullable public Integer testName() {
@@ -71,7 +73,7 @@ public boolean isInvestigated() {
private int getFailedButNotMutedCount() {
return (int)occurrences.stream()
.filter(Objects::nonNull)
.filter(t -> t.isFailedButNotMuted(STATUS_SUCCESS)).count();
.filter(t -> t.isFailedButNotMuted(STATUS_SUCCESS_CID)).count();
}

public int failuresCount() {
@@ -102,7 +104,7 @@ public Stream<ITest> getInvocationsStream() {
* @param baseBranchStat Base branch statistics.
* @return non null comment in case test failure is a blocker for merge into base branch.
*/
public String getPossibleBlockerComment(IRunHistSummary baseBranchStat) {
public String getPossibleBlockerComment(IRunHistory baseBranchStat) {
if (failuresCount() == 0) {
if (baseBranchStat == null) {
long durationMs = getAvgDurationMs();
@@ -124,7 +126,7 @@ public String getPossibleBlockerComment(IRunHistSummary baseBranchStat) {
boolean lowFailureRate = failRate * 100.0f < TcBotConst.NON_FLAKY_TEST_FAIL_RATE_BLOCKER_BORDER_PERCENTS;

if (lowFailureRate && !flaky) {
String runStatPrintable = IRunStat.getPercentPrintable(failRate * 100.0f);
String runStatPrintable = IRunHistory.getPercentPrintable(failRate * 100.0f);

return "Test has low fail rate in base branch "
+ runStatPrintable
@@ -142,9 +144,9 @@ public IRunHistory history(ITeamcityIgnited ignited, @Nullable Integer baseBranc
return history(ignited, baseBranchId, null);
}

public IRunHistory history(ITeamcityIgnited ignited,
@Nullable Integer baseBranchId,
@Nullable Map<Integer, Integer> requireParameters) {
@Nullable public IRunHistory history(ITeamcityIgnited ignited,
@Nullable Integer baseBranchId,
@Nullable Map<Integer, Integer> requireParameters) {
Integer name = testName();
if (name == null || baseBranchId == null)
return null;
@@ -160,7 +162,7 @@ public IRunHistory history(ITeamcityIgnited ignited,
/**
*/
public boolean isFailedButNotMuted() {
return occurrences.stream().anyMatch(o -> o.isFailedButNotMuted(STATUS_SUCCESS));
return occurrences.stream().anyMatch(o -> o.isFailedButNotMuted(STATUS_SUCCESS_CID));
}

/**

0 comments on commit a96c97d

Please sign in to comment.