From the application's perspective, Coherence is a
data store. That means that you will need to use it while testing the
data access code.
If you have ever had to test
data access code that uses a relational database as a data store, you
know that the whole process can be quite cumbersome. You need to set up
test data, perform the test, and then clean up after each test, in order
to ensure that the side effects of one test do not influence the
outcome of another.
Tools such as DbUnit (http://www.dbunit.org)
or Spring's transactional testing support can make the process somewhat
easier, but unfortunately, nothing of that nature exists for Coherence.
The good news is that no such
tools are necessary when working with Coherence. Setting up test data
can be as simple as creating a bunch of CSV files and using the loader
we implemented in the previous section to import them into the cache.
Clearing data from the cache between the tests is even simpler-just call
the clear method on the cache you are testing. In most cases, testing Coherence-related code will be very similar to the LoaderTests test case from the previous section and much simpler than testing database-related code.
However, Coherence is not only a
data store, but a distributed processing engine as well, and that is
where things can get interesting. When you execute a query or an
aggregator, it executes across all the nodes in the cluster. When you
execute an entry processor, it might execute on one or several, possibly
even all nodes in parallel, depending on how it was invoked.
For the most part, you can
test the code that executes within the cluster the same way you test
more conventional data access code, by having each test case start a
one-node cluster. This makes debugging quite simple, as it ensures that
all the code, from test, to Coherence, to your custom processing code
executing within Coherence runs in the same process.
However, you should bear in
mind that by doing so you are not testing your code in the same
environment it will eventually run in. All kinds of things change
internally when you move from a one-node cluster to two-node cluster.
For example, Coherence will not create backups in a single-node
scenario, but it will as soon as the second node is added to the
cluster.
In some cases you might have to
test and debug your code in a true distributed environment, because it
depends on things that are only true if you move beyond a single node.
Debugging in a
distributed environment can get quite tricky. First of all, you will
need to enable remote debugging on a cache server node by adding the
following JVM arguments to DefaultCacheServer run configuration:
-Xdebug
-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005
Second, you will need to
ensure that all the data is stored on a cache server node where remote
debugging is enabled. That will ensure that the code you need to debug
within the cluster, such as the entry processor mentioned earlier, is
guaranteed to execute on that node.
Even though you will only be able to start one DefaultCacheServer now (because of the remote debug port it is bound to), as soon as your test invokes any CacheFactory
method it will join the cluster as a second node. By default, the data
is balanced automatically across all the nodes in the cluster, which
will make it impossible to ensure that your processor executes where you
want.
Fortunately, Coherence provides a
feature that allows you to control which nodes are used to store cached
data and which aren't. This feature is normally used to disable cache
storage on application servers while allowing them to be full-blown
members of the cluster in all other respects, but it can also be used to
ensure that no data is cached on the test runner node when using remote
debugging.
In order to activate it, you need to add the following JVM argument to your test runner configuration:
-Dtangosol.coherence.distributed.localstorage=false
Once everything is
configured properly, you should be able to set a breakpoint, start the
cache server, attach the debugger to it, and run the test. When the
breakpoint is hit, the debugger will allow you to step through the code
and inspect the variables in a remote process as you normally would, as
shown in the following screenshot:
The bottom line is that
even though debugging a distributed system poses some new challenges,
you can overcome them using a combination of features found in Java,
modern IDEs, and Coherence.
Also keep in mind that you
won't have to do this very often-more likely than not you will be able
to test and debug most of your code using a simple,
single-node-in-a-single-process approach. However, it is good to know
how to do it in a distributed environment as well, because sooner or
later you will need to do it.