Todd Nichols, Anser Enterprise
This is a description of Grinder source code modifications made to automate testing the effects of WebLogic server configuration changes. For Grinder users, this tutorial may prompt ideas for general-purpose Grinder feature requests. For Grinder developers, it discusses implementation techniques, which may be of interest, while not exactly fitting with plans to provide a Grinder API for test automation.
Todd Nichols
Source code modifications and other techniques address these test automation functions:
This screenshot shows new controls that were added to the Console:
Target Tab
As with the Script Tab, users can select a root directory and a file in the Target Tab. These selections are independent of selections for the Script root directory and file made in the Script Tab. In the Target Tab, the user selects a XML file that contains the ranges of values for WebLogic configuration settings for the series of tests. In the Console picture, the selected file is “configTarget.xml”, whose format and origin is described below. In addition, this file contains the range of processes and threads values to be inserted into a grinder.properties file and distributed to Grinder agents.
Test result files are created in the same directory that contains the configuration XML file. As shown above, those files are named InputParmNames.txt, InputParms.txt, StatsMean.txt, and StatsNames.txt. The formats for these files will be described below as well.
Start test series
Like the existing Start processes menu item under Action, Start test series initiates the agent’s workload. However, it initiates a series of tests instead of a single test. To proceed through all of the tests, the Collect samples forever/Stop after XX samples text box must be non-zero. Once this sample limit has been reached for a test, the test automation code re-configures the WebLogic server, distributes a newly configured grinder.properties file to the agent(s) and begins the next test.
Stop test series
Like the existing Stop processes menu item, Stop test series stops the agent workload but for the remainder of the test series.
<?
xml version="1.0" encoding="UTF-8"
?>
<
Domain
ConfigurationVersion
="
8.1.2.0"
Name
="
workshop">
<
Server AcceptBacklog
="
10,20,30,40"
AdministrationPort
="
1"
DefaultProtocol
="
t3"
DefaultSecureProtocol
="
t3s"
HttpdEnabled
="
true"
ListenAddress
="
localhost
"
ListenPort
="
7001"
Name
="
cgServer
"
NativeIOEnabled
="
false,true"
ReliableDeliveryPolicy
="
RMDefaultPolicy
"
ServerVersion
="
8.1.2.0"
StdoutDebugEnabled
="
false"
StdoutSeverityLevel
="
32"
TransactionLogFilePrefix
="
./logs/"
TunnelingClientPingSecs
="
45"
TunnelingClientTimeoutSecs
="
40">
<
WebServer
AuthCookieEnabled
="
true"
LogFileName
="
./logs/access.log"
LoggingEnabled
="
true"
Name
="
cgServer
" />
<
COM
Name
="
cgServer
"
/>
<
ServerStart
Name
="
cgServer
" />
<
SSL
Enabled
="
true"
IdentityAndTrustLocations
="
KeyStores
"
ListenPort
="
7002"
Name
="
cgServer
" />
<
Log
FileMinSize
="
20000"
Name
="
cgServer
"
RotationType
="
bySize
" />
<
KernelDebug
Name
="
cgServer
" />
<
KernelDebug
Name
="
cgServer
" />
<
ServerDebug
Name
="
cgServer
" />
<
ExecuteQueue
Name="
weblogic.kernel.Default
"
QueueLength
="
65536"
QueueLengthThresholdPercent
="
90"
ThreadCount
="
10,15,20,25,30" />
<
JTAMigratableTarget
Name
="
cgServer
"
UserPreferredServer
="
cgServer
" />
</
Server
>
<
Grinder
FileName
="
C:\grinder3_0\test1_script\grinder.properties"
Processes
="
1"
Threads
="
15,50,100,200" />
The partial listing above is from the “configTarget.xml” file shown selected in the Target Tab. It specifies the range of values for the Grinder workloads and WebLogic configuration settings as comma-separated integers, Booleans, etc. in the attribute value strings. Most of the file XML content is copied from a WebLogic config.xml configuration file for the app server to be tested. For the configTarget.xml file, single attribute values from the config.xml file are replace by multiple values. For example, AcceptBacklog=”30” is changed to AcceptBacklog=”10,20,30,40” and NativeIOEnabled=”false” becomes NativeIOEnabled=”false,true”.
The <Grinder …/> element is added to the beginning of the config.xml-derived file to add specifications for the workloads that the Grinder agents will have. Here, the file, C:\grinder3_0\test1_script\grinder.properties, will be changed between tests so that its grinder.threads property will have values, 15, 50, 100, and 200.
The test automation code computes all permutations of these test values for the series of tests. See the InputParms.txt file below for an example of these permutations.
The order of appearance of an attribute in the XML file determines how fast the associated configuration settings will change for subsequent test in the series, just as bits to the right in a binary register toggle faster than bits to the left as you count up. In many cases when WebLogic configuration settings are changed, the app server must be re-started for the change to take affect. The test automation takes care of this re-start. Therefore, it’s best to place the <Grinder…/> element at the end, after all of the WebLogic configuration elements, to minimize the number of WebLogic server re-starts.
For each test in the series, its configuration settings (input parameters for the test) and its ending statistics are appended to two tab-delimited files. The names of the input parameters and statistics are recorded as well.
Input Parameter Files
The InputParmNames.txt file contains the names of Grinder workload and WebLogic configuration parameters for the tests as well as units of measure for charting purposes. For example below, “Grinder_Processes” is the name of an input parameter and its units of measure is “Agent Processes”. According to the configTarget.xml file above, its value in the next to last column of the InputParms.txt file discussed below will always be “1”. To make charting easier, “false” and “true” values such as for psServer_NativeIOEnabled are converted to “0” and “1” as in column 3 in the InputParms.txt file.
psServer_AcceptBacklog Messages
psServer_NativeIOEnabled 0/1 (No/Yes)
weblogic.kernel.Default_QueueLengthThresholdPercent Percent
weblogic.kernel.Default_ThreadCount Threads
Grinder_Processes Agent Processes
Grinder_Threads Agent Threads
The InputParms.txt file contains the values for each of the input parameters named in the InputParmNames.txt file above in columns. The first column contains the run number of the test. Here’s a partial listing of this file’s contents.
1 10 1 90 10 1 300
2 10 1 90 10 1 400
3 10 1 90 10 1 500
4 10 1 90 12 1 300
5 10 1 90 12 1 400
6 10 1 90 12 1 500
7 10 1 90 14 1 300
8 10 1 90 14 1 400
9 10 1 90 14 1 500
...
31 10 1 90 30 1 300
32 10 1 90 30 1 400
33 10 1 90 30 1 500
34 15 1 90 10 1 300
35 15 1 90 10 1 400
36 15 1 90 10 1 500
37 15 1 90 12 1 300
38 15 1 90 12 1 400
39 15 1 90 12 1 500
...
Statistics Files
The StatsNames.txt file contains the names of statistics presented in the Grinder Accumulated Test Statistics table in the Console Results Tab at the end of each test in the series. Here is an example:
Successful
tests Grinder transactions
Errors Grinder transactions
Mean
timeGrinder milliseconds
TPS Grinder transactions/second
Peak
TPS Grinder transactions/second
Mean
response length Grinder bytes/transaction
Response
bytes per second Grinder bytes/second
Response
errors Grinder transactions
Mean
time to resolve host Grinder milliseconds
This file is tab-delimited. The first column contains the name of the statistic. The word “Grinder” is inserted in the second column for charting purposes. The last column contains the unit of measure for the Grinder statistics, also used for chart scaling and labeling the Y axis.
The StatsMean.txt file contains the measured values for each of the statistics named in the StatsNames.txt file. There will be as many rows in this file as there are in the InputParms.txt file. Similarly, the first column contains the run number of the test.
1 1686102 593040.9115 14500 593000 0 1.68
2 16290 956040.5120 16000 647000 0 1.48
3 170929 12100 40.6102 17400 705000 0 0.427
4 178210 576042.379.014700 622000 0 0.788
5 17152 884041.5107 15900 660000 0 0.996
The contents of the input parameter and statistics files can be imported in to a spreadsheet for charting. Also, we’ve built a Java charting applet that will download these four files and chart the results in a browser. It requires the Java 1.5 plug-in. To see an example of these test results using the Java applet please visit, http://www.anser-e.com/run6/Run6a.html.
Grinder Version 3.0 beta 24 was used for these source code modifications. The following sections describe some development experiences, a functional overview and a sequence diagram and further discussion of the test series flow.
I started reusing source code in the net/grinder/console/swingui directory and the ConsoleUI class in particular. Some new Grinder test series objects were instantiated from existing classes, such as the ProcessControl, FileDistribution, and EditorModel classes below. Other Grinder classes were cloned and modified somewhat. For example FileTreeSUT for selecting the app server configuration file was cloned and modified from the existing FileTree class. I thought this would be the fastest approach and provide a level of isolation of new and existing functions. From the ConsoleUI.java file:
public final class
ConsoleUI implements ModelListener {
private final ProcessControl m_processControl;
private final ProcessControl m_process
SUTControl;
private final FileDistribution
m_fileDistribution;
private final FileDistribution
m_fileDistributionConfig;
private final EditorModel m_editorModel;
private final EditorModel m_editorModel
Config;
private final FileTree m_fileTree;
private final FileTreeSUT m_fileTreeConfig;
…
However, I found that I needed to go deeper into the code and create more similar classes and files such as my ‘ConsoleSUTCommunicationImplementation.java’ file derived from ‘net/grinder/console/ConsoleCommunicationImplementation.java’. I ended up going as far as modifying the ‘net/grinder/console/Console.java file, added lines such as these bolded ones:
public class Console
{
private final ConsoleCommunication
m_communication;
private final ConsoleCommunication m_
SUTcommunication;
...
public Console() throws GrinderException {
final ConsoleProperties properties =
new ConsoleProperties(resources,
new File(homeDirectory, ".grinder_console"));
final
ConsoleOtherProperties
otherProperties
=
new ConsoleOtherProperties(resources,
new File(homeDirectory, ".
grinder_console2"));
...
m_userInterface =
new ConsoleUI(m_model,
m_communication.getProcessControl(),
m_SUTcommunication.getProcessControl
(),
fileDistribution,
fileConfigDistribution
,
agentStatus);
This went on for longer that I would have liked, but now that it’s done I can live with the changes. It works for what I need. But I’m sure there is a more elegant approach for plug-in’s that would first involve some architecture changes.
Inputting XML Configuration
Data
The XML configuration template file selected in the Target Tab (described in Part 1) is parsed using the DOM API from these packages:
import
org.w3c.dom.*;
import
org.xml.sax.*;
Currently, only a subset of all attributes in a WebLogic config.xml file is supported. I can support others with only small amounts of additional coding as I need to test variations of other configuration parameters.
Creating and Executing
Configuration Permutations
As XML nodes are parsed and attributes are recognized, “ExecutableJMXCommand” objects are created and added to a list. The ExecutableJMXCommand class has members for WebLogicMBean objects and Method objects for verifying and setting WebLogic configuration parameters using the WebLogicMBean objects. During this discovery phase, the ServerMBean is found using MBeanHome’s getMBean method and other ConfigurationMBean’s are found from it. To complete the JMX command objects, the ranges of configuration values, which these JMX commands will use, are store with them as well.
There are <Grinder…/> elements in the XML file as well that are processed. They cause similar executable command objects to be created, but these commands modify a grinder.properties file, primarily changing the grinder.threads property value that determines a test’s workload.
Execution of JMX commands happens in a separate thread spawned by a “Start test series” menu item event. Once the entire XML file has been processed, the first JMX command object on the list is executed for the first configuration value in its range of values. The configuration value is recorded in an Input Parameters file. Then, other JMX command objects on the list are executed in turn until there are no more on the list. Their configuration values are appended to the same line in the Input Parameters file for a given test run. Going down this list is done in a recursive method. Once the bottom of the list is reached, the recursive method returns to its previous calling. There, it moves horizontal across to the next configuration value in a range for the JMX command object at that level. If there is another value in the range, the JMX Command at that recursion level is executed again with its new value and we go back down the recursion path. Each time we go back down, the JMX command that exhausted its range of values before starts over with its first configuration value.
Each time at the bottom of the recursion path, when all configuration parameters for a test have been set, the thread re-starts the WebLogic server. That is, if a re-start flag has been set somewhere along the way. This flag is set for any configuration change performed that requires the app server to be re-started. The thread waits until a connection has been re-established with the app server and then it signals a separate thread, which starts the Grinder agents.
Whenever there are no more values looking horizontally across configuration values in a range, we move back up the recursion path. When we get back to the top of the recession path, all permutations of configuration parameters and grinder workloads, and therefore all tests in the series, have been completed.
Starting Grinder Agents
Existing Grinder Console events are used to start a test for the new WebLogic server configuration and new Grinder agent workload. The separate thread mentioned above first fires the distribute files event. This passes the grinder.properties file with the new grinder.threads value to the agent(s). Then, the thread fires the start processes event to start the test and waits until it finishes.
A test in the series is finished when the specified number of samples is reached, as shown in the Console UI while the test is running. A listener callback signals this thread to wake up. At that point statistics from the CumulativeStatisticsTableModel object are read and written to the Statistics text file. Finally, this Grinder Process Control thread signals the JMX Command Process Control thread described above and the configuration process continues.
End of the Test Series
When the JMX Command thread finishes the last permutation of parameters and signals for the last test to run to completion, it returns to the top of the recursion path. As the last step before this thread terminates it sends an interrupt signal to the Grinder Process Control thread, which causes it to exit as well. This finishes the test series.
Alternatively, the Console user can click the “Stop test
series” menu item, which sends a StopSUTConfigAction event. This interrupts the
Grinder Process Control thread, which in turn interrupts the JMX Command
thread, causing both to terminate.
This sequence diagram depicts five threads of control as vertical dashed lines. The Grinder Console UI thread on the left causes the two additional threads for Grinder Agent control and JMX Process control to be spawned within the same Grinder Console JVM. The right two threads represent the Grinder agents running on a test driver machine and the WebLogic server on the system under test. Two additional dashed lines are included to show where reading the XML configuration file and writing Input Parameter and Statistics files happens in the flow, although these do not actually involve additional threads.
The horizontal block indicated by the green background color indicates the iterative setting of WebLogic configuration parameters followed by the communication with the Grinder agents and running the individual tests. Breaks in the vertical rectangles over the Grinder dashed lines indicate where a thread is blocked waiting for the active thread to relinquish control. Breaks in the flow for the WebLogic server indicate where the server has been terminated by the JMXProcessSeriesControl thread executing a ServerMBean stop() method. The WebLogic server start batch file, “startPetStoreWebLogic.cmd”, was modified to include an infinite loop to accomplish its re-start, as follows:
:
"%JAVA_HOME%\bin\java"
%JAVA_VM% %MEM_ARGS% %JAVA_OPTIONS% -Dweblogic.Name=%SERVER_NAME%
-Dweblogic.management.username=%WLS_USER% -Dweblogic.management.password=%WLS_PW% -Dweblogic.ProductionModeEnabled=%PRODUCTION_MODE%
-Djava.security.policy="%WL_HOME%\server\lib\weblogic.policy" weblogic.Server
GOTO
At the end of the test series, a Thread interrupt() method is used instead of a Thread notify() method to break out of an infinite loop in the GrinderProcessSeriesControl thread. Within the catch block for the InterruptException, StopAction and ResetProcessAction event are fired to terminate the Grinder agents’ workload.
Having access to Grinder source code made creation of a special version for testing the effects of WebLogic configuration settings possible. Having a Grinder API designed for plug-ins would make development easier. The advantages of the centralized control of the Grinder Console were retained while automation of its functions makes running a large number of tests feasible and less prone to error. A lot of additional work could be done to improve the test automation. Specifically, this includes 1) handling of WebLogic configuration settings that are not in the config.xml file or can’t be changed through JMX, 2) recovery from stoppage in the test series if a particular test hangs and 3) recording statistics for test components in addition to recording just the total statistics as presented in the Accumulated test statistics table.
Todd Nichols, Anser Enterprise
Copyright © 2014 Anser Enterprise