milleruntime closed pull request #289: ACCUMULO-4677 Sanitizing PathParam
values in REST-based Monitor
URL: https://github.com/apache/accumulo/pull/289
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
diff --git a/assemble/pom.xml b/assemble/pom.xml
index 2cf4d7aee0..4167de3d83 100644
--- a/assemble/pom.xml
+++ b/assemble/pom.xml
@@ -32,6 +32,10 @@
<artifactId>jcommander</artifactId>
<optional>true</optional>
</dependency>
+ <dependency>
+ <groupId>com.fasterxml</groupId>
+ <artifactId>classmate</artifactId>
+ </dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
@@ -79,6 +83,10 @@
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>javax.el</groupId>
+ <artifactId>javax.el-api</artifactId>
+ </dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
@@ -283,6 +291,10 @@
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.ext</groupId>
+ <artifactId>jersey-bean-validation</artifactId>
+ </dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-entity-filtering</artifactId>
@@ -303,10 +315,26 @@
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.glassfish.web</groupId>
+ <artifactId>el-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.web</groupId>
+ <artifactId>javax.el</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-validator</artifactId>
+ </dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.jboss.logging</groupId>
+ <artifactId>jboss-logging</artifactId>
+ </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
diff --git a/assemble/src/main/assemblies/component.xml
b/assemble/src/main/assemblies/component.xml
index 470b5f7578..405b7b3449 100644
--- a/assemble/src/main/assemblies/component.xml
+++ b/assemble/src/main/assemblies/component.xml
@@ -52,6 +52,7 @@
<include>org.slf4j:slf4j-api</include>
<include>org.slf4j:slf4j-log4j12</include>
<!-- Jersey/Jackson-based webservice -->
+ <include>com.fasterxml:classmate</include>
<include>com.fasterxml.jackson.core:jackson-annotations</include>
<include>com.fasterxml.jackson.core:jackson-core</include>
<include>com.fasterxml.jackson.core:jackson-databind</include>
@@ -59,6 +60,7 @@
<include>com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider</include>
<include>com.fasterxml.jackson.module:jackson-module-jaxb-annotations</include>
<include>javax.annotation:javax.annotation-api</include>
+ <include>javax.el:javax.el-api</include>
<include>javax.validation:validation-api</include>
<include>javax.ws.rs:javax.ws.rs-api</include>
<include>org.freemarker:freemarker</include>
@@ -75,12 +77,17 @@
<include>org.glassfish.jersey.core:jersey-client</include>
<include>org.glassfish.jersey.core:jersey-common</include>
<include>org.glassfish.jersey.core:jersey-server</include>
+ <include>org.glassfish.jersey.ext:jersey-bean-validation</include>
<include>org.glassfish.jersey.ext:jersey-entity-filtering</include>
<include>org.glassfish.jersey.ext:jersey-mvc-freemarker</include>
<include>org.glassfish.jersey.ext:jersey-mvc</include>
<include>org.glassfish.jersey.media:jersey-media-jaxb</include>
<include>org.glassfish.jersey.media:jersey-media-json-jackson</include>
+ <include>org.glassfish.web:javax.el</include>
+ <include>org.glassfish.web:el-impl</include>
+ <include>org.hibernate:hibernate-validator</include>
<include>org.javassist:javassist</include>
+ <include>org.jboss.logging:jboss-logging</include>
<include>log4j:log4j</include>
</includes>
</dependencySet>
diff --git a/pom.xml b/pom.xml
index 49ce9d8687..4cce01242f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -133,6 +133,7 @@
<httpclient.version>4.3.1</httpclient.version>
<it.failIfNoSpecifiedTests>false</it.failIfNoSpecifiedTests>
<jackson.version>2.9.0</jackson.version>
+ <javax.el.version>2.2.4</javax.el.version>
<jersey.version>2.25.1</jersey.version>
<jetty.version>9.3.21.v20170918</jetty.version>
<maven.compiler.source>1.8</maven.compiler.source>
@@ -162,6 +163,11 @@
<artifactId>jcommander</artifactId>
<version>1.72</version>
</dependency>
+ <dependency>
+ <groupId>com.fasterxml</groupId>
+ <artifactId>classmate</artifactId>
+ <version>1.0.0</version>
+ </dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
@@ -259,6 +265,11 @@
<artifactId>javax.annotation-api</artifactId>
<version>1.2</version>
</dependency>
+ <dependency>
+ <groupId>javax.el</groupId>
+ <artifactId>javax.el-api</artifactId>
+ <version>${javax.el.version}</version>
+ </dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
@@ -633,6 +644,11 @@
<artifactId>jersey-server</artifactId>
<version>${jersey.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.ext</groupId>
+ <artifactId>jersey-bean-validation</artifactId>
+ <version>${jersey.version}</version>
+ </dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-entity-filtering</artifactId>
@@ -658,16 +674,46 @@
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.test-framework</groupId>
+ <artifactId>jersey-test-framework-core</artifactId>
+ <version>${jersey.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+ <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
+ <version>${jersey.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.web</groupId>
+ <artifactId>el-impl</artifactId>
+ <version>2.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.web</groupId>
+ <artifactId>javax.el</artifactId>
+ <version>2.2.4</version>
+ </dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>1.3</version>
</dependency>
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-validator</artifactId>
+ <version>5.1.3.Final</version>
+ </dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.18.1-GA</version>
</dependency>
+ <dependency>
+ <groupId>org.jboss.logging</groupId>
+ <artifactId>jboss-logging</artifactId>
+ <version>3.1.3.GA</version>
+ </dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-easymock</artifactId>
@@ -1040,11 +1086,14 @@
<unusedDeclaredDependency>org.apache.hadoop:hadoop-minicluster:jar:${hadoop.version}</unusedDeclaredDependency>
<unusedDeclaredDependency>org.apache.httpcomponents:httpclient:jar:${httpclient.version}</unusedDeclaredDependency>
<unusedDeclaredDependency>org.glassfish.jersey.containers:jersey-container-jetty-http:jar:${jersey.version}</unusedDeclaredDependency>
+
<unusedDeclaredDependency>org.glassfish.jersey.ext:jersey-bean-validation:jar:${jersey.version}</unusedDeclaredDependency>
+
<unusedDeclaredDependency>org.glassfish.jersey.test-framework.providers:jersey-test-framework-provider-grizzly2:jar:${jersey.version}</unusedDeclaredDependency>
<unusedDeclaredDependency>org.powermock:powermock-api-easymock:jar:${powermock.version}</unusedDeclaredDependency>
<unusedDeclaredDependency>org.slf4j:slf4j-log4j12:jar:${slf4j.version}</unusedDeclaredDependency>
<unusedDeclaredDependency>org.apache.httpcomponents:httpclient:jar:${httpclient.version}</unusedDeclaredDependency>
<unusedDeclaredDependency>junit:junit:jar:4.12</unusedDeclaredDependency>
<unusedDeclaredDependency>javax.servlet:javax.servlet-api:jar:${servlet.api.version}</unusedDeclaredDependency>
+
<unusedDeclaredDependency>javax.el:javax.el-api:jar:${javax.el.version}</unusedDeclaredDependency>
</ignoredUnusedDeclaredDependencies>
</configuration>
</execution>
diff --git a/server/monitor/pom.xml b/server/monitor/pom.xml
index 8229d572fc..f22a48ba47 100644
--- a/server/monitor/pom.xml
+++ b/server/monitor/pom.xml
@@ -44,6 +44,10 @@
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>javax.validation</groupId>
+ <artifactId>validation-api</artifactId>
+ </dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
diff --git
a/server/monitor/src/main/java/org/apache/accumulo/monitor/Monitor.java
b/server/monitor/src/main/java/org/apache/accumulo/monitor/Monitor.java
index 68317b376e..868d32897a 100644
--- a/server/monitor/src/main/java/org/apache/accumulo/monitor/Monitor.java
+++ b/server/monitor/src/main/java/org/apache/accumulo/monitor/Monitor.java
@@ -90,6 +90,7 @@
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.logging.LoggingFeature;
import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.server.ServerProperties;
import org.glassfish.jersey.server.mvc.MvcFeature;
import org.glassfish.jersey.server.mvc.freemarker.FreemarkerMvcFeature;
import org.glassfish.jersey.servlet.ServletContainer;
@@ -547,13 +548,14 @@ public Resource getResource(String pathInContext) {
private ServletHolder getViewServlet() {
final ResourceConfig rc = new
ResourceConfig().packages("org.apache.accumulo.monitor.view")
.register(new
LoggingFeature(java.util.logging.Logger.getLogger(this.getClass().getSimpleName()))).register(FreemarkerMvcFeature.class)
- .property(MvcFeature.TEMPLATE_BASE_PATH, "/templates");
+ .property(MvcFeature.TEMPLATE_BASE_PATH,
"/templates").property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
return new ServletHolder(new ServletContainer(rc));
}
private ServletHolder getRestServlet() {
final ResourceConfig rc = new
ResourceConfig().packages("org.apache.accumulo.monitor.rest")
- .register(new
LoggingFeature(java.util.logging.Logger.getLogger(this.getClass().getSimpleName()))).register(JacksonFeature.class);
+ .register(new
LoggingFeature(java.util.logging.Logger.getLogger(this.getClass().getSimpleName()))).register(JacksonFeature.class)
+ .property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
return new ServletHolder(new ServletContainer(rc));
}
diff --git
a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/problems/ProblemsResource.java
b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/problems/ProblemsResource.java
index 8c7fed764c..f85f036f64 100644
---
a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/problems/ProblemsResource.java
+++
b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/problems/ProblemsResource.java
@@ -16,11 +16,16 @@
*/
package org.apache.accumulo.monitor.rest.problems;
+import static
org.apache.accumulo.monitor.util.ParameterValidator.ALPHA_NUM_REGEX;
+import static
org.apache.accumulo.monitor.util.ParameterValidator.RESOURCE_REGEX;
+
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
@@ -36,6 +41,7 @@
import org.apache.accumulo.server.problems.ProblemReport;
import org.apache.accumulo.server.problems.ProblemReports;
import org.apache.accumulo.server.problems.ProblemType;
+import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -93,12 +99,12 @@ public ProblemSummary getSummary() {
@POST
@Consumes(MediaType.TEXT_PLAIN)
@Path("summary")
- public void clearTableProblems(@QueryParam("s") String tableID) {
+ public void clearTableProblems(@QueryParam("s") @NotNull @Pattern(regexp =
ALPHA_NUM_REGEX) String tableID) {
Logger log = LoggerFactory.getLogger(Monitor.class);
try {
ProblemReports.getInstance(Monitor.getContext()).deleteProblemReports(Table.ID.of(tableID));
} catch (Exception e) {
- log.error("Failed to delete problem reports for table " + tableID, e);
+ log.error("Failed to delete problem reports for table " +
(StringUtils.isEmpty(tableID) ? StringUtils.EMPTY : tableID), e);
}
}
@@ -144,12 +150,13 @@ public ProblemDetail getDetails() {
@POST
@Consumes(MediaType.TEXT_PLAIN)
@Path("details")
- public void clearDetailsProblems(@QueryParam("table") String tableID,
@QueryParam("resource") String resource, @QueryParam("ptype") String ptype) {
+ public void clearDetailsProblems(@QueryParam("table") @NotNull
@Pattern(regexp = ALPHA_NUM_REGEX) String tableID, @QueryParam("resource")
@NotNull @Pattern(
+ regexp = RESOURCE_REGEX) String resource, @QueryParam("ptype") @NotNull
@Pattern(regexp = ALPHA_NUM_REGEX) String ptype) {
Logger log = LoggerFactory.getLogger(Monitor.class);
try {
ProblemReports.getInstance(Monitor.getContext()).deleteProblemReport(Table.ID.of(tableID),
ProblemType.valueOf(ptype), resource);
} catch (Exception e) {
- log.error("Failed to delete problem reports for table " + tableID, e);
+ log.error("Failed to delete problem reports for table " +
(StringUtils.isBlank(tableID) ? "" : tableID), e);
}
}
diff --git
a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tables/TablesResource.java
b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tables/TablesResource.java
index 8031931fb1..41d3825305 100644
---
a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tables/TablesResource.java
+++
b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tables/TablesResource.java
@@ -16,6 +16,11 @@
*/
package org.apache.accumulo.monitor.rest.tables;
+import static
org.apache.accumulo.monitor.util.ParameterValidator.ALPHA_NUM_REGEX;
+import static
org.apache.accumulo.monitor.util.ParameterValidator.NAMESPACE_LIST_REGEX;
+import static
org.apache.accumulo.monitor.util.ParameterValidator.NAMESPACE_REGEX;
+
+import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -26,6 +31,8 @@
import java.util.TreeSet;
import java.util.stream.Collectors;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
@@ -51,6 +58,7 @@
import org.apache.accumulo.server.master.state.TabletLocationState;
import org.apache.accumulo.server.tables.TableManager;
import org.apache.accumulo.server.util.TableInfoUtil;
+import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.io.Text;
/**
@@ -65,6 +73,7 @@
public class TablesResource {
private static final TabletServerStatus NO_STATUS = new TabletServerStatus();
+ private static final java.util.regex.Pattern COMMA =
java.util.regex.Pattern.compile(",");
/**
* Generates a table list based on the namespace
@@ -81,9 +90,11 @@ private static TablesList generateTables(String namespace) {
/*
* Add the tables that have the selected namespace Asterisk = All
namespaces Hyphen = Default namespace
*/
- for (String key : namespaces.keySet()) {
- if (namespace.equals("*") || namespace.equals(key) || (key.isEmpty() &&
namespace.equals("-"))) {
- tableNamespace.addTable(new TableNamespace(key));
+ if (null != namespace) {
+ for (String key : namespaces.keySet()) {
+ if (namespace.equals("*") || namespace.equals(key) || (key.isEmpty()
&& namespace.equals("-"))) {
+ tableNamespace.addTable(new TableNamespace(key));
+ }
}
}
@@ -161,7 +172,7 @@ public static TablesList getTables() {
*/
@GET
@Path("namespace/{namespace}")
- public TablesList getTable(@PathParam("namespace") String namespace) {
+ public TablesList getTable(@PathParam("namespace") @NotNull @Pattern(regexp
= NAMESPACE_REGEX) String namespace) throws UnsupportedEncodingException {
return generateTables(namespace);
}
@@ -174,14 +185,15 @@ public TablesList getTable(@PathParam("namespace") String
namespace) {
*/
@GET
@Path("namespaces/{namespaces}")
- public TablesList getTableWithNamespace(@PathParam("namespaces") String
namespaceList) {
+ public TablesList getTableWithNamespace(@PathParam("namespaces") @NotNull
@Pattern(regexp = NAMESPACE_LIST_REGEX) String namespaceList)
+ throws UnsupportedEncodingException {
SortedMap<String,Namespace.ID> namespaces =
Namespaces.getNameToIdMap(Monitor.getContext().getInstance());
TablesList tableNamespace = new TablesList();
/*
* Add the tables that have the selected namespace Asterisk = All
namespaces Hyphen = Default namespace
*/
- for (String namespace : namespaceList.split(",")) {
+ for (String namespace : COMMA.split(namespaceList)) {
for (String key : namespaces.keySet()) {
if (namespace.equals("*") || namespace.equals(key) || (key.isEmpty()
&& namespace.equals("-"))) {
tableNamespace.addTable(new TableNamespace(key));
@@ -201,12 +213,16 @@ public TablesList
getTableWithNamespace(@PathParam("namespaces") String namespac
*/
@Path("{tableId}")
@GET
- public TabletServers getParticipatingTabletServers(@PathParam("tableId")
String tableIdStr) throws Exception {
+ public TabletServers getParticipatingTabletServers(@PathParam("tableId")
@NotNull @Pattern(regexp = ALPHA_NUM_REGEX) String tableIdStr) throws Exception
{
Instance instance = Monitor.getContext().getInstance();
Table.ID tableId = Table.ID.of(tableIdStr);
TabletServers tabletServers = new
TabletServers(Monitor.getMmi().tServerInfo.size());
+ if (StringUtils.isBlank(tableIdStr)) {
+ return tabletServers;
+ }
+
TreeSet<String> locs = new TreeSet<>();
if (RootTable.ID.equals(tableId)) {
locs.add(instance.getRootTabletLocation());
diff --git
a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/trace/TracesResource.java
b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/trace/TracesResource.java
index 0084427bda..a73623d75a 100644
---
a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/trace/TracesResource.java
+++
b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/trace/TracesResource.java
@@ -18,6 +18,7 @@
import static java.lang.Math.min;
import static java.nio.charset.StandardCharsets.UTF_8;
+import static
org.apache.accumulo.monitor.util.ParameterValidator.ALPHA_NUM_REGEX;
import java.io.IOException;
import java.security.PrivilegedAction;
@@ -28,6 +29,10 @@
import java.util.Set;
import java.util.TreeMap;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
@@ -59,6 +64,7 @@
import org.apache.accumulo.tracer.TraceFormatter;
import org.apache.accumulo.tracer.thrift.Annotation;
import org.apache.accumulo.tracer.thrift.RemoteSpan;
+import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.security.UserGroupInformation;
@@ -77,12 +83,12 @@
* Generates a trace summary
*
* @param minutes
- * Range of minutes to filter traces
+ * Range of minutes to filter traces Min of 0 minutes, Max of 30
days
* @return Trace summary in specified range
*/
@Path("summary/{minutes}")
@GET
- public RecentTracesList getTraces(@DefaultValue("10") @PathParam("minutes")
int minutes) throws Exception {
+ public RecentTracesList getTraces(@DefaultValue("10") @PathParam("minutes")
@NotNull @Min(0) @Max(2592000) int minutes) throws Exception {
RecentTracesList recentTraces = new RecentTracesList();
@@ -122,12 +128,13 @@ public Void run() {
* @param type
* Type of the trace
* @param minutes
- * Range of minutes
+ * Range of minutes, Min of 0 and Max 0f 30 days
* @return List of traces filtered by type and range
*/
@Path("listType/{type}/{minutes}")
@GET
- public TraceType getTracesType(@PathParam("type") String type,
@PathParam("minutes") int minutes) throws Exception {
+ public TraceType getTracesType(@PathParam("type") @NotNull @Pattern(regexp =
ALPHA_NUM_REGEX) final String type,
+ @PathParam("minutes") @Min(0) @Max(2592000) int minutes) throws
Exception {
TraceType typeTraces = new TraceType(type);
@@ -175,12 +182,9 @@ public Void run() {
*/
@Path("show/{id}")
@GET
- public TraceList getTracesType(@PathParam("id") String id) throws Exception {
- TraceList traces = new TraceList(id);
+ public TraceList getTracesType(@PathParam("id") @NotNull @Pattern(regexp =
ALPHA_NUM_REGEX) String id) throws Exception {
- if (id == null) {
- return null;
- }
+ TraceList traces = new TraceList(id);
Pair<Scanner,UserGroupInformation> entry = getScanner();
final Scanner scanner = entry.getFirst();
@@ -258,8 +262,8 @@ protected Range getRangeForTrace(long minutesSince) {
long startTime = endTime - millisSince;
String startHexTime = Long.toHexString(startTime), endHexTime =
Long.toHexString(endTime);
- while (startHexTime.length() < endHexTime.length()) {
- startHexTime = "0" + startHexTime;
+ if (startHexTime.length() < endHexTime.length()) {
+ StringUtils.leftPad(startHexTime, endHexTime.length(), '0');
}
return new Range(new Text("start:" + startHexTime), new Text("start:" +
endHexTime));
diff --git
a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tservers/TabletServerResource.java
b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tservers/TabletServerResource.java
index d96e40dbe3..d966cff68a 100644
---
a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tservers/TabletServerResource.java
+++
b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tservers/TabletServerResource.java
@@ -16,12 +16,16 @@
*/
package org.apache.accumulo.monitor.rest.tservers;
+import static org.apache.accumulo.monitor.util.ParameterValidator.SERVER_REGEX;
+
import java.lang.management.ManagementFactory;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
@@ -101,7 +105,7 @@ public TabletServers getTserverSummary() {
*/
@POST
@Consumes(MediaType.TEXT_PLAIN)
- public void clearDeadServer(@QueryParam("server") String server) throws
Exception {
+ public void clearDeadServer(@QueryParam("server") @NotNull @Pattern(regexp =
SERVER_REGEX) String server) throws Exception {
DeadServerList obit = new
DeadServerList(ZooUtil.getRoot(Monitor.getContext().getInstance()) +
Constants.ZDEADTSERVERS);
obit.delete(server);
}
@@ -140,28 +144,23 @@ public TabletServersRecovery getTserverRecovery() {
/**
* Generates details for the selected tserver
*
- * @param tserverAddr
+ * @param tserverAddress
* TServer name
* @return TServer details
*/
@Path("{address}")
@GET
- public TabletServerSummary getTserverDetails(@PathParam("address") String
tserverAddr) throws Exception {
-
- String tserverAddress = tserverAddr;
+ public TabletServerSummary getTserverDetails(@PathParam("address") @NotNull
@Pattern(regexp = SERVER_REGEX) String tserverAddress) throws Exception {
boolean tserverExists = false;
- if (tserverAddress != null && tserverAddress.isEmpty() == false) {
- for (TabletServerStatus ts : Monitor.getMmi().getTServerInfo()) {
- if (tserverAddress.equals(ts.getName())) {
- tserverExists = true;
- break;
- }
+ for (TabletServerStatus ts : Monitor.getMmi().getTServerInfo()) {
+ if (tserverAddress.equals(ts.getName())) {
+ tserverExists = true;
+ break;
}
}
- if (tserverAddress == null || tserverAddress.isEmpty() || tserverExists ==
false) {
-
+ if (!tserverExists) {
return null;
}
diff --git
a/server/monitor/src/main/java/org/apache/accumulo/monitor/util/ParameterValidator.java
b/server/monitor/src/main/java/org/apache/accumulo/monitor/util/ParameterValidator.java
new file mode 100644
index 0000000000..a736a293bd
--- /dev/null
+++
b/server/monitor/src/main/java/org/apache/accumulo/monitor/util/ParameterValidator.java
@@ -0,0 +1,34 @@
+/*
+ * 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.accumulo.monitor.util;
+
+/**
+ * Simple utility class to validate Accumulo Monitor Query and Path parameters
+ */
+public interface ParameterValidator {
+
+ String ALPHA_NUM_REGEX = "\\w+";
+ String ALPHA_NUM_REGEX_BLANK_OK = "\\w*";
+
+ String RESOURCE_REGEX = "(\\w|:)+";
+
+ String NAMESPACE_REGEX = "[*-]?|(\\w)+";
+ String NAMESPACE_LIST_REGEX = "[*-]?|(\\w+,?\\w*)+";
+
+ String SERVER_REGEX = "(\\w+([.-])*\\w*)+(:[0-9]+)*";
+ String SERVER_REGEX_BLANK_OK = "((\\w+([.-])*\\w*)+(:[0-9]+)*)*";
+}
diff --git
a/server/monitor/src/main/java/org/apache/accumulo/monitor/view/WebViews.java
b/server/monitor/src/main/java/org/apache/accumulo/monitor/view/WebViews.java
index 750ea8cdc1..9e26a484ad 100644
---
a/server/monitor/src/main/java/org/apache/accumulo/monitor/view/WebViews.java
+++
b/server/monitor/src/main/java/org/apache/accumulo/monitor/view/WebViews.java
@@ -16,14 +16,24 @@
*/
package org.apache.accumulo.monitor.view;
+import static
org.apache.accumulo.monitor.util.ParameterValidator.ALPHA_NUM_REGEX;
+import static
org.apache.accumulo.monitor.util.ParameterValidator.ALPHA_NUM_REGEX_BLANK_OK;
+import static
org.apache.accumulo.monitor.util.ParameterValidator.SERVER_REGEX_BLANK_OK;
+import static org.apache.commons.lang.StringUtils.isBlank;
import static org.apache.commons.lang.StringUtils.isEmpty;
+import static org.apache.commons.lang.StringUtils.isNotBlank;
import java.io.IOException;
+import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
@@ -145,11 +155,11 @@ private void addExternalResources(Map<String,Object>
model) {
@GET
@Path("tservers")
@Template(name = "/default.ftl")
- public Map<String,Object> getTabletServers(@QueryParam("s") String server) {
+ public Map<String,Object> getTabletServers(@QueryParam("s") @Pattern(regexp
= SERVER_REGEX_BLANK_OK) String server) {
Map<String,Object> model = getModel();
model.put("title", "Tablet Server Status");
- if (server != null) {
+ if (isNotBlank(server)) {
model.put("template", "server.ftl");
model.put("js", "server.js");
model.put("server", server);
@@ -230,17 +240,22 @@ private void addExternalResources(Map<String,Object>
model) {
@GET
@Path("vis")
@Template(name = "/default.ftl")
- public Map<String,Object> getServerActivity(@QueryParam("shape")
@DefaultValue("circles") String shape, @QueryParam("size") @DefaultValue("40")
String size,
- @QueryParam("motion") @DefaultValue("") String motion,
@QueryParam("color") @DefaultValue("allavg") String color) {
+ public Map<String,Object> getServerActivity(@QueryParam("shape")
@DefaultValue("circles") @Pattern(regexp = ALPHA_NUM_REGEX_BLANK_OK) String
shape,
+ @QueryParam("size") @DefaultValue("40") @Min(1) @Max(100) int size,
+ @QueryParam("motion") @DefaultValue("") @Pattern(regexp =
ALPHA_NUM_REGEX_BLANK_OK) String motion, @QueryParam("color")
@DefaultValue("allavg") @Pattern(
+ regexp = ALPHA_NUM_REGEX_BLANK_OK) String color) {
+
+ shape = isNotBlank(shape) ? shape : "circles";
+ color = isNotBlank(color) ? color : "allavg";
Map<String,Object> model = getModel();
model.put("title", "Server Activity");
model.put("template", "vis.ftl");
model.put("shape", shape);
- model.put("size", size);
- model.put("motion", motion);
- model.put("color", color);
+ model.put("size", String.valueOf(size));
+ model.put("motion", isBlank(motion) ? "" : motion.trim());
+ model.put("color", isBlank(color) ? "allavg" : color); // Are there a set
of acceptable values?
return model;
}
@@ -274,7 +289,8 @@ private void addExternalResources(Map<String,Object> model)
{
@GET
@Path("tables/{tableID}")
@Template(name = "/default.ftl")
- public Map<String,Object> getTables(@PathParam("tableID") String tableID)
throws TableNotFoundException {
+ public Map<String,Object> getTables(@PathParam("tableID") @NotNull
@Pattern(regexp = ALPHA_NUM_REGEX) String tableID) throws
TableNotFoundException,
+ UnsupportedEncodingException {
String tableName = Tables.getTableName(Monitor.getContext().getInstance(),
Table.ID.of(tableID));
@@ -293,20 +309,19 @@ private void addExternalResources(Map<String,Object>
model) {
* Returns trace summary template
*
* @param minutes
- * Range of minutes
+ * Range of minutes, default 10 minutes Min of 0 Max of 30 days in
minutes
* @return Trace summary model
*/
@GET
@Path("trace/summary")
@Template(name = "/default.ftl")
- public Map<String,Object> getTracesSummary(@QueryParam("minutes")
@DefaultValue("10") String minutes) {
-
+ public Map<String,Object> getTracesSummary(@QueryParam("minutes")
@DefaultValue("10") @Min(0) @Max(2592000) int minutes) {
Map<String,Object> model = getModel();
- model.put("title", "Traces for the last " + minutes +
" minute(s)");
+ model.put("title", "Traces for the last " + String.valueOf(minutes) +
" minute(s)");
model.put("template", "summary.ftl");
model.put("js", "summary.js");
- model.put("minutes", minutes);
+ model.put("minutes", String.valueOf(minutes));
return model;
}
@@ -317,21 +332,21 @@ private void addExternalResources(Map<String,Object>
model) {
* @param type
* Type of trace
* @param minutes
- * Range of minutes
+ * Range of minutes, default 10 minutes Min of 0 Max of 30 days in
minutes
* @return Traces by type model
*/
@GET
@Path("trace/listType")
@Template(name = "/default.ftl")
- public Map<String,Object> getTracesForType(@QueryParam("type") String type,
@QueryParam("minutes") @DefaultValue("10") String minutes) {
-
+ public Map<String,Object> getTracesForType(@QueryParam("type") @NotNull
@Pattern(regexp = ALPHA_NUM_REGEX) String type,
+ @QueryParam("minutes") @DefaultValue("10") @Min(0) @Max(2592000) int
minutes) {
Map<String,Object> model = getModel();
- model.put("title", "Traces for " + type + " for the last " + minutes + "
minute(s)");
+ model.put("title", "Traces for " + type + " for the last " +
String.valueOf(minutes) + " minute(s)");
model.put("template", "listType.ftl");
model.put("js", "listType.js");
model.put("type", type);
- model.put("minutes", minutes);
+ model.put("minutes", String.valueOf(minutes));
return model;
}
@@ -346,7 +361,7 @@ private void addExternalResources(Map<String,Object> model)
{
@GET
@Path("trace/show")
@Template(name = "/default.ftl")
- public Map<String,Object> getTraceShow(@QueryParam("id") String id) {
+ public Map<String,Object> getTraceShow(@QueryParam("id") @NotNull
@Pattern(regexp = ALPHA_NUM_REGEX) String id) throws Exception {
Map<String,Object> model = getModel();
model.put("title", "Trace ID " + id);
@@ -387,7 +402,7 @@ private void addExternalResources(Map<String,Object> model)
{
@GET
@Path("problems")
@Template(name = "/default.ftl")
- public Map<String,Object> getProblems(@QueryParam("table") String table) {
+ public Map<String,Object> getProblems(@QueryParam("table") @Pattern(regexp =
ALPHA_NUM_REGEX_BLANK_OK) String table) {
Map<String,Object> model = getModel();
model.put("title", "Per-Table Problem Report");
@@ -395,7 +410,7 @@ private void addExternalResources(Map<String,Object> model)
{
model.put("template", "problems.ftl");
model.put("js", "problems.js");
- if (table != null) {
+ if (isNotBlank(table)) {
model.put("table", table);
}
diff --git
a/server/monitor/src/test/java/org/apache/accumulo/monitor/util/ParameterValidatorTest.java
b/server/monitor/src/test/java/org/apache/accumulo/monitor/util/ParameterValidatorTest.java
new file mode 100644
index 0000000000..d698029650
--- /dev/null
+++
b/server/monitor/src/test/java/org/apache/accumulo/monitor/util/ParameterValidatorTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.accumulo.monitor.util;
+
+import java.util.regex.Pattern;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Basic tests for ParameterValidator
+ */
+public class ParameterValidatorTest {
+
+ @Test
+ public void testAlphaNumRegex() {
+ Pattern p = Pattern.compile(ParameterValidator.ALPHA_NUM_REGEX);
+ Assert.assertTrue(p.matcher("asdlkfj234kj324").matches());
+ Assert.assertFalse(p.matcher("234-324").matches());
+ Assert.assertFalse(p.matcher("").matches());
+
+ p = Pattern.compile(ParameterValidator.ALPHA_NUM_REGEX_BLANK_OK);
+ Assert.assertTrue(p.matcher("asdlkfj234kj324").matches());
+ Assert.assertTrue(p.matcher("").matches());
+ Assert.assertFalse(p.matcher("234-324").matches());
+ }
+
+ @Test
+ public void testServerRegex() throws Exception {
+ Pattern p = Pattern.compile(ParameterValidator.SERVER_REGEX);
+ Assert.assertTrue("Did not match hostname with dots",
p.matcher("ab3cd.12d34.3xyz.net").matches());
+ Assert.assertTrue("Did not match hostname with dash",
p.matcher("abcd.123.server-foo.com").matches());
+ Assert.assertTrue("Did not match hostname and port",
p.matcher("abcd.123.server-foo.com:1234").matches());
+ Assert.assertTrue("Did not match all numeric",
p.matcher("127.0.0.1").matches());
+ Assert.assertTrue("Did not match all numeric and port",
p.matcher("127.0.0.1:9999").matches());
+ Assert.assertTrue("Did not match all numeric and port",
p.matcher("ServerName:9999").matches());
+
+ Assert.assertFalse(p.matcher("abcd.1234.*.xyz").matches());
+ Assert.assertFalse(p.matcher("abcd.1234.;xyz").matches());
+ Assert.assertFalse(p.matcher("abcd.12{3}4.xyz").matches());
+ Assert.assertFalse(p.matcher("abcd.12[3]4.xyz").matches());
+ Assert.assertFalse(p.matcher("abcd=4.xyz").matches());
+ Assert.assertFalse(p.matcher("abcd=\"4.xyz\"").matches());
+ Assert.assertFalse(p.matcher("abcd\"4.xyz\"").matches());
+
+ Pattern q = Pattern.compile(ParameterValidator.SERVER_REGEX_BLANK_OK);
+ Assert.assertTrue(q.matcher("abcd:9997").matches());
+ Assert.assertTrue(q.matcher("abcd.123:9997").matches());
+ Assert.assertTrue(q.matcher("abcd.123-xyz:9997").matches());
+ Assert.assertTrue(q.matcher("abcd.123-xyz").matches());
+ Assert.assertTrue(q.matcher("").matches());
+ }
+
+}
diff --git a/test/pom.xml b/test/pom.xml
index 81133b78e5..00ff2c7c1a 100644
--- a/test/pom.xml
+++ b/test/pom.xml
@@ -66,6 +66,14 @@
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
</dependency>
+ <dependency>
+ <groupId>javax.el</groupId>
+ <artifactId>javax.el-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>javax.ws.rs-api</artifactId>
+ </dependency>
<dependency>
<groupId>jline</groupId>
<artifactId>jline</artifactId>
@@ -133,6 +141,17 @@
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
+ <exclusions>
+ <!-- Pulls in an older jersey version -->
+ <exclusion>
+ <groupId>com.sun.jersey</groupId>
+ <artifactId>jersey-core</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>com.sun.jersey</groupId>
+ <artifactId>jersey-client</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
@@ -141,6 +160,29 @@
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-minicluster</artifactId>
+ <exclusions>
+ <!-- Pulls in an older jersey version -->
+ <exclusion>
+ <groupId>com.sun.jersey</groupId>
+ <artifactId>jersey-client</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>com.sun.jersey</groupId>
+ <artifactId>jersey-core</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>com.sun.jersey</groupId>
+ <artifactId>jersey-json</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>com.sun.jersey</groupId>
+ <artifactId>jersey-server</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>com.sun.jersey.contribs</groupId>
+ <artifactId>jersey-guice</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
@@ -173,10 +215,34 @@
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.core</groupId>
+ <artifactId>jersey-client</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.ext</groupId>
+ <artifactId>jersey-bean-validation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.test-framework</groupId>
+ <artifactId>jersey-test-framework-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+ <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
+ </dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.powermock</groupId>
+ <artifactId>powermock-api-easymock</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.powermock</groupId>
+ <artifactId>powermock-module-junit4</artifactId>
+ </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
diff --git
a/test/src/main/java/org/apache/accumulo/test/monitor/WebViewsIT.java
b/test/src/main/java/org/apache/accumulo/test/monitor/WebViewsIT.java
new file mode 100644
index 0000000000..8e9169d477
--- /dev/null
+++ b/test/src/main/java/org/apache/accumulo/test/monitor/WebViewsIT.java
@@ -0,0 +1,157 @@
+/*
+ * 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.accumulo.test.monitor;
+
+import static org.easymock.EasyMock.expect;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.HashMap;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.MessageBodyWriter;
+
+import org.apache.accumulo.core.client.Instance;
+import org.apache.accumulo.core.client.impl.Table;
+import org.apache.accumulo.core.client.impl.Tables;
+import org.apache.accumulo.core.conf.DefaultConfiguration;
+import org.apache.accumulo.monitor.Monitor;
+import org.apache.accumulo.monitor.view.WebViews;
+import org.apache.accumulo.server.AccumuloServerContext;
+import org.apache.accumulo.test.categories.SunnyDayTests;
+import org.easymock.EasyMock;
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.TestProperties;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.powermock.api.easymock.PowerMock;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+/**
+ * Basic tests for parameter validation constraints
+ */
+@Category(SunnyDayTests.class)
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({Monitor.class, Tables.class})
+public class WebViewsIT extends JerseyTest {
+
+ @Override
+ public Application configure() {
+ enable(TestProperties.LOG_TRAFFIC);
+ enable(TestProperties.DUMP_ENTITY);
+ ResourceConfig config = new ResourceConfig(WebViews.class);
+ config.register(WebViewsIT.HashMapWriter.class);
+ return config;
+ }
+
+ @Override
+ protected void configureClient(ClientConfig config) {
+ super.configureClient(config);
+ config.register(WebViewsIT.HashMapWriter.class);
+ }
+
+ /**
+ * Expect to fail the constraint validation on the REST endpoint. The
constraint is the pre-defined word character class Pattern so passing a table
name with
+ * punctuation will cause a 400 response code.
+ */
+ @Test
+ public void testGetTablesConstraintViolations() {
+ Response output = target("tables/f+o*o").request().get();
+ Assert.assertEquals("should return status 400", 400, output.getStatus());
+ }
+
+ /**
+ * Test path tables/{tableID} which passes constraints. On passing
constraints underlying logic will be executed so we need to mock a certain
amount of it.
+ * Note: If you get test failures here due to 500 server response, it's
likely an underlying class or method call was added/modified and needs mocking.
Note:
+ * To get the proper response code back, you need to make sure jersey has a
registered MessageBodyWriter capable of serializing/writing the object returned
+ * from your endpoint. We're using a simple stubbed out inner class
HashMapWriter for this.
+ *
+ * @throws Exception
+ * not expected
+ */
+ @Test
+ public void testGetTablesConstraintPassing() throws Exception {
+ Instance instanceMock = EasyMock.createMock(Instance.class);
+ expect(instanceMock.getInstanceID()).andReturn("foo").anyTimes();
+ AccumuloServerContext contextMock =
EasyMock.createMock(AccumuloServerContext.class);
+ expect(contextMock.getInstance()).andReturn(instanceMock).anyTimes();
+
expect(contextMock.getConfiguration()).andReturn(DefaultConfiguration.getInstance()).anyTimes();
+
+ PowerMock.mockStatic(Monitor.class);
+ expect(Monitor.getContext()).andReturn(contextMock).anyTimes();
+
+ PowerMock.mockStatic(Tables.class);
+ expect(Tables.getTableName(instanceMock,
Table.ID.of("foo"))).andReturn("bar");
+ PowerMock.replayAll();
+ org.easymock.EasyMock.replay(instanceMock, contextMock);
+
+ // Using the mocks we can verify that the getModel method gets called via
debugger
+ // however it's difficult to continue to mock through the jersey MVC code
for the properly built response.
+ // Our silly HashMapWriter registered in the configure method gets wired
in and used here.
+ Response output = target("tables/foo").request().get();
+ Assert.assertEquals("should return status 200", 200, output.getStatus());
+ String responseBody = output.readEntity(String.class);
+ Assert.assertTrue(responseBody.contains("tableID=foo") &&
responseBody.contains("table=bar"));
+ }
+
+ /**
+ * Test minutes parameter constraints. When outside range we should get a
400 response.
+ */
+ @Test
+ public void testGetTracesSummaryValidationConstraint() {
+ // Test upper bounds of constraint
+ Response output = target("trace/summary").queryParam("minutes",
5000000).request().get();
+ Assert.assertEquals("should return status 400", 400, output.getStatus());
+
+ // Test lower bounds of constraint
+ output = target("trace/summary").queryParam("minutes",
-27).request().get();
+ Assert.assertEquals("should return status 400", 400, output.getStatus());
+ }
+
+ /**
+ * Silly stub to handle MessageBodyWriter for Hashmap. Registered in
configure method and auto-wired by Jersey.
+ */
+ public static class HashMapWriter implements MessageBodyWriter<HashMap<?,?>>
{
+ @Override
+ public boolean isWriteable(Class<?> type, Type genericType, Annotation[]
annotations, MediaType mediaType) {
+ return true;
+ }
+
+ @Override
+ public long getSize(HashMap<?,?> hashMap, Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
+ return 0;
+ }
+
+ @Override
+ public void writeTo(HashMap<?,?> hashMap, Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType,
+ MultivaluedMap<String,Object> httpHeaders, OutputStream entityStream)
throws IOException, WebApplicationException {
+ String s = hashMap.toString();
+ entityStream.write(s.getBytes());
+ }
+ }
+}
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
With regards,
Apache Git Services