Using custom code to specify an end policy

You can write a custom Java class to specify when a socket receive element stops receiving. This offers the most flexibility, but requires that you write your own Java class using the Rational® Performance Tester extension API.

Before you begin

The end policy specifies how the receive element stops receiving and allows the test to resume. There are several predefined end policies that you can choose from, for example after a certain number of bytes has been received, or when a specific string is detected. However, in some cases, a complex condition must be defined. This can be done by delegating the decision to custom code.

Procedure

To create a new custom code class:
  1. In the test editor, select a socket receive element.
  2. In the End policy section, select Delegated to custom code and click Generate Code.
    This creates a Java class template that follows the Rational® Performance Tester extension API. The Java class in created in the src folder of the current project.
  3. Write the custom code by extending the generating class. See Extending test execution with custom code for more information about extending Rational® Performance Tester with Java code.
  4. Save the custom code and the test.
    You can click View Code to edit the Java class later.

Example

The following example is a sample custom class that demonstrates how to configure a custom end policy for the internet time protocol:
package test;

import java.text.DateFormat;
import java.util.Date;
import java.util.TimeZone;

import com.ibm.rational.test.lt.execution.socket.custom.ISckCustomReceivePolicy;
import com.ibm.rational.test.lt.execution.socket.custom.ISckReceiveAction;
import com.ibm.rational.test.lt.kernel.services.ITestExecutionServices;

/**
 *  Custom receive policy CustomReceive_TimeReceiver.
 *  For javadoc of ITestExecutionServices, select 'Help Contents' in the Help menu and select
 *  'Extending 
                    Rational® Performance
                    Tester functionality' -> 'Extending test execution with custom code'
 */
public class CustomReceive_TimeReceiver implements ISckCustomReceivePolicy {

	// static {
	//	 static blocks are called once on each run and allow for example to bind
	//	 to an external dynamic library
	// }

	ISckReceiveAction receiveAction;
	ITestExecutionServices testExecutionServices;

	public CustomReceive_TimeReceiver() {
		// The constructor is called during the test creation, not at the time of the execution of
		// the customized receive action
	}

	public void setup(ITestExecutionServices tesRef,
			ISckReceiveAction receiveActionRef) {
		testExecutionServices = tesRef;
		receiveAction = receiveActionRef;
	}

	public boolean onRead(int readByte) {
		// TIME protocol (RFC 868): a connected server returns 4 bytes and closes the connection
		// Those 4 bytes are the number of seconds since 1900/1/1
		// The test is simply made of a connection to one TIME server on port 37
		// (public servers are listed here: Got time server host name from http://tf.nist.gov/service/time-servers.html),
		// Then a receive delegated to this custom code class,
		// Then a close
		try {
			if (readByte == EndOfStream) {
				/* In case of success: */
				receiveAction.receiveSuccess();
				String message = extractAndCheckTime(receiveAction.getConnectionHolder().getFinallyReceivedBytes());
				/* A message is appended in the Test Log just after this receive action: */
				testExecutionServices.getTestLogManager().reportMessage(message);
				return true;
			}
		} catch (Throwable t) {
			/* In case of exception: */
			receiveAction.handleException(t);
			return true;
		}
		if (receiveAction.getConnectionHolder().getCurrentlyReceivedBytesCount()> 4) {
			/* Unexpected condition: */
			receiveAction.handleException(new Exception("Time protocol server returned more than 4 bytes"));
			return true;
		}
		/* We need further bytes to complete this receive */
		return false;
	}

	private String extractAndCheckTime(byte[] bytes) {
		// This is network order, i.e. big endian
		long remoteTime = ((((long)bytes[0]) & 0x00000000000000ff) << 24) +
						  ((((long)bytes[1]) & 0x00000000000000ff) << 16) +
						  ((((long)bytes[2]) & 0x00000000000000ff) << 8) +
						   (((long)bytes[3]) & 0x00000000000000ff);
		// 1900 to 1970: a difference of reference, see RFC 868 and java.util.Date javadoc
		remoteTime -= 2208988800L;
		Date remoteDate = new Date(remoteTime*1000);
		Date localDate = new Date();
		DateFormat dateFormat = DateFormat.getDateTimeInstance();
		dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
		String message = "Remote time: " + dateFormat.format(remoteDate) + " GMT (TIME server is " +
											receiveAction.getConnectionHolder().getHostName() + ", port 37)\n" +
						 "Local time:  " + dateFormat.format(localDate) + " GMT\n";
		long diff = localDate.getTime()/1000 - remoteTime;
		if (diff == 0) {
			message += "-> No difference";
		} else {
			message += "-> Difference (seconds): " + diff;
		}
		return message;
	}

}