You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by cp...@apache.org on 2016/11/30 17:06:42 UTC

lucene-solr:feature/metrics: SOLR-4735: SolrMetricsIntegrationTest (Kelvin Wong via Christine Poerschke)

Repository: lucene-solr
Updated Branches:
  refs/heads/feature/metrics e6f30e524 -> fea0e200a


SOLR-4735: SolrMetricsIntegrationTest (Kelvin Wong via Christine Poerschke)

Adds SolrMetricsIntegrationTest which uses solrconfig-metricreporter.xml which configures MockMetricReporter instances.

also:
* JmxUtil and SolrJmxReporter tweaks
* SolrMetricReporterTest.MockReporter turned into MockMetricReporter
* changes in SolrCoreMetricManagerTest and SolrJmxReporterTest:
** moved initCore from BeforeClass to Before(Test) so that After(Test) can do deleteCore
** TODO: verify interaction between tests (SolrCoreMetricManagerTest and SolrMetricsIntegrationTest and SolrJmxReporterTest)
* SolrCoreMetricManagerTest instead of SolrJmxReporter use MockMetricReporter


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/fea0e200
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/fea0e200
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/fea0e200

Branch: refs/heads/feature/metrics
Commit: fea0e200a8083ebd86d8e522939e4977d072bbe7
Parents: e6f30e5
Author: Kelvin Wong <kw...@bloomberg.net>
Authored: Tue Nov 29 20:21:00 2016 +0000
Committer: Christine Poerschke <cp...@apache.org>
Committed: Wed Nov 30 16:56:44 2016 +0000

----------------------------------------------------------------------
 .../src/java/org/apache/solr/core/SolrCore.java |  9 ++
 .../apache/solr/metrics/SolrMetricManager.java  |  2 +-
 .../solr/metrics/reporters/SolrJmxReporter.java |  8 +-
 .../src/java/org/apache/solr/util/JmxUtil.java  | 17 +---
 .../conf/solrconfig-metricreporter.xml          | 35 ++++++++
 .../solr/metrics/SolrCoreMetricManagerTest.java | 22 ++---
 .../solr/metrics/SolrMetricReporterTest.java    | 66 ++------------
 .../metrics/SolrMetricsIntegrationTest.java     | 91 ++++++++++++++++++++
 .../metrics/reporters/MockMetricReporter.java   | 80 +++++++++++++++++
 .../metrics/reporters/SolrJmxReporterTest.java  | 12 +--
 10 files changed, 244 insertions(+), 98 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/fea0e200/solr/core/src/java/org/apache/solr/core/SolrCore.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/core/SolrCore.java b/solr/core/src/java/org/apache/solr/core/SolrCore.java
index e2bf222..c907b36 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrCore.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java
@@ -401,6 +401,15 @@ public final class SolrCore implements SolrInfoMBean, Closeable {
   }
 
   /**
+   * Returns the {@link SolrCoreMetricManager} for this core.
+   *
+   * @return the {@link SolrCoreMetricManager} for this core
+   */
+  public SolrCoreMetricManager getMetricManager() {
+    return metricManager;
+  }
+
+  /**
    * Returns a Map of name vs SolrInfoMBean objects. The returned map is an instance of
    * a ConcurrentHashMap and therefore no synchronization is needed for putting, removing
    * or iterating over it.

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/fea0e200/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java b/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java
index a1edb96..041b65c 100644
--- a/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java
+++ b/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java
@@ -121,7 +121,7 @@ public class SolrMetricManager {
   }
 
   /**
-   * Remove some metrics from a named registry
+   * Remove a single specific metric from a named registry
    * @param registry registry name
    * @param metricPath (optional) top-most metric name path elements. If empty then
    *        this is equivalent to calling {@link #clearRegistry(String)},

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/fea0e200/solr/core/src/java/org/apache/solr/metrics/reporters/SolrJmxReporter.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/metrics/reporters/SolrJmxReporter.java b/solr/core/src/java/org/apache/solr/metrics/reporters/SolrJmxReporter.java
index f1a4097..c71d4aa 100644
--- a/solr/core/src/java/org/apache/solr/metrics/reporters/SolrJmxReporter.java
+++ b/solr/core/src/java/org/apache/solr/metrics/reporters/SolrJmxReporter.java
@@ -22,6 +22,7 @@ import javax.management.ObjectName;
 
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
+import java.lang.management.ManagementFactory;
 import java.util.Locale;
 
 import com.codahale.metrics.JmxReporter;
@@ -70,6 +71,7 @@ public class SolrJmxReporter extends SolrMetricReporter {
     super.init(pluginInfo);
 
     if (serviceUrl != null && agentId != null) {
+      ManagementFactory.getPlatformMBeanServer(); // Ensure at least one MBeanServer is available.
       mBeanServer = JmxUtil.findFirstMBeanServer();
       log.warn("No more than one of serviceUrl(%s) and agentId(%s) should be configured, using first MBeanServer instead of configuration.",
           serviceUrl, agentId, mBeanServer);
@@ -85,6 +87,7 @@ public class SolrJmxReporter extends SolrMetricReporter {
     else if (agentId != null) {
       mBeanServer = JmxUtil.findMBeanServerForAgentId(agentId);
     } else {
+      ManagementFactory.getPlatformMBeanServer(); // Ensure at least one MBeanServer is available.
       mBeanServer = JmxUtil.findFirstMBeanServer();
       log.warn("No serviceUrl or agentId was configured, using first MBeanServer.", mBeanServer);
     }
@@ -112,9 +115,8 @@ public class SolrJmxReporter extends SolrMetricReporter {
   @Override
   public synchronized void close() {
     if (reporter != null) {
-      reporter.stop();
-      // TODO: stop() vs. close() // change or add comment re: why stop instead of close is called
-      // maybe TODO: reporter = null;
+      reporter.close();
+      reporter = null;
     }
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/fea0e200/solr/core/src/java/org/apache/solr/util/JmxUtil.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/util/JmxUtil.java b/solr/core/src/java/org/apache/solr/util/JmxUtil.java
index 2224022..02a070d 100644
--- a/solr/core/src/java/org/apache/solr/util/JmxUtil.java
+++ b/solr/core/src/java/org/apache/solr/util/JmxUtil.java
@@ -23,7 +23,6 @@ import javax.management.remote.JMXConnectorServerFactory;
 import javax.management.remote.JMXServiceURL;
 
 import java.io.IOException;
-import java.lang.management.ManagementFactory;
 import java.util.List;
 
 /**
@@ -40,17 +39,7 @@ public final class JmxUtil {
    * @return the first MBeanServer found
    */
   public static MBeanServer findFirstMBeanServer() {
-    // TODO: does findMBeanServerForAgentId need the getPlatformMBeanServer call also?
-    // TODO: can findFirstMBeanServer be implemented as findMBeanServerForAgentId(null)?
-    // Ensure we have at least one MBeanServer available
-    MBeanServer platformServer = ManagementFactory.getPlatformMBeanServer();
-
-    List<MBeanServer> servers = MBeanServerFactory.findMBeanServer(null);
-    if (servers == null || servers.isEmpty()) {
-      return null;
-    }
-
-    return servers.get(0);
+    return findMBeanServerForAgentId(null);
   }
 
   /**
@@ -79,10 +68,6 @@ public final class JmxUtil {
    * @return a MBeanServer
    */
   public static MBeanServer findMBeanServerForAgentId(String agentId) {
-    if (agentId == null) {
-      return null;
-    }
-
     List<MBeanServer> servers = MBeanServerFactory.findMBeanServer(agentId);
     if (servers == null || servers.isEmpty()) {
       return null;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/fea0e200/solr/core/src/test-files/solr/collection1/conf/solrconfig-metricreporter.xml
----------------------------------------------------------------------
diff --git a/solr/core/src/test-files/solr/collection1/conf/solrconfig-metricreporter.xml b/solr/core/src/test-files/solr/collection1/conf/solrconfig-metricreporter.xml
new file mode 100644
index 0000000..faf96bd
--- /dev/null
+++ b/solr/core/src/test-files/solr/collection1/conf/solrconfig-metricreporter.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" ?>
+
+<!--
+ 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.
+-->
+
+<!-- a basic solrconfig that tests can use to test configuration metric reporters
+     DO NOT ADD THINGS TO THIS CONFIG! -->
+<config>
+  <luceneMatchVersion>${tests.luceneMatchVersion:LATEST}</luceneMatchVersion>
+  <dataDir>${solr.data.dir:}</dataDir>
+  <xi:include href="solrconfig.snippet.randomindexconfig.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
+  <directoryFactory name="DirectoryFactory" class="${solr.directoryFactory:solr.RAMDirectoryFactory}"/>
+  <schemaFactory class="ClassicIndexSchemaFactory"/>
+  <requestHandler name="standard" class="solr.StandardRequestHandler" />
+  <metricReporter name="reporter1" class="org.apache.solr.metrics.reporters.MockMetricReporter">
+    <str name="configurable">configured</str>
+  </metricReporter>
+  <metricReporter name="reporter2" class="org.apache.solr.metrics.reporters.MockMetricReporter">
+    <str name="configurable">configured</str>
+  </metricReporter>
+</config>

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/fea0e200/solr/core/src/test/org/apache/solr/metrics/SolrCoreMetricManagerTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/metrics/SolrCoreMetricManagerTest.java b/solr/core/src/test/org/apache/solr/metrics/SolrCoreMetricManagerTest.java
index 80b41b8..71429d4 100644
--- a/solr/core/src/test/org/apache/solr/metrics/SolrCoreMetricManagerTest.java
+++ b/solr/core/src/test/org/apache/solr/metrics/SolrCoreMetricManagerTest.java
@@ -30,11 +30,10 @@ import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.common.params.CoreAdminParams;
 import org.apache.solr.core.PluginInfo;
 import org.apache.solr.core.SolrInfoMBean;
-import org.apache.solr.metrics.reporters.SolrJmxReporter;
+import org.apache.solr.metrics.reporters.MockMetricReporter;
 import org.apache.solr.schema.FieldType;
 import org.junit.After;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 
 public class SolrCoreMetricManagerTest extends SolrTestCaseJ4 {
@@ -42,13 +41,9 @@ public class SolrCoreMetricManagerTest extends SolrTestCaseJ4 {
 
   private SolrCoreMetricManager metricManager;
 
-  @BeforeClass
-  public static void beforeClass() throws Exception {
-    initCore("solrconfig-basic.xml", "schema.xml");
-  }
-
   @Before
-  public void beforeTest() {
+  public void beforeTest() throws Exception {
+    initCore("solrconfig-basic.xml", "schema.xml");
     metricManager = new SolrCoreMetricManager(h.getCore());
   }
 
@@ -56,6 +51,7 @@ public class SolrCoreMetricManagerTest extends SolrTestCaseJ4 {
   public void afterTest() throws IOException {
     metricManager.close();
     assertTrue(metricManager.getReporters().isEmpty());
+    deleteCore();
   }
 
   @Test
@@ -104,13 +100,17 @@ public class SolrCoreMetricManagerTest extends SolrTestCaseJ4 {
   public void testLoadReporter() throws Exception {
     Random random = random();
 
-    String className = SolrJmxReporter.class.getName();
+    String className = MockMetricReporter.class.getName();
     String reporterName = TestUtil.randomUnicodeString(random);
 
     Map<String, Object> attrs = new HashMap<>();
     attrs.put(FieldType.CLASS_NAME, className);
     attrs.put(CoreAdminParams.NAME, reporterName);
 
+    boolean shouldDefineConfigurable = random.nextBoolean();
+    String configurable = TestUtil.randomUnicodeString(random);
+    if (shouldDefineConfigurable) attrs.put("configurable", configurable);
+
     boolean shouldDefinePlugin = random.nextBoolean();
     PluginInfo pluginInfo = shouldDefinePlugin ? new PluginInfo(TestUtil.randomUnicodeString(random), attrs) : null;
 
@@ -119,9 +119,9 @@ public class SolrCoreMetricManagerTest extends SolrTestCaseJ4 {
       assertNotNull(pluginInfo);
       assertEquals(1, metricManager.getReporters().size());
       assertNotNull(metricManager.getReporters().get(reporterName));
-      assertTrue(metricManager.getReporters().get(reporterName) instanceof SolrJmxReporter);
+      assertTrue(metricManager.getReporters().get(reporterName) instanceof MockMetricReporter);
     } catch (IllegalArgumentException e) {
-      assertNull(pluginInfo);
+      assertTrue(pluginInfo == null || attrs.get("configurable") == null);
       assertTrue(metricManager.getReporters().isEmpty());
     }
   }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/fea0e200/solr/core/src/test/org/apache/solr/metrics/SolrMetricReporterTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/metrics/SolrMetricReporterTest.java b/solr/core/src/test/org/apache/solr/metrics/SolrMetricReporterTest.java
index 76344c4..0cbf009 100644
--- a/solr/core/src/test/org/apache/solr/metrics/SolrMetricReporterTest.java
+++ b/solr/core/src/test/org/apache/solr/metrics/SolrMetricReporterTest.java
@@ -16,48 +16,29 @@
  */
 package org.apache.solr.metrics;
 
-import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Random;
 
+import org.apache.lucene.util.LuceneTestCase;
 import org.apache.lucene.util.TestUtil;
-import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.common.params.CoreAdminParams;
 import org.apache.solr.core.PluginInfo;
+import org.apache.solr.metrics.reporters.MockMetricReporter;
 import org.apache.solr.schema.FieldType;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 
-public class SolrMetricReporterTest extends SolrTestCaseJ4 {
-
-  private SolrCoreMetricManager metricManager;
-
-  @BeforeClass
-  public static void beforeClass() throws Exception {
-    initCore("solrconfig-basic.xml", "schema.xml");
-  }
-
-  @Before
-  public void beforeTest() {
-    metricManager = new SolrCoreMetricManager(h.getCore());
-  }
-
-  @After
-  public void afterTest() throws Exception {
-    metricManager.close();
-  }
+public class SolrMetricReporterTest extends LuceneTestCase {
 
   @Test
   public void testInit() throws Exception {
     Random random = random();
 
-    MockReporter reporter = new MockReporter(h.getCore().getName());
+    final String registryName = TestUtil.randomSimpleString(random);
+    final MockMetricReporter reporter = new MockMetricReporter(registryName);
 
     Map<String, Object> attrs = new HashMap<>();
-    attrs.put(FieldType.CLASS_NAME, MockReporter.class.getName());
+    attrs.put(FieldType.CLASS_NAME, MockMetricReporter.class.getName());
     attrs.put(CoreAdminParams.NAME, TestUtil.randomUnicodeString(random));
 
     boolean shouldDefineConfigurable = random.nextBoolean();
@@ -70,46 +51,17 @@ public class SolrMetricReporterTest extends SolrTestCaseJ4 {
 
     try {
       reporter.init(pluginInfo);
+      assertNotNull(pluginInfo);
+      assertEquals(configurable, attrs.get("configurable"));
       assertTrue(reporter.didValidate);
       assertNotNull(reporter.configurable);
       assertEquals(configurable, reporter.configurable);
-      assertTrue(pluginInfo != null && attrs.get("configurable") == configurable);
     } catch (IllegalStateException e) {
+      assertTrue(pluginInfo == null || attrs.get("configurable") == null);
       assertTrue(reporter.didValidate);
       assertNull(reporter.configurable);
-      assertTrue(pluginInfo == null || attrs.get("configurable") == null);
     } finally {
       reporter.close();
     }
   }
-
-  public static class MockReporter extends SolrMetricReporter {
-    String configurable;
-    boolean didValidate = false;
-
-    MockReporter(String registryName) {
-      super(registryName);
-    }
-
-    @Override
-    public void init(PluginInfo pluginInfo) {
-      super.init(pluginInfo);
-    }
-
-    @Override
-    public void close() throws IOException {
-    }
-
-    @Override
-    protected void validate() throws IllegalStateException {
-      didValidate = true;
-      if (configurable == null) {
-        throw new IllegalStateException("MockReporter::configurable not configured.");
-      }
-    }
-
-    public void setConfigurable(String configurable) {
-      this.configurable = configurable;
-    }
-  }
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/fea0e200/solr/core/src/test/org/apache/solr/metrics/SolrMetricsIntegrationTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/metrics/SolrMetricsIntegrationTest.java b/solr/core/src/test/org/apache/solr/metrics/SolrMetricsIntegrationTest.java
new file mode 100644
index 0000000..0393a86
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/metrics/SolrMetricsIntegrationTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.metrics;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+
+import com.codahale.metrics.Metric;
+import com.codahale.metrics.Timer;
+import org.apache.lucene.util.TestUtil;
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.metrics.reporters.MockMetricReporter;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class SolrMetricsIntegrationTest extends SolrTestCaseJ4 {
+  private static final int MAX_ITERATIONS = 20;
+  private static final String METRIC_NAME = "requestTimes";
+  private static final String HANDLER_NAME = "standard";
+  private static final String[] REPORTER_NAMES = {"reporter1", "reporter2"};
+  private static final SolrInfoMBean.Category HANDLER_CATEGORY = SolrInfoMBean.Category.QUERYHANDLER;
+
+  @Before
+  public void beforeTest() throws Exception {
+    initCore("solrconfig-metricreporter.xml", "schema.xml");
+  }
+
+  @After
+  public void afterTest() throws Exception {
+    SolrCoreMetricManager metricManager = h.getCore().getMetricManager();
+    Map<String, SolrMetricReporter> reporters = new HashMap<>(metricManager.getReporters());
+
+    deleteCore();
+
+    for (String reporterName : REPORTER_NAMES) {
+      SolrMetricReporter reporter = reporters.get(reporterName);
+      MockMetricReporter mockReporter = (MockMetricReporter) reporter;
+      assertTrue("Reporter " + reporterName + " was not closed: " + mockReporter, mockReporter.didClose);
+    }
+  }
+
+  @Test
+  public void testConfigureReporter() throws Exception {
+    Random random = random();
+
+    int iterations = TestUtil.nextInt(random, 0, MAX_ITERATIONS);
+    for (int i = 0; i < iterations; ++i) {
+      h.query(req("*"));
+    }
+
+    String metricName = SolrMetricManager.mkName(METRIC_NAME, HANDLER_CATEGORY.toString(), HANDLER_NAME);
+    SolrCoreMetricManager metricManager = h.getCore().getMetricManager();
+    assertEquals(REPORTER_NAMES.length, metricManager.getReporters().size());
+
+    for (String reporterName : REPORTER_NAMES) {
+      SolrMetricReporter reporter = metricManager.getReporters().get(reporterName);
+      assertNotNull("Reporter " + reporterName + " was not found.", reporter);
+      assertTrue(reporter instanceof MockMetricReporter);
+
+      MockMetricReporter mockReporter = (MockMetricReporter) reporter;
+      assertTrue("Reporter " + reporterName + " was not initialized: " + mockReporter, mockReporter.didInit);
+      assertTrue("Reporter " + reporterName + " was not validated: " + mockReporter, mockReporter.didValidate);
+      assertFalse("Reporter " + reporterName + " was incorrectly closed: " + mockReporter, mockReporter.didClose);
+
+      Metric metric = mockReporter.reportMetric(metricName);
+      assertNotNull("Metric " + metricName + " was not reported.", metric);
+      assertTrue("Metric " + metricName + " is not an instance of Timer: " + metric, metric instanceof Timer);
+
+      Timer timer = (Timer) metric;
+      assertEquals(iterations, timer.getCount());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/fea0e200/solr/core/src/test/org/apache/solr/metrics/reporters/MockMetricReporter.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/metrics/reporters/MockMetricReporter.java b/solr/core/src/test/org/apache/solr/metrics/reporters/MockMetricReporter.java
new file mode 100644
index 0000000..4d5ef69
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/metrics/reporters/MockMetricReporter.java
@@ -0,0 +1,80 @@
+/*
+ * 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.metrics.reporters;
+
+import java.io.IOException;
+import java.util.Locale;
+import java.util.NoSuchElementException;
+
+import com.codahale.metrics.Metric;
+import com.codahale.metrics.MetricRegistry;
+import org.apache.solr.core.PluginInfo;
+import org.apache.solr.metrics.SolrMetricManager;
+import org.apache.solr.metrics.SolrMetricReporter;
+
+public class MockMetricReporter extends SolrMetricReporter {
+
+  public String configurable;
+
+  public boolean didInit = false;
+  public boolean didClose = false;
+  public boolean didValidate = false;
+
+  public MockMetricReporter(String registryName) {
+    super(registryName);
+  }
+
+  @Override
+  public void init(PluginInfo pluginInfo) {
+    super.init(pluginInfo);
+    didInit = true;
+  }
+
+  @Override
+  public void close() throws IOException {
+    didClose = true;
+  }
+
+  @Override
+  protected void validate() throws IllegalStateException {
+    didValidate = true;
+    if (configurable == null) {
+      throw new IllegalStateException("MockMetricReporter::configurable not defined.");
+    }
+  }
+
+  public void setConfigurable(String configurable) {
+    this.configurable = configurable;
+  }
+
+  public Metric reportMetric(String metricName) throws NoSuchElementException {
+    MetricRegistry registry = SolrMetricManager.registry(registryName);
+    Metric metric = registry.getMetrics().get(metricName);
+    if (metric == null) {
+      throw new NoSuchElementException("Metric was not found for metric name = " + metricName);
+    }
+
+    return metric;
+  }
+
+  @Override
+  public String toString() {
+    return String.format(Locale.ENGLISH, "[%s@%s: configurable = %s, didInit = %b, didValidate = %b, didClose = %b]",
+        getClass().getName(), Integer.toHexString(hashCode()), configurable, didInit, didValidate, didClose);
+
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/fea0e200/solr/core/src/test/org/apache/solr/metrics/reporters/SolrJmxReporterTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/metrics/reporters/SolrJmxReporterTest.java b/solr/core/src/test/org/apache/solr/metrics/reporters/SolrJmxReporterTest.java
index b4b4c8c..73deb68 100644
--- a/solr/core/src/test/org/apache/solr/metrics/reporters/SolrJmxReporterTest.java
+++ b/solr/core/src/test/org/apache/solr/metrics/reporters/SolrJmxReporterTest.java
@@ -20,7 +20,6 @@ import javax.management.MBeanServer;
 import javax.management.ObjectInstance;
 import javax.management.ObjectName;
 
-import java.lang.management.ManagementFactory;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Random;
@@ -39,7 +38,6 @@ import org.apache.solr.metrics.SolrMetricTestUtils;
 import org.apache.solr.schema.FieldType;
 import org.junit.After;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 
 public class SolrJmxReporterTest extends SolrTestCaseJ4 {
@@ -52,16 +50,9 @@ public class SolrJmxReporterTest extends SolrTestCaseJ4 {
   private SolrJmxReporter reporter;
   private MBeanServer mBeanServer;
 
-  @BeforeClass
-  public static void beforeClass() throws Exception {
-    initCore("solrconfig-basic.xml", "schema.xml");
-  }
-
   @Before
   public void beforeTest() throws Exception {
-    // Ensure we have at least one MBeanServer available
-    MBeanServer platformServer = ManagementFactory.getPlatformMBeanServer();
-    // TODO: can we skip this call? either always or randomly?
+    initCore("solrconfig-basic.xml", "schema.xml");
 
     Random random = random();
 
@@ -102,6 +93,7 @@ public class SolrJmxReporterTest extends SolrTestCaseJ4 {
     assertTrue(objects.isEmpty());
 
     metricManager.close();
+    deleteCore();
   }
 
   @Test