blob: e40aac217257215ddcab792bdb2bebed648dc23d [file] [log] [blame]
/*
* 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);
}
}
}