/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.jmeter.protocol.java.test;
import java.io.Serializable;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.Interruptible;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.testelement.TestElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The <code>JavaTest</code> class is a simple sampler which is intended for
* use when developing test plans. The sampler generates results internally, so
* does not need access to any external resources such as web, ftp or LDAP
* servers. In addition, because the exact values of most of the SampleResult
* can be directly set, it is possible to easily test most Assertions that use
* the sample results.
*
* <p>
* During each sample, this client will sleep for some amount of time. The
* amount of time to sleep is determined from the two parameters Sleep_Time and
* Sleep_Mask using the formula:
*
* <pre>
* totalSleepTime = Sleep_Time + (System.currentTimeMillis() % Sleep_Mask)
* </pre>
*
* Thus, the Sleep_Mask provides a way to add a random component to the sleep
* time.
* <p>
* The sampler is able to define the precise values of:
*
* <pre>
*
* - responseCode
* - responseMessage
* - Label
* - success/fail status
*
* </pre>
*
* The elapsed time and end-time cannot be directly controlled.
* <p>
* Note: this class was derived from {@link SleepTest}.
*
*/
public class JavaTest extends AbstractJavaSamplerClient implements Serializable, Interruptible {
private static final Logger LOG = LoggerFactory.getLogger(JavaTest.class);
private static final long serialVersionUID = 241L;
/** The base number of milliseconds to sleep during each sample. */
private long sleepTime;
/** The default value of the SleepTime parameter, in milliseconds. */
public static final long DEFAULT_SLEEP_TIME = 100;
/** The name used to store the SleepTime parameter. */
private static final String SLEEP_NAME = "Sleep_Time";
/**
* A mask to be applied to the current time in order to add a semi-random
* component to the sleep time.
*/
private long sleepMask;
/** The default value of the SleepMask parameter. */
public static final long DEFAULT_SLEEP_MASK = 0xff;
/** Formatted string representation of the default SleepMask. */
private static final String DEFAULT_MASK_STRING = "0x" + (Long.toHexString(DEFAULT_SLEEP_MASK)).toUpperCase(java.util.Locale.ENGLISH);
/** The name used to store the SleepMask parameter. */
private static final String MASK_NAME = "Sleep_Mask";
/** The label to store in the sample result. */
private String label;
/** The name used to store the Label parameter. */
private static final String LABEL_NAME = "Label";
/** The response message to store in the sample result. */
private String responseMessage;
/** The default value of the ResponseMessage parameter. */
private static final String RESPONSE_MESSAGE_DEFAULT = "";
/** The name used to store the ResponseMessage parameter. */
private static final String RESPONSE_MESSAGE_NAME = "ResponseMessage";
/** The response code to be stored in the sample result. */
private String responseCode;
/** The default value of the ResponseCode parameter. */
private static final String RESPONSE_CODE_DEFAULT = "";
/** The name used to store the ResponseCode parameter. */
private static final String RESPONSE_CODE_NAME = "ResponseCode";
/** The sampler data (shown as Request Data in the Tree display). */
private String samplerData;
/** The default value of the SamplerData parameter. */
private static final String SAMPLER_DATA_DEFAULT = "";
/** The name used to store the SamplerData parameter. */
private static final String SAMPLER_DATA_NAME = "SamplerData";
/** Holds the result data (shown as Response Data in the Tree display). */
private String resultData;
/** The default value of the ResultData parameter. */
private static final String RESULT_DATA_DEFAULT = "";
/** The name used to store the ResultData parameter. */
private static final String RESULT_DATA_NAME = "ResultData";
/** The success status to be stored in the sample result. */
private boolean success;
/** The default value of the Success Status parameter. */
private static final String SUCCESS_DEFAULT = "OK";
/** The name used to store the Success Status parameter. */
private static final String SUCCESS_NAME = "Status";
private transient volatile Thread myThread;
/**
* Default constructor for <code>JavaTest</code>.
*
* The Java Sampler uses the default constructor to instantiate an instance
* of the client class.
*/
public JavaTest() {
LOG.debug(whoAmI() + "\tConstruct");
}
/*
* Utility method to set up all the values
*/
private void setupValues(JavaSamplerContext context) {
sleepTime = context.getLongParameter(SLEEP_NAME, DEFAULT_SLEEP_TIME);
sleepMask = context.getLongParameter(MASK_NAME, DEFAULT_SLEEP_MASK);
responseMessage = context.getParameter(RESPONSE_MESSAGE_NAME, RESPONSE_MESSAGE_DEFAULT);
responseCode = context.getParameter(RESPONSE_CODE_NAME, RESPONSE_CODE_DEFAULT);
success = "OK".equalsIgnoreCase(context.getParameter(SUCCESS_NAME, SUCCESS_DEFAULT));
label = context.getParameter(LABEL_NAME, "");
if (label.length() == 0) {
label = context.getParameter(TestElement.NAME); // default to name of element
}
samplerData = context.getParameter(SAMPLER_DATA_NAME, SAMPLER_DATA_DEFAULT);
resultData = context.getParameter(RESULT_DATA_NAME, RESULT_DATA_DEFAULT);
}
/**
* Do any initialization required by this client.
*
* There is none, as it is done in runTest() in order to be able to vary the
* data for each sample.
*
* @param context
* the context to run with. This provides access to
* initialization parameters.
*/
@Override
public void setupTest(JavaSamplerContext context) {
if (LOG.isDebugEnabled()) {
LOG.debug(whoAmI() + "\tsetupTest()");
listParameters(context);
}
}
/**
* Provide a list of parameters which this test supports. Any parameter
* names and associated values returned by this method will appear in the
* GUI by default so the user doesn't have to remember the exact names. The
* user can add other parameters which are not listed here. If this method
* returns null then no parameters will be listed. If the value for some
* parameter is null then that parameter will be listed in the GUI with an
* empty value.
*
* @return a specification of the parameters used by this test which should
* be listed in the GUI, or null if no parameters should be listed.
*/
@Override
public Arguments getDefaultParameters() {
Arguments params = new Arguments();
params.addArgument(SLEEP_NAME, String.valueOf(DEFAULT_SLEEP_TIME));
params.addArgument(MASK_NAME, DEFAULT_MASK_STRING);
params.addArgument(LABEL_NAME, "");
params.addArgument(RESPONSE_CODE_NAME, RESPONSE_CODE_DEFAULT);
params.addArgument(RESPONSE_MESSAGE_NAME, RESPONSE_MESSAGE_DEFAULT);
params.addArgument(SUCCESS_NAME, SUCCESS_DEFAULT);
params.addArgument(SAMPLER_DATA_NAME, SAMPLER_DATA_DEFAULT);
params.addArgument(RESULT_DATA_NAME, SAMPLER_DATA_DEFAULT);
return params;
}
/**
* Perform a single sample.<br>
* In this case, this method will simply sleep for some amount of time.
*
* This method returns a <code>SampleResult</code> object.
*
* <pre>
*
* The following fields are always set:
* - responseCode (default "")
* - responseMessage (default "")
* - label (set from LABEL_NAME parameter if it exists, else element name)
* - success (default true)
*
* </pre>
*
* The following fields are set from the user-defined parameters, if
* supplied:
*
* <pre>
* -samplerData - responseData
* </pre>
*
* @see org.apache.jmeter.samplers.SampleResult#sampleStart()
* @see org.apache.jmeter.samplers.SampleResult#sampleEnd()
* @see org.apache.jmeter.samplers.SampleResult#setSuccessful(boolean)
* @see org.apache.jmeter.samplers.SampleResult#setSampleLabel(String)
* @see org.apache.jmeter.samplers.SampleResult#setResponseCode(String)
* @see org.apache.jmeter.samplers.SampleResult#setResponseMessage(String)
* @see org.apache.jmeter.samplers.SampleResult#setResponseData(byte[])
* @see org.apache.jmeter.samplers.SampleResult#setDataType(String)
*
* @param context
* the context to run with. This provides access to
* initialization parameters.
*
* @return a SampleResult giving the results of this sample.
*/
@Override
public SampleResult runTest(JavaSamplerContext context) {
setupValues(context);
SampleResult results = new SampleResult();
results.setResponseCode(responseCode);
results.setResponseMessage(responseMessage);
results.setSampleLabel(label);
if (samplerData != null && samplerData.length() > 0) {
results.setSamplerData(samplerData);
}
if(samplerData != null) {
results.setSentBytes(samplerData.length());
}
if (resultData != null && resultData.length() > 0) {
results.setResponseData(resultData, null);
}
results.setDataType(SampleResult.TEXT); // It's always text type even if empty
// Record sample start time.
results.sampleStart();
long sleep = sleepTime;
if (sleepTime > 0 && sleepMask > 0) { // / Only do the calculation if
// it is needed
long start = System.currentTimeMillis();
// Generate a random-ish offset value using the current time.
sleep = sleepTime + (start % sleepMask);
}
try {
// Execute the sample. In this case sleep for the
// specified time, if any
if (sleep > 0) {
myThread = Thread.currentThread();
TimeUnit.MILLISECONDS.sleep(sleep);
myThread = null;
}
results.setSuccessful(success);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LOG.warn("JavaTest: interrupted.");
results.setSuccessful(false);
} catch (Exception e) {
LOG.error("JavaTest: error during sample", e);
results.setSuccessful(false);
} finally {
// Record end time and populate the results.
results.sampleEnd();
}
if (LOG.isDebugEnabled()) {
LOG.debug(whoAmI() + "\trunTest()" + "\tTime:\t" + results.getTime());
listParameters(context);
}
return results;
}
/**
* Dump a list of the parameters in this context to the debug log.
* Should only be called if debug is enabled.
*
* @param context
* the context which contains the initialization parameters.
*/
private void listParameters(JavaSamplerContext context) {
Iterator<String> argsIt = context.getParameterNamesIterator();
while (argsIt.hasNext()) {
String name = argsIt.next();
LOG.debug(name + "=" + context.getParameter(name));
}
}
/**
* Generate a String identifier of this test for debugging purposes.
*
* @return a String identifier for this test instance
*/
private String whoAmI() {
StringBuilder sb = new StringBuilder();
sb.append(Thread.currentThread().toString());
sb.append("@");
sb.append(Integer.toHexString(hashCode()));
return sb.toString();
}
@Override
public boolean interrupt() {
Thread t = myThread;
if (t!= null) {
t.interrupt();
}
return t != null;
}
}