- Index

< Previous |  | Next >

# Using the EventFlow Fragment Unit TimeService

## Introduction

You can control the passage of time when running EventFlow Fragment Unit Tests of EventFlow applications. This feature allows you to run unit tests of modules that react to time, such as those containing timeouts or those that use metronomes. Using the TimeService to set a custom start time is analogous to temporarily setting the BIOS system time of the machine hosting StreamBase Server, when using exclusively StreamBase APIs and facilities to obtain time or duration.

For example, you can run a unit test, enqueue events that should all be received by the application within one second, and then tell the Server that the one-second time period has elapsed. This allows you to align the EventFlow logic more closely with a real-world input stream.

See Creating and Running EventFlow Fragment Unit Tests for an introduction to configuring and running StreamBase JUnit tests.

## Configuring Controllable Time

To manage the reference starting point time of a EventFlow module, you must use the project's EventFlow Engine configuration file to specify the `timeService` property and one or two of its properties.

To be able to advance the current time of a running StreamBase Server, the StreamBaseEngine root object in the project's sbengine configuration file must contain the following:

    name = "engine"
    version = "1.0.0"
    type = "com.tibco.ep.streambase.configuration.sbengine"
    configuration = {
      StreamBaseEngine = {
        streamBase = {
          timeService = {
            type = "CONTROLLABLE"
          }
      }

To restore the default behavior, change the CONTROLLABLE keyword to WALLCLOCK, or comment out the entire property.

To specify a custom start timestamp for the module, use the `targetTime` property in addition to `type`. The `targetTime` property is ignored unless `type` is set to CONTROLLABLE. For example:

    timeService = {
            type = "CONTROLLABLE"
            targetTime = "2018-06-06 12:12:24.123+0000"
          }

## Utilities for Controlling Time

When a StreamBase application is configured as described in the previous section, you can control the reference start time of the running application either at the command prompt or in expression language constructions.

- Three expression language functions can be used to manage the running application's reference start time: advanceTimeBy(), advanceTimeTo(), and getTargetTime().

- Two jsbadmin subcommands, getTargetTime and fastForwardTime, can retrieve the current time and advance it by a specified number of milliseconds, as described on the jsbadmin reference page.

## Advancing Time Programmatically in Unit Tests

The overall steps to control time in your EventFlow Fragment Unit Tests are:

- When configuring your EventFlow Fragment Unit Java file, modify the BaseTestEnvironment's `NowImplementation` to use an `IMPL_TIME_SERVICE`.

- Create a ControllableTimeService and set that as the server's time service.

- In your test, use `timeService.advanceBy()` and `advanceTo()` to manage the clock.

The `TimeServiceFactory` class methods create TimeService objects to manage time:

- `getWallClockTimeService()` — Returns a TimeService that uses wall clock time (that is, it uses your operating system's clock); this is the default.

- `getControllableTimeService()` — Returns a ControllableTimeService instance initialized with the current system time. This is the usual starting point if you are trying to control time.

- `getControllableTimeService(long initTargetTimeMsec)` — Returns a ControllableTimeService instance initialized with a specified time.

In the `SBTestEnvironment` interface, the enum `NowImplementation` indicates how `now()` behaves. It takes these values:

- `IMPL_SYSTEM` — Uses calls to `System.currentTimeMillis()` on the calling thread

- `IMPL_THREAD` — Uses calls to `System.currentTimeMillis()` on a dedicated thread

- `IMPL_TIME_SERVICE` — Uses the current `TimeService` implementation to get the current time

To get the current implementation use `getNowImpl()`. To set it to one of the above, use `setNowImpl(NowImplementation)`.

In addition, the `SBServerManager` class has two methods for time services:

- `getTimeService()` — Returns the current TimeService implementation used by StreamBase Server.

- `setTimeService(TimeService timeservice)` — Set a TimeService for the StreamBase Server instance controlled by this Manager.

  The input TimeService value can be either a valid object or null. In the latter case it is assumed to be `WallClockTimeService` object.

  ### Caution

  The `setTimeService` method is not thread safe. It can be called from any thread but it should not be called from more than one thread at the same time.

## Modifying Generated Test Code to Control Time

When you select an application to test and click New → StreamBase Unit Test (JUnit), the StreamBase Unit Test Class wizard opens. When you click Finish, it generates code that begins like this:

    package com.sb.support.test;

    import com.streambase.sb.unittest.SBServerManager;
    import com.streambase.sb.unittest.ServerManagerFactory;

    public class baseMainTest {

      private static SBServerManager server;

      @BeforeClass
      public static void setupServer() throws Exception {
        // create a StreamBase server and load applications once for
        // all tests in this class
        server = ServerManagerFactory.getEmbeddedServer();
        server.startServer();
        server.loadApp("main.sbapp");
      }

As the default time service is wall clock time, the wizard generates no code to control time service. To establish control of time, modify the the `@BeforeClass` block as follows:

    @BeforeClass
    public static void setupServer() throws Exception {
      // create a StreamBase server and load applications once
      // for all tests in this class

      // Set NowImplementation to IMPL_TIME_SERVICE instead of the default
      BaseTestEnvironment.DEFAULT_ENVIRONMENT.setNowImpl(NowImplementation
        .IMPL_TIME_SERVICE);

      server = ServerManagerFactory.getEmbeddedServer();

      // Create a ControllableTimeService to use as the server's time service
      timeService = TimeServiceFactory.getControllableTimeService();
      server.setTimeService(timeService);

      server.startServer();
      server.loadApp("main.sbapp");
    }

Then, at the beginning of each test, you must initialize the time with this code:

    timeService.advanceTo(System.currentTimeMillis());

When you advance the clock, specify the advance interval size and unit. In this example, the advance is 15 seconds:

    timeService.advanceBy(15, TimeUnit.SECONDS);

See Java API Documentation in the StreamBase API Documentation for documentation on the classes involved, which are in the packages `com.streambase.sb` and `com.streambase.sb.unittest`.