/*************************GO-LICENSE-START********************************* * Copyright 2014 ThoughtWorks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *************************GO-LICENSE-END***********************************/ package com.thoughtworks.go.domain.testinfo; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Collections; import java.util.ArrayList; import com.thoughtworks.go.domain.JobIdentifier; /** * @understands information about what caused a build to fail */ public class StageTestRuns { private LinkedList<FailingTestsInPipeline> failingTestsInPipelines = new LinkedList<>(); private Map<Integer, FailingTestsInPipeline> failingTestsInPipelineByCounter = new HashMap<>(); private int numberOfTests; private final int failureCounts; private final int errorCounts; public StageTestRuns(int numberOfTests, int failureCounts, int errorCounts) { this.numberOfTests = numberOfTests; this.failureCounts = failureCounts; this.errorCounts = errorCounts; } public int numberOfTests() { return numberOfTests; } public FailingTestsInPipeline add(int pipelineCounter, String pipelineLabel) { if (!failingTestsInPipelineByCounter.containsKey(pipelineCounter)) { FailingTestsInPipeline failingTestsInPipeline = new FailingTestsInPipeline(pipelineLabel, pipelineCounter); failingTestsInPipelines.add(failingTestsInPipeline); failingTestsInPipelineByCounter.put(pipelineCounter, failingTestsInPipeline); } return failingTestsInPipelineByCounter.get(pipelineCounter); } // assume piplines are added recent to oldest ... maybe write a runtime assertion for this ? public void add(int pipelineCounter, String pipelineLabel, String suiteName, String testName, TestStatus testStatus, JobIdentifier jobIdentifier) { FailingTestsInPipeline pipelineForThisTestCase = add(pipelineCounter, pipelineLabel); FailingTestsInPipeline currentPipeline = failingTestsInPipelines.getFirst(); if ((pipelineForThisTestCase == currentPipeline) || currentPipeline.contains(suiteName, testName)) { pipelineForThisTestCase.add(suiteName, testName, testStatus, jobIdentifier); } } public void removeDuplicateTestEntries(){ removeTestsThatStartedFailingInPreviousPipelines(); removeTestsThatWereFixedInInterimPipelines(); } private void removeTestsThatWereFixedInInterimPipelines() { Iterator<FailingTestsInPipeline> pipelineIterator = failingTestsInPipelines.iterator(); while (pipelineIterator.hasNext()) { FailingTestsInPipeline failingTestsInPipeline = pipelineIterator.next(); FailingTestsInPipeline previousPipeline = previousPipeline(failingTestsInPipeline); if (previousPipeline != null) { for (TestSuite failingSuite : failingTestsInPipeline.failingSuites()) { for (TestInformation failingTest : failingSuite.tests()) { if (!previousPipeline.contains(failingSuite.fullName(), failingTest.getName())) { removeAllTestsBeyond(failingSuite.fullName(), failingTest.getName(), previousPipeline); } } } } } } private void removeAllTestsBeyond(String suiteName, String testName, FailingTestsInPipeline beyondPipeline) { FailingTestsInPipeline previous = previousPipeline(beyondPipeline); while (previous != null) { previous.removeTest(suiteName, testName); previous = previousPipeline(previous); } } private void removeTestsThatStartedFailingInPreviousPipelines() { Iterator<FailingTestsInPipeline> pipelineIterator = failingTestsInPipelines.iterator(); while (pipelineIterator.hasNext()) { FailingTestsInPipeline failingTestsInPipeline = pipelineIterator.next(); FailingTestsInPipeline previousPipeline = previousPipeline(failingTestsInPipeline); if (previousPipeline != null) { failingTestsInPipeline.removeDuplicateTestEntries(previousPipeline); } } } private FailingTestsInPipeline previousPipeline(FailingTestsInPipeline pipeline) { int prevIndex = failingTestsInPipelines.indexOf(pipeline) + 1; if (prevIndex < failingTestsInPipelines.size()) { return failingTestsInPipelines.get(prevIndex); } else { return null; } } public List<FailingTestsInPipeline> failingTestsInPipelines() { return failingTestsInPipelines; } public int totalFailureCount() { return failureCounts; } public int totalErrorCount() { return errorCounts; } int count(TestStatus status) { int count = 0; for (FailingTestsInPipeline failingTestsInPipeline : failingTestsInPipelines) { count += failingTestsInPipeline.count(status); } return count; } public void addUser(int pipelineCounter, String pipelineLabel, String user) { add(pipelineCounter, pipelineLabel).addUser(user); } public List<Integer> failingCounters() { List<Integer> list = new ArrayList<>(failingTestsInPipelineByCounter.keySet()); Collections.sort(list); return list; } public List<TestSuite> failingTestSuitesForNthPipelineRun(int n) { return failingTestsInPipelines.get(n).failingSuites(); } }