Chapter 48. ProActive Test Suite API

This tour is a practical introduction to create, run and manage tests or benchmarks.

First you will get an API's description with its features.

Second, you will be guided through some examples of tests and benchmarks.

48.1. Structure of the API

48.1.1. Goals of the API

  • Benchmarks on ProActive

  • Functional Tests framework

  • Interlinked Tests

  • Automatic results generation

48.1.2. Functional Tests & Benchmarks

48.1.2.1. Test definition

A Test runs successfully of:

  • Its Pre-Conditions are verified

  • Its action method runs with no Java Exception

  • Its Post-Conditions are also verified

48.1.2.2. Benchmark definition

Benchmark is a Test, its result is a time.

48.1.2.3. Interlinked Functional Tests

First, we specify parents Tests.

To do this, just overload Action method with needed inputs and outputs, after, with the Java reflection mechanism we found the first good Action method to execute the Test.

Mechanism in details

In standalone mode the test runs with this method:

 void action() throws Exception;  

In interlinked mode, the developer must to add a similar method in his code Test:

  A action(B toto, C tutu, …) throws Exception; 

Where toto is the result output of the first parent of this test and tutu the result output of second parent, … A is the type of result output of this Test.

Reflection code

Find the first action method:

 Method[] methods = getClass().getMethods();
            Method actionWithParams = null;
            for (int i = 0; i < methods.length; i++) {
                if ((methods[i].getName().compareTo('action') == 0) &&
                        (methods[i].getReturnType().getName().compareTo('void') != 0)) {
                    actionWithParams = methods[i];
                    break;
                }
            }

Array of params type:

            if (actionWithParams != null) {
                Object[] args = null;
                if (tests != null) {
                    args = new Object[tests.length];
                    for (int i = 0; i < tests.length; i++)
                        args[i] = tests[i].getOut();
                } else {
                    args = new Object[1];
                    args[0] = null;
                }

Call the method:

 out = actionWithParams.invoke(this, args); 

48.1.3. Group

What is a Group of Tests?

  • Collection of Tests

What is the role of a Group?

  • Initialise and cleanup all Tests

  • Collect Results

  • Add, remove, … Tests like a Java Collection

48.1.4. Manager

What is a Manager in Testsuite API?

  • Collection of Groups

What is the role of a Manager?

  • Initialise and launch all Tests

  • Collect and format Results

We have different types of Manager to better manage of specialised Tests or Benchmarks:

  • BenchmarkManager

  • ProActiveBenchManager

  • FunctionalTestManager

  • ProActiveFuncTestManager

48.2. Timer for the Benchmarks

In this API, it is the benchmark programmer who make the measure, he can simply use: System.currentTimeMillis() of Java. This method is in the wrong !

If you want to change the method to make measure you must to modify the code of all your Benchmarks.

48.2.1. The solution

To solve this problem, we have chosen an interface: Timeable

package testsuite.timer;
public interface Timeable {
    // Start the timer
    public void start();
    // Stop the timer
    public void stop();
    // Get the total time, measured
    public long getCumulatedTime();
    // To print the time unit
    public String getUnit();
}

By default the API provides two timer which of implement this interface:

To make measure in milliseconds: testsuite.timer.ms.MsTimer

To make measure in microseconds: testsuite.timer.micro.MicroTimer

By implementing the interface you can easily create new timer for more performents for you needs.

48.2.2. How to use Timer in Benchmarck?

Use this.timer like this:

public long action() throws Exception {
        String className = ReifiableObject.class.getName();
        Node node = getNode();
        this.timer.start();
        object = (ReifiableObject) ProActive.newActive(className, null, node);
        this.timer.stop();
        return this.timer.getCumulatedTime();
    }

48.2.3. How to configure the Manager with your Timer?

By a prop file or a XML file:

        <prop key="Timer" value="testsuite.timer.micro.MicroTimer"/>
        Timer=testsuite.timer.micro.MicroTimer

Or by the code:

yourManager.setTimer('class.name.YourTimer');

48.3. Results

This section describes, how to format the Results of the tests.

48.3.1. What is a Result?

In this API, the result concept is two things:

  • A real result: the test successes or fails, the benchmark runs in 2.0ms

  • Like a logger to log error, message, ...

48.3.2. What we don't use a real logger API?

The problem with a real logger (like log4J) is we don't have the notion of results.

In the TestSuite APi we decide to split logs of the program and results.

48.3.3. Structure of Results classes in TestSuite

There is a super-class abstract: AbstractResult where there is the bare essentials to specify a Result:

  • The type of the result, in order of increase importance:

    • INFO: an information message to debug

    • MSG: a message to debbug

    • RESULT: a none important result, typically a middle result

    • IMP_MSG: an important message

    • GLOBAL_RESULT: an important result, typically a group result

    • ERROR: typically an error in out Test method, for example: can't init a group

  • A message to describe the result

  • An exception to show the stack trace of an error

  • Time of creation of the result

There are two classes which implements this abstract class:

  • AbstractResult is only abstract to make generic formating, so TestResult can print itself like a Java String and a XML node.

  • BenchmarkResult add a time result to print.

48.3.4. How to export results

In TestSuite API, the results are stocked in ResultsCollection, there are two classes who contains a ResultCollection:

  • Manager

  • Group

These classes implements the ResultsExporter interface. After the execution of your Manager you can choose where and how to print results:

 yourManager.toXXX();  

Where toXXX() is:

  • String toString(): return all results, if yourManager.setVerbatim(true), as a String else only results who the level >= IMP_MSG

  • void toPrintWriter(PrintWriter out): return all results, if yourManager.setVerbatim(true), in out else only results who the level >= IMP_MSG

  • void toOutPutStream(OutputStream out): return all results, if yourManager.setVerbatim(true), in out else only results who the level >= IM_MSG

  • Document toXML(): return all results, in a DOM tree, it is useful to transform, to format, to operate, ... results like you want.

  • void toHTML(File location): return all results, in location file like an HTML document. To do this the API export the results in a DOM tree, with the precedent method, and transform the XML with XSLT into a HTML file.

48.3.4.1. About the Manager Verbatim option

In Manager you can modify this by:

yourManager.setVerbatim(true/false)  

If Verbatim value is:

  • true: All results types could be show.

  • false: Only results with a level >= IMP_MSG could be show. In concrete terms, on your output you have only the messages from the Manager, final result of group and th errors.

By default Verbatim is at false

This option has no effect on XML and HTML exports.

To see the value of Verbatim:

  yourManager.isVerbatim() 

48.3.4.2. By the file configurator

See Section 48.5, “Configuration File” for more detail to configure result output through the file descriptor.

48.3.5. Format Results like you want

If you export your results in a XML DOM tree, with toXML() method, you can use XSLT to create new formats.

48.4. Logs

TestSuite API offers to tests developers a log system, to tace or debug their tests.

48.4.1. Which logger?

As in ProActive API we choose Jakarta Log4J like logger.

48.4.2. How it works in TestSuite API?

A static logger is create in Manager, all Groups and Tests who are added in the Manager have a reference to this logger.

By default all logs are written in a simple text file: $HOME/tests.log

With this file, it very easy to debug your test. You can also, with Log4J, specify a different place and different format for your logs. For more details see the next part.

48.4.3. How to use it?

48.4.3.1. Log your code

To add logs in your Test code it is very easy: you can directly use the variable logger or the getter getLogger(). This is a org.apache.log4j.Logger

In your Test code just add logs like this:

if (logger.isDebugEnabled())
     logger.debug('A debug message ...');

For more information about use logger see the log4J manual.

48.4.3.2. Configure the logger

By default all logs with a level higher than INFO are written in $HOME/tests.log.

But you can configure the format and plac where you want to get logs.

The log4j environment is fully configurable programmatically. However, it is far more flexible to configure log4j using configuration files. Currently, configuration files can be written in XML or in Java properties (key=value) format.

You can also configure the logger by the Section 48.5, “Configuration File”.

Use default configuration of log4J. Add this code Manager constructor:

// Set up a simple configuration that logs on the console.
 BasicConfigurator.configure();

An another example to write logs in an HTML file:

  public YourManager() {
        super('Function calls', 'Alpha version');
        HTMLLayout layout = new HTMLLayout();
        WriterAppender appender = null;
        try {
            FileOutputStream output = new FileOutputStream(
                    '/net/home/adicosta/output2.html');
            appender = new WriterAppender(layout, output);
        } catch (Exception e) {
        }
        logger.addAppender(appender);
        logger.setLevel(Level.DEBUG);
    }

For more information about logger configuration see the log4J manual.

48.5. Configuration File

48.5.1. How many configuration files you need?

  • You can have just no file.

  • One file to configure the Manager.

  • One file for the Manager and all its Tests (recommended).

  • One file for the Manager and one file for each Tests.

  • No file for the Manager and one file for each Tests.

48.5.2. A simple Java Properties file

With this file you can configure Manager's properties and Tests properties. You can have just one file for the Manager and all Tests or just one for the Manager and one file for each Tests.

By default the name of this file is the class name of the Manager or the Test which it is associated with .prop as file extention. For example:

ManagerToto.class <-> ManagerToto.prop

48.5.2.1. How to use it?

It is very simple to use it. Just do like this example:

You have a private variable in your Manager or Test:

 private int packetSize = 1024;

First add a setter of which it take a String in input:

     public void setPacketSize(String value){
          this.packetSize = Integer.parseInt(value);
        }

Next, int the prop file:

 PacketSize=2048 

Warning: the key in the prop file must be the same of the setter name without the prefix set.

Now, to load the prop file:

        // Level: Manager
        // At the execution load properties
        manager.execute(yes);
        // To load properties from differents  types of sources
        manager.loadAttributes();
        manager.loadAttributes(java.io.File propFile);
        manager.loadAttributes(java.util.Properties javaProp);
        // Level: Test
        
        // To load properties from differents  types of sources
        test.loadAttributes();
        test.loadAttributes(java.io.File propFile);
        test.loadAttributes(java.util.Properties javaProp);

48.5.3. A XML properties file

To configure all from just one file.

Like a simple prop file this one must be have the same name of the Manager class:

 YourManager <-> YourManager.xml 

48.5.3.1. The structure of the XML document

<Manager>
  <name>A Manager </name>
  <description>Try XML descriptor file. </description>
  <!-- by default nbRuns is 1, but for benchmarks you can change it -->
  <nbRuns>100 </nbRuns>
</Manager>

48.5.3.2. Add a simple group of tests

<simpleGroup name="A simple Group" description="just for test.">
      <unitTest class="test.objectcreation.TestNewActive"/>
      <unitTest class="test.groupmigration.TestGroupCreation"/>
      <unitTest class="test.groupmigration.TestGroupCreation"/>
      <unitTest class="test.objectcreation.TestNewActive"/>
 </simpleGroup>

You have created a group with 4 tests.

48.5.3.3. Add a group from a Java package

<packageGroup name="A Package Group" 
              description="Construct Group from package." 
              dir="/net/home/adicosta/workspace/ProActive/classes" 
              packageName="nonregressiontest" >
</packageGroup>

You have created a group with all Tests was found in the package nonregressiontest

With this method you don't have any order on Tests, but you can specify some order:

<packageGroup name="A Package Group" description="Construct Group from  package." 
                dir="/net/home/adicosta/workspace/ProActive/classes" 
                packageName="nonregressiontest" >
     <unitTest class="nonregressiontest.runtime.defaultruntime.Test" />
     <unitTest class="nonregressiontest.node.nodefactory.Test" />
     <unitTest class="nonregressiontest.stub.stubgeneration.Test" />
     <unitTest class="nonregressiontest.stub.stubinterface.Test" />
     <unitTest class="nonregressiontest.activeobject.creation.local.newactive.Test" />
     <unitTest class="nonregressiontest.activeobject.creation.local.turnactive.Test" />
     <unitTest class="nonregressiontest.activeobject.creation.remote.newactive.Test" />
     <unitTest class="nonregressiontest.activeobject.creation.remote.turnactive.Test" />
</packageGroup>

All classes in package nonregressiontest are added, only the specified tests are sorted.

48.5.3.4. Add a group of InterLinked Tests

<interLinkedGroup name="Group with interlinked tests" description="Construct a Group with
 interlinked tests">
         <!-- Declare the tests in the execution order -->
 <idTest class="test.groupmigration.TestGroupCreation" id="1"/>
 <idTest class="test.groupmigration.TestGroupMigration" id="2"/>
 <idTest class="test.groupmigration.TestGroupMessage" id="3"/>
         <interLinks>
                 <link id="3">
                   <parent id="1"/>
                   <parent id="2"/>
                 </link>
           </interLinks>
 </interLinkedGroup>

TestGroupMessage depends from TestGroupCreation and TestGroupMigration.

48.5.3.5. How to configure log4j

<log4j>
  /net/home/adicosta/log4j/config/file/path/log4j-file-config
</log4j>

48.5.3.6. How to configure results output?

Results in a text file:

 <result type="text" file="/net/home/adicosta/tmp/results.txt" /> 

Results in a HTML file:

 <result type="html" file="/net/home/adicosta/tmp/results.html" /> 

Results in the console:

 <result type="console" /> 

Results in a XML file:

 <result type="xml" file="/net/home/adicosta/tmp/results.xml"/> 

To execute all with the XML file configuration:

Manager manager = new Manager(java.io.File xmlConfigFile);
manager.execute();

48.5.3.7. Configure properties

Like in simple prop file:

<properties>
   <prop key="RemoteHostname" value="nahuel"/>
</properties>

48.6. Extends the API

Thanks to the structure of the API, with many Interfaces and Abstracts classes, you can easily extends the API for you needs.

For more details about this, you can the class: ProActiveManager, ProActiveFuncTest or ProActiveBenchmark which they are extends the API.

The choice of XML to export results can to help you with XSLT to export and format results for you needs.

The logger log4j is also configurable like you want.

48.7. Your first Test

This section describes how to write simple test and execute it.

48.7.1. Description

For this example, we choose to test the object creation in ProActive API with newActive() method. This test aims to perform object creation on the same JVM, on an other local JVM and on a remote JVM.

48.7.2. First step: write the Test

Create a new class who extends testsuite.test.ProActiveFunctionalTest, it is an abstract class.

See this template code:

import testsuite.test.ProActiveFunctionalTest;
import org.objectweb.proactive.core.node.Node;
public class TestNewActive extends ProActiveFunctionalTest {
 public TestNewActive() {
            super();
            setName('newActive');
               setDescription('Test object creation with newActive in a node.');
   }
       public TestNewActive(Node node, String name) {
              super(node,name,
                    'Test object creation with newActive in a node.');
  }
       public void initTest() throws Exception {
       }
       public void action() throws Exception {
 }
       public void endTest() throws Exception {
        }
}

We also override two methods from the super-super class: testsuite.test.FunctionalTest, to check if post and pre-conditions are verified:

  public boolean postConditions() throws Exception { }
  public boolean preConditions() throws Exception { }

48.7.2.1. Implementing initTest() and endTest()

In this example both methods are empty, but they could be overridden in order to initialize and finalyze the test.

48.7.2.2. Implementing preConditions()

We will simply verify if the node is created:

    public boolean preConditions() throws Exception {
        return getNode() != null;
    }

48.7.2.3. Implementing action()

This method is the test, we will create an active object:

 private ReifiableObject active = null;
  public void action() throws Exception {
        active = (ReifiableObject) ProActive.newActive(ReifiableObject.class.getName(),
                null, getNode());
    }

Remarks: The ReifiableObject class is a simple class who just extends java.lang.Object, implements java.io.Serilizable and has an empty constructor with no argument.

48.7.2.4. Implementing postConditions()

We will check if active is different of null and if the node contains active:

 public boolean postConditions() throws Exception {
        Object[] activeObjects = getNode().getActiveObjects();
        return (active != null) && (activeObjects != null) &&
        (activeObjects.length == 1) && activeObjects[0].equals(active);
    }

48.7.2.5. The complete code of the test

import org.objectweb.proactive.ProActive;
import org.objectweb.proactive.core.node.Node;
import testsuite.test.ProActiveFunctionalTest;
public class TestNewActive extends ProActiveFunctionalTest {
    private ReifiableObject active = null;
    public TestNewActive() {
        super();
        setName('newActive');
        setDescription('Test object creation with newActive in a node.');
    }
    public TestNewActive(Node node, String name) {
        super(node, name,
            'Test object creation with newActive in a node.');
    }
    public void initTest() throws Exception {
        // nothing to do
    }
    public boolean preConditions() throws Exception {
        return getNode() != null;
    }
    public void action() throws Exception {
        active = (ReifiableObject) ProActive.newActive(ReifiableObject.class.getName(),
                null, getNode());
    }
    public boolean postConditions() throws Exception {
        Object[] activeObjects = getNode().getActiveObjects();
        return (active != null) && (activeObjects != null) &&
        (activeObjects.length == 1) && activeObjects[0].equals(active);
    }
    public void endTest() throws Exception {
           // nothing to do
    }
}

Tips: if you want to make a trace in your test or in all classes who extends a testsuite class, you have access to a log4j logger by: getLogger()

48.7.3. Second step: write a manager

Now, we will write a Manager to execute our test.

For this example it is very simple, you have just to extends testsuite.manager.ProActiveFuncTestManager:

import testsuite.manager.ProActiveFuncTestManager;
public class ObjectCreationManager extends ProActiveFuncTestManager {
  public ObjectCreationManager() {
            super('Object Creation','Manage objects creation tests.');
  }
}

48.7.3.1. Override initManager()

Normaly, you have nothing to do to initialize the manager. In this example, we choose to create tests and group in this method , but you can do this in the same place where you create the manager.

Create group by the initManager():

import testsuite.group.Group;
public void initManager() throws Exception {
        Group testGroup = new Group('Test Group', 'no description.');
        // adding a test in same VM
        testGroup.add(new TestNewActive(getSameVMNode(),'NewActive same VM'));
        // adding a test in local VM
        testGroup.add(new TestNewActive(getLocalVMNode(),'NewActive local VM'));
        // adding a test in remote VM
        testGroup.add(new TestNewActive(getRemoteVMNode(),'NewActive remote VM'));
        // adding the group
        add(testGroup);
    }

Create group in the same place of the manager:

ObjectCreationManager manager = new ObjectCreationManager();
Group testGroup = new Group('Test Group', 'no description.');
// adding a test in same VM
testGroup.add(new TestNewActive(getSameVMNode(),'NewActive same VM'));
// adding a test in local VM
testGroup.add(new TestNewActive(getLocalVMNode(),'NewActive local VM'));
// adding a test in remote VM
testGroup.add(new TestNewActive(getRemoteVMNode(),'NewActive remote VM'));
// adding the group
manager.add(testGroup);

Warning: if you override endManager() method in a ProActiveManager you must to add in this code:

 super.endManager() 

The reason is to delete the ProActive nodes create at the beginning.

48.7.3.2. The attribute file

Our manager is a ProActiveManager, so an attibutes file is mandatory.

Create a file ObjectCreationManager.prop in the same directory of the manager. This file must contains the name (or URL) of the remote host, like this:

 RemoteHostname=owenii  

Warning: respect the upper an lower cases.

Tips: you can use this file to specify attributes for your tests classes. You can also use a different file, in this case you must specify its path in the execute() method of the manager.

48.7.4. Now launch the test ...

Add this code in your main method:

ObjectCreationManager manager = new ObjectCreationManager();
// the argument must have true value, because it is a ProActiveManager
// and the attributes file is obligatory
manager.execute(true);

Warning: when you use a ProActiveManager you must had System.exit(0) at the end of the main method. If you don't do that, the manager can't stop properly.

48.7.5. Get the results

 System.out.println(manager.getResults()); 

If you want all details:

 manager.setVerbatim(true); 

You can also have the results in a HTML or XML file or in a stream, in Section 48.3, “Results”, look for: testssuite.result.ResultsExporter

48.7.5.1. An example of results for this test with verbatim option

8/22/03 13:48:10.450 [MESSAGE] Local hostname: amda.inria.fr
8/22/03 13:48:10.450 [MESSAGE] Remote hostname: owenii
8/22/03 13:48:10.452 [MESSAGE] Starting ...
8/22/03 13:48:10.458 [MESSAGE] Init Manager with success
8/22/03 13:48:10.749 [RESULT] NewActive same VM: Test run with success [SUCCESS]
8/22/03 13:48:11.141 [RESULT] NewActive local VM: Test run with success [SUCCESS]
8/22/03 13:48:12.195 [RESULT] NewActive remote VM: Test run with success [SUCCESS]
8/22/03 13:48:12.195 [RESULT] Group: Test Group Runs: 3 Errors: 0 [SUCCESS]
8/22/03 13:48:12.195 [MESSAGE] ... Finish

48.7.6. All the code

TestNewActive.java

import org.objectweb.proactive.ProActive;
import org.objectweb.proactive.core.node.Node;
import testsuite.test.ProActiveFunctionalTest;
public class TestNewActive extends ProActiveFunctionalTest {
    private ReifiableObject active = null;
    public TestNewActive() {
        super();
        setName('newActive');
        setDescription('Test object creation with newActive in a node.');
    }
    public TestNewActive(Node node, String name) {
        super(node, name,
            'Test object creation with newActive in a node.');
    }
    public void initTest() throws Exception {
     // nothing to do
    }
    public boolean preConditions() throws Exception {
        return getNode() != null;
    }
    public void action() throws Exception {
        active = (ReifiableObject) ProActive.newActive(ReifiableObject.class.getName(),
                null, getNode());
    }
    public boolean postConditions() throws Exception {
        Object[] activeObjects = getNode().getActiveObjects();
        return (active != null) && (activeObjects != null) &&
        (activeObjects.length == 1) && activeObjects[0].equals(active);
    }
    public void endTest() throws Exception {
           // nothing to do
    }
}

ReaifiableObject.java

import java.io.Serializable;
public class ReifiableObject implements Serializable {
        public ReifiableObject() {
  }
}  

ObjectCreationManager.prop

 RemoteHostname=owenii  

ObjectCreationManager.java

import testsuite.group.Group;
import testsuite.manager.ProActiveFuncTestManager;
public class ObjectCreationManager extends ProActiveFuncTestManager {
    public ObjectCreationManager() {
        super('Object Creation', 'Manage objects creation tests.');
    }
    public void initManager() throws Exception {
        Group testGroup = new Group('Test Group', 'no description.');
        // adding a test in same VM
        testGroup.add(new TestNewActive(getSameVMNode(),'NewActive same VM'));
        // adding a test in local VM
        testGroup.add(new TestNewActive(getLocalVMNode(),'NewActive local VM'));
        // adding a test in remote VM
        testGroup.add(new TestNewActive(getRemoteVMNode(),'NewActive remote VM'));
        // adding the group
        add(testGroup);
    }
    public static void main(String[] args) {
        ObjectCreationManager manager = new ObjectCreationManager();
        // the argument must have true value, because it is a ProActiveManager
        // and the attributes file is obligatory
        manager.execute(true);
          manager.setVerbatim(true);
        System.out.println(manager.getResults());
         // for exit, also ProActive don't stop the application
        System.exit(0);
        
    }
}

48.8. Your first Benchmark

This section describes how to write and execute a simple Benchmark.

48.8.1. Description

For this example, we choose to measure the time of an object creation with ProActive.newActive(). This benchmark aims to perform object creation on the same JVM, on an other local JVM and on a remote JVM.

48.8.2. First step: write the Benchmark

Create new class who extends testsuite.test.ProActiveBenchmark, it is an abstract class.

See this template code:

import org.objectweb.proactive.ProActive;
import org.objectweb.proactive.core.node.Node;
import testsuite.test.ProActiveBenchmark;
public class BenchNewActive extends ProActiveBenchmark {
    public BenchNewActive() {
        super(null, 'Object Creation with newActive',
            'Measure time to create an active object with newActive.');
    }
    public BenchNewActive(Node node) {
        super(node, 'Object Creation with newActive',
            'Measure time to create an active object with newActive.');
    }
    public long action() throws Exception {
    }
    public void initTest() throws Exception {
    }
    public void endTest() throws Exception {
    }
}

We also override two methods from the super-class: testsuite.test.Benchmark, to check if post and pre-conditions are verified:

   public boolean postConditions() throws Exception { }
   public boolean preConditions() throws Exception { }

48.8.2.1. Implementing initTest() and endTest()

In this exampple both methods are empty, but they could be overridden in order to initialize and finalyze the benchmark.

48.8.2.2. Implementing preConditions()

We will simply verify if the node is created:

   public boolean preConditions() throws Exception {
     return getNode() != null;
   }

48.8.2.3. Implementing action()

This method measures the time of a creation of an Object with ProActive.newActive() on a specified node:

    private ReifiableObject object = null;
    public long action() throws Exception {
        ReifiableObject object;
        String className = ReifiableObject.class.getName();
        Node node = getNode();
        this.timer.start();
        object = (ReifiableObject) ProActive.newActive(className, null, node);
        this.timer.stop();
        return this.timer.getCumulatedTime();
    }
[Note]Note

It is the benchmark's programmer who measure the time of the action with a configurable timer, see the Section 48.2, “Timer for the Benchmarks” for more details.

The ReifiableObject class is a simple class who just extends java.lang.Object, implements java.io.Serilizable and has an empty constructor with no argument.

48.8.2.4. Implementing postConditions()

We will check if object is different of null and if the node contains object:

 public boolean postConditions() throws Exception {
     Object[] activeObjects = getNode().getActiveObjects();
     return (object != null) && (activeObjects != null) &&
       (activeObjects.length == 1) && activeObjects[0].equals(object);
   }

Tips: if you want to make a trace in your benchmark , you have access to a log4j logger by: getLogger() or by the variable logger

48.8.3. Second step: write a manager

Now, we will write a Manager to execute ou test.

For this example it is very simple, you have just to extends testsuite.manager.ProActiveBenchManager:

import testsuite.manager.ProActiveBenchManager;
public class Manager extends ProActiveBenchManager {
        public Manager() {
          super('Manager','To manage ProActive Benchmarks.');
        }
}

48.8.3.1. Override initManager() and endManager()

Normaly, you have nothing to do to initialize the manager. In this example, we choose to create benchmarks and group in this method , but you can do this in the same place where you create the manager.

Create group by initManager():

import testsuite.group.Group;
  public void initManager() throwsException {
    Group benchGroup = new Group('Bnechmark Group','no description.');
    // adding bench in same VM
    benchGroup.add(new BenchNewActive(getSameVMNode()));
    // adding bench in local VM
    benchGroup.add(new BenchNewActive(getLocalVMNode()));
    // adding bench in remote VM
    benchGroup.add(new BenchNewActive(getRemoteVMNode()));
    // adding the group
    add(benchGroup);
  }

Create group int the same place of the manager:

  // ...
  Manager manager  = new Manager();
  Group  benchGroup = new Group('Bnechmark Group','no description.');
  // adding bench in same VM
  benchGroup.add(new BenchNewActive(getSameVMNode()));
  // adding bench in local VM
  benchGroup.add(new BenchNewActive(getLocalVMNode()));
  // adding bench in remote VM
  benchGroup.add(new BenchNewActive(getRemoteVMNode()));
  manager.add(benchGroup);
  // ...

Warning: if you override endManager() method in a ProActiveManager you must to add in this code:

 super.endManager() 

The reason is to delete the ProActive nodes create at the beginning.

48.8.3.2. The attribute file

Our manager is a ProActiveManager, so an attibutes file is mandatory.

Create a file Manager.prop in the same directory of the manager. This file must contains the name (or URL) of the remote host, like this:

 RemoteHostname=owenii 

Warning: respect the upper an lower cases.

Tips: you can use this file to specify attributes for your tests classes. You can also use a different file, in this case you must specify its path in the execute() method of the manager.

48.8.4. Now launch the benchmark ...

Add this code in your main method:

Manager manager = new Manager();
// the argument must have true value, because it is a ProActiveManager
// and the attributes file is obligatory
manager.execute(true);

Warning: when you use a ProActiveManager you must to had System.exit(0) at the end of the main method. If don't do that, the manager can't properly.

48.8.4.1. Get the results

Results in your console:

 System.out.println(manager); 

If you want all details:

 manager.setVerbatim(true); 

For benchmarks it is more interesting to export results in a HTML file. Indeed, you have average, min, max, STDEV and charts to help you to analyse all results

Object Creation
Object Creation with newActive and turnActive. 
Messages of Object Creation:
9/18/2003 at 13:0:32.527 [RESULT] 
Object Creation with newActive -- Same VM: no message [SUCCESS] See the chart
Max=113ms Moy=24.0ms STDEV=24.64ms --> Min1ms
9/18/2003 at 13:0:36.693 [RESULT]
 Object Creation with turnActive -- Same VM: no message [SUCCESS]See the chart
 Max=98ms Moy=41.0ms STDEV=32.20ms --> Min1ms
9/18/2003 at 13:0:43.425 [RESULT]
 Object Creation with newActive -- Local VM: no message [SUCCESS]See the chart
 Max=376ms Moy=67.03ms STDEV=83.73ms --> Min6ms
9/18/2003 at 13:0:50.434 [RESULT]
 Object Creation with turnActive -- Local VM: no message [SUCCESS]See the chart
 Max=326ms Moy=69.82ms STDEV=86.15ms --> Min6ms
9/18/2003 at 13:0:53.297 [RESULT]
 Object Creation with newActive -- Remote VM: no message [SUCCESS]See the chart
 Max=290ms Moy=28.03ms STDEV=50.79ms --> Min5ms
9/18/2003 at 13:0:55.980 [RESULT]
 Object Creation with turnActive -- Remote VM: no message [SUCCESS]See the chart
 Max=250ms Moy=26.32ms STDEV=53.46ms --> Min5ms
9/18/2003 at 13:0:55.982 [RESULT]:
 Group: Object Creation, Moy in 42.7ms Runs: 600 Errors: 0
 To see all results of this group in a BarChart.

Example 48.1. Example of HTML results

48.8.5. All the Code

BenchnewActive.java

import org.objectweb.proactive.ProActive;
import org.objectweb.proactive.core.node.Node;
import testsuite.test.ProActiveBenchmark;
import util.ReifiableObject;
public class BenchNewActive extends ProActiveBenchmark {
    private ReifiableObject object = null;
    public BenchNewActive() {
        super(null, 'Object Creation with newActive',
            'Measure time to create an active object with newActive.');
    }
    public BenchNewActive(Node node) {
        super(node, 'Object Creation with newActive',
            'Measure time to create an active object with newActive.');
    }
    public long action() throws Exception {
        String className = ReifiableObject.class.getName();
        Node node = getNode();
        this.timer.start();
        object = (ReifiableObject) ProActive.newActive(className, null, node);
        this.timer.stop();
        return this.timer.getCumulatedTime();
    }
    public void initTest() throws Exception {
        // nothing to do
    }
    public void endTest() throws Exception {
        // nothing to do
    }
    public boolean preConditions() throws Exception {
        return getNode() != null;
    }
    
    public boolean postConditions() throws Exception {
        Object[] activeObjects = getNode().getActiveObjects();
        return (object != null) && (activeObjects != null) &&
        (activeObjects.length == 1) && activeObjects[0].equals(object);
    }
}

ReifiableObject.java

import java.io.Serializable;
public class ReifiableObject implements Serializable {
        public ReifiableObject() {
        }
}

Manager.prop

 RemoteHostname=owenii 

Manager.java

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.HTMLLayout;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.WriterAppender;
import testsuite.group.Group;
import testsuite.manager.ProActiveBenchManager;
import java.io.File;
public class Manager extends ProActiveBenchManager {
    private Logger logger = Logger.getLogger(Test1.class);
    public Manager() {
        super('Manager','To manage ProActive Benchmarks.');
        // Log in a HTML file
        HTMLLayout layout = new HTMLLayout();
        WriterAppender appender = null;
        try {
            FileOutputStream output = new FileOutputStream(
                    '/net/home/adicosta/output2.html');
            appender = new WriterAppender(layout, output);
        } catch (Exception e) {
        }
        logger.addAppender(appender);
        BasicConfigurator.configure();
        logger.setLevel(Level.DEBUG);
    }
    public void initManager() throws Exception {
        Group benchGroup = new Group('Bnechmark Group','no description.');
        // adding bench in same VM
        benchGroup.add(new BenchNewActive(getSameVMNode()));
        // adding bench in local VM
        benchGroup.add(new BenchNewActive(getLocalVMNode()));
        // adding bench in remote VM
        benchGroup.add(new BenchNewActive(getRemoteVMNode()));
        // adding the group
        add(benchGroup);
    }
    public static void main(String[] args) {
        Manager manager = new Manager();
        // To run all benchmarks 100 times
        manager.setNbRuns(100);
        // Execute all benchmarks
        manager.execute(true);
        //Write results in a HTML file
        try {
            File file = new File(System.getProperty('user.home') +
                    File.separatorChar + 'results.html');
            manager.toHTML(file);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.exit(0);
    }
}

48.9. How to create a Test Suite with interlinked Tests

In this part we will not explain how to write a simple test, for this see Section 48.7, “Your first Test” .

48.9.1. Description of our Test

In first step, we will test a ProActive Group creation with 3 Agents, and after this creation we will test the Agents migration by a group communication.

48.9.2. Root Test: ProActive Group Creation

48.9.2.1. A simply ProActiveTest

Create a new class who extends testsuite.test.ProActiveFunctionalTest, it is an abstract class.

See this template code:

import org.objectweb.proactive.core.node.Node;
import testsuite.test.ProActiveFunctionalTest;
import java.io.Serializable;
public class TestGroupCreation extends ProActiveFunctionalTest
    implements Serializable {
    public TestGroupCreation() {
        super(null, 'Group Creation',
            'Create a Group of active object in specify node.');
    }
    public TestGroupCreation(Node node) {
        super(node, 'Group Creation',
            'Create a Group of active object in specify node.');
    }
    public void action() throws Exception {
    }
    public boolean postConditions() throws Exception {
    }
    public boolean preConditions() throws Exception {
    }
    public void initTest() throws Exception {
        // nothing to do
    }
    public void endTest() throws Exception {
        // nothing to do
    }
}

Next we will simply test in preconditions if the node exists (different of null):

   public boolean preConditions() throws Exception {
        return getNode() != null;
    }

Now we will implement the action method to create a ProActive Group with 3 Agent (see the Agent code at the end of this section - Example 48.2, “Agent class”):

import org.objectweb.proactive.core.group.Group;
import org.objectweb.proactive.core.group.ProActiveGroup;
public class TestGroupCreation extends ProActiveFunctionalTest
    implements Serializable {
     private Agent group = null;
 
    // ...
  public void action() throws Exception {
             createGroupAgent();
 }
   
    private void createGroupAgent() throws Exception {
          Object[][] params = {
                       { 'Agent0' },
                       { 'Agent1' },
                       { 'Agent2' }
                };
          Node node = getNode();
              Node[] nodes = { node };
            group = (Agent) ProActiveGroup.newGroup(Agent.class.getName(), params,
              nodes);
     }
       // ...
}

Remarks: We use an external method to create the group is for the simple reason of we use this code after in another method.

Remarks: We don't explain the Agent code because it is a ProActive example.

For the postconditions we will test if the group containts 3 elements and they are in the good node:

    public boolean postConditions() throws Exception {
        if (group == null) {
            return false;
        } else {
            Group agentGroup = ProActiveGroup.getGroup(group);
            if (agentGroup.size() != 3) {
                return false;
            } else {
                Agent agent0 = (Agent) agentGroup.get(0);
                Agent agent1 = (Agent) agentGroup.get(1);
                Agent agent2 = (Agent) agentGroup.get(2);
                String nodeURL = getNode().getNodeInformation().getURL()
                                     .toUpperCase();
                return (agent0.getNodeName().compareTo(nodeURL) == 0) &&
                (agent1.getNodeName().compareTo(nodeURL) == 0) &&
                (agent2.getNodeName().compareTo(nodeURL) == 0);
            }
        }
    }

This class is now readi for a standalone use.

48.9.2.2. Action method for interlinked mode

Now, we will add a new action method who return a ProActive Group:

    public Agent action(Object o) throws Exception {
        createGroupAgent();
        return this.group;
    }

This method return an Agent (who is the group) and have one argument: o. This argument will not use , we must to put this argument is for have a different method signature from action().

Our test for group creation is now ready.

48.9.3. An independant Test: A Group migration

All the code is the same of the precedant class unexcepted for the actions methods and for the method to create group of course.

48.9.3.1. The default action method

In this test we can't run this method in a standalone test, but for other maybe you can. It is just for this test.

    public void action() throws Exception {
        throw new Exception('This test doesn't work in standalone mode');
    }

48.9.3.2. The action method for interlinked tests

The result of the precedent test is an Agent, so the argument will be an Agent. This test have no result but we must to return an Object here it is null because the API use the reflection mechanism of Java.

    public Object action(Agent group) throws Exception {
        this.group = group;
        this.group.moveTo(getNode().getNodeInformation().getURL());
        return null;
    }

48.9.4. Run your tests

Create a simple ProActiveFuncTestManager with a main:

import testsuite.manager.ProActiveFuncTestManager;
public class Manager extends ProActiveFuncTestManager {
    public Manager(String name, String description) {
        super(name, description);
    }
    public static void main(String[] args) {
        Manager manager = new Manager('Migration Tests',
                'Create a group and migrate its objects.');
    }
}

Create a new Group (testsuite.group.Group) in our main:

import testsuite.group.Group;
    // ...
    Group group = new Group('Group Migration', 'Migration on an active group objects.');
    // ...

Create and add the 2 precends tests in the group:

    // ...
    TestGroupCreation creation = new TestGroupCreation(manager.getLocalVMNode());
        group.add(creation);
        TestGroupMigration migration = new TestGroupMigration(manager.getRemoteVMNode());
        group.add(migration);
    // ...

Specify the ancestor test of migration is creation:

  // ...
  FunctionalTest[] params = { creation };
             migration.setTests(params);
  // ...

You can see in the Section 48.5, “Configuration File” how to do this by a configuration file.

Warning: Don't forget to write a prop file with the name of the remote host.

Add the group and launch the test:

   // ...
   manager.add(group);
   manager.execute(group, migration, true);
   // ...

Warning: when you use a ProActiveManager you must to had System.exit(0) at the end of the main method. If don't do that, the manager can't properly.

48.9.4.1. An example of results for this test with verbatim option

8/26/03 12:40:47.407 [MESSAGE] Local hostname: amda.inria.fr
8/26/03 12:40:47.408 [MESSAGE] Remote hostname: owenii
8/26/03 12:40:47.498 [MESSAGE] Starting with interlinked Tests ...
8/26/03 12:40:47.498 [MESSAGE] Init Manager with success
8/26/03 12:40:48.547 [RESULT] Group Creation: Test run with success [SUCCESS]
8/26/03 12:40:50.149 [RESULT] Group Migration: Test run with success [SUCCESS]
8/26/03 12:40:50.149 [RESULT] Group: Group Migration Runs: 2 Errors: 0 [SUCCESS]
8/26/03 12:40:50.243 [MESSAGE] ... Finish

48.9.5. All the code

Manager.prop

 RemoteHostname=owenii 

Manager.java

import testsuite.group.Group;
import testsuite.manager.ProActiveFuncTestManager;
public class Manager extends ProActiveFuncTestManager {
    public Manager(String name, String description) {
        super(name, description);
    }
    public static void main(String[] args) {
        Manager manager = new Manager('Migration Tests',
                'Create a group and migrate its objects.');
        Group group = new Group('Group Migration',
                'Migration on an active group objects.');
        TestGroupCreation creation = new TestGroupCreation(manager.getLocalVMNode());
        group.add(creation);
        TestGroupMigration migration = new TestGroupMigration(manager.getRemoteVMNode());
        group.add(migration);
        FunctionalTest[] params = { creation };
        migration.setTests(params);
        manager.add(group);
        manager.execute(group, migration, true);
        manager.setVerbatim(true);
        manager.getResults().toOutPutStream(System.out);
        System.exit(0);
    }
}

TestGroupMigration.java

import java.io.Serializable;
import org.objectweb.proactive.core.group.Group;
import org.objectweb.proactive.core.group.ProActiveGroup;
import org.objectweb.proactive.core.node.Node;
import testsuite.test.ProActiveFunctionalTest;
public class TestGroupMigration extends ProActiveFunctionalTest
    implements Serializable {
    private Agent group = null;
    public TestGroupMigration() {
        super(null, 'Group Migration',
            'Migrate all Group Element in a specified node.');
    }
    public TestGroupMigration(Node node) {
        super(node, 'Group Migration',
            'Migrate all Group Element in a specified node.');
    }
    public boolean postConditions() throws Exception {
        if (group == null) {
            return false;
        } else {
            Group agentGroup = ProActiveGroup.getGroup(group);
            if (agentGroup.size() != 3) {
                return false;
            } else {
                Agent agent0 = (Agent) agentGroup.get(0);
                Agent agent1 = (Agent) agentGroup.get(1);
                Agent agent2 = (Agent) agentGroup.get(2);
                String nodeURL = getNode().getNodeInformation().getURL()
                                     .toUpperCase();
                return (agent0.getNodeName().compareTo(nodeURL) == 0) &&
                (agent1.getNodeName().compareTo(nodeURL) == 0) &&
                (agent2.getNodeName().compareTo(nodeURL) == 0);
            }
        }
    }
    public boolean preConditions() throws Exception {
        return getNode() != null;
    }
    public void action() throws Exception {
        throw new Exception('This test doesn't work in standalone mode');
    }
    public Object action(Agent group) throws Exception {
        this.group = group;
        this.group.moveTo(getNode().getNodeInformation().getURL());
        return null;
    }
    public void initTest() throws Exception {
        // nothing to do
    }
    public void endTest() throws Exception {
        // nothing to do
    }
}

TestGroupCreation.java

import org.objectweb.proactive.core.group.Group;
import org.objectweb.proactive.core.group.ProActiveGroup;
import org.objectweb.proactive.core.node.Node;
import testsuite.test.ProActiveFunctionalTest;
import java.io.Serializable;
public class TestGroupCreation extends ProActiveFunctionalTest
    implements Serializable {
    private Agent group = null;
    public TestGroupCreation() {
        super(null, 'Group Creation',
            'Create a Group of active object in specify node.');
    }
    public TestGroupCreation(Node node) {
        super(node, 'Group Creation',
            'Create a Group of active object in specify node.');
    }
    // Default action method
    public void action() throws Exception {
        createGroupAgent();
    }
    // For interlinked tests action method
    public Agent action(Object o) throws Exception {
        createGroupAgent();
        return this.group;
    }
    private void createGroupAgent() throws Exception {
        Object[][] params = {
            { 'Agent0' },
            { 'Agent1' },
            { 'Agent2' }
        };
        Node node = getNode();
        Node[] nodes = { node };
        group = (Agent) ProActiveGroup.newGroup(Agent.class.getName(), params,
                nodes);
    }
    public boolean postConditions() throws Exception {
        if (group == null) {
            return false;
        } else {
            Group agentGroup = ProActiveGroup.getGroup(group);
            if (agentGroup.size() != 3) {
                return false;
            } else {
                Agent agent0 = (Agent) agentGroup.get(0);
                Agent agent1 = (Agent) agentGroup.get(1);
                Agent agent2 = (Agent) agentGroup.get(2);
                String nodeURL = getNode().getNodeInformation().getURL()
                                     .toUpperCase();
                return (agent0.getNodeName().compareTo(nodeURL) == 0) &&
                (agent1.getNodeName().compareTo(nodeURL) == 0) &&
                (agent2.getNodeName().compareTo(nodeURL) == 0);
            }
        }
    }
    public boolean preConditions() throws Exception {
        return getNode() != null;
    }
    public void initTest() throws Exception {
        // nothing to do
    }
    public void endTest() throws Exception {
        // nothing to do
    }
}

Agent.java

import org.objectweb.proactive.Body;
import org.objectweb.proactive.EndActive;
import org.objectweb.proactive.InitActive;
import org.objectweb.proactive.ProActive;
import org.objectweb.proactive.RunActive;
public class Agent implements InitActive, RunActive, 
                                EndActive, java.io.Serializable {
    private String name;
    private String nodename;
    private String hostname;
    public Agent() {
    }
    public Agent(String name) {
        this.name = name;
    }
    public String getName() {
        try {
            //return the name of the Host
            return java.net.InetAddress.getLocalHost().getHostName()
                                       .toUpperCase();
        } catch (Exception e) {
            e.printStackTrace();
            return 'getName failed';
        }
    }
    public String getNodeName() {
        try {
            //return the name of the Node  
            return ProActive.getBodyOnThis().getNodeURL().toUpperCase();
        } catch (Exception e) {
            e.printStackTrace();
            return 'getNodeName failed';
        }
    }
    public void moveTo(String nodeURL) {
        try {
            System.out.println(' I am going to migate');
            ProActive.migrateTo(nodeURL);
            System.out.println('migration done');
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void endBodyActivity() {
        ProActive.getBodyOnThis().terminate();
    }
    public void initActivity(Body body) {
        System.out.println('Initialization of the Activity');
    }
    public void runActivity(Body body) {
        org.objectweb.proactive.Service service = 
                    new org.objectweb.proactive.Service(body);
        while (body.isActive()) {
            // The synchro policy is FIFO
            service.blockingServeOldest();
        }
    }
    public void endActivity(Body body) {
        System.out.println('End of the activity of this Active Object');
    }
}
 

Example 48.2. Agent class

48.10. Conclusion

This tour was intented to guide you through an overview of ProActive TestSuite API.

You can now easily use it for testing and benchmarking your ProActive's applications.

Thanks to its extending mechanism, you can also use it for non-ProActive's applications. Which means that use it for all Java programs.

Your suggestions are welcome.