Friday, May 8, 2015

Artifact life cycle through obsolescence and modernization

This is a short article that deals with artifact life cycle through obsolescence and modernization. It also gives some hints when designing artifacts to delay obsolescence and anticipate modernization.

Artifact life cycle

The following diagram illustrates the life cycle of any artifact:



Artifact life cycle starts with the implementation of a modern artifact.

But time goes on, and leads inevitably to a software erosion :
  • the artifact does not match technology standards,
  • users experience is degraded because of too old user interfaces,
  • huge technical debt, 
  • security vulnerabilities,
  • insufficient features,
  • high TCO

At this moment, there is 2 possible choices: modernize the artifact or build a new one that meet the standards and finally end the cycle with the process of decommissioning of the artifact.

Modernization will be realized through rewriting code, replacing frameworks, platforms and designing new architectures. It is preferable to automate the process of modernization.

Delay obsolescence

To prevent obsolescence to occur too soon, you can try to:
  • carefully build your software stack to rely on proven frameworks that will last for at least several years
  • set up a continuous inspection platform to measure the software code quality and keep a high maintainability of the source code
  • rely on an efficient software factory to build, assemble and deploy. That way, it is easy to evolve and maintain your artifacts.
  • standardize your practices and architecture choices to avoid the maintenance of a too heterogeneous set of technologies across your artifcats. 

Anticipate modernization

To simplify the process of modernization, you can:
    • favor simple design to ease the reverse engineering activity when modernization team works on artifacts
    • design by abstraction to easily replace one specific part, without rewriting the whole artifact
    • abuse of automated tests to lower the cost of testing changes induced by modernization and spot with ease any regression that modernization could introduce
    • choose frameworks that can be evolved easily

    Sunday, February 23, 2014

    JBoss monitoring with Twiddle


    This short article introduces twiddle, a command line utility to administer a JBoss instance and shows how you can monitor a given instance of JBoss with it through a shell script.

    JBoss provides a simple command line tool that allows for interaction with a remote JMX server instance. This tool is called twiddle (for twiddling bits via JMX) and is located in the bin directory of the distribution. Twiddle is a command execution tool, not a general command shell.

    The 2 following links show basic usage of twiddle:


    All available metrics can be found using the jmx-console deployed by the JBoss instance.

    Next, here is a simple shell script that automate the collect of JBoss metrics (free & total memories, active threads count and active sessions count):

    #!/bin/sh
    
    # path to the log file (the directory /var/log/jboss must exist. Adapt this path to reflect your needs)
    LOGFILE=/var/log/jboss/jbossmon-`hostname`-`date +"%Y%m%d"`.log
    echo Logging JBoss metrics to $LOGFILE
    
    # function that uses twiddle to get jboss metrics, given:
    #  a first parameter that is the path to the MBean
    #  a second parameter that is the name of the attribute of the MBean
    # Notice that you may need to adapt the call to twiddle to use authentication or a dedicated port
    # e.g: ./twiddle.sh -u user -p password -s jnp://localhost:9099
    # Also update the path to the twiddle.sh, if this script is not saved in the same directory, i.e the bin directory of the JBoss distribution
    function getJbossMetric() {
     ./twiddle.sh get $1 $2 | cut -d'=' -f2
    }
    
    # collects metrics every 5 mn forever (naive approach)
    # Notice that a better way would be to replace the loop by a scheduler like cron
    until false 
    do
     # collects some metrics within JBoss using twiddle
     FREEMEM=$(getJbossMetric jboss.system:type=ServerInfo FreeMemory)
     TOTALMEM=$(getJbossMetric jboss.system:type=ServerInfo TotalMemory)
     THREADS=$(getJbossMetric jboss.system:type=ServerInfo ActiveThreadCount)
     # NB: you need to update the path property to reflect the context path of your web application
     SESSIONS=$(getJbossMetric jboss.web:host=localhost,path=/contextPathOfMyWebApp,type=Manager activeSessions)
    
     echo "-------------------------------------"
     echo "Free memory:    $FREEMEM"
     echo "Total memory:   $TOTALMEM"
     echo "Active Threads: $THREADS"
     echo "Sessions:       $SESSIONS"
     echo "-------------------------------------"
     
     # append metrics to the log file in a CSV manner
     TIMESTAMP=`date +"%d/%m/%Y %T"`
     echo "$TIMESTAMP;$TOTALMEM;$FREEMEM;$SESSIONS;$THREADS" >> $LOGFILE
    
     # waits for 300s (5mn)
     sleep 300
    done
    
    I hope this will be useful to those who want to monitor JBoss in a simple way.

    Monday, July 29, 2013

    Compute Java Object Memory Footprint at runtime with JAMM (Java Agent for Memory Measurements)

    This short article shows how to measure java object memory size at runtime with JAMM, a java agent dedicated to measure actual object memory use including JVM overhead.

    JAMM uses the Instrumentation implementation provided by the JVM to compute memory usage of a given object by calling the getObjectSize(..) method.

    It is quite simple to use, as explained by the author:

    MemoryMeter meter = new MemoryMeter();
    meter.measure(object);
    meter.measureDeep(object);
    meter.countChildren(object);
    

    The only constraint is to attach JAMM java agent to the JVM before using it to measure memory usage, by starting the JVM with the -javaagent option pointing to the JAMM jar.

    So, we are going to write a JUnit that shows how to use JAMM, but before we need to setup maven to achieve this:
        
            
                junit
                junit
                4.11
                test
            
        
            
            
                com.github.stephenc
                jamm
                0.2.5
                test
            
                
        
        
        
            
                
                
                
                    org.apache.maven.plugins
                    maven-dependency-plugin
                    2.8
                    
                        
                            copy-dependencies
                            generate-test-resources
                            
                                copy
                            
                            
                                
                                    
                                        com.github.stephenc
                                        jamm
                                        0.2.5
                                        jar
                                        ${project.build.directory}
                                        jamm.jar
                                    
                                
                            
                        
                    
                
                
                
                
                    org.apache.maven.plugins
                    maven-surefire-plugin
                    2.14
                    
                        -javaagent:${project.build.directory}/jamm.jar
                    
                
                
            
        
    

    Next, write the following JUnit that explores the JAMM features:
    package org.javabenchmark.memory;
    
    import java.util.ArrayList;
    import java.util.List;
    import org.github.jamm.MemoryMeter;
    import org.junit.Test;
    
    public class MemoryMeterTest {
    
        private MemoryMeter meter = new MemoryMeter();
        
        @Test
        public void shouldMeasureMemoryUsage() {
    
            String st1 = "This is the string #1";
            measure(st1);
            
            String st2 = "This is the string #2 and it has more chars.";
            measure(st2);
            
            List aList = new ArrayList(0);
            measure(aList);
            
            aList.add(st1);
            measure(aList);
            
            aList.add(st2);
            measure(aList);
            
        }
    
        private void measure(Object anObject) {
            
            System.out.println("-----------------------------------");
            System.out.printf("size: %d bytes\n", meter.measure(anObject));
            System.out.printf("retained size: %d bytes\n", meter.measureDeep(anObject));
            System.out.printf("inner object count: %d\n", meter.countChildren(anObject));
        }
    }
    

    Running the test produces the following output on my computer:
    -----------------------------------
    size: 24 bytes
    retained size: 88 bytes
    inner object count: 2
    -----------------------------------
    size: 24 bytes
    retained size: 128 bytes
    inner object count: 2
    -----------------------------------
    size: 24 bytes
    retained size: 40 bytes
    inner object count: 2
    -----------------------------------
    size: 24 bytes
    retained size: 136 bytes
    inner object count: 4
    -----------------------------------
    size: 24 bytes
    retained size: 264 bytes
    inner object count: 6
    
    To conclude, you can see how it is easy to monitor the memory usage of your objects. It is very handy when dealing with huge collections, or when using caches such as the ones provided by Guava or EHCache. That way you can setup trigger that alert when memory consumption is excessive.


    UPDATE: 2013-07-30

    To answer to the rxin's comment, i did a quick (trivial) test with a list of 1,000,000 random strings, that represents 116 Mo in memory.

    For the test, i sized the heap with the following JVM options: -Xms256m -Xmx256m.

    Below is the memory usage during the test:


    From my point of view, the memory overhead introduced by JAMM is negligible in that simple test case, but notice that the measureDeep() method takes time (reflection is slow).


     
      

    Sunday, May 19, 2013

    Monitoring Memory Usage inside a Java Web Application with JSF, PrimeFaces and MemoryMXBean

    This article explains how to monitor memory usage in your web application by requesting the MemoryMXBean and exposing collected metrics within a Primefaces LineChart component in a JSF page.

    Principle

    The monitoring of the memory usage involves:

    The overall design is illustrated below:



    1. The LineChart component calls every minute the MonitorController instance.
    2. The MonitorController instance requests the MemoryMXBean instance to get the current memory usage.
    3. The MonitorController instance updates a CartesianChartModel instance by adding a memory usage snapshot.
    4. The CartesianChartModel instance is returned to the LineChart component that renders it inside a JSF page.

    PrimeFaces LineChart

    To enable PrimeFaces components into your web application, update your maven pom.xml with the following repository and dependency:
        
            
                primefaces-maven-repo
                PrimeFaces Maven Repository
                http://repository.primefaces.org
                default
            
        
    
            
                org.primefaces
                primefaces
                3.4.2
            
    
    Next, inside a JSF page, add the following code to display the LineChart and make it polling the MonitorController every minute:
    <html xmlns="http://www.w3.org/1999/xhtml"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:p="http://primefaces.org/ui"
          xmlns:c="http://java.sun.com/jsp/jstl/core"
          xmlns:ui="http://java.sun.com/jsf/facelets">
    
        <h:head>
           ...
        </h:head>
    
        <h:body>
           ...
                    <h:form id="form">  
    
                        <!-- polls every minute -->
                        <p:poll interval="60" update="memoryChart" />  
    
                        <!-- memory line chart -->
                        <p:lineChart id="memoryChart" value="#{monitorController.memoryModel}"
                                     legendPosition="ne" title="Memory Usage" style="height:300px;margin-top:20px"
                                     xaxisLabel="Minutes" yaxisLabel="Bytes" zoom="true"/>  
    
                    </h:form>  
           ...
    
        </h:body>
    </html>
    


    MonitorController

    The code corresponding to the monitor controller class is:
    package org.javabenchmark;
    
    import java.io.Serializable;
    import java.lang.management.ManagementFactory;
    import java.lang.management.MemoryMXBean;
    import java.lang.management.MemoryUsage;
    import javax.faces.bean.ManagedBean;
    import javax.faces.bean.SessionScoped;
    import org.primefaces.model.chart.CartesianChartModel;
    import org.primefaces.model.chart.ChartSeries;
    import org.slf4j.LoggerFactory;
    
    /**
     * JSF Managed Bean to get JVM memory usage.
     *
     */
    @ManagedBean
    @SessionScoped
    public class MonitorController implements Serializable {
    
        /**
         * memory model.
         */
        private CartesianChartModel memoryModel;
        /**
         * memory usage series.
         */
        private ChartSeries memoryUsageSerie, maxMemorySerie;
        /**
         * elapsed time in minutes since the monitoring starts
         */
        private long elapsedTime = -1;
    
        /**
         * instantiates a new monitoring controller.
         */
        public MonitorController() {
            
            createMemoryModel();
        }
        
        /**
         * initializes memory usage model.
         */
        private void createMemoryModel() {  
            // model
            memoryModel = new CartesianChartModel(); 
            // heap serie
            memoryUsageSerie = new ChartSeries();  
            memoryUsageSerie.setLabel("Heap");
            memoryModel.addSeries(memoryUsageSerie);
            // max serie
            maxMemorySerie = new ChartSeries();  
            maxMemorySerie.setLabel("Max");
            memoryModel.addSeries(maxMemorySerie); 
        }
        
        /**
         * gets the memory model that will be rendered within a LineChart
         * component. The LineChart component should call this method every minute.
         * @return the updated memory model
         */
        public CartesianChartModel getMemoryModel() {  
            
            // gets data
            MemoryMXBean memoryMxBean = ManagementFactory.getMemoryMXBean();
            MemoryUsage memoryUsage = memoryMxBean.getHeapMemoryUsage();
            
            // one more minute
            elapsedTime++;
            
            // updates series
            memoryUsageSerie.set(elapsedTime, memoryUsage.getUsed());
            maxMemorySerie.set(elapsedTime, memoryUsage.getMax()); 
            
            return memoryModel;  
        }
    }
    


    Screenshot

    Finally, a screenshot of the PrimeFaces line chart representing the memory usage :


    Notice that it is possible to zoom with drag and drop, if you have a lot of points displayed.

    Conclusion

    As you can see, it is quite easy to monitor the JVM and to display collected metrics within a JSF page. You can go further by monitoring CPU usage for instance, or by adding some features like starting/stopping/resetting the monitoring.

    Sunday, May 5, 2013

    Java instrumentation tutorial

    This article explains how Java instrumentation works, and how you can write your own agent to do some basic profiling/tracing.

    Overview

    JVM instrumentation feature was introduced in JDK 1.5 and is based on byte code instrumentation (BCI). Actually, when a class is loaded, you can alter the corresponding byte code to introduce features such as methods execution profiling or event tracing. Most of Java Application Performance Management (APM) solutions use this mechanism to monitor JVM.

    Instrumentation Agent

    To enable JVM instrumentation,  you have to provide an agent (or more) that is deployed as a JAR file. An attribute in the JAR file manifest specifies the agent class which will be loaded to start the agent.

    There is 2 ways to load the agent:
    • with a command-line interfaceby adding this option to the command-line: -javaagent:jarpath[=options] where jarpath is the path to the agent JAR file. options is the agent options. This switch may be used multiple times on the same command-line, thus creating multiple agents. More than one agent may use the same jarpath.
    • by dynamic loading: the JVM must implement a mechanism to start agents sometime after the the VM has started. That way, a tool can "attach" an agent to a running JVM (for instance profilers or ByteMan)


    After the JVM has initializedthe agent class will be loaded by the system class loader. If the class loader fails to load the agent, the JVM will abort.



    Next, the JVM instantiates an Instrumentation interface implementation and given the context, tries to invoke one of the two methods that an agent must implement: premain or agentmain.

    The premain method is invoked after JVM initialization and the agentmain method is invoked sometime after the JVM has started (if the JVM provides such a mechanism). When the agent is started using a command-line option (with -javaagent), the agentmain method is not invokedThe agent class may also have a premain method for use when the agent is started using a command-line option. When the agent is started after JVM startup the premain method is not invoked.




    The signatures of the premain method are:
    public static void premain(String agentArgs, Instrumentation inst);
    public static void premain(String agentArgs);

    And the signatures of the agentmain method are:
    public static void agentmain(String agentArgs, Instrumentation inst);
    public static void agentmain(String agentArgs);
    
    The agent needs to implement only one signature per method.  The JVM first attempts to invoke the first signature, and if the agent class does not implement it then the JVM will attempt to invoke the second signature.

    Byte Code Instrumentation

    With the premain and agentmain methods, the agent can register a ClassFileTransformer instance by providing an implementation of this interface in order to transform class files. To register the transformer, the agent can use the addTransformer method of the given Instrumentation instance.


    Now, all future class definitions will be seen by the transformer, except definitions of classes upon which any registered transformer is dependent. The transformer is called when classes are loaded, when they are redefined. and optionally, when they are retransformed (if the transformer was added to the instrumentation instance with the boolean canRetransform set to true).

    The following method of the ClassFileTransformer interface is responsible of any class file transformation:
    byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
                     ProtectionDomain protectionDomain, byte[] classfileBuffer);

    This is where things get complicated because you need to manipulate raw byte code. To achieve this, i strongly suggest to rely on dedicated tools such as ASM or Javassist.

    Basic Profiling

    To illustrate how the class file transformer can be used, we are going to set up some basic method profiling with Javassist:
    1. Write a trivial class that will be instrumented
    2. Write a ClassFileTransformer to inject some code to print method execution time
    3. Write an agent that registers the previous transformer
    4. Write the corresponding JUnit test
    The class to be instrumented is:
    package org.javabenchmark.instrumentation;
    
    public class Sleeping {
        
        public void randomSleep() throws InterruptedException {
            
            // randomly sleeps between 500ms and 1200s
            long randomSleepDuration = (long) (500 + Math.random() * 700);
            System.out.printf("Sleeping for %d ms ..\n", randomSleepDuration);
            Thread.sleep(randomSleepDuration);
        }
    }

    The transformer class is:
    package org.javabenchmark.instrumentation;
    
    import java.lang.instrument.ClassFileTransformer;
    import java.lang.instrument.IllegalClassFormatException;
    import java.security.ProtectionDomain;
    import javassist.ClassPool;
    import javassist.CtClass;
    import javassist.CtMethod;
    
    public class SleepingClassFileTransformer implements ClassFileTransformer {
    
        public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined,
            ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
    
            byte[] byteCode = classfileBuffer;
    
            if (className.equals("org/javabenchmark/instrumentation/Sleeping")) {
    
                try {
                    ClassPool cp = ClassPool.getDefault();
                    CtClass cc = cp.get("org.javabenchmark.instrumentation.Sleeping");
                    CtMethod m = cc.getDeclaredMethod("randomSleep");
                    m.addLocalVariable("elapsedTime", CtClass.longType);
                    m.insertBefore("elapsedTime = System.currentTimeMillis();");
                    m.insertAfter("{elapsedTime = System.currentTimeMillis() - elapsedTime;"
                            + "System.out.println(\"Method Executed in ms: \" + elapsedTime);}");
                    byteCode = cc.toBytecode();
                    cc.detach();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
    
            return byteCode;
        }
    }
    

    The transformer checks if the class to transform is the Sleeping one, then it injects the code that prints the time elapsed by the execution of the randomSleep() method.

    The agent class is:
    package org.javabenchmark.instrumentation;
    
    import java.lang.instrument.Instrumentation;
    
    public class Agent {
    
        public static void premain(String agentArgs, Instrumentation inst) {
            
            // registers the transformer
            inst.addTransformer(new SleepingClassFileTransformer());
        }
    }
    
    And finally, the corresponding JUnit code:
    package org.javabenchmark.instrumentation;
    
    import org.junit.Test;
    
    public class AgentTest {
    
        @Test
        public void shouldInstantiateSleepingInstance() throws InterruptedException {
    
            Sleeping sleeping = new Sleeping();
            sleeping.randomSleep();
        }
    }
    But, before executing the test you need to setup Maven to enable the JVM agent:
    • build the JAR that contains the agent's code before running test
    • add the JVM option -javagent to the JVM that runs the test
    • add the Javassist dependency
    To achieve this, add the following XML code to your pom.xml file, inside the <build><plugins> ... </plugins></build> section:
                
                
                    org.apache.maven.plugins
                    maven-jar-plugin
                    2.4
                    
                        
                            process-classes
                            
                                jar
                            
                            
                                
                                    
                                        org.javabenchmark.instrumentation.Agent
                                    
                                
                            
                        
                    
                
    
                
                
                    org.apache.maven.plugins
                    maven-surefire-plugin
                    2.14
                    
                        -javaagent:target/${project.build.finalName}.jar
                    
                
    Next, add the Javassist dependency:
            
                org.javassist
                javassist
                3.14.0-GA
                jar
            
    

    Then, running the test should produce something like this:
    -------------------------------------------------------
     T E S T S
    -------------------------------------------------------
    Running org.javabenchmark.instrumentation.AgentTest
    Sleeping for 818 ms ..
    Method Executed in ms: 820
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.001 sec
    
    You can see that there is a new trace: Method Executed in ms: 820 proving that instrumentation works. Without instrumentation, you would only have the Sleeping for 818 ms .. trace.

    Conclusion

    It is easy to profile your code with the instrumentation API and the Javassist API: write transformers with Javassist, write an agent to register them, then use the -javaagent option and you're done !

    Sunday, April 21, 2013

    Fault injection in your JUnit with ByteMan

    This article shows how to use ByteMan from JBoss to inject fault when testing Java code.

    As usual, let us start with some trivial code to test: a simple class that appends strings to a given file.
    package org.javabenchmark.byteman;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    
    /**
     * Logging helper class.
     *
     */
    public class LogHelper {
    
        public static final String LOG_FILE_PROPERTY = "logHelperFile";
        public static final String DEFAULT_LOG_FILE = "sample.log";
        private static final File LOG_FILE = new File(System.getProperty(LOG_FILE_PROPERTY, DEFAULT_LOG_FILE));
    
        /**
         * logs the given trace to a dedicated file.
         *
         * @param trace a string to be written into the log file.
         */
        public static void log(String trace) {
    
            try {
                FileOutputStream fos = new FileOutputStream(LOG_FILE, true);
                fos.write(trace.getBytes());
                fos.write('\n');
                fos.flush();
                fos.close();
            } catch (IOException ex) {
                final String msg = "Log Helper can't write trace to the log file: " + LOG_FILE.getAbsolutePath();
                System.err.println(msg);
            }
        }
    }
    
    

    The next step is to write the corresponding test:
    package org.javabenchmark.byteman;
    
    import java.io.File;
    import static org.fest.assertions.api.Assertions.*;
    import org.jboss.byteman.contrib.bmunit.BMRule;
    import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    
    /**
     * Unit Test dedicated to LogHelper.
     */
    public class LogHelperTest {
    
        private static final String SUCCESSFULL_TEST_LABEL = "Successfull Test";
    
        private void deleteFile(File file) {
            // clean
            file.delete();
            assertThat(file).doesNotExist();
        }
        
        @Test
        public void shouldLog() {
    
            File logFile = new File(LogHelper.DEFAULT_LOG_FILE);
    
            // clean
            deleteFile(logFile);
    
            // one line test
            LogHelper.log(SUCCESSFULL_TEST_LABEL);
    
            // control
            assertThat(logFile).exists();
            assertThat(logFile).hasContent(SUCCESSFULL_TEST_LABEL);
    
            // several lines test
            LogHelper.log(SUCCESSFULL_TEST_LABEL);
            LogHelper.log(SUCCESSFULL_TEST_LABEL);
    
            // control
            assertThat(logFile).hasContent(SUCCESSFULL_TEST_LABEL + '\n' + SUCCESSFULL_TEST_LABEL + '\n' + SUCCESSFULL_TEST_LABEL);
            deleteFile(logFile);
        }
    }
    

    Running the test produces the following output:
    Testsuite: org.javabenchmark.byteman.LogHelperTest
    Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.136 sec
    

    And if you enable code coverage in your favorite IDE, you should have something like this:

    Red regions show us parts of the code that are not covered by the test. In our case, we can see that the code that handles IO exception is never invoked. Then, it is not possible to cover all the code of the method without raising an IOException. Hopefully, there is a powerful tool for this: ByteMan.

    As explained by the authors:
    Byteman is a tool which simplifies tracing and testing of Java programs. Byteman allows you to insert extra Java code into your application, either as it is loaded during JVM startup or even after it has already started running.

    Actually, ByteMan is a java agent that does instrumentation and we are going to use it to inject IO exception during the execution of our test to check the code that deals with it. The idea is to throw an IOException when the method FileOutputStream.write(byte[]) is called.

    Firstly, the dependency for ByteMan:
    
      org.jboss.byteman
      byteman-bmunit
      2.1.2
    
    

    Secondly, modify the previous test to add ByteMan to our JUnit and write a new method to test the code that handles IOException:
    package org.javabenchmark.byteman;
    
    import java.io.File;
    import static org.fest.assertions.api.Assertions.*;
    import org.jboss.byteman.contrib.bmunit.BMRule;
    import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    
    /**
     * Unit Test dedicated to LogHelper.
     */
    @RunWith(BMUnitRunner.class)
    public class LogHelperTest {
    
        private static final String SUCCESSFULL_TEST_LABEL = "Successfull Test";
    
        private void deleteFile(File file) {
            // ...
        }
        
        @Test
        public void shouldLog() {
            // ...
        }
    
        @Test
        @BMRule(name = "IOException Rule",
                targetClass = "FileOutputStream",
                targetMethod = "write(byte[])",
                targetLocation = "AT ENTRY",
                condition = "TRUE",
                action = "throw new java.io.IOException()")
        public void shouldHandleIOException() {
            
            File logFile = new File(LogHelper.DEFAULT_LOG_FILE);
    
            // clean
            deleteFile(logFile);
    
            // one line test that should raise an io exception
            LogHelper.log(SUCCESSFULL_TEST_LABEL);
            
            // control
            assertThat(logFile).exists();
            assertThat(logFile).hasContent("");
            
            // clean
            deleteFile(logFile);
        }
    }
    
    

    The BMRule annotation defines the execution context for ByteMan:
    • name: to set the name of the rule
    • targetClass and targetMethod: to set the method that must be instrumented
    • targetLocation: to set when to inject  the code (at the beginning, at the end or somewhere in the body of the method)
    • condition: to set some condition to be met
    • action: the code to be injected
    So, we have a rule named "IOException Rule" that is activated when the method write(byte[]) of the FileOutputStream class begins. The rule then injects a given code that throws an IOException. When the shouldHandleIOException test runs, every time that write(byte[]) is called then a java.io.IOException is raised.

    Now, running all tests produces:
    Testsuite: org.javabenchmark.byteman.LogHelperTest
    byteman jar is /home/javabenchmark/.m2/repository/org/jboss/byteman/byteman/2.1.2/byteman-2.1.2.jar
    Log Helper can't write trace to the log file: /home/javabenchmark/Documents/projects/javabenchmark/sample.log
    Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 0.534 sec
    

    And the code coverage looks like this:

    The log(String) method is now fully covered (the implicit constructor of the LogHelper class is not tested, explaining the missing percents to reach 100%).

    Conclusion

    ByteMan is very useful to test code that deals with Exception, especially fault tolerant one. That way, you can check that your fault tolerance strategy is really resilient, or that your code gives you relevant traces when errors occur.

    Thursday, April 11, 2013

    Check that your code is thread-safe with JUnit and ContiPerf

    This short article shows how to check that you write thread-safe code by transforming a JUnit test into a concurrent one with ContiPerf.

    Suppose that you have to test a date formatter component that uses the famous SimpleDateFormat class, as illustrated below:
    package org.javabenchmark;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    /**
     * Helper dedicated to format date in a standard way.
     */
    public class NonThreadSafeDateFormatHelper {
    
        /**
         * the date format for standard representation.
         */
        private SimpleDateFormat standardDateFormat = new SimpleDateFormat("yyyy-MM-dd");
    
        /**
         * formats the given date using the standard date format: yyyy-MM-dd.
         *
         * @param date the date to format
         * @return a literal representation of the given date.
         */
        public String toStandardString(Date date) {
            return standardDateFormat.format(date);
        }
    }
    

    Then, you could write a junit test like this:
    package org.javabenchmark;
    
    import org.junit.Test;
    
    import java.util.Calendar;
    
    import static org.fest.assertions.api.Assertions.*;
    
    public class NonThreadSafeDateFormatHelperTest {
    
        @Test
        public void shouldFormatRandomDate() {
    
            // random date
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.YEAR, (int) (1000 + Math.random() * 1000));
            calendar.set(Calendar.DAY_OF_YEAR, (int) (Math.random() * 365));
    
            // test
            NonThreadSafeDateFormatHelper dateFormatHelperToTest = new NonThreadSafeDateFormatHelper();
            String randomDateString = dateFormatHelperToTest.toStandardString(calendar.getTime());
    
            // general controls
            assertThat(randomDateString).isNotNull();
            assertThat(randomDateString).hasSize(10);
            // year control
            String literalYear = String.valueOf(calendar.get(Calendar.YEAR));
            assertThat(literalYear).isEqualTo(randomDateString.substring(0, 4));
            // month control
            String literalMonth = String.valueOf(calendar.get(Calendar.MONTH) + 1);
            if (literalMonth.length() == 1) {
                literalMonth = "0" + literalMonth;
            }
            assertThat(literalMonth).isEqualTo(randomDateString.substring(5, 7));
            // day control
            String literalDayh = String.valueOf(calendar.get(Calendar.DAY_OF_MONTH));
            if (literalDayh.length() == 1) {
                literalDayh = "0" + literalDayh;
            }
            assertThat(literalDayh).isEqualTo(randomDateString.substring(8));
        }
    }
    

    Next, running the test will produce the following output:
    Testsuite: org.javabenchmark.NonThreadSafeDateFormatHelperTest
    Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.173 sec

    The test passes, and you could think that everything is fine, but what will happen if the DateFormatHelper class is used in a concurrent way, for instance from a JSF page to display the current date ?

    To check that your code can handle concurrency, you can modify the previous JUnit test like this:
    package org.javabenchmark;
    
    import org.junit.Rule;
    import org.junit.Test;
    
    import java.text.ParseException;
    import java.util.Calendar;
    import org.databene.contiperf.PerfTest;
    import org.databene.contiperf.junit.ContiPerfRule;
    
    import static org.fest.assertions.api.Assertions.assertThat;
    
    public class NonThreadSafeDateFormatHelperPerfTest {
    
        @Rule
        public ContiPerfRule i = new ContiPerfRule();
        /**
         * the date format helper to test.
         */
        private NonThreadSafeDateFormatHelper dateFormatHelperToTest = new NonThreadSafeDateFormatHelper();
    
        @Test
        @PerfTest(invocations = 1000, threads = 2)
        public void shouldFormatRandomDatesConcurrently() throws ParseException {
    
            // random date
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.YEAR, (int) (1000 + Math.random() * 1013));
            calendar.set(Calendar.DAY_OF_YEAR, (int) (Math.random() * 365));
            
            // test
            String randomDateString = dateFormatHelperToTest.toStandardString(calendar.getTime());
    
            // general controls
            assertThat(randomDateString).isNotNull();
            assertThat(randomDateString).hasSize(10);
            // year control
            String literalYear = String.valueOf(calendar.get(Calendar.YEAR));
            assertThat(literalYear).isEqualTo(randomDateString.substring(0, 4));
            // month control
            String literalMonth = String.valueOf(calendar.get(Calendar.MONTH) + 1);
            if (literalMonth.length() == 1) {
                literalMonth = "0" + literalMonth;
            }
            assertThat(literalMonth).isEqualTo(randomDateString.substring(5, 7));
            // day control
            String literalDayh = String.valueOf(calendar.get(Calendar.DAY_OF_MONTH));
            if (literalDayh.length() == 1) {
                literalDayh = "0" + literalDayh;
            }
            assertThat(literalDayh).isEqualTo(randomDateString.substring(8));
        }
    }
    

    This is the same test, except that the test method is invoked 1000 times by 2 threads, producing this output:
    Testsuite: org.javabenchmark.NonThreadSafeDateFormatHelperPerfTest
    org.javabenchmark.NonThreadSafeDateFormatHelperPerfTest.shouldFormatRandomDatesConcurrently
    samples: 999
    max:     19
    average: 0.04804804804804805
    median:  0
    Tests run: 1, Failures: 0, Errors: 1, Time elapsed: 0.377 sec
    
    So, there is now an error, indicating that the DateFormatHelper component is not thread-safe: do not let it go into production :)

    Summary

    Good unit tests are not sufficient when you are writing components that will evolve in multi-threaded environment, like web applications. You can easily check if your code is vulnerable to race condition with contiperf.