You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ab...@apache.org on 2017/04/20 10:20:35 UTC

[02/23] lucene-solr:feature/autoscaling: Squash-merge from master.

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d8df9f8c/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/eval/ConversionEvaluatorsTest.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/eval/ConversionEvaluatorsTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/eval/ConversionEvaluatorsTest.java
new file mode 100644
index 0000000..94124ad
--- /dev/null
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/eval/ConversionEvaluatorsTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.solr.client.solrj.io.stream.eval;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.collections.map.HashedMap;
+import org.apache.solr.client.solrj.io.Tuple;
+import org.apache.solr.client.solrj.io.eval.ConversionEvaluator;
+import org.apache.solr.client.solrj.io.eval.RawValueEvaluator;
+import org.apache.solr.client.solrj.io.eval.StreamEvaluator;
+import org.apache.solr.client.solrj.io.stream.StreamContext;
+import org.apache.solr.client.solrj.io.stream.expr.StreamFactory;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+/**
+ * Test ConversionEvaluators
+ */
+public class ConversionEvaluatorsTest {
+
+
+  StreamFactory factory;
+  Map<String, Object> values;
+
+  public ConversionEvaluatorsTest() {
+    super();
+
+    factory = new StreamFactory();
+    factory.withFunctionName("convert", ConversionEvaluator.class).withFunctionName("raw", RawValueEvaluator.class);
+
+    values = new HashedMap();
+  }
+
+  @Test
+  public void testInvalidExpression() throws Exception {
+
+    StreamEvaluator evaluator;
+
+    try {
+      evaluator = factory.constructEvaluator("convert(inches)");
+      StreamContext streamContext = new StreamContext();
+      evaluator.setStreamContext(streamContext);
+      assertTrue(false);
+    } catch (IOException e) {
+      assertTrue(e.getCause().getCause().getMessage().contains("Invalid expression convert(inches) - expecting 3 value but found 1"));
+    }
+
+    try {
+      evaluator = factory.constructEvaluator("convert(inches, yards, 3)");
+      StreamContext streamContext = new StreamContext();
+      evaluator.setStreamContext(streamContext);
+      Tuple tuple = new Tuple(new HashMap());
+      evaluator.evaluate(tuple);
+      assertTrue(false);
+    } catch (IOException e) {
+      assertTrue(e.getCause().getCause().getMessage().contains("No conversion available from INCHES to YARDS"));
+    }
+  }
+
+  @Test
+  public void testInches() throws Exception {
+    testFunction("convert(inches, centimeters, 2)", (double)(2*2.54));
+    testFunction("convert(inches, meters, 2)", (double)(2*0.0254));
+    testFunction("convert(inches, millimeters, 2)", (double)(2*25.40));
+  }
+
+  @Test
+  public void testYards() throws Exception {
+    testFunction("convert(yards, meters, 2)", (double)(2*.91));
+    testFunction("convert(yards, kilometers, 2)", (double)(2*.00091));
+  }
+
+  @Test
+  public void testMiles() throws Exception {
+    testFunction("convert(miles, kilometers, 2)", (double)(2*1.61));
+  }
+
+  @Test
+  public void testMillimeters() throws Exception {
+    testFunction("convert(millimeters, inches, 2)", (double)(2*.039));
+  }
+
+  @Test
+  public void testCentimeters() throws Exception {
+    testFunction("convert(centimeters, inches, 2)", (double)(2*.39));
+  }
+
+  @Test
+  public void testMeters() throws Exception {
+    testFunction("convert(meters, feet, 2)", (double)(2*3.28));
+  }
+
+  @Test
+  public void testKiloMeters() throws Exception {
+    testFunction("convert(kilometers, feet, 2)", (double)(2*3280.8));
+    testFunction("convert(kilometers, miles, 2)", (double)(2*.62));
+  }
+
+  public void testFunction(String expression, Number expected) throws Exception {
+    StreamEvaluator evaluator = factory.constructEvaluator(expression);
+    StreamContext streamContext = new StreamContext();
+    evaluator.setStreamContext(streamContext);
+    Object result = evaluator.evaluate(new Tuple(values));
+    assertTrue(result instanceof Number);
+    assertEquals(expected, result);
+  }
+
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d8df9f8c/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/eval/TemporalEvaluatorsTest.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/eval/TemporalEvaluatorsTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/eval/TemporalEvaluatorsTest.java
new file mode 100644
index 0000000..8205cea
--- /dev/null
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/io/stream/eval/TemporalEvaluatorsTest.java
@@ -0,0 +1,305 @@
+/*
+ * 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.solr.client.solrj.io.stream.eval;
+
+import java.io.IOException;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.MonthDay;
+import java.time.YearMonth;
+import java.time.ZoneOffset;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+
+import org.apache.commons.collections.map.HashedMap;
+import org.apache.solr.client.solrj.io.Tuple;
+import org.apache.solr.client.solrj.io.eval.TemporalEvaluatorDay;
+import org.apache.solr.client.solrj.io.eval.TemporalEvaluatorDayOfQuarter;
+import org.apache.solr.client.solrj.io.eval.TemporalEvaluatorDayOfYear;
+import org.apache.solr.client.solrj.io.eval.TemporalEvaluatorEpoch;
+import org.apache.solr.client.solrj.io.eval.TemporalEvaluatorHour;
+import org.apache.solr.client.solrj.io.eval.TemporalEvaluatorMinute;
+import org.apache.solr.client.solrj.io.eval.TemporalEvaluatorMonth;
+import org.apache.solr.client.solrj.io.eval.StreamEvaluator;
+import org.apache.solr.client.solrj.io.eval.TemporalEvaluatorQuarter;
+import org.apache.solr.client.solrj.io.eval.TemporalEvaluatorSecond;
+import org.apache.solr.client.solrj.io.eval.TemporalEvaluatorWeek;
+import org.apache.solr.client.solrj.io.eval.TemporalEvaluatorYear;
+import org.apache.solr.client.solrj.io.stream.StreamContext;
+import org.apache.solr.client.solrj.io.stream.expr.Explanation;
+import org.apache.solr.client.solrj.io.stream.expr.StreamExpression;
+import org.apache.solr.client.solrj.io.stream.expr.StreamExpressionParser;
+import org.apache.solr.client.solrj.io.stream.expr.StreamFactory;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+/**
+ * Tests numeric Date/Time stream evaluators
+ */
+public class TemporalEvaluatorsTest {
+
+
+  StreamFactory factory;
+  Map<String, Object> values;
+
+  public TemporalEvaluatorsTest() {
+    super();
+
+    factory = new StreamFactory();
+
+    factory.withFunctionName(TemporalEvaluatorYear.FUNCTION_NAME,  TemporalEvaluatorYear.class);
+    factory.withFunctionName(TemporalEvaluatorMonth.FUNCTION_NAME, TemporalEvaluatorMonth.class);
+    factory.withFunctionName(TemporalEvaluatorDay.FUNCTION_NAME,   TemporalEvaluatorDay.class);
+    factory.withFunctionName(TemporalEvaluatorDayOfYear.FUNCTION_NAME,   TemporalEvaluatorDayOfYear.class);
+    factory.withFunctionName(TemporalEvaluatorHour.FUNCTION_NAME,   TemporalEvaluatorHour.class);
+    factory.withFunctionName(TemporalEvaluatorMinute.FUNCTION_NAME,   TemporalEvaluatorMinute.class);
+    factory.withFunctionName(TemporalEvaluatorSecond.FUNCTION_NAME,   TemporalEvaluatorSecond.class);
+    factory.withFunctionName(TemporalEvaluatorEpoch.FUNCTION_NAME,   TemporalEvaluatorEpoch.class);
+    factory.withFunctionName(TemporalEvaluatorWeek.FUNCTION_NAME,   TemporalEvaluatorWeek.class);
+    factory.withFunctionName(TemporalEvaluatorQuarter.FUNCTION_NAME,   TemporalEvaluatorQuarter.class);
+    factory.withFunctionName(TemporalEvaluatorDayOfQuarter.FUNCTION_NAME,   TemporalEvaluatorDayOfQuarter.class);
+
+    values = new HashedMap();
+  }
+
+  @Test
+  public void testInvalidExpression() throws Exception {
+
+    StreamEvaluator evaluator;
+
+    try {
+      evaluator = factory.constructEvaluator("week()");
+      StreamContext streamContext = new StreamContext();
+      evaluator.setStreamContext(streamContext);
+      assertTrue(false);
+    } catch (IOException e) {
+      assertTrue(e.getCause().getCause().getMessage().contains("Invalid expression week()"));
+    }
+
+    try {
+      evaluator = factory.constructEvaluator("week(a, b)");
+      StreamContext streamContext = new StreamContext();
+      evaluator.setStreamContext(streamContext);
+      assertTrue(false);
+    } catch (IOException e) {
+      assertTrue(e.getCause().getCause().getMessage().contains("expecting one value but found 2"));
+    }
+
+    try {
+      evaluator = factory.constructEvaluator("Week()");
+      StreamContext streamContext = new StreamContext();
+      evaluator.setStreamContext(streamContext);
+      assertTrue(false);
+    } catch (IOException e) {
+      assertTrue(e.getMessage().contains("Invalid evaluator expression Week() - function 'Week' is unknown"));
+    }
+  }
+
+
+  @Test
+  public void testInvalidValues() throws Exception {
+    StreamEvaluator evaluator = factory.constructEvaluator("year(a)");
+
+
+    try {
+      values.clear();
+      values.put("a", 12);
+      StreamContext streamContext = new StreamContext();
+      evaluator.setStreamContext(streamContext);
+      Object result = evaluator.evaluate(new Tuple(values));
+      assertTrue(false);
+    } catch (IOException e) {
+      assertEquals("Invalid parameter 12 - The parameter must be a string formatted ISO_INSTANT or of type Long,Instant,Date,LocalDateTime or TemporalAccessor.", e.getMessage());
+    }
+
+    try {
+      values.clear();
+      values.put("a", "1995-12-31");
+      StreamContext streamContext = new StreamContext();
+      evaluator.setStreamContext(streamContext);
+      Object result = evaluator.evaluate(new Tuple(values));
+      assertTrue(false);
+    } catch (IOException e) {
+      assertEquals("Invalid parameter 1995-12-31 - The String must be formatted in the ISO_INSTANT date format.", e.getMessage());
+    }
+
+    try {
+      values.clear();
+      values.put("a", "");
+      StreamContext streamContext = new StreamContext();
+      evaluator.setStreamContext(streamContext);
+      Object result = evaluator.evaluate(new Tuple(values));
+      assertTrue(false);
+    } catch (IOException e) {
+      assertEquals("Invalid parameter  - The parameter must be a string formatted ISO_INSTANT or of type Long,Instant,Date,LocalDateTime or TemporalAccessor.", e.getMessage());
+    }
+
+    values.clear();
+    values.put("a", null);
+    assertNull(evaluator.evaluate(new Tuple(values)));
+  }
+
+  @Test
+  public void testAllFunctions() throws Exception {
+
+    //year, month, day, dayofyear, hour, minute, quarter, week, second, epoch
+    testFunction("year(a)", "1995-12-31T23:59:59Z", 1995);
+    testFunction("month(a)","1995-12-31T23:59:59Z", 12);
+    testFunction("day(a)",  "1995-12-31T23:59:59Z", 31);
+    testFunction("dayOfYear(a)",  "1995-12-31T23:59:59Z", 365);
+    testFunction("dayOfQuarter(a)",  "1995-12-31T23:59:59Z", 92);
+    testFunction("hour(a)",   "1995-12-31T23:59:59Z", 23);
+    testFunction("minute(a)", "1995-12-31T23:59:59Z", 59);
+    testFunction("quarter(a)","1995-12-31T23:59:59Z", 4);
+    testFunction("week(a)",   "1995-12-31T23:59:59Z", 52);
+    testFunction("second(a)", "1995-12-31T23:59:58Z", 58);
+    testFunction("epoch(a)",  "1995-12-31T23:59:59Z", 820454399000l);
+
+    testFunction("year(a)", "2017-03-17T10:30:45Z", 2017);
+    testFunction("year('a')", "2017-03-17T10:30:45Z", 2017);
+    testFunction("month(a)","2017-03-17T10:30:45Z", 3);
+    testFunction("day(a)",  "2017-03-17T10:30:45Z", 17);
+    testFunction("day('a')",  "2017-03-17T10:30:45Z", 17);
+    testFunction("dayOfYear(a)",  "2017-03-17T10:30:45Z", 76);
+    testFunction("dayOfQuarter(a)",  "2017-03-17T10:30:45Z", 76);
+    testFunction("hour(a)",   "2017-03-17T10:30:45Z", 10);
+    testFunction("minute(a)", "2017-03-17T10:30:45Z", 30);
+    testFunction("quarter(a)","2017-03-17T10:30:45Z", 1);
+    testFunction("week(a)",   "2017-03-17T10:30:45Z", 11);
+    testFunction("second(a)", "2017-03-17T10:30:45Z", 45);
+    testFunction("epoch(a)",  "2017-03-17T10:30:45Z", 1489746645000l);
+
+    testFunction("epoch(a)",  new Date(1489746645500l).toInstant().toString(), 1489746645500l);
+    testFunction("epoch(a)",  new Date(820454399990l).toInstant().toString(), 820454399990l);
+
+  }
+
+  @Test
+  public void testFunctionsOnDate() throws Exception {
+    Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"), Locale.ROOT);
+    calendar.set(2017, 12, 5, 23, 59);
+    Date aDate = calendar.getTime();
+    testFunction("year(a)", aDate, calendar.get(Calendar.YEAR));
+    testFunction("month(a)", aDate, calendar.get(Calendar.MONTH)+1);
+    testFunction("day(a)", aDate, calendar.get(Calendar.DAY_OF_MONTH));
+    testFunction("hour(a)", aDate, calendar.get(Calendar.HOUR_OF_DAY));
+    testFunction("minute(a)", aDate, calendar.get(Calendar.MINUTE));
+    testFunction("epoch(a)", aDate, aDate.getTime());
+  }
+
+  @Test
+  public void testFunctionsOnInstant() throws Exception {
+    Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"), Locale.ROOT);
+    calendar.set(2017, 12, 5, 23, 59);
+    Date aDate = calendar.getTime();
+    Instant instant = aDate.toInstant();
+    testFunction("year(a)", instant, calendar.get(Calendar.YEAR));
+    testFunction("month(a)", instant, calendar.get(Calendar.MONTH)+1);
+    testFunction("day(a)", instant, calendar.get(Calendar.DAY_OF_MONTH));
+    testFunction("hour(a)", instant, calendar.get(Calendar.HOUR_OF_DAY));
+    testFunction("minute(a)", instant, calendar.get(Calendar.MINUTE));
+    testFunction("epoch(a)", instant, aDate.getTime());
+  }
+
+  @Test
+  public void testFunctionsLocalDateTime() throws Exception {
+
+    LocalDateTime localDateTime = LocalDateTime.of(2017,12,5, 23, 59);
+    Date aDate = Date.from(localDateTime.atZone(ZoneOffset.UTC).toInstant());
+    testFunction("year(a)", localDateTime, 2017);
+    testFunction("month(a)", localDateTime, 12);
+    testFunction("day(a)", localDateTime, 5);
+    testFunction("hour(a)", localDateTime, 23);
+    testFunction("minute(a)", localDateTime, 59);
+    testFunction("epoch(a)", localDateTime, aDate.getTime());
+  }
+
+  @Test
+  public void testFunctionsOnLong() throws Exception {
+
+    Long longDate = 1512518340000l;
+
+    testFunction("year(a)", longDate, 2017);
+    testFunction("month(a)", longDate, 12);
+    testFunction("day(a)", longDate, 5);
+    testFunction("hour(a)", longDate, 23);
+    testFunction("minute(a)", longDate, 59);
+    testFunction("second(a)", longDate, 0);
+    testFunction("epoch(a)", longDate, longDate);
+
+  }
+
+  @Test
+  public void testLimitedFunctions() throws Exception {
+
+    MonthDay monthDay = MonthDay.of(12,5);
+    testFunction("month(a)", monthDay, 12);
+    testFunction("day(a)", monthDay, 5);
+
+    try {
+      testFunction("year(a)", monthDay, 2017);
+      assertTrue(false);
+    } catch (IOException e) {
+      assertEquals("It is not possible to call 'year' function on java.time.MonthDay", e.getMessage());
+    }
+
+    YearMonth yearMonth = YearMonth.of(2018, 4);
+    testFunction("month(a)", yearMonth, 4);
+    testFunction("year(a)", yearMonth, 2018);
+
+    try {
+      testFunction("day(a)", yearMonth, 5);
+      assertTrue(false);
+    } catch (IOException e) {
+      assertEquals("It is not possible to call 'day' function on java.time.YearMonth", e.getMessage());
+    }
+
+  }
+
+
+  public void testFunction(String expression, Object value, Number expected) throws Exception {
+    StreamEvaluator evaluator = factory.constructEvaluator(expression);
+    StreamContext streamContext = new StreamContext();
+    evaluator.setStreamContext(streamContext);
+    values.clear();
+    values.put("a", value);
+    Object result = evaluator.evaluate(new Tuple(values));
+    assertTrue(result instanceof Number);
+    assertEquals(expected, result);
+  }
+
+  @Test
+  public void testExplain() throws IOException {
+    StreamExpression express = StreamExpressionParser.parse("month('myfield')");
+    TemporalEvaluatorMonth datePartEvaluator = new TemporalEvaluatorMonth(express,factory);
+    Explanation explain = datePartEvaluator.toExplanation(factory);
+    assertEquals("month(myfield)", explain.getExpression());
+
+    express = StreamExpressionParser.parse("day(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbb)");
+    TemporalEvaluatorDay dayPartEvaluator = new TemporalEvaluatorDay(express,factory);
+    explain = dayPartEvaluator.toExplanation(factory);
+    assertEquals("day(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbb)", explain.getExpression());
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d8df9f8c/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
----------------------------------------------------------------------
diff --git a/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java b/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
index 0d4cedd..54ab06d 100644
--- a/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
+++ b/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
@@ -33,6 +33,7 @@ import java.lang.annotation.Target;
 import java.lang.invoke.MethodHandles;
 import java.lang.reflect.Method;
 import java.net.MalformedURLException;
+import java.net.ServerSocket;
 import java.net.URL;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
@@ -802,6 +803,19 @@ public abstract class SolrTestCaseJ4 extends LuceneTestCase {
     configString = schemaString = null;
   }
 
+  /**
+   * Find next available local port.
+   * @return available port number or -1 if none could be found
+   * @throws Exception on IO errors
+   */
+  protected static int getNextAvailablePort() throws Exception {
+    int port = -1;
+    try (ServerSocket s = new ServerSocket(0)) {
+      port = s.getLocalPort();
+    }
+    return port;
+  }
+
 
   /** Validates an update XML String is successful
    */

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d8df9f8c/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java
----------------------------------------------------------------------
diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java
index ade1c69..48f7670 100644
--- a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java
+++ b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java
@@ -19,7 +19,6 @@ package org.apache.solr.cloud;
 import java.io.File;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
-import java.net.ServerSocket;
 import java.net.URI;
 import java.net.URL;
 import java.nio.file.Path;
@@ -598,14 +597,6 @@ public abstract class AbstractFullDistribZkTestBase extends AbstractDistribZkTes
     return proxy;
   }
 
-  protected int getNextAvailablePort() throws Exception {
-    int port = -1;
-    try (ServerSocket s = new ServerSocket(0)) {
-      port = s.getLocalPort();
-    }
-    return port;
-  }
-
   private File getRelativeSolrHomePath(File solrHome) {
     final Path solrHomePath = solrHome.toPath();
     final Path curDirPath = new File("").getAbsoluteFile().toPath();

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d8df9f8c/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java
----------------------------------------------------------------------
diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java b/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java
index 15895d3..0605281 100644
--- a/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java
+++ b/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java
@@ -87,6 +87,11 @@ public class MiniSolrCloudCluster {
       "    <int name=\"distribUpdateConnTimeout\">${distribUpdateConnTimeout:45000}</int>\n" +
       "    <int name=\"distribUpdateSoTimeout\">${distribUpdateSoTimeout:340000}</int>\n" +
       "  </solrcloud>\n" +
+      "  <metrics>\n" +
+      "    <reporter name=\"default\" class=\"org.apache.solr.metrics.reporters.SolrJmxReporter\">\n" +
+      "      <str name=\"rootName\">solr_${hostPort:8983}</str>\n" +
+      "    </reporter>\n" +
+      "  </metrics>\n" +
       "  \n" +
       "</solr>\n";
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d8df9f8c/solr/test-framework/src/java/org/apache/solr/util/ReadOnlyCoresLocator.java
----------------------------------------------------------------------
diff --git a/solr/test-framework/src/java/org/apache/solr/util/ReadOnlyCoresLocator.java b/solr/test-framework/src/java/org/apache/solr/util/ReadOnlyCoresLocator.java
index 3d11ff7..3ad3ce2 100644
--- a/solr/test-framework/src/java/org/apache/solr/util/ReadOnlyCoresLocator.java
+++ b/solr/test-framework/src/java/org/apache/solr/util/ReadOnlyCoresLocator.java
@@ -47,4 +47,10 @@ public abstract class ReadOnlyCoresLocator implements CoresLocator {
     // no-op
   }
 
+  @Override
+  public CoreDescriptor reload(CoreContainer cc, CoreDescriptor cd) {
+    return null; // no-op
+  }
+
+
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d8df9f8c/solr/test-framework/src/java/org/apache/solr/util/TestHarness.java
----------------------------------------------------------------------
diff --git a/solr/test-framework/src/java/org/apache/solr/util/TestHarness.java b/solr/test-framework/src/java/org/apache/solr/util/TestHarness.java
index 2386681..b8e1899 100644
--- a/solr/test-framework/src/java/org/apache/solr/util/TestHarness.java
+++ b/solr/test-framework/src/java/org/apache/solr/util/TestHarness.java
@@ -187,16 +187,16 @@ public class TestHarness extends BaseTestHarness {
         .build();
     if (System.getProperty("zkHost") == null)
       cloudConfig = null;
-    UpdateShardHandlerConfig updateShardHandlerConfig
-        = new UpdateShardHandlerConfig(UpdateShardHandlerConfig.DEFAULT_MAXUPDATECONNECTIONS,
-                                       UpdateShardHandlerConfig.DEFAULT_MAXUPDATECONNECTIONSPERHOST,
-                                       30000, 30000,
-                                        UpdateShardHandlerConfig.DEFAULT_METRICNAMESTRATEGY);
+    UpdateShardHandlerConfig updateShardHandlerConfig = new UpdateShardHandlerConfig(
+        UpdateShardHandlerConfig.DEFAULT_MAXUPDATECONNECTIONS,
+        UpdateShardHandlerConfig.DEFAULT_MAXUPDATECONNECTIONSPERHOST,
+        30000, 30000,
+        UpdateShardHandlerConfig.DEFAULT_METRICNAMESTRATEGY, UpdateShardHandlerConfig.DEFAULT_MAXRECOVERYTHREADS);
     // universal default metric reporter
-    Map<String,String> attributes = new HashMap<>();
+    Map<String,Object> attributes = new HashMap<>();
     attributes.put("name", "default");
     attributes.put("class", SolrJmxReporter.class.getName());
-    PluginInfo defaultPlugin = new PluginInfo("reporter", attributes, null, null);
+    PluginInfo defaultPlugin = new PluginInfo("reporter", attributes);
 
     return new NodeConfig.NodeConfigBuilder("testNode", loader)
         .setUseSchemaCache(Boolean.getBoolean("shareSchema"))
@@ -222,13 +222,19 @@ public class TestHarness extends BaseTestHarness {
 
     @Override
     public List<CoreDescriptor> discover(CoreContainer cc) {
-      return ImmutableList.of(new CoreDescriptor(cc, coreName, cc.getCoreRootDirectory().resolve(coreName),
+      return ImmutableList.of(new CoreDescriptor(coreName, cc.getCoreRootDirectory().resolve(coreName),
+          cc.getContainerProperties(), cc.isZooKeeperAware(),
           CoreDescriptor.CORE_DATADIR, dataDir,
           CoreDescriptor.CORE_CONFIG, solrConfig,
           CoreDescriptor.CORE_SCHEMA, schema,
           CoreDescriptor.CORE_COLLECTION, System.getProperty("collection", "collection1"),
           CoreDescriptor.CORE_SHARD, System.getProperty("shard", "shard1")));
     }
+
+    @Override
+    public CoreDescriptor reload(CoreContainer cc, CoreDescriptor cd) {
+      return cd;
+    }
   }
   
   public CoreContainer getCoreContainer() {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d8df9f8c/solr/webapp/web/css/angular/plugins.css
----------------------------------------------------------------------
diff --git a/solr/webapp/web/css/angular/plugins.css b/solr/webapp/web/css/angular/plugins.css
index 0310e0e..03dc2ea 100644
--- a/solr/webapp/web/css/angular/plugins.css
+++ b/solr/webapp/web/css/angular/plugins.css
@@ -33,6 +33,8 @@ limitations under the License.
 #content #plugins #navigation .PLUGINCHANGES { margin-top: 20px; }
 #content #plugins #navigation .PLUGINCHANGES a { background-image: url( ../../img/ico/eye.png ); }
 #content #plugins #navigation .RELOAD a { background-image: url( ../../img/ico/arrow-circle.png ); }
+#content #plugins #navigation .NOTE { margin-top: 20px; }
+#content #plugins #navigation .NOTE p { color: #c0c0c0; font-style: italic; }
 
 
 #content #plugins #navigation a
@@ -125,14 +127,14 @@ limitations under the License.
 #content #plugins #frame .entry .stats span
 {
   float: left;
-  width: 11%;
+  width: 9%;
 }
 
 #content #plugins #frame .entry dd,
 #content #plugins #frame .entry .stats ul
 {
   float: right;
-  width: 88%;
+  width: 90%;
 }
 
 #content #plugins #frame .entry .stats ul
@@ -144,12 +146,12 @@ limitations under the License.
 
 #content #plugins #frame .entry .stats dt
 {
-  width: 27%;
+  width: 40%;
 }
 
 #content #plugins #frame .entry .stats dd
 {
-  width: 72%;
+  width: 59%;
 }
 
 #content #plugins #frame .entry.expanded a.linker {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d8df9f8c/solr/webapp/web/js/angular/controllers/documents.js
----------------------------------------------------------------------
diff --git a/solr/webapp/web/js/angular/controllers/documents.js b/solr/webapp/web/js/angular/controllers/documents.js
index be37c9f..d38265a 100644
--- a/solr/webapp/web/js/angular/controllers/documents.js
+++ b/solr/webapp/web/js/angular/controllers/documents.js
@@ -38,7 +38,6 @@ solrAdminApp.controller('DocumentsController',
             $scope.type = "json";
             $scope.commitWithin = 1000;
             $scope.overwrite = true;
-            $scope.boost = "1.0";
         };
 
         $scope.refresh();
@@ -78,7 +77,6 @@ solrAdminApp.controller('DocumentsController',
             }
 
             params.commitWithin = $scope.commitWithin;
-            params.boost = $scope.boost;
             params.overwrite = $scope.overwrite;
             params.core = $routeParams.core;
             params.wt = "json";

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d8df9f8c/solr/webapp/web/js/scripts/documents.js
----------------------------------------------------------------------
diff --git a/solr/webapp/web/js/scripts/documents.js b/solr/webapp/web/js/scripts/documents.js
index 9d12e23..45cfbed 100644
--- a/solr/webapp/web/js/scripts/documents.js
+++ b/solr/webapp/web/js/scripts/documents.js
@@ -29,7 +29,6 @@ var content_generator = {
 
 //Utiltity function for turning on/off various elements
 function toggles(documents_form, show_json, show_file, show_doc, doc_text, show_wizard) {
-  var json_only = $('#json-only');
   var the_document = $('#document', documents_form);
   if (show_doc) {
     //console.log("doc: " + doc_text);
@@ -38,11 +37,6 @@ function toggles(documents_form, show_json, show_file, show_doc, doc_text, show_
   } else {
     the_document.hide();
   }
-  if (show_json) {
-    json_only.show();
-  } else {
-    json_only.hide();
-  }
   var file_upload = $('#file-upload', documents_form);
   var upload_only = $('#upload-only', documents_form);
   if (show_file) {
@@ -233,7 +227,6 @@ sammy.get
                       .trigger('change');
                   var the_document = $('#document', documents_form).val();
                   var commit_within = $('#commitWithin', documents_form).val();
-                  var boost = $('#boost', documents_form).val();
                   var overwrite = $('#overwrite', documents_form).val();
                   var the_command = "";
                   var content_type = "";
@@ -245,7 +238,6 @@ sammy.get
                     //create a JSON command
                     the_command = "{"
                         + '"add":{ "doc":' + the_document + ","
-                        + '"boost":' + boost + ","
                         + '"overwrite":' + overwrite + ","
                         + '"commitWithin":' + commit_within
                         + "}}";

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d8df9f8c/solr/webapp/web/partials/documents.html
----------------------------------------------------------------------
diff --git a/solr/webapp/web/partials/documents.html b/solr/webapp/web/partials/documents.html
index 74d034f..2bf3f12 100644
--- a/solr/webapp/web/partials/documents.html
+++ b/solr/webapp/web/partials/documents.html
@@ -88,13 +88,6 @@
             </label>
             <input ng-model="overwrite" type="text" id="overwrite" value="true" title="Overwrite">
           </div>
-          <!-- Boost is json only, since the XML has it embedded -->
-          <div id="json-only" ng-show="type=='json'">
-            <label for="boost">
-              <a rel="help">Boost</a>
-            </label>
-            <input ng-model="boost" type="text" id="boost" value="1.0" title="Document Boost">
-          </div>
         </div>
       </div>
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d8df9f8c/solr/webapp/web/partials/plugins.html
----------------------------------------------------------------------
diff --git a/solr/webapp/web/partials/plugins.html b/solr/webapp/web/partials/plugins.html
index d95fc9b..bd122a7 100644
--- a/solr/webapp/web/partials/plugins.html
+++ b/solr/webapp/web/partials/plugins.html
@@ -55,8 +55,8 @@ limitations under the License.
         </li>
         <li class="PLUGINCHANGES"><a ng-click="startRecording()">Watch Changes</a></li>
         <li class="RELOAD"><a ng-click="refresh()">Refresh Values</a></li>
+        <li class="NOTE"><p>NOTE: Only selected metrics are shown here. Full metrics can be accessed via /admin/metrics handler.</p></li>
     </ul>
-  
   </div>
 
   <div id="recording" ng-show="isRecording">

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d8df9f8c/solr/webapp/web/tpl/documents.html
----------------------------------------------------------------------
diff --git a/solr/webapp/web/tpl/documents.html b/solr/webapp/web/tpl/documents.html
index bd953a4..d2a2e0e 100644
--- a/solr/webapp/web/tpl/documents.html
+++ b/solr/webapp/web/tpl/documents.html
@@ -85,13 +85,6 @@
             </label>
             <input type="text" id="overwrite" value="true" title="Overwrite">
           </div>
-          <!-- Boost is json only, since the XML has it embedded -->
-          <div id="json-only">
-            <label for="boost">
-              <a rel="help">Boost</a>
-            </label>
-            <input type="text" id="boost" value="1.0" title="Document Boost">
-          </div>
         </div>
       </div>