| /* |
| * 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.geode.management; |
| |
| import static org.apache.geode.distributed.ConfigurationProperties.ENABLE_TIME_STATISTICS; |
| import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT; |
| import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER; |
| import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT; |
| import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START; |
| import static org.apache.geode.distributed.ConfigurationProperties.NAME; |
| import static org.apache.geode.distributed.ConfigurationProperties.STATISTIC_SAMPLING_ENABLED; |
| import static org.apache.geode.test.dunit.Host.getHost; |
| import static org.assertj.core.api.Assertions.assertThat; |
| |
| import java.io.Serializable; |
| import java.lang.annotation.Annotation; |
| import java.lang.reflect.Field; |
| import java.util.HashSet; |
| import java.util.Properties; |
| import java.util.Set; |
| |
| import org.junit.rules.MethodRule; |
| import org.junit.runners.model.FrameworkMethod; |
| import org.junit.runners.model.Statement; |
| |
| import org.apache.geode.cache.Cache; |
| import org.apache.geode.cache.client.ClientCacheFactory; |
| import org.apache.geode.cache.client.internal.InternalClientCache; |
| import org.apache.geode.distributed.DistributedMember; |
| import org.apache.geode.distributed.DistributedSystemDisconnectedException; |
| import org.apache.geode.distributed.internal.DistributionManager; |
| import org.apache.geode.distributed.internal.membership.InternalDistributedMember; |
| import org.apache.geode.internal.cache.GemFireCacheImpl; |
| import org.apache.geode.internal.cache.InternalCache; |
| import org.apache.geode.management.internal.SystemManagementService; |
| import org.apache.geode.test.dunit.Invoke; |
| import org.apache.geode.test.dunit.VM; |
| import org.apache.geode.test.dunit.cache.internal.JUnit4CacheTestCase; |
| import org.apache.geode.test.dunit.internal.DUnitLauncher; |
| import org.apache.geode.test.dunit.internal.JUnit4DistributedTestCase; |
| |
| /** |
| * Note: Overriding MethodRule is only way to get {@code Object target} |
| */ |
| @SuppressWarnings("unused") |
| public class ManagementTestRule implements MethodRule, Serializable { |
| |
| public static Builder builder() { |
| return new Builder(); |
| } |
| |
| private final int numberOfManagers; |
| private final int numberOfMembers; |
| private final boolean start; |
| private final boolean defineManagersFirst; |
| private final boolean defineManagers; |
| private final boolean defineMembers; |
| |
| private JUnit4CacheTestCase helper; |
| |
| private VM[] managers; |
| private VM[] members; |
| |
| protected ManagementTestRule(final Builder builder) { |
| helper = new JUnit4CacheTestCase() {}; |
| numberOfManagers = builder.numberOfManagers; |
| numberOfMembers = builder.numberOfMembers; |
| start = builder.start; |
| defineManagersFirst = builder.defineManagersFirst; |
| defineManagers = builder.defineManagers; |
| defineMembers = builder.defineMembers; |
| } |
| |
| @Override |
| public Statement apply(final Statement base, final FrameworkMethod method, final Object target) { |
| return new Statement() { |
| @Override |
| public void evaluate() throws Throwable { |
| setUp(target); |
| try { |
| base.evaluate(); |
| } finally { |
| tearDown(); |
| } |
| } |
| }; |
| } |
| |
| public DistributedMember getDistributedMember() { |
| return getCache().getDistributedSystem().getDistributedMember(); |
| } |
| |
| public DistributedMember getDistributedMember(final VM vm) { |
| return vm.invoke("getDistributedMember", () -> getDistributedMember()); |
| } |
| |
| public void createManagers() { |
| for (VM manager : managers) { |
| manager.invoke(() -> createManager(true)); |
| } |
| } |
| |
| public void createMembers() { |
| for (VM member : members) { |
| member.invoke(() -> createMember()); |
| } |
| } |
| |
| public void createManager() { |
| createManager(true); |
| } |
| |
| public void createManager(final Properties properties) { |
| createManager(properties, true); |
| } |
| |
| public void createManager(final boolean start) { |
| createManager(new Properties(), start); |
| } |
| |
| public void createManager(final Properties properties, final boolean start) { |
| setPropertyIfNotSet(properties, JMX_MANAGER, "true"); |
| setPropertyIfNotSet(properties, JMX_MANAGER_START, "false"); |
| setPropertyIfNotSet(properties, JMX_MANAGER_PORT, "0"); |
| setPropertyIfNotSet(properties, HTTP_SERVICE_PORT, "0"); |
| setPropertyIfNotSet(properties, ENABLE_TIME_STATISTICS, "true"); |
| setPropertyIfNotSet(properties, STATISTIC_SAMPLING_ENABLED, "true"); |
| |
| helper.getCache(properties); |
| |
| if (start) { |
| startManager(); |
| } |
| } |
| |
| public void createManager(final VM managerVM) { |
| managerVM.invoke("createManager", () -> createManager()); |
| } |
| |
| public void createManager(final VM managerVM, final boolean start) { |
| managerVM.invoke("createManager", () -> createManager(start)); |
| } |
| |
| public void createManager(final VM managerVM, final Properties properties) { |
| managerVM.invoke("createManager", () -> createManager(properties, true)); |
| } |
| |
| public void createManager(final VM managerVM, final Properties properties, final boolean start) { |
| managerVM.invoke("createManager", () -> createManager(properties, start)); |
| } |
| |
| public void createMember() { |
| createMember(new Properties()); |
| } |
| |
| public void createMember(final Properties properties) { |
| setPropertyIfNotSet(properties, JMX_MANAGER, "false"); |
| setPropertyIfNotSet(properties, ENABLE_TIME_STATISTICS, "true"); |
| setPropertyIfNotSet(properties, STATISTIC_SAMPLING_ENABLED, "true"); |
| |
| helper.getCache(properties); |
| } |
| |
| public void createMember(final VM memberVM) { |
| Properties properties = new Properties(); |
| properties.setProperty(NAME, "memberVM-" + memberVM.getId()); |
| memberVM.invoke("createMember", () -> createMember(properties)); |
| } |
| |
| public void createMember(final VM memberVM, final Properties properties) { |
| memberVM.invoke("createMember", () -> createMember(properties)); |
| } |
| |
| public InternalCache getCache() { |
| return helper.getCache(); |
| } |
| |
| public InternalClientCache getClientCache() { |
| return (InternalClientCache) helper.getClientCache(new ClientCacheFactory()); |
| } |
| |
| public boolean hasCache() { |
| return helper.hasCache(); |
| } |
| |
| public Cache basicGetCache() { |
| return helper.basicGetCache(); |
| } |
| |
| public ManagementService getManagementService() { |
| assertThat(hasCache()).isTrue(); |
| return ManagementService.getManagementService(basicGetCache()); |
| } |
| |
| public SystemManagementService getSystemManagementService() { |
| assertThat(hasCache()).isTrue(); |
| return (SystemManagementService) ManagementService.getManagementService(basicGetCache()); |
| } |
| |
| public ManagementService getExistingManagementService() { |
| assertThat(hasCache()).isTrue(); |
| return ManagementService.getExistingManagementService(basicGetCache()); |
| } |
| |
| public void startManager() { |
| SystemManagementService service = getSystemManagementService(); |
| service.createManager(); |
| service.startManager(); |
| } |
| |
| public void startManager(final VM managerVM) { |
| managerVM.invoke("startManager", () -> startManager()); |
| } |
| |
| public void stopManager() { |
| if (getManagementService().isManager()) { |
| getManagementService().stopManager(); |
| } |
| } |
| |
| public void stopManager(final VM managerVM) { |
| managerVM.invoke("stopManager", () -> stopManager()); |
| } |
| |
| public Set<DistributedMember> getOtherNormalMembers() { |
| Set<DistributedMember> allMembers = new HashSet<>(getAllNormalMembers()); |
| allMembers.remove(getDistributedMember()); |
| return allMembers; |
| } |
| |
| private Set<InternalDistributedMember> getAllNormalMembers() { |
| return getDistributionManager().getNormalDistributionManagerIds(); // excludes LOCATOR_DM_TYPE |
| } |
| |
| public void disconnectAllFromDS() { |
| stopManagerQuietly(); |
| Invoke.invokeInEveryVM("stopManager", () -> stopManagerQuietly()); |
| JUnit4DistributedTestCase.disconnectFromDS(); |
| Invoke.invokeInEveryVM("disconnectFromDS", () -> JUnit4DistributedTestCase.disconnectFromDS()); |
| } |
| |
| private DistributionManager getDistributionManager() { |
| return ((GemFireCacheImpl) getCache()).getDistributionManager(); |
| } |
| |
| private void setPropertyIfNotSet(final Properties properties, final String key, |
| final String value) { |
| if (!properties.containsKey(key)) { |
| properties.setProperty(key, value); |
| } |
| } |
| |
| private void stopManagerQuietly() { |
| try { |
| if (hasCache() && !basicGetCache().isClosed()) { |
| stopManager(); |
| } |
| } catch (DistributedSystemDisconnectedException | NullPointerException ignore) { |
| } |
| } |
| |
| private void setUp(final Object target) { |
| DUnitLauncher.launchIfNeeded(); |
| JUnit4DistributedTestCase.disconnectAllFromDS(); |
| |
| int whichVM = 0; |
| |
| managers = new VM[numberOfManagers]; |
| for (int i = 0; i < numberOfManagers; i++) { |
| managers[i] = getHost(0).getVM(whichVM); |
| whichVM++; |
| } |
| |
| members = new VM[numberOfMembers]; |
| for (int i = 0; i < numberOfMembers; i++) { |
| members[i] = getHost(0).getVM(whichVM); |
| whichVM++; |
| } |
| |
| if (start) { |
| start(); |
| } |
| |
| processAnnotations(target); |
| } |
| |
| private void start() { |
| if (defineManagers && defineManagersFirst) { |
| createManagers(); |
| } |
| if (defineMembers) { |
| createMembers(); |
| } |
| if (defineManagers && !defineManagersFirst) { |
| createManagers(); |
| } |
| } |
| |
| private void tearDown() { |
| JUnit4DistributedTestCase.disconnectAllFromDS(); |
| } |
| |
| private void processAnnotations(final Object target) { |
| try { |
| Class<?> clazz = target.getClass(); |
| |
| Field[] fields = clazz.getDeclaredFields(); |
| for (Field field : fields) { |
| boolean alreadyAssigned = false; |
| for (Annotation annotation : field.getAnnotations()) { |
| if (annotation.annotationType().equals(Manager.class)) { |
| // annotated with @Manager |
| throwIfAlreadyAssigned(field, alreadyAssigned); |
| assignManagerField(target, field); |
| alreadyAssigned = true; |
| } |
| if (annotation.annotationType().equals(Member.class)) { |
| // annotated with @Manager |
| throwIfAlreadyAssigned(field, alreadyAssigned); |
| assignMemberField(target, field); |
| alreadyAssigned = true; |
| } |
| } |
| } |
| } catch (IllegalAccessException e) { |
| throw new Error(e); |
| } |
| } |
| |
| private void throwIfAlreadyAssigned(final Field field, final boolean alreadyAssigned) { |
| if (alreadyAssigned) { |
| throw new IllegalStateException( |
| "Field " + field.getName() + " is already annotated with " + field.getAnnotations()); |
| } |
| } |
| |
| private void assignManagerField(final Object target, final Field field) |
| throws IllegalAccessException { |
| throwIfNotSameType(field, VM.class); |
| |
| field.setAccessible(true); |
| if (field.getType().isArray()) { |
| field.set(target, managers); |
| } else { |
| field.set(target, managers[0]); |
| } |
| } |
| |
| private void assignMemberField(final Object target, final Field field) |
| throws IllegalAccessException { |
| throwIfNotSameType(field, VM.class); |
| |
| field.setAccessible(true); |
| if (field.getType().isArray()) { |
| field.set(target, members); |
| } else { |
| field.set(target, members[0]); |
| } |
| } |
| |
| private void throwIfNotSameType(final Field field, final Class clazz) { |
| if (!field.getType().equals(clazz) && // non-array |
| !field.getType().getComponentType().equals(clazz)) { // array |
| throw new IllegalArgumentException( |
| "Field " + field.getName() + " is not same type as " + clazz.getName()); |
| } |
| } |
| |
| /** |
| * Configures and builds a ManagementTestRule |
| */ |
| public static class Builder { |
| |
| private boolean start = false; |
| |
| private boolean defineManagers = true; |
| |
| private boolean defineMembers = true; |
| |
| private int numberOfManagers = 1; |
| |
| private int numberOfMembers = 3; |
| |
| private boolean defineManagersFirst = true; |
| |
| private Builder() {} |
| |
| /** |
| * Define VMs annotated with {@literal @}Manager as Managers. Default is true. |
| */ |
| public Builder defineManagers(final boolean value) { |
| defineManagers = value; |
| return this; |
| } |
| |
| /** |
| * Define VMs annotated with {@literal @}Manager as Members. Default is true. |
| */ |
| public Builder defineMembers(final boolean value) { |
| defineMembers = value; |
| return this; |
| } |
| |
| /** |
| * Number of Manager(s) to define. Default is 1. |
| */ |
| public Builder numberOfManagers(final int count) { |
| numberOfManagers = count; |
| return this; |
| } |
| |
| /** |
| * Number of Member(s) to define. Default is 3. |
| */ |
| public Builder numberOfMembers(final int count) { |
| numberOfMembers = count; |
| return this; |
| } |
| |
| /** |
| * Define Manager(s) to DUnit VMs before Member(s). Default is true. |
| */ |
| public Builder defineManagersFirst(final boolean value) { |
| defineManagersFirst = value; |
| return this; |
| } |
| |
| /** |
| * Start Manager(s) and Member(s) before tests. Default is true. |
| */ |
| public Builder start(final boolean value) { |
| start = value; |
| return this; |
| } |
| |
| public ManagementTestRule build() { |
| return new ManagementTestRule(this); |
| } |
| } |
| } |