Pages

Showing posts with label maven. Show all posts
Showing posts with label maven. Show all posts

Friday, May 29, 2015

Multi-Module Integration Test Coverage with Jacoco and Sonar

Yesterday I have struggled to capture IT coverage results in a multi-module project setup, which I eventually solved.

So lets assume, I have the following setup:

rootModule
+Module1
+Module2
| +SubModule2-1
|    +SubModule2-1-1
| +SubModule2-2
+ITModule
  +ITModule1

The ITModule contains only integration tests, where ITModule1 is a special scenario, that requires a single module. Module2 consists of nested submodules. There are several examples out there to use a path like ../target/jacoco-it.exec but that's obviously not working if you more than one nesting level.

To know how to solve it, you must understand, how sonar is doing the analysis. When analysing the coverage information sonar checks the code of each module against the coverage file that is specified in the sonar.jacoco.itReportPath property which defaults to target/jacoco-it.exec. So when analyzing Module1 it check for coverage info in Module1/target/jacoco-it.exec. But as the coverage data is captured in the ITModule, respectively ITModule1, I have to point sonar to the file generated in the IT module.
So the best location to gather the coverage data is to the use rootModule, i.e. rootModule/target/jacoco-it.exec and append the results of all IT tests to that file.

I use the following plugin configuration that uses separate files for unit-test coverage (don't forget the append flag otherwise overall coverage will be incorrect) and the central file for IT covergage.
<plugin>
  <groupId>org.jacoco</groupId>
  <artifactId>jacoco-maven-plugin</artifactId>
  <version>0.7.4.201502262128</version>
  <executions>
    <execution>
      <id>prepare-agent</id>
      <goals>
        <goal>prepare-agent</goal>
      </goals>
      <configuration>
        <destFile>target/jacoco.exec</destFile>
        <append>true</append>
        <propertyName>surefireArgLine</propertyName>
      </configuration>
    </execution>
    <execution>
      <id>prepare-it-agent</id>
      <phase>pre-integration-test</phase>
      <goals>
        <goal>prepare-agent</goal>
      </goals>
      <configuration>
        <destFile>${session.executionRootDirectory}/target/jacoco-it.exec</destFile>
        <append>true</append>
        <propertyName>failsafeArgLine</propertyName>
      </configuration>
    </execution>
  </executions>
 </plugin>
The ${session.executionRootDirectory} property is the root of execution, when I build the entire project, it will point to the rootModule. So this is the best path to use, when you have multi-module with more than one level of nesting.

For the analysis, I need to point sonar to use that file when analyzing IT coverage. So I have to set the sonar.jacoco.itReportPath to that file. Unfortunately, this does not work with the session.executionRootDirectory property and I have to set the absolute path to the file manually. I do not recommend to specify the absolute path in the pom.xml as this path is specific to the build environment. So either set the path in Sonar or as System property of your build environment. I set it directly in the Sonar Project Settings (Java > Jacoco), for example /opt/buildroot/myProject/target/jacoco-it.exec. Now sonar will check that file for the IT coverage analysis of each module.



Tuesday, September 23, 2014

Rasterizing scalable images during build


In most web projects your content does not only include code, html or css but also images. Those images are typically delivered as non-scalable graphics to the clients (i.e. jpg, png, gif). But ususally those images are created from a scalable image that allows to "design" the actual image and produce versions of various sizes from the scalable image. The process of transforming a scalable graphic to a non-scalable graphic is called rasterization and fortunately the process can be automated when you're running your build with Maven.

The Batik Maven plugin allows you to convert your svg (Scalable Vector Graphics) images to non-scalable images, supported types are png, jpeg, tiff or pdf. The plugin can be added to your build lifecycle. The plugin documentation states that adding the following snippet to your pom.xml

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>batik-maven-plugin</artifactId>
  <version>1.0-beta-1</version>
  <executions>
    <execution>
      <goals>
        <goal>rasterize</goal>
      </goals>
    </execution>
  </executions>
</plugin>
Unfortunately that's not sufficient as not all dependencies seem to be satisfied. But the following snippet worked for me (see also https://jira.codehaus.org/browse/MOJO-1670 )

<build>
  <plugins>
    <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>batik-maven-plugin</artifactId>
      <version>1.0-beta-1</version>
      <executions>
        <execution>
          <goals>
            <goal>rasterize</goal>
          </goals>
        </execution>
      </executions>
      <dependencies>
        <dependency>
          <groupId>batik</groupId>
          <artifactId>batik-rasterizer</artifactId>
          <version>1.6</version>
        </dependency>
        <dependency>
          <groupId>org.axsl.org.w3c.dom.svg</groupId>
          <artifactId>svg-dom-java</artifactId>
          <version>1.1</version>
        </dependency>
        <dependency>
          <groupId>org.w3c.css</groupId>
          <artifactId>sac</artifactId>
          <version>1.3</version>
        </dependency>
      </dependencies>
      </plugin>
    </plugins>
</build>

With that snippet I could place my svg files into /src/main/svg and during the build those files are rasterized to png files in the /target/generated-resources/images (locations and type are default settings and can be configured). From now on it's quite easy to "compile" your images during the build and you never have to paint your images by pixel anymore.

If you're looking for a free and powerful SVG "editor", try Inkscape.


Monday, April 28, 2014

Configuring SLF4J with Log4J2 using Maven

In our current project we had to decide for a logging framework. As it apears to be a common standard to use the Simple Logging Facade for Java (SLF4J) on caller side, there were various options on the logging framework itself. In the end we decided to use Log4J 2 as logging framework, mainly for reasons of better performance in comparison to other frameworks (see The Logging Olympics).
The setup of this combination is fairly ease, and there are good examples how to add a SLF4J binding to your Maven project as in this good blog article. But as Log4J is rather new and no final release has been announced yet (current is release candidate 1), it's hard to find a definitive configuration example, so I decided to put down ours.

<properties>
  <slf4j.version>1.7.6</slf4j.version>
  <!-- current log4j 2 release -->
  <log4j.version>2.0-rc1</log4j.version> 
</properties>
...
<dependencies>
  <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>${slf4j.version}</version>
  </dependency>
  <!-- Binding for Log4J -->
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>${log4j.version}</version>
  </dependency>
  <!-- Log4j API and Core implementation required for binding -->
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>${log4j.version}</version>
  </dependency>
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>${log4j.version}</version>
  </dependency>
</dependencies> 

And a basic log4j configuration (located at your src/main/resources path) could look like this
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="OFF">
 <appenders>
  <Console name="Console" target="SYSTEM_OUT">
   <PatternLayout pattern="%d{HH:mm:ss} [%t] %-5level %logger{36} - %msg%n" />
  </Console>
 </appenders>
 <Loggers>
  <Logger name="yourLogger" level="debug" additivity="false">
   <AppenderRef ref="Console" />
  </Logger>
  <Root level="error">
   <AppenderRef ref="Console" />
  </Root>
 </Loggers>
</configuration>