How to Write Tests for Your own Kieker Probes

Writing your own probes with Kieker is quite simple. However, testing them requires additional insight into Kieker which require reading a lot of source code. As this is an unpleasant task, I collected some basic ideas in this how-to.

Let say you have a written a probe ExampleProbe:

 1import kieker.common.record.IMonitoringRecord;
 2import kieker.common.record.flow.trace.TraceMetadata;
 3import kieker.common.record.flow.trace.operation.BeforeOperationEvent;
 4import kieker.monitoring.core.controller.IMonitoringController;
 5import kieker.monitoring.core.controller.MonitoringController;
 6import kieker.monitoring.core.registry.TraceRegistry;
 7
 8public class ExampleProbe {
 9        private final IMonitoringController ctrl = MonitoringController.getInstance();
10        private final TraceRegistry registry = TraceRegistry.INSTANCE;
11
12        public ExampleProbe() {
13        }
14
15        public void takeMeasurement(final String operationSignature,
16                final String classSignature) {
17
18                /** collect event data. */
19                final TraceMetadata trace = this.registry.getTrace();
20                final long timestamp = this.ctrl.getTimeSource().getTime();
21                final long traceId = trace.getTraceId();
22                final int orderIndex = trace.getNextOrderId();
23
24                /** create event. */
25                final IMonitoringRecord event = new BeforeOperationEvent(timestamp,
26                        traceId, orderIndex, operationSignature,
27                        classSignature);
28
29                /** log event. */
30                this.ctrl.newMonitoringRecord(event);
31        }
32}

When you use this in an application, the IMonitoringController will refer to a singleton within the application, which is great within an application. You can pass a configuration via a file at a default location or by specifying an environment variable. Unfortunately, this makes is more complicated for testers to pass their configuration to the controller. In case you instantiate a controller in the test class, it will create a separate controller for the test class. Fortunately, there is a way around this limitation. As the MonitoringController factory method checks on environment variables, you can set them in a test statically. Therefore, they are set before creating the first MonitoringController.

 1package example.probe.test;
 2
 3import kieker.monitoring.core.configuration.ConfigurationKeys;
 4import org.junit.Test;
 5
 6public class ExampleProbeTest {
 7
 8        /**
 9         * Set system properties before instantiation anything.
10         * Otherwise the MonitoringController will not see the
11         * configuration.
12         */
13        static {
14                System.setProperty(ConfigurationKeys.CONTROLLER_NAME, "ExampleProbeTest Controller");
15
16                System.setProperty(ConfigurationKeys.WRITER_CLASSNAME,
17                        TestDummyWriter.class.getCanonicalName());
18        }
19
20        @Test
21        public void test() {
22                final ExampleProbe probe = new ExampleProbe();
23                probe.takeMeasurement("myOperation()", "example.ExampleClass");
24
25                /** first record. */
26                final IMonitoringRecord metadata = TestDummyWriter.getEvents().get(0);
27
28                Assert.assertEquals("First record should be KiekerMetaData",
29                        metadata.getClass().getName(),
30                        KiekerMetadataRecord.class.getName());
31
32                /** second record. */
33                final IMonitoringRecord beforeEvent =
34                        TestDummyWriter.getEvents().get(1);
35
36                Assert.assertEquals("First record should be KiekerMetaData",
37                        beforeEvent.getClass().getName(),
38
39                BeforeOperationEvent.class.getName());
40        }
41}

In this test class, we set two properties. Firstly, we specify a controller name. This helps when debugging tests, as we can check whether the used controller is really the one with the internal name “ExampleProbeTest Controller”. Secondly, we set the writer class. By default Kieker would write into a text log file. However, during testing we do not want that Kieker creates a directory and stores log information there. Instead we want to access logged data programmatically. The TestDummyWriter allows to access events from a statically defined internal list, which is most convenient for testing. The list is statically accessed with TestDummyWriter.getEvents(). The first event is always KiekerMetadataRecord, except you configure the controller to omit the metadata record.

Based on this simple setup, you can test your own probes easily. Please note, currently the TestDummyWriter is still part of iObserve and will move to Kieker in the near future.