diff --git a/enterprise/metrics/pom.xml b/enterprise/metrics/pom.xml index 28fe79734bb7a..175e6498a6b11 100644 --- a/enterprise/metrics/pom.xml +++ b/enterprise/metrics/pom.xml @@ -100,7 +100,7 @@ org.neo4j - neo4j-kernel + neo4j-ha ${project.version} test test-jar @@ -137,5 +137,10 @@ hamcrest-all test + + org.mockito + mockito-core + test + diff --git a/enterprise/metrics/src/main/java/org/neo4j/metrics/MetricsExtension.java b/enterprise/metrics/src/main/java/org/neo4j/metrics/MetricsExtension.java index 160343de6768f..63639455ad2fe 100644 --- a/enterprise/metrics/src/main/java/org/neo4j/metrics/MetricsExtension.java +++ b/enterprise/metrics/src/main/java/org/neo4j/metrics/MetricsExtension.java @@ -22,9 +22,11 @@ import com.codahale.metrics.MetricRegistry; import org.neo4j.cluster.ClusterSettings; +import org.neo4j.graphdb.DependencyResolver; import org.neo4j.io.pagecache.monitoring.PageCacheMonitor; import org.neo4j.kernel.IdGeneratorFactory; import org.neo4j.kernel.configuration.Config; +import org.neo4j.kernel.ha.cluster.member.ClusterMembers; import org.neo4j.kernel.impl.api.LogRotationMonitor; import org.neo4j.kernel.impl.logging.LogService; import org.neo4j.kernel.impl.transaction.TransactionCounters; @@ -49,7 +51,7 @@ public class MetricsExtension implements Lifecycle private final CheckPointerMonitor checkPointerMonitor; private final IdGeneratorFactory idGeneratorFactory; private final LogRotationMonitor logRotationMonitor; - + private final DependencyResolver dependencyResolver; public MetricsExtension( MetricsKernelExtensionFactory.Dependencies dependencies ) { @@ -62,6 +64,7 @@ public MetricsExtension( MetricsKernelExtensionFactory.Dependencies dependencies checkPointerMonitor = dependencies.checkPointerCounters(); logRotationMonitor = dependencies.logRotationCounters(); idGeneratorFactory = dependencies.idGeneratorFactory(); + dependencyResolver = dependencies.getDependencyResolver(); } @Override @@ -83,7 +86,8 @@ public void init() throws Throwable // Setup metric gathering Neo4jMetricsFactory factory = new Neo4jMetricsFactory( registry, configuration, monitors, - transactionCounters, pageCacheCounters, checkPointerMonitor, logRotationMonitor, idGeneratorFactory ); + transactionCounters, pageCacheCounters, checkPointerMonitor, logRotationMonitor, idGeneratorFactory, + dependencyResolver, logService); life.add( factory.newInstance() ); life.init(); diff --git a/enterprise/metrics/src/main/java/org/neo4j/metrics/MetricsKernelExtensionFactory.java b/enterprise/metrics/src/main/java/org/neo4j/metrics/MetricsKernelExtensionFactory.java index 11bf9725266a8..f87c9bfc4bf31 100644 --- a/enterprise/metrics/src/main/java/org/neo4j/metrics/MetricsKernelExtensionFactory.java +++ b/enterprise/metrics/src/main/java/org/neo4j/metrics/MetricsKernelExtensionFactory.java @@ -19,6 +19,7 @@ */ package org.neo4j.metrics; +import org.neo4j.graphdb.DependencyResolver; import org.neo4j.io.pagecache.monitoring.PageCacheMonitor; import org.neo4j.kernel.IdGeneratorFactory; import org.neo4j.kernel.configuration.Config; @@ -51,6 +52,8 @@ public interface Dependencies IdGeneratorFactory idGeneratorFactory(); Monitors monitors(); + + DependencyResolver getDependencyResolver(); } public MetricsKernelExtensionFactory() diff --git a/enterprise/metrics/src/main/java/org/neo4j/metrics/source/ClusterMetrics.java b/enterprise/metrics/src/main/java/org/neo4j/metrics/source/ClusterMetrics.java index 9c840b59fce07..1df81d8f9e1a8 100644 --- a/enterprise/metrics/src/main/java/org/neo4j/metrics/source/ClusterMetrics.java +++ b/enterprise/metrics/src/main/java/org/neo4j/metrics/source/ClusterMetrics.java @@ -25,39 +25,57 @@ import java.io.IOException; import java.util.concurrent.atomic.AtomicLong; +import org.neo4j.function.Predicate; +import org.neo4j.function.Predicates; +import org.neo4j.graphdb.DependencyResolver; import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.ha.SlaveUpdatePuller; +import org.neo4j.kernel.ha.cluster.member.ClusterMembers; +import org.neo4j.kernel.impl.logging.LogService; import org.neo4j.kernel.lifecycle.LifecycleAdapter; import org.neo4j.kernel.monitoring.Monitors; import org.neo4j.metrics.MetricsSettings; import static com.codahale.metrics.MetricRegistry.name; +import static org.neo4j.kernel.ha.cluster.modeswitch.HighAvailabilityModeSwitcher.MASTER; +import static org.neo4j.kernel.ha.cluster.modeswitch.HighAvailabilityModeSwitcher.UNKNOWN; public class ClusterMetrics extends LifecycleAdapter { private static final String NAME_PREFIX = "neo4j.cluster"; private static final String SLAVE_PULL_UPDATES = name( NAME_PREFIX, "slave_pull_updates" ); private static final String SLAVE_PULL_UPDATE_UP_TO_TX = name( NAME_PREFIX, "slave_pull_update_up_to_tx" ); + static final String IS_MASTER = name( NAME_PREFIX, "is_master" ); + static final String IS_AVAILABLE = name( NAME_PREFIX, "is_available" ); private final Config config; private final Monitors monitors; private final MetricRegistry registry; + private final DependencyResolver dependencyResolver; + private final LogService logService; private final SlaveUpdatePullerMonitor monitor = new SlaveUpdatePullerMonitor(); + private ClusterMembers clusterMembers = null; - public ClusterMetrics( Config config, Monitors monitors, MetricRegistry registry ) + public ClusterMetrics( Config config, Monitors monitors, MetricRegistry registry, + DependencyResolver dependencyResolver, LogService logService ) { this.config = config; this.monitors = monitors; this.registry = registry; + this.dependencyResolver = dependencyResolver; + this.logService = logService; } @Override public void start() throws Throwable { - if ( config.get( MetricsSettings.neoClusterEnabled ) ) + if ( config.get( MetricsSettings.neoClusterEnabled ) && resolveClusterMembersDependencyOrLogWarning() ) { monitors.addMonitorListener( monitor ); + registry.register( IS_MASTER, new RoleGauge( Predicates.equalTo( MASTER ) ) ); + registry.register( IS_AVAILABLE, new RoleGauge( Predicates.not( Predicates.equalTo( UNKNOWN ) ) ) ); + registry.register( SLAVE_PULL_UPDATES, new Gauge() { @Override @@ -75,17 +93,36 @@ public Long getValue() return monitor.lastAppliedTxId; } } ); + + } + } + + private boolean resolveClusterMembersDependencyOrLogWarning() + { + try + { + clusterMembers = dependencyResolver.resolveDependency( ClusterMembers.class ); + return true; + } + catch ( IllegalArgumentException e ) + { + logService.getUserLog( getClass() ).warn( "Cluster metrics was enabled but the graph database" + + "is not in HA mode." ); + return false; } } @Override public void stop() throws IOException { - if ( config.get( MetricsSettings.neoClusterEnabled ) ) + if ( config.get( MetricsSettings.neoClusterEnabled ) && (clusterMembers != null) ) { registry.remove( SLAVE_PULL_UPDATES ); registry.remove( SLAVE_PULL_UPDATE_UP_TO_TX ); + registry.remove( IS_MASTER ); + registry.remove( IS_AVAILABLE ); + monitors.removeMonitorListener( monitor ); } } @@ -102,4 +139,24 @@ public void pulledUpdates( long lastAppliedTxId ) this.lastAppliedTxId = lastAppliedTxId; } } + + private class RoleGauge implements Gauge + { + private Predicate rolePredicate; + + public RoleGauge( Predicate rolePredicate ) + { + this.rolePredicate = rolePredicate; + } + + public Integer getValue() + { + int value = 0; + if ( clusterMembers != null ) + { + value = rolePredicate.test( clusterMembers.getCurrentMemberRole() ) ? 1 : 0; + } + return value; + } + } } diff --git a/enterprise/metrics/src/main/java/org/neo4j/metrics/source/Neo4jMetricsFactory.java b/enterprise/metrics/src/main/java/org/neo4j/metrics/source/Neo4jMetricsFactory.java index f78aa621affde..c900816aff133 100644 --- a/enterprise/metrics/src/main/java/org/neo4j/metrics/source/Neo4jMetricsFactory.java +++ b/enterprise/metrics/src/main/java/org/neo4j/metrics/source/Neo4jMetricsFactory.java @@ -24,10 +24,12 @@ import java.io.IOException; import org.neo4j.function.Factory; +import org.neo4j.graphdb.DependencyResolver; import org.neo4j.io.pagecache.monitoring.PageCacheMonitor; import org.neo4j.kernel.IdGeneratorFactory; import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.impl.api.LogRotationMonitor; +import org.neo4j.kernel.impl.logging.LogService; import org.neo4j.kernel.impl.transaction.TransactionCounters; import org.neo4j.kernel.impl.transaction.log.checkpoint.CheckPointerMonitor; import org.neo4j.kernel.lifecycle.Lifecycle; @@ -44,11 +46,13 @@ public class Neo4jMetricsFactory implements Factory private final CheckPointerMonitor checkPointerMonitor; private final LogRotationMonitor logRotationMonitor; private final IdGeneratorFactory idGeneratorFactory; + private final DependencyResolver dependencyResolver; + private final LogService logService; public Neo4jMetricsFactory( MetricRegistry registry, Config config, Monitors monitors, TransactionCounters transactionCounters, PageCacheMonitor pageCacheCounters, CheckPointerMonitor checkPointerMonitor, LogRotationMonitor logRotationMonitor, - IdGeneratorFactory idGeneratorFactory ) + IdGeneratorFactory idGeneratorFactory, DependencyResolver dependencyResolver, LogService logService ) { this.registry = registry; this.config = config; @@ -58,6 +62,8 @@ public Neo4jMetricsFactory( MetricRegistry registry, Config config, Monitors mon this.checkPointerMonitor = checkPointerMonitor; this.logRotationMonitor = logRotationMonitor; this.idGeneratorFactory = idGeneratorFactory; + this.dependencyResolver = dependencyResolver; + this.logService = logService; } @Override @@ -66,9 +72,10 @@ public Lifecycle newInstance() final DBMetrics dbMetrics = new DBMetrics( registry, config, transactionCounters, pageCacheCounters, checkPointerMonitor, logRotationMonitor, idGeneratorFactory ); final NetworkMetrics networkMetrics = new NetworkMetrics( config, monitors, registry ); - final ClusterMetrics clusterMetrics = new ClusterMetrics( config, monitors, registry ); - final JvmMetrics jvmMetrics = new JvmMetrics( config, registry ); + final ClusterMetrics clusterMetrics = new ClusterMetrics( config, monitors, registry, dependencyResolver, + logService ); final CypherMetrics cypherMetrics = new CypherMetrics( config, monitors, registry ); + final JvmMetrics jvmMetrics = new JvmMetrics( config, registry ); return new LifecycleAdapter() { @Override diff --git a/enterprise/metrics/src/test/java/org/neo4j/metrics/MetricsKernelExtensionFactoryIT.java b/enterprise/metrics/src/test/java/org/neo4j/metrics/MetricsKernelExtensionFactoryIT.java index 13753c99b3d3a..7edadc81d891c 100644 --- a/enterprise/metrics/src/test/java/org/neo4j/metrics/MetricsKernelExtensionFactoryIT.java +++ b/enterprise/metrics/src/test/java/org/neo4j/metrics/MetricsKernelExtensionFactoryIT.java @@ -19,7 +19,6 @@ */ package org.neo4j.metrics; -import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -27,24 +26,27 @@ import java.io.BufferedReader; import java.io.File; import java.io.FileReader; -import java.io.IOException; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import java.util.UUID; import org.neo4j.graphdb.DynamicLabel; -import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Transaction; -import org.neo4j.graphdb.factory.GraphDatabaseFactory; -import org.neo4j.graphdb.factory.GraphDatabaseSettings; import org.neo4j.helpers.Settings; +import org.neo4j.kernel.ha.HighlyAvailableGraphDatabase; +import org.neo4j.kernel.impl.ha.ClusterManager; import org.neo4j.metrics.source.CypherMetrics; import org.neo4j.test.TargetDirectory; +import org.neo4j.test.ha.ClusterRule; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.junit.Assert.assertThat; +import static org.neo4j.graphdb.factory.GraphDatabaseSettings.cypher_min_replan_interval; +import static org.neo4j.kernel.impl.ha.ClusterManager.clusterOfSize; import static org.neo4j.metrics.MetricsSettings.CsvFile.single; import static org.neo4j.metrics.MetricsSettings.csvEnabled; import static org.neo4j.metrics.MetricsSettings.csvFile; @@ -54,34 +56,32 @@ public class MetricsKernelExtensionFactoryIT { @Rule public final TargetDirectory.TestDirectory folder = TargetDirectory.testDirForTest( getClass() ); + @Rule + public final ClusterRule clusterRule = new ClusterRule( getClass() ); - GraphDatabaseService db; private File outputFile; + private ClusterManager.ManagedCluster cluster; + private HighlyAvailableGraphDatabase db; @Before - public void setup() throws IOException + public void setup() throws Exception { - String dbPath = folder.directory( "data" ).getAbsolutePath(); outputFile = folder.file( "metrics.csv" ); - db = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder( dbPath ). - setConfig( GraphDatabaseSettings.allow_store_upgrade, Settings.TRUE ). - setConfig( GraphDatabaseSettings.cypher_min_replan_interval, "0" ). - setConfig( csvEnabled, Settings.TRUE ). - setConfig( csvFile, single.name() ). - setConfig( csvPath, outputFile.getAbsolutePath() ).newGraphDatabase(); - } - - @After - public void shutdown() - { - db.shutdown(); + Map config = new HashMap<>(); + config.put( csvEnabled.name(), Settings.TRUE ); + config.put( cypher_min_replan_interval.name(), "0" ); + config.put( csvFile.name(), single.name() ); + config.put( csvPath.name(), outputFile.getAbsolutePath() ); + cluster = clusterRule.withSharedConfig( config ).withProvider( clusterOfSize( 1 ) ).startCluster(); + db = cluster.getMaster(); } @Test - public void mustLoadMetricsExtensionWhenConfigured() throws Exception + public void mustLoadMetricsExtensionWhenConfigured() throws Throwable { // Create some activity that will show up in the metrics data. addNodes( 1000 ); + cluster.stop(); // Awesome. Let's get some metric numbers. // We should at least have a "timestamp" column, and a "neo4j.transaction.committed" column @@ -106,12 +106,12 @@ public void mustLoadMetricsExtensionWhenConfigured() throws Exception } @Test - public void showReplanEvents() throws Exception + public void showReplanEvents() throws Throwable { //do a simple query to populate cache try ( Transaction tx = db.beginTx() ) { - db.execute( "match (n:Label {name: 'Pontus'}) return n.name"); + db.execute( "match (n:Label {name: 'Pontus'}) return n.name" ); tx.success(); } //add some data, should make plan stale @@ -124,12 +124,13 @@ public void showReplanEvents() throws Exception } //add more data just to make sure metrics are flushed addNodes( 1000 ); + cluster.stop(); //now we should have one replan event try ( BufferedReader reader = new BufferedReader( new FileReader( outputFile ) ) ) { String[] headers = reader.readLine().split( "," ); - int replanColumn = Arrays.binarySearch( headers, CypherMetrics.REPLAN_EVENTS); + int replanColumn = Arrays.binarySearch( headers, CypherMetrics.REPLAN_EVENTS ); assertThat( replanColumn, is( not( -1 ) ) ); // Now we can verify that the number of committed transactions should never decrease. @@ -147,7 +148,8 @@ public void showReplanEvents() throws Exception } } - private void addNodes( int numberOfNodes ) { + private void addNodes( int numberOfNodes ) + { for ( int i = 0; i < numberOfNodes; i++ ) { try ( Transaction tx = db.beginTx() ) @@ -158,5 +160,4 @@ private void addNodes( int numberOfNodes ) { } } } - } diff --git a/enterprise/metrics/src/test/java/org/neo4j/metrics/source/ClusterMetricsTest.java b/enterprise/metrics/src/test/java/org/neo4j/metrics/source/ClusterMetricsTest.java new file mode 100644 index 0000000000000..2e8e7fceae9af --- /dev/null +++ b/enterprise/metrics/src/test/java/org/neo4j/metrics/source/ClusterMetricsTest.java @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2002-2015 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.neo4j.metrics.source; + +import com.codahale.metrics.Counter; +import com.codahale.metrics.Gauge; +import com.codahale.metrics.Histogram; +import com.codahale.metrics.Meter; +import com.codahale.metrics.MetricFilter; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.ScheduledReporter; +import com.codahale.metrics.Timer; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.util.SortedMap; +import java.util.concurrent.TimeUnit; + +import org.neo4j.cluster.InstanceId; +import org.neo4j.graphdb.DependencyResolver; +import org.neo4j.helpers.Settings; +import org.neo4j.kernel.configuration.Config; +import org.neo4j.kernel.ha.cluster.HighAvailabilityMemberState; +import org.neo4j.kernel.ha.cluster.HighAvailabilityMemberStateMachine; +import org.neo4j.kernel.ha.cluster.member.ClusterMember; +import org.neo4j.kernel.ha.cluster.member.ClusterMembers; +import org.neo4j.kernel.ha.cluster.member.ObservedClusterMembers; +import org.neo4j.kernel.ha.cluster.modeswitch.HighAvailabilityModeSwitcher; +import org.neo4j.kernel.impl.logging.LogService; +import org.neo4j.kernel.lifecycle.LifeSupport; +import org.neo4j.kernel.monitoring.Monitors; +import org.neo4j.metrics.MetricsSettings; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; +import static org.neo4j.helpers.collection.MapUtil.stringMap; + + +public class ClusterMetricsTest +{ + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void clusterMetricsReportMasterAvailable() + { + // given + MetricRegistry metricRegistry = new MetricRegistry(); + Config config = new Config( stringMap( MetricsSettings.neoClusterEnabled.name(), Settings.TRUE ) ); + Monitors monitors = new Monitors(); + LifeSupport life = new LifeSupport(); + ClusterMembers clusterMembers = + getClusterMembers( HighAvailabilityModeSwitcher.MASTER, HighAvailabilityMemberState.MASTER ); + DependencyResolver dependencyResolver = mock( DependencyResolver.class ); + when( dependencyResolver.resolveDependency( ClusterMembers.class ) ).thenReturn( clusterMembers ); + LogService logService = mock( LogService.class ); + + life.add( new ClusterMetrics( config, monitors, metricRegistry, dependencyResolver, logService ) ); + life.start(); + + // when + TestReporter reporter = new TestReporter( metricRegistry ); + reporter.start( 10, TimeUnit.MILLISECONDS ); + + // then wait for the reporter to get a report + reporter.report(); + assertEquals( 1, reporter.isMasterValue ); + assertEquals( 1, reporter.isAvailableValue ); + } + + @Test + public void clusterMetricsReportSlaveAvailable() + { + // given + MetricRegistry metricRegistry = new MetricRegistry(); + Config config = new Config( stringMap( MetricsSettings.neoClusterEnabled.name(), Settings.TRUE ) ); + ClusterMembers clusterMembers = + getClusterMembers( HighAvailabilityModeSwitcher.SLAVE, HighAvailabilityMemberState.SLAVE ); + DependencyResolver dependencyResolver = mock( DependencyResolver.class ); + when( dependencyResolver.resolveDependency( ClusterMembers.class ) ).thenReturn( clusterMembers ); + LogService logService = mock( LogService.class ); + + Monitors monitors = new Monitors(); + LifeSupport life = new LifeSupport(); + life.add( new ClusterMetrics( config, monitors, metricRegistry, dependencyResolver, logService ) ); + life.start(); + + // when + TestReporter reporter = new TestReporter( metricRegistry ); + reporter.start( 10, TimeUnit.MILLISECONDS ); + + //then wait for the reporter to get a report + reporter.report(); + assertEquals( 0, reporter.isMasterValue ); + assertEquals( 1, reporter.isAvailableValue ); + } + + @Test + public void testClusterMemberNotEnabled() + { + // given + MetricRegistry metricRegistry = new MetricRegistry(); + Config config = new Config( stringMap( MetricsSettings.neoClusterEnabled.name(), Settings.FALSE ) ); + ClusterMembers clusterMembers = + getClusterMembers( HighAvailabilityModeSwitcher.SLAVE, HighAvailabilityMemberState.SLAVE ); + DependencyResolver dependencyResolver = mock( DependencyResolver.class ); + when( dependencyResolver.resolveDependency( ClusterMembers.class ) ).thenReturn( clusterMembers ); + LogService logService = mock( LogService.class ); + + Monitors monitors = new Monitors(); + LifeSupport life = new LifeSupport(); + life.add( new ClusterMetrics( config, monitors, metricRegistry, dependencyResolver, logService ) ); + life.start(); + + // when + TestReporter reporter = new TestReporter( metricRegistry ); + reporter.start( 10, TimeUnit.MILLISECONDS ); + + //then the reporter should fail + thrown.expect( NullPointerException.class ); + reporter.report(); + } + + @Test + public void testClusterMembersNull() + { + // given + MetricRegistry metricRegistry = new MetricRegistry(); + Config config = new Config( stringMap( MetricsSettings.neoClusterEnabled.name(), Settings.TRUE ) ); + ClusterMembers clusterMembers = null; + DependencyResolver dependencyResolver = mock( DependencyResolver.class ); + when( dependencyResolver.resolveDependency( ClusterMembers.class ) ).thenReturn( clusterMembers ); + LogService logService = mock( LogService.class ); + + Monitors monitors = new Monitors(); + LifeSupport life = new LifeSupport(); + life.add( new ClusterMetrics( config, monitors, metricRegistry, dependencyResolver, logService ) ); + life.start(); + + // when + TestReporter reporter = new TestReporter( metricRegistry ); + reporter.start( 10, TimeUnit.MILLISECONDS ); + + //then the reporter should fail + reporter.report(); + assertEquals( 0, reporter.isMasterValue ); + assertEquals( 0, reporter.isAvailableValue ); + } + + ClusterMembers getClusterMembers( String memberRole, HighAvailabilityMemberState memberState ) + { + HighAvailabilityMemberStateMachine stateMachine = mock( HighAvailabilityMemberStateMachine.class ); + when( stateMachine.getCurrentState() ).thenReturn( memberState ); + ClusterMember clusterMember = spy( new ClusterMember( new InstanceId( 1 ) ) ); + when( clusterMember.getHARole() ).thenReturn( memberRole ); + ObservedClusterMembers observedClusterMembers = mock( ObservedClusterMembers.class ); + when( observedClusterMembers.getCurrentMember() ).thenReturn( clusterMember ); + return new ClusterMembers( observedClusterMembers, stateMachine ); + } + + class TestReporter extends ScheduledReporter + { + private int isMasterValue, isAvailableValue; + + protected TestReporter( MetricRegistry registry ) + { + super( registry, "TestReporter", MetricFilter.ALL, TimeUnit.MILLISECONDS, TimeUnit.MILLISECONDS ); + } + + @Override + public void report( SortedMap gauges, SortedMap counters, + SortedMap histograms, SortedMap meters, SortedMap timers ) + { + isMasterValue = (Integer) gauges.get( ClusterMetrics.IS_MASTER ).getValue(); + isAvailableValue = (Integer) gauges.get( ClusterMetrics.IS_AVAILABLE ).getValue(); + } + } + +}