You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by je...@apache.org on 2013/08/11 08:30:07 UTC

svn commit: r1512879 - in /hbase/branches/0.95/dev-support/jenkins-tools: ./ buildstats/ buildstats/src/ buildstats/src/main/ buildstats/src/main/java/ buildstats/src/main/java/org/ buildstats/src/main/java/org/apache/ buildstats/src/main/java/org/apac...

Author: jeffreyz
Date: Sun Aug 11 06:30:07 2013
New Revision: 1512879

URL: http://svn.apache.org/r1512879
Log:
hbase-8018: Add 'Flaky Testcase Detector' tool into dev-tools

Added:
    hbase/branches/0.95/dev-support/jenkins-tools/
    hbase/branches/0.95/dev-support/jenkins-tools/README.md
    hbase/branches/0.95/dev-support/jenkins-tools/buildstats/
    hbase/branches/0.95/dev-support/jenkins-tools/buildstats/pom.xml
    hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/
    hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/
    hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/
    hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/
    hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/
    hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/
    hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/
    hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/
    hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/
    hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/BuildResultWithTestCaseDetails.java
    hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/HistoryReport.java
    hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/TestCaseResult.java
    hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/TestResultHistory.java
    hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/TestSuite.java
    hbase/branches/0.95/dev-support/jenkins-tools/pom.xml

Added: hbase/branches/0.95/dev-support/jenkins-tools/README.md
URL: http://svn.apache.org/viewvc/hbase/branches/0.95/dev-support/jenkins-tools/README.md?rev=1512879&view=auto
==============================================================================
--- hbase/branches/0.95/dev-support/jenkins-tools/README.md (added)
+++ hbase/branches/0.95/dev-support/jenkins-tools/README.md Sun Aug 11 06:30:07 2013
@@ -0,0 +1,67 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+jenkins-tools
+=============
+
+A tool which pulls test case results from Jenkins server. It displays a union of failed test cases 
+from the last 15(by default and actual number of jobs can be less depending on availablity) runs 
+recorded in Jenkins sever and track how each of them are performed for all the last 15 runs(passed, 
+not run or failed)
+
+Pre-requirement(run under folder jenkins-tools)
+       Please download jenkins-client from https://github.com/cosmin/jenkins-client
+       1) git clone git://github.com/cosmin/jenkins-client.git
+       2) make sure the dependency jenkins-client version in ./buildstats/pom.xml matches the 
+          downloaded jenkins-client(current value is 0.1.6-SNAPSHOT)
+       
+Build command(run under folder jenkins-tools):
+
+       mvn clean package
+
+Usage are: 
+
+       java -jar ./buildstats/target/buildstats.jar <Jenkins HTTP URL> <Job Name> [number of last most recent jobs to check]
+
+Sample commands are:
+
+       java -jar ./buildstats/target/buildstats.jar https://builds.apache.org HBase-TRUNK
+
+Sample output(where 1 means "PASSED", 0 means "NOT RUN AT ALL", -1 means "FAILED"):
+
+Failed Test Cases              3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3632 3633 3634 3635
+
+org.apache.hadoop.hbase.catalog.testmetareadereditor.testretrying    1    1   -1    0    1    1    1    1   -1    0    1    1    1    1
+org.apache.hadoop.hbase.client.testadmin.testdeleteeditunknowncolumnfamilyandortable    0    1    1    1   -1    0    1    1    0    1    1    1    1    1
+org.apache.hadoop.hbase.client.testfromclientsidewithcoprocessor.testclientpoolthreadlocal    1    1    1    1    1    1    1    1    0    1    1   -1    0    1
+org.apache.hadoop.hbase.client.testhcm.testregioncaching    1    1   -1    0    1    1   -1    0   -1    0   -1    0    1    1
+org.apache.hadoop.hbase.client.testmultiparallel.testflushcommitswithabort    1    1    1    1    1    1    1    1   -1    0    1    1    1    1
+org.apache.hadoop.hbase.client.testscannertimeout.test3686a    1    1    1    1    1    1    1    1   -1    0    1    1    1    1
+org.apache.hadoop.hbase.coprocessor.example.testrowcountendpoint.org.apache.hadoop.hbase.coprocessor.example.testrowcountendpoint    0   -1    0   -1    0    0    0   -1    0    0    0    0    0    0
+org.apache.hadoop.hbase.coprocessor.example.testzookeeperscanpolicyobserver.org.apache.hadoop.hbase.coprocessor.example.testzookeeperscanpolicyobserver    0   -1    0   -1    0    0    0   -1    0    0    0    0    0    0
+org.apache.hadoop.hbase.master.testrollingrestart.testbasicrollingrestart    1    1    1    1   -1    0    1    1    1    1    1    1   -1    0
+org.apache.hadoop.hbase.regionserver.testcompactionstate.testmajorcompaction    1    1   -1    0    1    1    1    1    1    1    1    1    1    1
+org.apache.hadoop.hbase.regionserver.testcompactionstate.testminorcompaction    1    1   -1    0    1    1    1    1    1    1    1    1    1    1
+org.apache.hadoop.hbase.replication.testreplication.loadtesting    1    1    1    1    1    1    1    1    1   -1    0    1    1    1
+org.apache.hadoop.hbase.rest.client.testremoteadmin.org.apache.hadoop.hbase.rest.client.testremoteadmin    0    0    0    0    0    0    0    0   -1    0    0    0    0    0
+org.apache.hadoop.hbase.rest.client.testremotetable.org.apache.hadoop.hbase.rest.client.testremotetable    0    0    0    0    0    0    0    0   -1    0    0    0    0    0
+org.apache.hadoop.hbase.security.access.testtablepermissions.testbasicwrite    0    1    1    1    1    1    1    1    1    1    1    1    1   -1
+org.apache.hadoop.hbase.testdrainingserver.testdrainingserverwithabort    1    1    1    1    1   -1    0    1    1    1    1    1   -1    0
+org.apache.hadoop.hbase.util.testhbasefsck.testregionshouldnotbedeployed    1    1    1    1    1    1   -1    0   -1    0   -1   -1    0   -1
+
+

Added: hbase/branches/0.95/dev-support/jenkins-tools/buildstats/pom.xml
URL: http://svn.apache.org/viewvc/hbase/branches/0.95/dev-support/jenkins-tools/buildstats/pom.xml?rev=1512879&view=auto
==============================================================================
--- hbase/branches/0.95/dev-support/jenkins-tools/buildstats/pom.xml (added)
+++ hbase/branches/0.95/dev-support/jenkins-tools/buildstats/pom.xml Sun Aug 11 06:30:07 2013
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <!--
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+-->
+	<modelVersion>4.0.0</modelVersion>
+
+	<groupId>org.apache.hbase</groupId>
+	<artifactId>buildstats</artifactId>
+	<version>1.0</version>
+	<packaging>jar</packaging>
+	<name>buildstats</name>
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+	</properties>
+
+	<dependencies>
+		<dependency>
+			<groupId>com.offbytwo.jenkins</groupId>
+			<artifactId>jenkins-client</artifactId>
+			<version>0.1.6-SNAPSHOT</version>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-jar-plugin</artifactId>
+				<version>2.4</version>
+				<inherited>true</inherited>
+				<configuration>
+					<archive>
+						<manifest>
+							<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
+							<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
+						</manifest>
+					</archive>
+				</configuration>
+			</plugin>
+	
+			<plugin>
+				<artifactId>maven-assembly-plugin</artifactId>
+				<configuration>
+					<archive>
+						<manifest>
+							<addClasspath>true</addClasspath>
+							<mainClass>org.apache.hadoop.hbase.devtools.buildstats.TestResultHistory</mainClass>
+						</manifest>
+					</archive>
+					<descriptorRefs>
+						<descriptorRef>jar-with-dependencies</descriptorRef>
+					</descriptorRefs>
+					<finalName>buildstats</finalName>
+					<appendAssemblyId>false</appendAssemblyId>
+				</configuration>
+				<executions>
+					<execution>
+						<id>make-my-jar-with-dependencies</id>
+						<phase>package</phase>
+						<goals>
+							<goal>single</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+	
+		</plugins>
+	</build>
+</project>

Added: hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/BuildResultWithTestCaseDetails.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/BuildResultWithTestCaseDetails.java?rev=1512879&view=auto
==============================================================================
--- hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/BuildResultWithTestCaseDetails.java (added)
+++ hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/BuildResultWithTestCaseDetails.java Sun Aug 11 06:30:07 2013
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.hadoop.hbase.devtools.buildstats;
+
+import com.offbytwo.jenkins.model.BaseModel;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class BuildResultWithTestCaseDetails extends BaseModel {
+
+  List<TestSuite> suites;
+
+  /* default constructor needed for Jackson */
+  public BuildResultWithTestCaseDetails() {
+    this(new ArrayList<TestSuite>());
+  }
+
+  public BuildResultWithTestCaseDetails(List<TestSuite> s) {
+    this.suites = s;
+  }
+
+  public BuildResultWithTestCaseDetails(TestSuite... s) {
+    this(Arrays.asList(s));
+  }
+
+  public List<TestSuite> getSuites() {
+    return suites;
+  }
+
+  public void setSuites(List<TestSuite> s) {
+    suites = s;
+  }
+}

Added: hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/HistoryReport.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/HistoryReport.java?rev=1512879&view=auto
==============================================================================
--- hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/HistoryReport.java (added)
+++ hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/HistoryReport.java Sun Aug 11 06:30:07 2013
@@ -0,0 +1,88 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.hadoop.hbase.devtools.buildstats;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.Set;
+
+public class HistoryReport {
+  private List<Integer> buildsWithTestResults;
+  private Map<String, int[]> historyResults;
+  private Map<Integer, Set<String>> skippedTests;
+
+  public HistoryReport() {
+    buildsWithTestResults = new ArrayList<Integer>();
+    this.historyResults = new HashMap<String, int[]>();
+  }
+
+  public Map<String, int[]> getHistoryResults() {
+    return this.historyResults;
+  }
+
+  public Map<Integer, Set<String>> getSkippedTests() {
+    return this.skippedTests;
+  }
+
+  public List<Integer> getBuildsWithTestResults() {
+    return this.buildsWithTestResults;
+  }
+
+  public void setBuildsWithTestResults(List<Integer> src) {
+    this.buildsWithTestResults = src;
+  }
+
+  public void setHistoryResults(Map<String, int[]> src, Map<Integer, Set<String>> skippedTests) {
+    this.skippedTests = skippedTests;
+    this.historyResults = src;
+  }
+
+  public void printReport() {
+    System.out.printf("%-30s", "Failed Test Cases Stats");
+    for (Integer i : getBuildsWithTestResults()) {
+      System.out.printf("%5d", i);
+    }
+    System.out.println("\n========================================================");
+    SortedSet<String> keys = new TreeSet<String>(getHistoryResults().keySet());
+    for (String failedTestCase : keys) {
+      System.out.println();
+      int[] resultHistory = getHistoryResults().get(failedTestCase);
+      System.out.print(failedTestCase);
+      for (int i = 0; i < resultHistory.length; i++) {
+        System.out.printf("%5d", resultHistory[i]);
+      }
+    }
+    System.out.println();
+
+    if (skippedTests == null) return;
+
+    System.out.printf("\n%-30s\n", "Skipped Test Cases Stats");
+    for (Integer i : getBuildsWithTestResults()) {
+      Set<String> tmpSkippedTests = skippedTests.get(i);
+      if (tmpSkippedTests == null || tmpSkippedTests.isEmpty()) continue;
+      System.out.printf("======= %d skipped(Or don't have) following test suites =======\n", i);
+      for (String skippedTestcase : tmpSkippedTests) {
+        System.out.println(skippedTestcase);
+      }
+    }
+  }
+}
\ No newline at end of file

Added: hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/TestCaseResult.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/TestCaseResult.java?rev=1512879&view=auto
==============================================================================
--- hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/TestCaseResult.java (added)
+++ hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/TestCaseResult.java Sun Aug 11 06:30:07 2013
@@ -0,0 +1,61 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.hadoop.hbase.devtools.buildstats;
+
+public class TestCaseResult {
+  private String className;
+  private int failedSince;
+  private String name;
+  private String status;
+
+  public String getName() {
+    return name;
+  }
+
+  public String getClassName() {
+    return className;
+  }
+
+  public int failedSince() {
+    return failedSince;
+  }
+
+  public String getStatus() {
+    return status;
+  }
+
+  public void setName(String s) {
+    name = s;
+  }
+
+  public void setClassName(String s) {
+    className = s;
+  }
+
+  public void setFailedSince(int s) {
+    failedSince = s;
+  }
+
+  public void setStatus(String s) {
+    status = s;
+  }
+
+  public String getFullName() {
+    return (this.className + "." + this.name).toLowerCase();
+  }
+}

Added: hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/TestResultHistory.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/TestResultHistory.java?rev=1512879&view=auto
==============================================================================
--- hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/TestResultHistory.java (added)
+++ hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/TestResultHistory.java Sun Aug 11 06:30:07 2013
@@ -0,0 +1,260 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.hadoop.hbase.devtools.buildstats;
+
+import com.offbytwo.jenkins.JenkinsServer;
+import com.offbytwo.jenkins.client.JenkinsHttpClient;
+import com.offbytwo.jenkins.model.*;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.*;
+
+public class TestResultHistory {
+  public final static String STATUS_REGRESSION = "REGRESSION";
+  public final static String STATUS_FAILED = "FAILED";
+  public final static String STATUS_PASSED = "PASSED";
+  public final static String STATUS_FIXED = "FIXED";
+  public static int BUILD_HISTORY_NUM = 15;
+
+  private JenkinsHttpClient client;
+  private String jobName;
+
+  public TestResultHistory(String apacheHTTPURL, String jobName, String userName, String passWord)
+      throws URISyntaxException {
+    this.client = new JenkinsHttpClient(new URI(apacheHTTPURL), userName, passWord);
+    this.jobName = jobName;
+  }
+
+  public static void main(String[] args) {
+
+    if (args.length < 2) {
+      printUsage();
+      return;
+    }
+
+    String apacheHTTPUrl = args[0];
+    String jobName = args[1];
+    if (args.length > 2) {
+      int tmpHistoryJobNum = -1;
+      try {
+        tmpHistoryJobNum = Integer.parseInt(args[2]);
+      } catch (NumberFormatException ex) {
+        // ignore
+      }
+      if (tmpHistoryJobNum > 0) {
+        BUILD_HISTORY_NUM = tmpHistoryJobNum;
+      }
+    }
+
+    try {
+      TestResultHistory buildHistory = new TestResultHistory(apacheHTTPUrl, jobName, "", "");
+      HistoryReport report = buildHistory.getReport();
+      // display result in console
+      report.printReport();
+    } catch (Exception ex) {
+      System.out.println("Got unexpected exception: " + ex.getMessage());
+    }
+  }
+
+  protected static void printUsage() {
+    System.out.println("<Jenkins HTTP URL> <Job Name> [Number of Historical Jobs to Check]");
+    System.out.println("Sample Input: \"https://builds.apache.org\" "
+        + "\"HBase-TRUNK-on-Hadoop-2.0.0\" ");
+  }
+
+  public HistoryReport getReport() {
+    HistoryReport report = new HistoryReport();
+
+    List<Integer> buildWithTestResults = new ArrayList<Integer>();
+    Map<String, int[]> failureStats = new HashMap<String, int[]>();
+
+    try {
+      JenkinsServer jenkins = new JenkinsServer(this.client);
+      Map<String, Job> jobs = jenkins.getJobs();
+      JobWithDetails job = jobs.get(jobName.toLowerCase()).details();
+
+      // build test case failures stats for the past 10 builds
+      Build lastBuild = job.getLastBuild();
+      int startingBuildNumber =
+          (lastBuild.getNumber() - BUILD_HISTORY_NUM > 0) ? lastBuild.getNumber()
+              - BUILD_HISTORY_NUM + 1 : 1;
+
+      Map<Integer, HashMap<String, String>> executedTestCases =
+          new HashMap<Integer, HashMap<String, String>>();
+      Map<Integer, Set<String>> skippedTestCases = new TreeMap<Integer, Set<String>>();
+      Set<String> allExecutedTestCases = new HashSet<String>();
+      Map<Integer, Set<String>> normalizedTestSet = new HashMap<Integer, Set<String>>();
+      String buildUrl = lastBuild.getUrl();
+      for (int i = startingBuildNumber; i <= lastBuild.getNumber(); i++) {
+        HashMap<String, String> buildExecutedTestCases = new HashMap<String, String>(2048);
+        String curBuildUrl = buildUrl.replaceFirst("/" + lastBuild.getNumber(), "/" + i);
+        List<String> failedCases = null;
+        try {
+          failedCases = getBuildFailedTestCases(curBuildUrl, buildExecutedTestCases);
+          buildWithTestResults.add(i);
+        } catch (Exception ex) {
+          // can't get result so skip it
+          continue;
+        }
+        executedTestCases.put(i, buildExecutedTestCases);
+        HashSet<String> tmpSet = new HashSet<String>();
+        for (String tmpTestCase : buildExecutedTestCases.keySet()) {
+          allExecutedTestCases.add(tmpTestCase.substring(0, tmpTestCase.lastIndexOf(".")));
+          tmpSet.add(tmpTestCase.substring(0, tmpTestCase.lastIndexOf(".")));
+        }
+        normalizedTestSet.put(i, tmpSet);
+
+        // set test result failed cases of current build
+        for (String curFailedTestCase : failedCases) {
+          if (failureStats.containsKey(curFailedTestCase)) {
+            int[] testCaseResultArray = failureStats.get(curFailedTestCase);
+            testCaseResultArray[i - startingBuildNumber] = -1;
+          } else {
+            int[] testResult = new int[BUILD_HISTORY_NUM];
+            testResult[i - startingBuildNumber] = -1;
+            // refill previous build test results for newly failed test case
+            for (int k = startingBuildNumber; k < i; k++) {
+              HashMap<String, String> tmpBuildExecutedTestCases = executedTestCases.get(k);
+              if (tmpBuildExecutedTestCases != null
+                  && tmpBuildExecutedTestCases.containsKey(curFailedTestCase)) {
+                String statusStr = tmpBuildExecutedTestCases.get(curFailedTestCase);
+                testResult[k - startingBuildNumber] = convertStatusStringToInt(statusStr);
+              }
+            }
+            failureStats.put(curFailedTestCase, testResult);
+          }
+
+        }
+
+        // set test result for previous failed test cases
+        for (String curTestCase : failureStats.keySet()) {
+          if (!failedCases.contains(curTestCase) && buildExecutedTestCases.containsKey(curTestCase)) {
+            String statusVal = buildExecutedTestCases.get(curTestCase);
+            int[] testCaseResultArray = failureStats.get(curTestCase);
+            testCaseResultArray[i - startingBuildNumber] = convertStatusStringToInt(statusVal);
+          }
+        }
+      }
+
+      // check which test suits skipped
+      for (int i = startingBuildNumber; i <= lastBuild.getNumber(); i++) {
+        Set<String> skippedTests = new HashSet<String>();
+        HashMap<String, String> tmpBuildExecutedTestCases = executedTestCases.get(i);
+        if (tmpBuildExecutedTestCases == null || tmpBuildExecutedTestCases.isEmpty()) continue;
+        // normalize test case names
+        Set<String> tmpNormalizedTestCaseSet = normalizedTestSet.get(i);
+        for (String testCase : allExecutedTestCases) {
+          if (!tmpNormalizedTestCaseSet.contains(testCase)) {
+            skippedTests.add(testCase);
+          }
+        }
+        skippedTestCases.put(i, skippedTests);
+      }
+
+      report.setBuildsWithTestResults(buildWithTestResults);
+      for (String failedTestCase : failureStats.keySet()) {
+        int[] resultHistory = failureStats.get(failedTestCase);
+        int[] compactHistory = new int[buildWithTestResults.size()];
+        int index = 0;
+        for (Integer i : buildWithTestResults) {
+          compactHistory[index] = resultHistory[i - startingBuildNumber];
+          index++;
+        }
+        failureStats.put(failedTestCase, compactHistory);
+      }
+
+      report.setHistoryResults(failureStats, skippedTestCases);
+
+    } catch (Exception ex) {
+      System.out.println(ex);
+      ex.printStackTrace();
+    }
+
+    return report;
+  }
+
+  /**
+   * @param statusVal
+   * @return 1 means PASSED, -1 means FAILED, 0 means SKIPPED
+   */
+  static int convertStatusStringToInt(String statusVal) {
+
+    if (statusVal.equalsIgnoreCase(STATUS_REGRESSION) || statusVal.equalsIgnoreCase(STATUS_FAILED)) {
+      return -1;
+    } else if (statusVal.equalsIgnoreCase(STATUS_PASSED)) {
+      return 1;
+    }
+
+    return 0;
+  }
+
+  /**
+   * Get failed test cases of a build
+   * @param buildURL Jenkins build job URL
+   * @param executedTestCases Set of test cases which was executed for the build
+   * @return list of failed test case names
+   */
+  List<String> getBuildFailedTestCases(String buildURL, HashMap<String, String> executedTestCases)
+      throws IOException {
+    List<String> result = new ArrayList<String>();
+
+    String apiPath =
+        urlJoin(buildURL,
+          "testReport?depth=10&tree=suites[cases[className,name,status,failedSince]]");
+
+    List<TestSuite> suites = client.get(apiPath, BuildResultWithTestCaseDetails.class).getSuites();
+
+    result = getTestSuiteFailedTestcase(suites, executedTestCases);
+
+    return result;
+  }
+
+  private List<String> getTestSuiteFailedTestcase(List<TestSuite> suites,
+      HashMap<String, String> executedTestCases) {
+    List<String> result = new ArrayList<String>();
+
+    if (suites == null) {
+      return result;
+    }
+
+    for (TestSuite curTestSuite : suites) {
+      for (TestCaseResult curTestCaseResult : curTestSuite.getCases()) {
+        if (curTestCaseResult.getStatus().equalsIgnoreCase(STATUS_FAILED)
+            || curTestCaseResult.getStatus().equalsIgnoreCase(STATUS_REGRESSION)) {
+          // failed test case
+          result.add(curTestCaseResult.getFullName());
+        }
+        executedTestCases.put(curTestCaseResult.getFullName(), curTestCaseResult.getStatus());
+      }
+    }
+
+    return result;
+  }
+
+  String urlJoin(String path1, String path2) {
+    if (!path1.endsWith("/")) {
+      path1 += "/";
+    }
+    if (path2.startsWith("/")) {
+      path2 = path2.substring(1);
+    }
+    return path1 + path2;
+  }
+}

Added: hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/TestSuite.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/TestSuite.java?rev=1512879&view=auto
==============================================================================
--- hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/TestSuite.java (added)
+++ hbase/branches/0.95/dev-support/jenkins-tools/buildstats/src/main/java/org/apache/hadoop/hbase/devtools/buildstats/TestSuite.java Sun Aug 11 06:30:07 2013
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.hadoop.hbase.devtools.buildstats;
+
+import com.offbytwo.jenkins.model.BaseModel;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class TestSuite extends BaseModel {
+  List<TestCaseResult> cases;
+
+  public TestSuite() {
+    this(new ArrayList<TestCaseResult>());
+  }
+
+  public TestSuite(List<TestCaseResult> s) {
+    this.cases = s;
+  }
+
+  public TestSuite(TestCaseResult... s) {
+    this(Arrays.asList(s));
+  }
+
+  public List<TestCaseResult> getCases() {
+    return cases;
+  }
+
+  public void setCases(List<TestCaseResult> s) {
+    cases = s;
+  }
+}

Added: hbase/branches/0.95/dev-support/jenkins-tools/pom.xml
URL: http://svn.apache.org/viewvc/hbase/branches/0.95/dev-support/jenkins-tools/pom.xml?rev=1512879&view=auto
==============================================================================
--- hbase/branches/0.95/dev-support/jenkins-tools/pom.xml (added)
+++ hbase/branches/0.95/dev-support/jenkins-tools/pom.xml Sun Aug 11 06:30:07 2013
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <!--
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+-->
+
+	<modelVersion>4.0.0</modelVersion>
+	
+	<groupId>org.apache.hbase</groupId>
+	<artifactId>jenkins-tools</artifactId>
+	<version>1.0</version>
+	<packaging>pom</packaging>
+	
+	<modules>
+		<module>jenkins-client</module>
+		<module>buildstats</module>
+	</modules>
+</project>