From 540edbe7bd20a2c85f7954e3ee9855bede012cff Mon Sep 17 00:00:00 2001 From: dbiggs Date: Thu, 3 Jun 2021 22:53:01 -0400 Subject: [PATCH] TestFailures: Support showing partial results for jobs that succeed in a view Exclude jobs for which api calls fail as opposed to the entire view. --- .../java/com/vmware/jenkins/domain/Job.java | 19 +++++- .../com/vmware/jenkins/domain/JobView.java | 4 -- .../action/jenkins/FindRealTestFailures.java | 60 ++++++++++++------- .../main/java/com/vmware/util/db/DbUtils.java | 8 +++ 4 files changed, 62 insertions(+), 29 deletions(-) diff --git a/config/src/main/java/com/vmware/jenkins/domain/Job.java b/config/src/main/java/com/vmware/jenkins/domain/Job.java index bcb9d10c..8467773b 100644 --- a/config/src/main/java/com/vmware/jenkins/domain/Job.java +++ b/config/src/main/java/com/vmware/jenkins/domain/Job.java @@ -205,9 +205,20 @@ public boolean addTestResultsToMasterList() { log.info("Adding presumed pass result for test {} in build {}", result.classAndTestName(), build.buildNumber); result.addTestResult(new TestResult(result, build, PRESUMED_PASS)); })); + return presumedPassResultsAdded.get(); } + public boolean addPassResultsForSavedTestResults(JobBuild stableBuild) { + AtomicBoolean passResultsAdded = new AtomicBoolean(false); + testResults.stream().filter(result -> !result.containsBuildNumbers(stableBuild.buildNumber)).forEach(result -> { + passResultsAdded.set(true); + log.info("Adding pass result for test {} in build {}", result.classAndTestName(), stableBuild.buildNumber); + result.addTestResult(new TestResult(result, stableBuild, PASS)); + }); + return passResultsAdded.get(); + } + public void saveFetchedBuildsInfo() { if (dbUtils == null || (CollectionUtils.isEmpty(fetchedResults))) { return; @@ -228,8 +239,8 @@ public void saveFetchedBuildsInfo() { savedBuilds = dbUtils.query(JobBuild.class, "SELECT * from JOB_BUILD WHERE JOB_ID = ? ORDER BY BUILD_NUMBER DESC", id); } - public void saveTestResultsToDb(boolean presumedPassedResultsAdded) { - if (dbUtils == null || (CollectionUtils.isEmpty(fetchedResults) && !presumedPassedResultsAdded)) { + public void saveTestResultsToDb(boolean passResultsAdded) { + if (dbUtils == null || (CollectionUtils.isEmpty(fetchedResults) && !passResultsAdded)) { return; } @@ -277,6 +288,10 @@ public boolean hasSavedBuild(int buildNumber) { return savedBuilds != null && savedBuilds.stream().anyMatch(build -> build.buildNumber == buildNumber); } + public boolean hasSavedBuilds() { + return CollectionUtils.isNotEmpty(savedBuilds); + } + public void removeOldBuilds(int maxJenkinsBuildsToCheck) { if (dbUtils == null) { return; diff --git a/config/src/main/java/com/vmware/jenkins/domain/JobView.java b/config/src/main/java/com/vmware/jenkins/domain/JobView.java index 3813cdd5..803ddc9e 100644 --- a/config/src/main/java/com/vmware/jenkins/domain/JobView.java +++ b/config/src/main/java/com/vmware/jenkins/domain/JobView.java @@ -67,10 +67,6 @@ public List usableJobs(int maxJenkinsBuildsToCheck) { log.info("Skipping {} as there are no recent completed builds", job.name); return false; } - if (job.lastBuildWasSuccessful()) { - log.info("Skipping {} as most recent build {} was successful", job.name, job.lastStableBuild.buildNumber); - return false; - } if (job.lastUnstableBuild == null) { log.info("Skipping {} as there are no recent unstable builds", job.name); return false; diff --git a/core/src/main/java/com/vmware/action/jenkins/FindRealTestFailures.java b/core/src/main/java/com/vmware/action/jenkins/FindRealTestFailures.java index d8fc8c8c..d4d1a483 100644 --- a/core/src/main/java/com/vmware/action/jenkins/FindRealTestFailures.java +++ b/core/src/main/java/com/vmware/action/jenkins/FindRealTestFailures.java @@ -151,17 +151,27 @@ private void saveResultsPageForView(HomePage.View view, boolean includeViewsLink view.failingTestsCount = failingTestMethods.values().stream().mapToInt(List::size).sum(); log.info("{} failing tests found for view {}", view.failingTestsCount, view.name); - final StringBuilder jobFragments = new StringBuilder(""); final AtomicInteger counter = new AtomicInteger(); - failingTestMethods.keySet().stream().sorted(comparing(jobDetails -> jobDetails.name)).forEach(key -> { - List failingTests = failingTestMethods.get(key); - String jobFragment = createJobFragment(counter.getAndIncrement(), key, failingTests); - if (jobFragments.length() > 0) { - jobFragments.append("\n"); - } - jobFragments.append(jobFragment); - }); + String jobsResultsHtml = failingTestMethods.keySet().stream().sorted(comparing(jobDetails -> jobDetails.name)).map(job -> { + List failingTests = failingTestMethods.get(job); + return createJobFragment(counter.getAndIncrement(), job, failingTests); + }).collect(Collectors.joining("\n")); + + String resultsPage = createTestResultsHtmlPage(view, includeViewsLink, failingTestMethods, jobsResultsHtml); + + File destinationFile = new File(fileSystemConfig.destinationFile); + if (destinationFile.exists() && destinationFile.isDirectory()) { + File failurePageFile = new File(fileSystemConfig.destinationFile + File.separator + view.htmlFileName()); + log.info("Saving test results to {}", failurePageFile); + IOUtils.write(failurePageFile, resultsPage); + } else { + log.info("Saving test results to {}", destinationFile); + IOUtils.write(destinationFile, resultsPage); + } + viewPadder.infoTitle(); + } + private String createTestResultsHtmlPage(HomePage.View view, boolean includeViewsLink, Map> failingTestMethods, String jobsTestResultsHtml) { String resultsPage; String footer = "Generated at " + generationDate; if (includeViewsLink) { @@ -170,7 +180,7 @@ private void saveResultsPageForView(HomePage.View view, boolean includeViewsLink if (!failingTestMethods.isEmpty()) { String failuresPage = new ClasspathResource("/testFailuresTemplate/testFailuresWebPage.html", this.getClass()).getText(); resultsPage = failuresPage.replace("#viewName", view.viewNameWithFailureCount()); - resultsPage = resultsPage.replace("#body", jobFragments.toString()); + resultsPage = resultsPage.replace("#body", jobsTestResultsHtml); resultsPage = resultsPage.replace("#footer", footer); log.trace("Test Failures for view {}:\n{}", view.name, resultsPage); } else { @@ -178,17 +188,7 @@ private void saveResultsPageForView(HomePage.View view, boolean includeViewsLink resultsPage = allPassedPage.replace("#viewName", view.name); resultsPage = resultsPage.replace("#footer", footer); } - - File destinationFile = new File(fileSystemConfig.destinationFile); - if (destinationFile.exists() && destinationFile.isDirectory()) { - File failurePageFile = new File(fileSystemConfig.destinationFile + File.separator + view.htmlFileName()); - log.info("Saving test results to {}", failurePageFile); - IOUtils.write(failurePageFile, resultsPage); - } else { - log.info("Saving test results to {}", destinationFile); - IOUtils.write(destinationFile, resultsPage); - } - viewPadder.infoTitle(); + return resultsPage; } private Map> findAllRealFailingTests(JobView jobView) { @@ -222,8 +222,9 @@ private Map> findAllRealFailingTests(JobView jobView) { usableJobs.stream().filter(job -> !failedJobs.contains(job)).forEach(job -> { job.saveFetchedBuildsInfo(); - boolean presumedPassedResultsAdded = job.addTestResultsToMasterList(); - job.saveTestResultsToDb(presumedPassedResultsAdded); + boolean passResultsAdded = addPassResultsIfNeeded(job); + boolean presumedPassResultsAdded = job.addTestResultsToMasterList(); + job.saveTestResultsToDb(passResultsAdded || presumedPassResultsAdded); job.removeOldBuilds(jenkinsConfig.maxJenkinsBuildsToCheck); List failingTests = job.createFailingTestsList(jenkinsConfig.maxJenkinsBuildsToCheck); @@ -238,8 +239,21 @@ private Map> findAllRealFailingTests(JobView jobView) { return allFailingTests; } + private boolean addPassResultsIfNeeded(Job job) { + boolean passResultsAdded = false; + if (dbUtils != null && job.hasSavedBuilds() && job.lastBuildWasSuccessful() && !job.hasSavedBuild(job.lastStableBuild.buildNumber)) { + JobBuild stableBuild = jenkinsExecutor.execute(jenkins -> jenkins.getJobBuildDetails(job.name, job.lastStableBuild.buildNumber)); + dbUtils.insert(stableBuild); + passResultsAdded = job.addPassResultsForSavedTestResults(stableBuild); + } + return passResultsAdded; + } + private void fetchLatestTestResults(Job job, int lastFetchAmount) { job.fetchedResults = Collections.emptyList(); + if (job.lastBuildWasSuccessful()) { + log.info("No need to fetch latest results for job {} as last build was successful", job); + } int latestUsableBuildNumber = job.latestUsableBuildNumber(); if (lastFetchAmount >= jenkinsConfig.maxJenkinsBuildsToCheck && job.hasSavedBuild(latestUsableBuildNumber)) { log.info("Saved builds for {} already include latest build {}", job.name, latestUsableBuildNumber); diff --git a/utils/src/main/java/com/vmware/util/db/DbUtils.java b/utils/src/main/java/com/vmware/util/db/DbUtils.java index d21ff125..25f12422 100644 --- a/utils/src/main/java/com/vmware/util/db/DbUtils.java +++ b/utils/src/main/java/com/vmware/util/db/DbUtils.java @@ -128,6 +128,14 @@ public List query(Connection connection, Class recordClass, String que } + public void insert(T record) { + try (Connection connection = createConnection()) { + insert(connection, record); + } catch (SQLException se) { + throw new RuntimeException(se); + } + } + public void insert(Connection connection, T record) { insertIfNeeded(connection, record, null); }