Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Note: Please see The Green Report for latest recommendations in writing DistributedTests.

A DistributedTest in Geode is a test written with Geode's DUnit framework involving multiple members of a distributed system.

...

If you write an DistributedTest to expose a bug and confirm its fix, then you should name it with the suffix *RegressionTest. Otherwise you should use the suffix *DistributedTest or *DUnitTest.

Preferred Testing Frameworks and Libraries for Geode DistributedTests

Overall Framework

  • JUnit 4 (including Rules)
  • Paramerized – JUnit 4.12 has a bug which prevents Parameterized and Category from working together properly
    • Please use CategoryWithParameterizedRunnerFactory from Geode when using Parameterized (see GEODE-1350)
  • TemporaryFolder – provides isolated file system that will be cleaned up after the test
  • TestName – provides name of the test method currently being tested
  • ErrorCollector – use this when performing assertions in callbacks such as CacheListener

Assertion Library

  • AssertJ – richer API with better failure messages than JUnit 4 Assert

Mocking Library

  • Mockito
  • PowerMock – use this as a last resort – refactoring code to facilitate better testing is preferred

Expected Exceptions

  • Use AssertJ or Catch-Exception instead of JUnit 4 Rule ExpectedException
  • AssertJ (assertThatThrownBy) – this is the cleanest and preferred way to test for expected exception
  • Catch-Exception – better support for complex nesting of exceptions or exceptions with unusual APIs

Additional 3rd Party Libraries for UnitTests

  • JUnitParams – provides test method parameterization (usually better to use than JUnit 4 Parameterized)
  • System Rules – powerful set of JUnit 4 Rules
    • RestoreSystemProperties
  • Awaitility – useful for awaiting asynchronous conditions

Custom Geode JUnit 4 Rules

...

  • ExpectedTimeoutRule – verifies that an API times out and potentially throws TimeoutException
  • JarFileRule – creates a Jar file in an internal TemporaryFolder containing a dynamically generated class
  • RequiresGeodeHome – asserts precondition that GEODE_HOME system property is specified
  • RestoreLocaleRule – restores JVM to original Locale
  • RestoreTCCLRule – restores Thread Context Class Loader
  • RetryRule – retries a test until it passes or exceeds specified number of retries
  • TemporaryFileRule – destroys specified files or directories that aren't created in a TemporaryFolder
  • UseJacksonForJsonPathRule – specifies that JsonPath should use Jackson instead of its default JSON library
  • GfshRule – allows use of Gfsh script string to fork a JVM process in an IntegrationTest

Custom Geode

...

DUnit Rules

  • CacheXmlRule – uses CacheCreation to generate cache.xml
  • DistributedRule DistributedTestRule – launches the DUnit VMs
  • CacheRule – simple Cache creation and reference for CleanupDUnitVMsRule – bounces all DUnit VMs
  • ClusterStartupRule – creates Server or Locator in any DUnit VM
  • DistributedDisconnectRule – disconnects all DUnit VMsDistributedExecutorServiceRule – provides ExecutorService for concurrent testing
  • DistributedRestoreSystemProperties – extends RestoreSystemProperties for all DUnit VMs
  • DistributedUseJacksonForJsonPathRule – extends UseJacksonForJsonPathRule for all DUnit VMs
  • SerializableTestName – extends TestName to be serializableusable within all DUnit VMs
  • SerializableTemporaryFolder – extends TemporaryFolder to be usable within all DUnit VMs
  • SharedCountersRule – shared counter API for all DUnit VMs
  • SharedErrorCollector – extends ErrorCollector for all DUnit VMs

Custom Geode API DUnit Rules

  • CacheRule – simple Cache creation and reference for all DUnit VMs
  • ClientCacheRule – simple ClientCache creation and reference for all DUnit VMs
  • ClusterStartupRule – starts cluster and creates Server or Locator in any DUnit VM

Custom Geode DUnit API Classes

  • AsyncInvocation – return type from VM#invokeAsync and implements Future
  • Disconnect – disconnect in all or specified VM
  • Host – provides the DUnit VMs
  • VM – provides invocation API for a DUnit VM

Custom Geode DUnit TestCases

  • DistributedTestCase – extend this class for an old-school DUnit test
  • CacheTestCase – adds Cache API to DistributedTestCase

Examples of actual tests

Examples of some good DistributedTests:

...

Code Block
package org.apache.geode.internal.cache.backup;


import static org.apache.geode.test.dunit.Disconnect.disconnectAllFromDS;
import static org.apache.geode.test.dunit.Disconnect.disconnectFromDS;
import static org.apache.geode.test.dunit.Host.getHost;
import static org.apache.geode.test.dunit.IgnoredException.addIgnoredException;
import static org.apache.geode.test.dunit.Invoke.invokeInEveryVM;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.awaitility.Awaitility.await;
 
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
 
import org.apache.geode.test.dunit.VM;
import org.apache.geode.test.dunit.rules.CacheRule;
import org.apache.geode.test.dunit.rules.DistributedRestoreSystemProperties;
import org.apache.geode.test.dunit.rules.DistributedTestRule;
import org.apache.geode.test.dunit.rules.SharedCountersRule;
import org.apache.geode.test.dunit.rules.SharedErrorCollector;
import org.apache.geode.test.junit.categories.DistributedTest;


/**
 * Use DistributedTestRuleDistributedRule to launch additional JVMs to use in the test.<br>
 * Use CacheRule to keep references to Cache in each JVM which will be cleaned up.<br>
 * Use DistributedRestoreSystemProperties to restore properties across all JVMs.<br>
 * Use SharedCountersRule for blackboard style counters in all JVMs.<br>
 * Use SharedErrorCollector to perform assertions in callbacks/listeners.<br>
 * Use SerializableTemporaryFolder to provide temporary directories for all JVMs.<br>
 * <p>
 * Above static imports show the most commonly used DUnit utilities, AssertJ and 
 * Awaitility.
 */ 
@SuppressWarnings("serial")
public class OpsWithChangingMembershipDistributedTest implements Serializable {
   
  private VM vm0;
  private VM vm1;
  private VM vm2;
  private VM vm3;


  @ClassRule@Rule
  public staticDistributedRule DistributedTestRuledistributedRule distributedTestRule = new DistributedTestRuleDistributedRule();

  @Rule
  public CacheRule cacheRule = new CacheRule();
 
  @Rule
  public DistributedRestoreSystemProperties restoreSystemProperties =
      new DistributedRestoreSystemProperties();

  @Rule
  public SharedErrorCollector errorCollector = new SharedErrorCollector();

  @Rule
  public SerializableTemporaryFolder temporaryFolder = new SerializableTemporaryFolder();
 
  @Before
  public void setUp() {
    // arrange: perform as much of your setUp as possible in @Before
 
    vm0.invoke(() -> {
      Cache cache = cacheRule.getOrCreateCache();
      // additional setup
    });
  }
 
  @Test
  public void incrementalBackupWithMissingBaselineThrows() {
    // act: manipulate VMs with invoke or invokeAsync

    // assert: don't forget to actually use assertions!
  }
}