IGNITE-12628 Add tests for jmx metrics return types - Fixes #7369.
Signed-off-by: Ivan Rakov <irakov@apache.org>
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/GridJobStealingSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/GridJobStealingSelfTest.java
index 1d01282..26dcfa6 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/GridJobStealingSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/GridJobStealingSelfTest.java
@@ -51,6 +51,7 @@
import org.apache.ignite.testframework.junits.common.GridCommonTest;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.junit.Ignore;
import org.junit.Test;
/**
@@ -301,6 +302,19 @@
ret.get(ignite3.cluster().localNode().id());
}
+ /**
+ * @throws Exception If fatiled.
+ */
+ @Ignore("https://issues.apache.org/jira/browse/IGNITE-12629")
+ @Test
+ public void testJobStealingMbeanValidity() throws Exception {
+ String[] beansToValidate = new String[] {
+ "org.apache.ignite.spi.collision.jobstealing.JobStealingCollisionSpi$JobStealingCollisionSpiMBeanImpl",
+ "org.apache.ignite.spi.failover.jobstealing.JobStealingFailoverSpi$JobStealingFailoverSpiMBeanImpl"};
+
+ validateMbeans(ignite1, beansToValidate);
+ }
+
/** {@inheritDoc} */
@Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/GridMBeansTest.java b/modules/core/src/test/java/org/apache/ignite/internal/GridMBeansTest.java
index db82643..5bbbbe3 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/GridMBeansTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/GridMBeansTest.java
@@ -17,12 +17,12 @@
package org.apache.ignite.internal;
+import javax.management.ObjectName;
import org.apache.ignite.configuration.ExecutorConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.internal.util.typedef.G;
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
-
-import javax.management.ObjectName;
import org.junit.Test;
/**
@@ -86,4 +86,34 @@
assertEquals(expAttributeVal, attributeVal);
}
+
+ /**
+ * @throws Exception If failed to validate methods.
+ */
+ @Test
+ public void testBeansClasses() throws Exception {
+ String[] clsNames = new String[]{"org.apache.ignite.internal.ClusterLocalNodeMetricsMXBeanImpl",
+ "org.apache.ignite.internal.ClusterMetricsMXBeanImpl",
+ "org.apache.ignite.internal.IgniteKernal",
+ "org.apache.ignite.internal.IgnitionMXBeanAdapter",
+ "org.apache.ignite.internal.StripedExecutorMXBeanAdapter",
+ "org.apache.ignite.internal.ThreadPoolMXBeanAdapter",
+ "org.apache.ignite.internal.TransactionMetricsMxBeanImpl",
+ "org.apache.ignite.internal.TransactionsMXBeanImpl",
+ "org.apache.ignite.internal.processors.cache.persistence.DataRegionMetricsMXBeanImpl",
+ "org.apache.ignite.internal.processors.cache.persistence.DataStorageMXBeanImpl",
+ "org.apache.ignite.internal.processors.cache.persistence.diagnostic.pagelocktracker.PageLockTrackerMXBeanImpl",
+ "org.apache.ignite.internal.processors.cluster.BaselineAutoAdjustMXBeanImpl",
+ "org.apache.ignite.internal.processors.odbc.ClientListenerProcessor$ClientProcessorMXBeanImpl",
+ "org.apache.ignite.internal.worker.FailureHandlingMxBeanImpl",
+ "org.apache.ignite.spi.checkpoint.sharedfs.SharedFsCheckpointSpi$SharedFsCheckpointSpiMBeanImpl",
+ "org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi$TcpCommunicationSpiMBeanImpl",
+ "org.apache.ignite.spi.deployment.local.LocalDeploymentSpi$LocalDeploymentSpiMBeanImpl",
+ "org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi$TcpDiscoverySpiMBeanImpl",
+ "org.apache.ignite.spi.eventstorage.memory.MemoryEventStorageSpi$MemoryEventStorageSpiMBeanImpl",
+ "org.apache.ignite.spi.failover.always.AlwaysFailoverSpi$AlwaysFailoverSpiMBeanImpl",
+ "org.apache.ignite.spi.loadbalancing.roundrobin.RoundRobinLoadBalancingSpi$RoundRobinLoadBalancingSpiMBeanImpl"};
+
+ validateMbeans(G.allGrids().get(0), clsNames);
+ }
}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/GridMbeansMiscTest.java b/modules/core/src/test/java/org/apache/ignite/internal/GridMbeansMiscTest.java
new file mode 100644
index 0000000..d4b20c7
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/GridMbeansMiscTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.ignite.internal;
+
+import org.apache.ignite.Ignite;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.spi.checkpoint.CheckpointSpi;
+import org.apache.ignite.spi.checkpoint.sharedfs.SharedFsCheckpointSpi;
+import org.apache.ignite.spi.collision.CollisionSpi;
+import org.apache.ignite.spi.collision.fifoqueue.FifoQueueCollisionSpi;
+import org.apache.ignite.spi.collision.priorityqueue.PriorityQueueCollisionSpi;
+import org.apache.ignite.spi.deployment.DeploymentSpi;
+import org.apache.ignite.spi.deployment.local.LocalDeploymentSpi;
+import org.apache.ignite.spi.loadbalancing.LoadBalancingSpi;
+import org.apache.ignite.spi.loadbalancing.adaptive.AdaptiveLoadBalancingSpi;
+import org.apache.ignite.spi.loadbalancing.weightedrandom.WeightedRandomLoadBalancingSpi;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+
+/**
+ * Checks mbeans validity for miscelenious spis.
+ */
+public class GridMbeansMiscTest extends GridCommonAbstractTest {
+ /** */
+ private CollisionSpi collisionSpi;
+
+ /** */
+ private LoadBalancingSpi loadBalancingSpi;
+
+ /** */
+ private DeploymentSpi deploymentSpi;
+
+ /** */
+ private CheckpointSpi checkpointSpi;
+
+ /** {@inheritDoc} */
+ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+ IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+ if (collisionSpi != null)
+ cfg.setCollisionSpi(collisionSpi);
+
+ if (loadBalancingSpi != null)
+ cfg.setLoadBalancingSpi(loadBalancingSpi);
+
+ if (deploymentSpi != null)
+ cfg.setDeploymentSpi(deploymentSpi);
+
+ if (checkpointSpi != null)
+ cfg.setCheckpointSpi(checkpointSpi);
+
+ return cfg;
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testMbeansSet1() throws Exception {
+ collisionSpi = new FifoQueueCollisionSpi();
+ loadBalancingSpi = new WeightedRandomLoadBalancingSpi();
+ deploymentSpi = new LocalDeploymentSpi();
+ checkpointSpi = new SharedFsCheckpointSpi();
+
+ String[] beansToValidate = new String[] {
+ "org.apache.ignite.spi.collision.fifoqueue.FifoQueueCollisionSpi$FifoQueueCollisionSpiMBeanImpl",
+ "org.apache.ignite.spi.loadbalancing.weightedrandom.WeightedRandomLoadBalancingSpi$WeightedRandomLoadBalancingSpiMBeanImpl",
+ "org.apache.ignite.spi.deployment.local.LocalDeploymentSpi$LocalDeploymentSpiMBeanImpl",
+ "org.apache.ignite.spi.checkpoint.sharedfs.SharedFsCheckpointSpi$SharedFsCheckpointSpiMBeanImpl"
+ };
+
+ doTest(beansToValidate);
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testMbeansSet2() throws Exception {
+ collisionSpi = new PriorityQueueCollisionSpi();
+ loadBalancingSpi = new AdaptiveLoadBalancingSpi();
+
+ String[] beansToValidate = new String[] {
+ "org.apache.ignite.spi.collision.priorityqueue.PriorityQueueCollisionSpi$PriorityQueueCollisionSpiMBeanImpl",
+ "org.apache.ignite.spi.loadbalancing.adaptive.AdaptiveLoadBalancingSpi$AdaptiveLoadBalancingSpiMBeanImpl"
+ };
+
+ doTest(beansToValidate);
+ }
+
+ /** */
+ private void doTest(String[] beansToValidate) throws Exception {
+ try {
+ Ignite ignite = startGrid();
+
+ validateMbeans(ignite, beansToValidate);
+ }
+ finally {
+ stopAllGrids();
+ }
+ }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/managers/checkpoint/GridCheckpointTaskSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/managers/checkpoint/GridCheckpointTaskSelfTest.java
index a9db0ae..2fe7683 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/managers/checkpoint/GridCheckpointTaskSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/managers/checkpoint/GridCheckpointTaskSelfTest.java
@@ -119,6 +119,14 @@
}
/**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testCacheCheckpointSpiMbeanValidity() throws Exception {
+ validateMbeans(grid(1), "org.apache.ignite.spi.checkpoint.cache.CacheCheckpointSpi$CacheCheckpointSpiMBeanImpl");
+ }
+
+ /**
* Failover test task.
*/
@ComputeTaskSessionFullSupport
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/EvictionAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/EvictionAbstractTest.java
index bcc0799..6191f4d 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/EvictionAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/EvictionAbstractTest.java
@@ -736,6 +736,24 @@
}
/**
+ * @throws Exception if failed.
+ */
+ @Test
+ public void testEvictionPolicyMbeanValidity() throws Exception {
+ try {
+ Ignite ignite = startGrids(2);
+
+ //Instantiate policy object to know exact class.
+ EvictionPolicy plc = createPolicy(0);
+
+ validateMbeans(ignite, plc.getClass().getName());
+ }
+ finally {
+ stopAllGrids();
+ }
+ }
+
+ /**
* @throws Exception If failed.
*/
protected void checkPartitioned() throws Exception {
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java
index 593d1c3..d86cfd4 100755
--- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java
@@ -18,6 +18,7 @@
package org.apache.ignite.testframework.junits.common;
import java.lang.management.ManagementFactory;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
@@ -41,6 +42,7 @@
import javax.cache.integration.CompletionListener;
import javax.management.MBeanServer;
import javax.management.MBeanServerInvocationHandler;
+import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
@@ -118,6 +120,7 @@
import org.apache.ignite.lang.IgniteInClosure;
import org.apache.ignite.lang.IgnitePredicate;
import org.apache.ignite.lang.IgniteRunnable;
+import org.apache.ignite.mxbean.MXBeanDescription;
import org.apache.ignite.resources.IgniteInstanceResource;
import org.apache.ignite.resources.LoggerResource;
import org.apache.ignite.testframework.GridTestNode;
@@ -131,6 +134,7 @@
import org.jetbrains.annotations.Nullable;
import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toSet;
import static org.apache.ignite.IgniteSystemProperties.IGNITE_EVENT_DRIVEN_SERVICE_PROCESSOR_ENABLED;
import static org.apache.ignite.IgniteSystemProperties.getBoolean;
import static org.apache.ignite.cache.CacheMode.LOCAL;
@@ -2375,4 +2379,137 @@
return MBeanServerInvocationHandler.newProxyInstance(mbeanSrv, mbeanName, cls, true);
}
+
+ /**
+ * Checks that return types of all registered ignite metrics methods are correct.
+ * Also checks that all classes from {@code namesToCheck} are registered as mbeans.
+ *
+ * @param ignite Ignite instance to collect metrics from.
+ * @param namesToCheck Mbean classes names that must be registered in {@code MBeanServer}.
+ * @throws Exception If failed to obtain mbeans.
+ */
+ protected void validateMbeans(Ignite ignite, String... namesToCheck) throws Exception {
+ logMbeansValidation(getNotRegisteredMbeans(ignite, namesToCheck), "Not registered mbeans");
+ logMbeansValidation(getInvalidMbeansMethods(ignite), "Invalid metrics methods");
+ }
+
+ /**
+ * @param ignite Ignite instance to collect metrics from.
+ * @param namesToCheck Mbean classes names that must be registered in {@code MBeanServer}.
+ * @return {@code Set} of class names that are contained in {@code namesToCheck}
+ * but not registered in {@code MBeanServer}.
+ */
+ protected Set<String> getNotRegisteredMbeans(Ignite ignite, String... namesToCheck) {
+ MBeanServer srv = ignite.configuration().getMBeanServer();
+
+ Set<String> beancClsNames = srv.queryMBeans(null, null).stream()
+ .map(ObjectInstance::getClassName)
+ .collect(toSet());
+
+ return Arrays.stream(namesToCheck)
+ .filter(nameToCheck -> beancClsNames.stream().noneMatch(clsName -> clsName.contains(nameToCheck)))
+ .collect(toSet());
+ }
+
+ /**
+ * @param ignite Ignite instance to collect metrics from.
+ * @return {@code Set} of metrics methods that have forbidden return types.
+ * @throws Exception If failed to obtain metrics.
+ */
+ protected Set<String> getInvalidMbeansMethods(Ignite ignite) throws Exception {
+ Set<String> sysMetricsPackages = new HashSet<>();
+ sysMetricsPackages.add("sun.management");
+ sysMetricsPackages.add("javax.management");
+
+ MBeanServer srv = ignite.configuration().getMBeanServer();
+
+ Set<String> invalidMethods = new HashSet<>();
+
+ final Set<ObjectInstance> instances = srv.queryMBeans(null, null);
+
+ for (ObjectInstance instance: instances) {
+ final String clsName = instance.getClassName();
+
+ if (sysMetricsPackages.stream().anyMatch(clsName::startsWith))
+ continue;
+
+ Class c;
+
+ try {
+ c = Class.forName(clsName);
+ }
+ catch (ClassNotFoundException e) {
+ log.warning("Failed to load class: " + clsName);
+
+ continue;
+ }
+
+ for (Class interf : c.getInterfaces()) {
+ for (Method m : interf.getMethods()) {
+ if (!m.isAnnotationPresent(MXBeanDescription.class))
+ continue;
+
+ if (!validateMetricsMethod(m))
+ invalidMethods.add(m.toString());
+ }
+ }
+ }
+
+ return invalidMethods;
+ }
+
+ /** */
+ private void logMbeansValidation(Set<String> invalidSet, String errorMsgPrefix) {
+ if (!invalidSet.isEmpty()) {
+ log.info("****************************************");
+ log.info(errorMsgPrefix + ":");
+
+ invalidSet.stream()
+ .sorted()
+ .forEach(log::info);
+
+ log.info("****************************************");
+
+ fail(errorMsgPrefix + " detected^");
+ }
+ }
+
+ /**
+ * Validates return type for metrics method.
+ * Validity rules are not carved in stone and can be changed in future.
+ * See https://issues.apache.org/jira/browse/IGNITE-12629.
+ *
+ * @param m Metric method to check.
+ * @return {@code True} if method return type is allowed.
+ */
+ private boolean validateMetricsMethod(Method m) {
+ Set<String> primitives = new HashSet<>();
+ primitives.add("char");
+ primitives.add("short");
+ primitives.add("int");
+ primitives.add("long");
+ primitives.add("double");
+ primitives.add("float");
+ primitives.add("byte");
+ primitives.add("boolean");
+ primitives.add("void");
+
+ Set<String> allowedPackages = new HashSet<>();
+ allowedPackages.add("java.lang");
+ allowedPackages.add("java.util");
+
+ final String returnTypeName = m.getGenericReturnType().getTypeName();
+
+ if (primitives.stream().anyMatch(type -> type.equals(returnTypeName) || (type + "[]").equals(returnTypeName)))
+ return true;
+
+ String[] parts = returnTypeName.split("[<>,]");
+
+ for (String part: parts) {
+ if (allowedPackages.stream().noneMatch(pack -> part.trim().startsWith(pack)))
+ return false;
+ }
+
+ return true;
+ }
}
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
index aeead5f..711048e 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
@@ -33,6 +33,7 @@
import org.apache.ignite.internal.GridLifecycleAwareSelfTest;
import org.apache.ignite.internal.GridLifecycleBeanSelfTest;
import org.apache.ignite.internal.GridMBeansTest;
+import org.apache.ignite.internal.GridMbeansMiscTest;
import org.apache.ignite.internal.GridNodeMetricsLogSelfTest;
import org.apache.ignite.internal.GridPeerDeploymentRetryModifiedTest;
import org.apache.ignite.internal.GridPeerDeploymentRetryTest;
@@ -183,6 +184,7 @@
GridNodeMetricsLogSelfTest.class,
GridLocalIgniteSerializationTest.class,
GridMBeansTest.class,
+ GridMbeansMiscTest.class,
TransactionsMXBeanImplTest.class,
SetTxTimeoutOnPartitionMapExchangeTest.class,
DiscoveryDataDeserializationFailureHanderTest.class,
diff --git a/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryMiscTest.java b/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryMiscTest.java
index f51da78..18493c9 100644
--- a/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryMiscTest.java
+++ b/modules/zookeeper/src/test/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryMiscTest.java
@@ -462,6 +462,21 @@
}
/**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testZkMbeansValidity() throws Exception {
+ try {
+ Ignite ignite = startGrid();
+
+ validateMbeans(ignite, "org.apache.ignite.spi.discovery.zk.ZookeeperDiscoverySpi$ZookeeperDiscoverySpiMBeanImpl");
+ }
+ finally {
+ stopAllGrids();
+ }
+ }
+
+ /**
*
*/
private static class ValidationTestAffinity extends RendezvousAffinityFunction {