| /* |
| * 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.test.dunit.rules; |
| |
| import static org.apache.geode.test.dunit.Disconnect.disconnectAllFromDS; |
| import static org.apache.geode.test.dunit.VM.DEFAULT_VM_COUNT; |
| import static org.apache.geode.test.dunit.internal.DUnitLauncher.getDistributedSystemProperties; |
| import static org.assertj.core.api.Assertions.assertThat; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Properties; |
| |
| import org.apache.geode.cache.Cache; |
| import org.apache.geode.cache.CacheFactory; |
| import org.apache.geode.cache.Region; |
| import org.apache.geode.distributed.internal.InternalDistributedSystem; |
| import org.apache.geode.internal.cache.HARegion; |
| import org.apache.geode.internal.cache.InternalCache; |
| import org.apache.geode.internal.cache.PartitionedRegion; |
| import org.apache.geode.test.dunit.VM; |
| |
| /** |
| * JUnit Rule that creates Cache instances in DistributedTest VMs without {@code CacheTestCase}. |
| * |
| * <p> |
| * {@code CacheRule} can be used in DistributedTests as a {@code Rule}: |
| * |
| * <pre> |
| * {@literal @}Rule |
| * public DistributedRule distributedRule = new DistributedRule(); |
| * |
| * {@literal @}Rule |
| * public CacheRule cacheRule = new CacheRule(); |
| * |
| * {@literal @}Before |
| * public void setUp() { |
| * getVM(0).invoke(() -> cacheRule.createCache(new CacheFactory().setPdxDiskStore(myDiskStore)))); |
| * } |
| * |
| * {@literal @}Test |
| * public void createRegionWithRegionFactory() { |
| * getVM(0).invoke(() -> { |
| * RegionFactory regionFactory = cacheRule.getCache().createRegionFactory(); |
| * Region region = regionFactory.create("RegionName"); |
| * assertThat(region).isNotNull(); |
| * }); |
| * } |
| * </pre> |
| * |
| * <p> |
| * {@link CacheRule.Builder} can also be used to construct an instance with more options: |
| * |
| * <pre> |
| * {@literal @}Rule |
| * public DistributedRule distributedRule = new DistributedRule(); |
| * |
| * {@literal @}Rule |
| * public CacheRule cacheRule = CacheRule.builder().createCacheInAll().build(); |
| * |
| * {@literal @}Test |
| * public void controllerVmCreatedCache() { |
| * assertThat(cacheRule.getCache()).isNotNull(); |
| * } |
| * |
| * {@literal @}Test |
| * public void remoteVmsCreatedCache() { |
| * for (VM vm : Host.getHost(0).getAllVMs()) { |
| * vm.invoke(() -> assertThat(cacheRule.getCache()).isNotNull()); |
| * } |
| * } |
| * </pre> |
| */ |
| @SuppressWarnings("serial,unused") |
| public class CacheRule extends AbstractDistributedRule { |
| |
| private static volatile InternalCache cache; |
| |
| private final boolean createCacheInAll; |
| private final boolean createCache; |
| private final boolean disconnectAfter; |
| private final boolean destroyRegions; |
| private final boolean replaceConfig; |
| private final List<VM> createCacheInVMs; |
| private final Properties config; |
| private final Properties systemProperties; |
| |
| /** |
| * Use {@code Builder} for more options in constructing {@code CacheRule}. |
| */ |
| public static Builder builder() { |
| return new Builder(); |
| } |
| |
| public CacheRule() { |
| this(new Builder()); |
| } |
| |
| public CacheRule(final int vmCount) { |
| this(new Builder().vmCount(vmCount)); |
| } |
| |
| CacheRule(final Builder builder) { |
| super(builder.vmCount); |
| createCacheInAll = builder.createCacheInAll; |
| createCache = builder.createCache; |
| disconnectAfter = builder.disconnectAfter; |
| destroyRegions = builder.destroyRegions; |
| replaceConfig = builder.replaceConfig; |
| createCacheInVMs = builder.createCacheInVMs; |
| config = builder.config; |
| systemProperties = builder.systemProperties; |
| } |
| |
| @Override |
| protected void before() { |
| if (createCacheInAll) { |
| invoker().invokeInEveryVMAndController(() -> createCache(config(), systemProperties)); |
| } else { |
| if (createCache) { |
| createCache(config(), systemProperties); |
| } |
| for (VM vm : createCacheInVMs) { |
| vm.invoke(() -> createCache(config(), systemProperties)); |
| } |
| } |
| } |
| |
| @Override |
| protected void after() { |
| closeAndNullCache(); |
| invoker().invokeInEveryVMAndController(() -> closeAndNullCache()); |
| |
| if (disconnectAfter) { |
| disconnectAllFromDS(); |
| } |
| } |
| |
| public InternalCache getCache() { |
| return cache; |
| } |
| |
| public InternalDistributedSystem getSystem() { |
| return cache.getInternalDistributedSystem(); |
| } |
| |
| public void createCache() { |
| cache = (InternalCache) new CacheFactory(config()).create(); |
| } |
| |
| public void createCache(final CacheFactory cacheFactory) { |
| cache = (InternalCache) cacheFactory.create(); |
| } |
| |
| public void createCache(final Properties config) { |
| cache = (InternalCache) new CacheFactory(config(config)).create(); |
| } |
| |
| public void createCache(final Properties config, final Properties systemProperties) { |
| System.getProperties().putAll(systemProperties); |
| cache = (InternalCache) new CacheFactory(config(config)).create(); |
| } |
| |
| public InternalCache getOrCreateCache() { |
| if (cache == null || cache.isClosed()) { |
| cache = null; |
| createCache(); |
| assertThat(cache).isNotNull(); |
| } |
| return cache; |
| } |
| |
| public InternalCache getOrCreateCache(final CacheFactory cacheFactory) { |
| if (cache == null || cache.isClosed()) { |
| cache = null; |
| createCache(cacheFactory); |
| assertThat(cache).isNotNull(); |
| } |
| return cache; |
| } |
| |
| public InternalCache getOrCreateCache(final Properties config) { |
| if (cache == null || cache.isClosed()) { |
| cache = null; |
| createCache(config); |
| assertThat(cache).isNotNull(); |
| } |
| return cache; |
| } |
| |
| public InternalCache getOrCreateCache(final Properties config, |
| final Properties systemProperties) { |
| if (cache == null || cache.isClosed()) { |
| cache = null; |
| createCache(config, systemProperties); |
| assertThat(cache).isNotNull(); |
| } |
| return cache; |
| } |
| |
| public void closeAndNullCache() { |
| closeCache(); |
| nullCache(); |
| } |
| |
| private Properties config() { |
| return config(new Properties()); |
| } |
| |
| private Properties config(final Properties config) { |
| if (replaceConfig) { |
| return config; |
| } |
| Properties allConfig = getDistributedSystemProperties(); |
| allConfig.putAll(this.config); |
| allConfig.putAll(config); |
| return allConfig; |
| } |
| |
| private void closeCache() { |
| try { |
| if (cache != null) { |
| if (destroyRegions) { |
| destroyRegions(cache); |
| } |
| cache.close(); |
| } |
| } catch (Exception ignored) { |
| // ignored |
| } |
| } |
| |
| private static void nullCache() { |
| cache = null; |
| } |
| |
| private static void destroyRegions(final Cache cache) { |
| if (cache != null && !cache.isClosed()) { |
| // try to destroy the root regions first so that we clean up any persistent files. |
| for (Region<?, ?> root : cache.rootRegions()) { |
| String regionFullPath = root == null ? null : root.getFullPath(); |
| // for colocated regions you can't locally destroy a partitioned region. |
| if (root.isDestroyed() || root instanceof HARegion || root instanceof PartitionedRegion) { |
| continue; |
| } |
| try { |
| root.localDestroyRegion("CacheRule_tearDown"); |
| } catch (Exception ignore) { |
| } |
| } |
| } |
| } |
| |
| /** |
| * Builds an instance of CacheRule. |
| */ |
| public static class Builder { |
| |
| private final List<VM> createCacheInVMs = new ArrayList<>(); |
| private final Properties systemProperties = new Properties(); |
| |
| private boolean createCacheInAll; |
| private boolean createCache; |
| private boolean disconnectAfter; |
| private boolean destroyRegions; |
| private boolean replaceConfig; |
| private Properties config = new Properties(); |
| private int vmCount = DEFAULT_VM_COUNT; |
| |
| public Builder() { |
| // nothing |
| } |
| |
| /** |
| * Create Cache in every VM including controller and all DUnit VMs. Default is false. |
| */ |
| public Builder createCacheInAll() { |
| createCacheInAll = true; |
| return this; |
| } |
| |
| /** |
| * Create Cache in specified VM. Default is none. |
| */ |
| public Builder createCacheIn(final VM vm) { |
| if (!createCacheInVMs.contains(vm)) { |
| createCacheInVMs.add(vm); |
| } |
| return this; |
| } |
| |
| /** |
| * Create Cache in local JVM (controller). Default is false. |
| */ |
| public Builder createCacheInLocal() { |
| createCache = true; |
| return this; |
| } |
| |
| /** |
| * Disconnect all VMs from DistributedSystem after each test. Cache is always closed regardless. |
| * Default is false. |
| */ |
| public Builder disconnectAfter() { |
| disconnectAfter = true; |
| return this; |
| } |
| |
| /** |
| * Destroy all Regions before closing the Cache. This will cleanup the presence of each Region |
| * in DiskStores, but this is not needed if the disk files are on a TemporaryFolder. Default is |
| * false. |
| */ |
| public Builder destroyRegions() { |
| destroyRegions = true; |
| return this; |
| } |
| |
| public Builder replaceConfig(final Properties config) { |
| this.config = config; |
| replaceConfig = true; |
| return this; |
| } |
| |
| public Builder addConfig(final String key, final String value) { |
| config.put(key, value); |
| return this; |
| } |
| |
| public Builder addConfig(final Properties config) { |
| this.config.putAll(config); |
| return this; |
| } |
| |
| public Builder addSystemProperty(final String key, final String value) { |
| systemProperties.put(key, value); |
| return this; |
| } |
| |
| public Builder addSystemProperties(final Properties config) { |
| systemProperties.putAll(config); |
| return this; |
| } |
| |
| public Builder vmCount(final int vmCount) { |
| this.vmCount = vmCount; |
| return this; |
| } |
| |
| public CacheRule build() { |
| return new CacheRule(this); |
| } |
| } |
| } |