Execute Java code
Introduction
During a load test, it is possible to execute Java code that is external to the Virtual Users. This feature allows NeoLoad functional range to be extended in order to create Virtual Users with a very complex behavior.
This tutorial takes as its example RMI (Remote Method Invocation) calls to a remote Java server. The server provides two services: one gives the dollar value of a stock on the US Stock Exchange, the other provides for the conversion of one currency to another. You are going to string together the call to these two services to obtain a stock price in Euros.
Caution: The Java code must be compiled with a Java version lower or equal to the NeoLoad Java version. To know the NeoLoad Java version, execute command jre\bin\java -version from the NeoLoad installation directory.
Operation and syntax
In NeoLoad, Java code may be invoked from JavaScript code, as part of the "JavaScript" logical action.
For Java classes to be used in JavaScript, the class names must be fully qualified (even for Java classes such as java.util.List) and preceded by "Packages
.".
For example:
var myObj = new Packages.com.company.MyClass();
var result = myObj.compute(myArg);
var result2 = Packages.com.company.MyClass.someStaticMethod(result);
Write the Java code
Depending on the case, it may be useful to hide part of the complexity of a call to an API behind a "business" layer.
In the present example, you will choose to handle the intermediate result, namely the dollar stock price, transparently. The aim of this is to simplify as far as possible the succeeding JavaScript calls.
public class SampleClient
{ private StockProvider remoteStockProvider;
private CurrencyConverter remoteCurrencyConverter;
private float usdStockQuote=-1;
public void connect() throws NotBoundException, IOException {
this.remoteStockProvider = (StockProvider) Naming.lookup(
"//fooserver/StockProvider"
);
this.remoteCurrencyConverter = (CurrencyConverter) Naming.lookup(
"//fooserver/CurrencyConverter"
);
}
public boolean isConnected() {
return this.remoteStockProvider != null && remoteCurrencyConverter != null;
}
public void getStockQuoteUSD(String stockSymbol) throws RemoteException {
if (!isConnected()) {
throw new IllegalStateException("Not connected to server");
}
this.usdStockQuote = this.remoteStockProvider.getStockQuote(stockSymbol);
}
public float getStockQuoteEur() throws RemoteException {
if (this.usdStockQuote < 0) {
throw new IllegalStateException("The method getStockQuoteUSD() " +
"has not been called.");
}
return this.remoteCurrencyConverter.currencyConvert(
"USD", "EUR", this.usdStockQuote
);
}
}
The connect()
method is used to connect to the remote object, getStockQuoteUSD()
retrieves the specified stock price and stores it internally, and getStockQuoteEur()
returns the stock price converted into Euros.
Configure NeoLoad
Generally speaking, NeoLoad must have access to the Java classes used. It is necessary to copy the code to be called, and the libraries used, into <neoload-project>/lib/jslib/
. Either JAR files or .class
files can be stored in the directory. For example, the SampleClient
class compiled in <neoload-project>/lib/jslib/
can be copied, as well as the JARs containing the interfaces for the remote objects to be used, namely StockProvider
and CurrencyConverter
.
Using Eclipse for NeoLoad
Eclipse can be used to write Java code for NeoLoad. Eclipse must be configured to output the compiled classes of the project into <neoload-project>/lib/jslib/
. Optionally the Java sources can be configured to be in the NeoLoad project to keep all related sources in the same location. The classes are taken in account automatically each time a Virtual User is checked or at each new test without restarting NeoLoad. The only requisite is saving the code in Eclipse before launching a test.
Prepare the data
The RMI calls require entry data, in this case the symbols for the stocks whose price you want to retrieve. Create the "stockSymbols
" File
- type variable with the required values:
Create the stockQuotes.csv
file:
symbol;description
IBM;IBM
MSFT;Microsoft
AAPL;Apple
ORCL;Oracle
JAVA;Sun
GOOG;Google
To create the "stockSymbols
" variable, follow these steps:
-
Use the Edit > Variables command.
-
Click on the Create a variable button.
-
Select File type.
-
Name the variable, "stockSymbols".
-
Use the file previously created.
-
Select the Use first line as header option.
-
Leave the value change policies to their default setting: Each line of the file corresponds to a Virtual User instance.
-
Click OK.
Design the Virtual User
Create a new Virtual User in the current project. You are going to create one action for each RMI call, as this will allow you to retrieve access time statistics for each call.
To design a Virtual User, follow these steps:
-
Place three "JavaScript" logical actions in the Virtual User. For example: "
connect
" ,"getStockQuoteUSD
", and "getStockQuoteEur
". -
Place a "Delay" action in between each JavaScript action.
-
Modify the wait time for each delay. This must correspond to the time between the two calls in the simulated application.
-
Replace the default code for each action. The JavaScript code for the three actions is as follows:
-
connect
:var sampleClient = Packages.com.neotys.test.rmi.client.SampleClient();
sampleClient.connect();
context.currentVU.put("sampleClient", sampleClient);
logger.debug("sampleClient connected");The script creates an instance of the SampleClient class and makes the connection to the server. The
sampleClient
instance is stored within the Virtual User instance, for use by the subsequent requests. Thus, you have one instance of SampleClient per Virtual User instance throughout the test. -
getStockQuoteUSD
:var sampleClient = context.currentVU.get("sampleClient");
var stockSymbol = context.variableManager.getValue("stockSymbols.symbol");
logger.debug("stockSymbol=" + stockSymbol);
sampleClient.getStockQuoteUSD(stockSymbol);The script retrieves the
sampleClient
instance stored by the previous script, then interprets the "stockSymbols
" variable created previously. ThegetStockQuoteUSD
method makes the RMI call that retrieves the price for the stock whose symbol is taken from the CSV file. The dollar value is stored within theSampleClient
, to be used as an argument in the following call. -
getStockQuoteEuro
:var sampleClient = context.currentVU.get("sampleClient");
var stockValueEuro = sampleClient.getStockQuoteEUR();
logger.debug("Stock price €" + stockValueEuro);
context.variableManager.setValue("stockPriceEUR", stockValueEuro);The script retrieves the
sampleClient
instance stored by the first script, then makes the call to the RMI method that allows the previously-stored dollar value to be converted into Euros. The call to theVariableManager
allows the value retrieved by RMI to be injected into a NeoLoad variable. This value may then be used in NeoLoad, for example as a classic HTTP request parameter. This is outside the scope of this example however.
-
Validate the Virtual User
As with a standard Virtual User, the Virtual User must be validated in order to verify its proper execution.
To validate a Virtual User, follow these steps:
-
Open the validation pane with the Run > Start checking command.
-
Select the appropriate user in the drop-down list ("
RMIUser
"). -
Click on the Start Checking button.
Error Handling
The "JS-OK" return code denotes that the JavaScript code was correctly executed. In the case of a JavaScript error, or if the Java code produces an exception, the "JavaScript" action is flagged as containing an error, accompanied by the JS-ERROR-EVAL
or JS-FAIL
error code.
The logger.debug()
method provides for the logging of useful information for checking that the scenario runs correctly during the validation. In the example, the result of the last RMI call is displayed. By default, DEBUG-level logs are only displayed during the validation process. For more information, see Logger.
Tests and results
Once the Virtual User has been created and checked, create a Population and configure your scenario as for a normal test.
In NeoLoad, the "JavaScript" logical action is not considered a request. Therefore, most of the NeoLoad statistics, such as average pages/sec, average hits/sec, average request response times... all return zero. This is true during test monitoring, in the test summary and in the generated reports.
Thus, the only place the JavaScript statistics can be found is in NeoLoad "Values
" and "Graphs
" tabs. The information available in these tabs is the same as for an HTTP request.
Related links
For more information about using JavaScript in NeoLoad, see JavaScript.
For more information, see JavaScript Action API.