The Emma Sensor is an Ant task that sends Java test coverage metrics produced by Emma to the Hackystat server. The Emma sensor represents this metric data using the Coverage sensor data type, documented in Section 25.8, “Coverage”
Table 26.7, “Emma Metrics” lists the coverage data gathered by the Emma sensor.Table 26.7. Emma Metrics
| Metric | Description |
|---|---|
| granularity | The coverage granularity, which for Emma is class, method, block and line level coverage. |
| timestamp | The time at which Emma was invoked. (Accurate to within a few seconds.) |
| File Name | The fully qualified Java source code file path. Since emma report only contains Java class name information, you need to enumerate all your source code locations to get the java file path. |
| Class | The fully qualified name of the class whose coverage is being represented. This is sent in the optional pMap field under the key className. |
| Covered Methods | The number of methods that were invoked during testing. |
| Uncovered Methods | The number of methods that were not invoked during testing. |
The Emma sensor requires Java 1.5.0 or later, Ant 1.6.5 or later, and Emma 2.0.5 or later. Emma usage typically requires some sort of test infrastructure such as JUnit.
Download Emma 2.0.5 or later from its home page and install into your local environment. Section 4.9, “Measurement: Test coverage with Emma” provides a recommended approach to Emma installation for use with Hackystat.
Follow the instructions in Chapter 2, Client-side configuration: Tool sensor installation to set your Hackystat host and user key.
In the HackyInstaller main window, select the Emma sensor and press "Configure Selected Sensor". Figure 26.1, “ Ant Build installer configuration window ” shows what the configuration window should look like after the path to Ant is set, the sensor is enabled, and the "Install" button has been pressed to install the sensor.
This sensor supports the following properties and paths:
Enable Emma Sensor: This property controls whether the sensor is active or not. If not checked, the sensor will not collect or send data even if installed.
Ant home directory: This path specifies the top-level directory for Ant. The Emma sensor requires the placement of a sensor executable into Ant's lib/ directory.
Example 26.32, “Example emma.tool and emma.sensor targets” illustrates one possible definition of these targets.
Example 26.32. Example emma.tool and emma.sensor targets
<target name="emma.tool" depends="clean, compile"
description="Cleans, compiles, instruments byte codes, runs unit tests, generates Emma report.">
<!-- Verify that Emma is installed. -->
<available file="${env.EMMA_HOME}/lib/emma.jar" property="emma.available"/>
<fail unless="emma.available" message="Error: EMMA_HOME not set or emma.jar not found, indicating Emma is not installed."/>
<!-- Define the path and taskdef containing the emma binaries. -->
<property name="emma.lib.dir" value="${env.EMMA_HOME}/lib" />
<path id="emma.lib.dir" >
<pathelement location="${emma.lib.dir}/emma.jar" />
<pathelement location="${emma.lib.dir}/emma_ant.jar" />
</path>
<taskdef resource="emma_ant.properties" classpathref="emma.lib.dir" />
<!-- Instrument the .class files. -->
<mkdir dir="${emma.dir}" />
<emma enabled="true" >
<instr instrpath="${build.dir}/classes"
destdir="${build.dir}/classes"
metadatafile="${emma.dir}/metadata.emma"
merge="true" mode="overwrite">
</instr>
</emma>
<!-- Run JUnit with the instrumented class files. -->
<mkdir dir="${junit.dir}" />
<junit printsummary="withOutAndErr" fork="yes">
<classpath path="${build.dir}/classes;${java.class.path}">
<path refid="emma.lib.dir" />
</classpath>
<sysproperty key="emma.coverage.out.file" value="${build.dir}/emma/coverage.emma" />
<sysproperty key="emma.coverage.out.merge" value="true" />
<formatter type="xml" />
<batchtest todir="${junit.dir}">
<fileset dir="${src.dir}">
<include name="**/Test*.java" />
</fileset>
</batchtest>
</junit>
<!-- Generate Emma reports. -->
<emma enabled="true" >
<report sourcepath="${src.dir}"
sort="+name"
metrics="method:70,block:80,line:80,class:100">
<fileset dir="${emma.dir}" >
<include name="*.emma" />
</fileset>
<xml outfile="${emma.dir}/coverage.xml" depth="method" />
<html outfile="${emma.dir}/coverage.html"
depth="method" columns="name,class,method,block,line" />
</report>
</emma>
<!-- Now delete the instrumented .class files. -->
<delete dir="${build.dir}/classes" />
</target>
<target name="emma.sensor" description="Sends Emma coverage data to Hackystat using the Emma sensor.">
<!-- Define the emma sensor taskdef, failing the build if the sensor is not installed. -->
<available classname="org.hackystat.sensor.emma.EmmaSensor" property="emma.sensor.available"/>
<fail unless="emma.sensor.available" message="Error: Emma sensor not installed."/>
<taskdef name="hacky-emma" classname="org.hackystat.sensor.emma.EmmaSensor"/>
<!-- Send Coverage data to Hackystat using the Emma sensor. -->
<hacky-emma verbose="true" emmaReportXmlFile="${emma.dir}/coverage.xml">
<fileset dir="${src.dir}" includes="**/*.java" />
</hacky-emma>
</target>
For more details on these targets, see Section 4.9, “Measurement: Test coverage with Emma”, which illustrates the installation and use of Emma on a sample Java system called StackyHack.
To verify your Emma sensor installation, invoke the target and check to see that data is sent to the server. Example 26.33, “Example Emma output” shows the shell output from an example run on the Stack system.
Example 26.33. Example Emma output
C:\svn-csdl\StackyHack>ant emma
Buildfile: build.xml
installBuildSensor:
init:
clean:
[delete] Deleting directory C:\svn-csdl\StackyHack\build
checkstyle:
compile:
[mkdir] Created dir: C:\svn-csdl\StackyHack\build\classes
[javac] Compiling 5 source files to C:\svn-csdl\StackyHack\build\classes
[javac] Note: Some input files use unchecked or unsafe operations.
[javac] Note: Recompile with -Xlint:unchecked for details.
emma:
[mkdir] Created dir: C:\svn-csdl\StackyHack\build\emma
[instr] processing instrumentation path ...
[instr] instrumentation path processed in 141 ms
[instr] [5 class(es) instrumented, 0 resource(s) copied]
[instr] metadata merged into [C:\svn-csdl\StackyHack\build\emma\metadata.emma] {in 0 ms}
installBuildSensor:
init:
checkstyle:
compile:
junit-emma:
[mkdir] Created dir: C:\svn-csdl\StackyHack\build\junit
[junit] Running edu.hawaii.stack.TestClearStack
[junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.281 sec
[junit] Running edu.hawaii.stack.TestStack
[junit] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 0.234 sec
[junitreport] Transform time: 687ms
[echo] JUnit results in C:\svn-csdl\StackyHack\build\junit/index.html
[hacky-junit] JUnitSensor disabled; no data sent.
[report] processing input files ...
[report] 2 file(s) read and merged in 16 ms
[report] writing [xml] report to [C:\svn-csdl\StackyHack\build\emma\coverage.xml] ...
[report] writing [html] report to [C:\svn-csdl\StackyHack\build\emma\coverage.html] ...
[hacky-emma] Sensor enabled?: true
[hacky-emma] Processing file: C:\svn-csdl\StackyHack\build\emma\coverage.xml
[hacky-emma] Hackystat data on 20 coverage entries sent to http://localhost:8080/ (0 secs.)
[delete] Deleting directory C:\svn-csdl\StackyHack\build\classes
BUILD SUCCESSFUL
Total time: 10 seconds
C:\svn-csdl\StackyHack>
Once you verify that Emma data is being sent from the client using verbose mode, login to your account on your Hackystat server, and use the "List Sensor Data" command on the Extras page to verify that Coverage data for today's date was received by the server for the Emma tool, as illustrated in Figure 26.28, “ List Sensor Data with Emma data ”.
The first step in troubleshooting your sensor installation is to verify that your Hackystat host and key settings are valid and that you can contact the Hackystat server, as described in Section 2.4, “HackyInstaller GUI: Setting and verifying the Hackystat host and user key”
The Emma sensor writes out a file called Emma.0.log to the .hackystat/logs directory that can be useful in debugging your installation. Under normal conditions, this file should look similar to Example 26.34, “Log file for Emma sensor”.
Example 26.34. Log file for Emma sensor
Hackystat Version: 7.0.1201 (December 1 2005 14:18:13)
SensorShell started at: 12/02/2005 20:42:33
Type 'help' for a list of commands.
Host: http://hackystat.ics.hawaii.edu/ is available and key is valid.
Defined shell command: Dependency
Defined shell command: Issue
Defined shell command: CodeIssue
Defined shell command: EvolSdt
Defined shell command: Perf
Defined shell command: FileMetric
Defined shell command: ReviewIssue
Defined shell command: Activity
Defined shell command: Cli
Defined shell command: ReviewActivity
Defined shell command: Coverage
Defined shell command: UnitTest
Defined shell command: BuffTrans
Defined shell command: Commit
Defined shell command: Build
#> AutoSend [10]
AutoSend OK (set to 10 minutes)
AutoSend enabled every 10 minutes.
Checking for offline data to recover.
No offline data found.
#> Coverage [set, tool=Emma]
set OK
#> Coverage [add, runTime=1133592153054, className=edu.hawaii.stack.ClearStack, granularity=class, covered=1, uncovered=0]
Coverage add OK (1 total)
#> Coverage [add, runTime=1133592153054, className=edu.hawaii.stack.ClearStack, granularity=method, covered=2, uncovered=1]
Coverage add OK (2 total)
#> Coverage [add, runTime=1133592153054, className=edu.hawaii.stack.ClearStack, granularity=block, covered=7, uncovered=3]
Coverage add OK (3 total)
#> Coverage [add, runTime=1133592153054, className=edu.hawaii.stack.ClearStack, granularity=line, covered=2, uncovered=1]
Coverage add OK (4 total)
#> Coverage [add, runTime=1133592153054, className=edu.hawaii.stack.EmptyStackException, granularity=class, covered=1, uncovered=0]
Coverage add OK (5 total)
#> Coverage [add, runTime=1133592153054, className=edu.hawaii.stack.EmptyStackException, granularity=method, covered=1, uncovered=0]
Coverage add OK (6 total)
#> Coverage [add, runTime=1133592153054, className=edu.hawaii.stack.EmptyStackException, granularity=block, covered=5, uncovered=0]
Coverage add OK (7 total)
#> Coverage [add, runTime=1133592153054, className=edu.hawaii.stack.EmptyStackException, granularity=line, covered=2, uncovered=0]
Coverage add OK (8 total)
#> Coverage [add, runTime=1133592153054, className=edu.hawaii.stack.Stack, granularity=class, covered=1, uncovered=0]
Coverage add OK (9 total)
#> Coverage [add, runTime=1133592153054, className=edu.hawaii.stack.Stack, granularity=method, covered=6, uncovered=2]
Coverage add OK (10 total)
#> Coverage [add, runTime=1133592153054, className=edu.hawaii.stack.Stack, granularity=block, covered=75, uncovered=31]
Coverage add OK (11 total)
#> Coverage [add, runTime=1133592153054, className=edu.hawaii.stack.Stack, granularity=line, covered=17, uncovered=7]
Coverage add OK (12 total)
#> Coverage [add, runTime=1133592153054, className=edu.hawaii.stack.TestClearStack, granularity=class, covered=1, uncovered=0]
Coverage add OK (13 total)
#> Coverage [add, runTime=1133592153054, className=edu.hawaii.stack.TestClearStack, granularity=method, covered=2, uncovered=0]
Coverage add OK (14 total)
#> Coverage [add, runTime=1133592153054, className=edu.hawaii.stack.TestClearStack, granularity=block, covered=78, uncovered=0]
Coverage add OK (15 total)
#> Coverage [add, runTime=1133592153054, className=edu.hawaii.stack.TestClearStack, granularity=line, covered=17, uncovered=0]
Coverage add OK (16 total)
#> Coverage [add, runTime=1133592153054, className=edu.hawaii.stack.TestStack, granularity=class, covered=1, uncovered=0]
Coverage add OK (17 total)
#> Coverage [add, runTime=1133592153054, className=edu.hawaii.stack.TestStack, granularity=method, covered=3, uncovered=0]
Coverage add OK (18 total)
#> Coverage [add, runTime=1133592153054, className=edu.hawaii.stack.TestStack, granularity=block, covered=72, uncovered=10]
Coverage add OK (19 total)
#> Coverage [add, runTime=1133592153054, className=edu.hawaii.stack.TestStack, granularity=line, covered=17, uncovered=4]
Coverage add OK (20 total)
#> send
Sending sensor data (12/02 20:42:33)
Ping: Ping OK (contacted server http://hackystat.ics.hawaii.edu/ with valid key.)
Dependency: Send OK (No entries to send.)
AutoSend: AutoSend OK ('send' command ignored)
Issue: Send OK (No entries to send.)
CodeIssue: Send OK (No entries to send.)
EvolSdt: Send OK (No entries to send.)
Perf: Send OK (No entries to send.)
FileMetric: Send OK (No entries to send.)
ReviewIssue: Send OK (No entries to send.)
Activity: Send OK (No entries to send.)
Cli: Send OK (No entries to send.)
ReviewActivity: Send OK (No entries to send.)
Coverage: Send OK (20 entries)
Commit: Send OK (No entries to send.)
BuffTrans: Send OK (No entries to send.)
UnitTest: Send OK (No entries to send.)
Build: Send OK (No entries to send.)
If none of the above troubleshooting activities solves your problem, then you should send an email to your Hackystat Administrator to request help. Please include in your email the following information:
The output from 'java -version'.
The output from 'java -jar sensorshell.jar -verify'.
The contents of your sensor.properties file.
The contents of the Emma.0.log file.
A description of the problem you are having.
You probably don't want to have to invoke "ant emma" manually each time you want coverage data sent to Hackystat. It is better to have the Emma coverage data calculated and sent to Hackystat automatically as a natural course of development. One strategy is to make the emma target a dependent target of an "install" or "distribution" target so that coverage data is recorded each time significant changes occur to the system. This provides a historical record of the structural evolution that can be later used by Hackystat analyses.
To disable Emma data collection temporarily, invoke HackyInstaller, bring up the Emma configuration window, and uncheck the "Enable Emma sensor" property, and apply the setting. To permanently uninstall the Emma sensor, press the "Uninstall" button and remove the Emma sensor targets from your Ant build.xml files.