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 1d012829a28ef..26dcfa6fa6ee8 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 @@ public void testProjectionPredicateDifferentClassLoaders() throws Exception { 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 db826433df9b0..5bbbbe3f8045b 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 @@ private void checkBean(String grp, String name, String attributeName, Object exp 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 0000000000000..d4b20c7947a5c --- /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 a9db0aec486dc..2fe76831070bf 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 @@ -118,6 +118,14 @@ public void testReduce() throws Exception { grid(1).compute().execute(ReduceTestTask.class, null); } + /** + * @throws Exception If failed. + */ + @Test + public void testCacheCheckpointSpiMbeanValidity() throws Exception { + validateMbeans(grid(1), "org.apache.ignite.spi.checkpoint.cache.CacheCheckpointSpi$CacheCheckpointSpiMBeanImpl"); + } + /** * Failover test task. */ 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 bcc0799d2a520..6191f4d43f543 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 @@ -735,6 +735,24 @@ public void testPartitionedNearEnabledMultiThreaded() throws Exception { checkPartitionedMultiThreaded(); } + /** + * @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. */ 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 05b4941530768..35e5d7f2e17d2 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; @@ -40,6 +41,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; @@ -117,6 +119,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; @@ -130,6 +133,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; @@ -2374,4 +2378,137 @@ protected T getMxBean( 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 getNotRegisteredMbeans(Ignite ignite, String... namesToCheck) { + MBeanServer srv = ignite.configuration().getMBeanServer(); + + Set 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 getInvalidMbeansMethods(Ignite ignite) throws Exception { + Set sysMetricsPackages = new HashSet<>(); + sysMetricsPackages.add("sun.management"); + sysMetricsPackages.add("javax.management"); + + MBeanServer srv = ignite.configuration().getMBeanServer(); + + Set invalidMethods = new HashSet<>(); + + final Set 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 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 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 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 5dbdea74a2537..d841067b626bf 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; @@ -180,6 +181,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 f51da78ed7a49..18493c9074052 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 @@ -461,6 +461,21 @@ public void testStopNode_1() throws Exception { waitForTopology(5); } + /** + * @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(); + } + } + /** * */