SampleResult.java
| Index Score | ||
|---|---|---|
![]() |
![]() |
org.apache.jmeter.samplers |
![]() |
![]() |
JMeter |
View: Reasons, Metrics, Source Code
These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.
/*
* 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.samplers;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.jmeter.assertions.AssertionResult;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.jorphan.util.JOrphanUtils;
import org.apache.log.Logger;
// For unit tests, @see TestSampleResult
/**
* This is a nice packaging for the various information returned from taking a
* sample of an entry.
*
*/
public class SampleResult implements Serializable {
public static final String DEFAULT_HTTP_ENCODING = "ISO-8859-1"; // $NON-NLS-1$
// Needs to be accessible from Test code
static final Logger log = LoggingManager.getLoggerForClass();
// Bug 33196 - encoding ISO-8859-1 is only suitable for Western countries
// However the suggested System.getProperty("file.encoding") is Cp1252 on
// Windows
// So use a new property with the original value as default
// needs to be accessible from test code
static final String DEFAULT_ENCODING
= JMeterUtils.getPropDefault("sampleresult.default.encoding", // $NON-NLS-1$
DEFAULT_HTTP_ENCODING);
/**
* Data type value indicating that the response data is text.
*
* @see #getDataType
* @see #setDataType(java.lang.String)
*/
public final static String TEXT = "text"; // $NON-NLS-1$
/**
* Data type value indicating that the response data is binary.
*
* @see #getDataType
* @see #setDataType(java.lang.String)
*/
public final static String BINARY = "bin"; // $NON-NLS-1$
/* empty arrays which can be returned instead of null */
private static final byte[] EMPTY_BA = new byte[0];
private static final SampleResult[] EMPTY_SR = new SampleResult[0];
private static final AssertionResult[] EMPTY_AR = new AssertionResult[0];
private SampleSaveConfiguration saveConfig;
private SampleResult parent = null;
/**
* @param propertiesToSave
* The propertiesToSave to set.
*/
public void setSaveConfig(SampleSaveConfiguration propertiesToSave) {
this.saveConfig = propertiesToSave;
}
public SampleSaveConfiguration getSaveConfig() {
return saveConfig;
}
private byte[] responseData = EMPTY_BA;
private String responseCode = "";// Never return null
private String label = "";// Never return null
private String resultFileName = ""; // Filename used by ResultSaver
private String samplerData;
private String threadName = ""; // Never return null
private String responseMessage = "";
private String responseHeaders = ""; // Never return null
private String contentType = ""; // e.g. text/html; charset=utf-8
private String requestHeaders = "";
// TODO timeStamp == 0 means either not yet initialised or no stamp available (e.g. when loading a results file)
private long timeStamp = 0;// the time stamp - can be start or end
private long startTime = 0;
private long endTime = 0;
private long idleTime = 0;// Allow for non-sample time
private long pauseTime = 0;// Start of pause (if any)
private List assertionResults;
private List subResults;
private String dataType=""; // Don't return null if not set
private boolean success;
private Set files; // files that this sample has been saved in
private String dataEncoding;// (is this really the character set?) e.g.
// ISO-8895-1, UTF-8
private static Method initNanoTimeMethod() {
try {
return System.class.getMethod("nanoTime", null);
} catch (NoSuchMethodException e) {
return null;
}
}
private static boolean haveNanoTime() {
return nanoTimeMethod != null;
}
private static long nanoTime() {
Long result = null;
try {
result = (Long) nanoTimeMethod.invoke(null, null);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
return result.longValue();
}
private static final Method nanoTimeMethod = initNanoTimeMethod();
// a reference time from the nanosecond clock
private static final long referenceTimeNsClock = haveNanoTime() ? sampleNsClockInMs() : Long.MIN_VALUE;
// a reference time from the millisecond clock
private static final long referenceTimeMsClock = System.currentTimeMillis();
private long time = 0; // elapsed time
private long latency = 0; // time to first response
private boolean stopThread = false; // Should thread terminate?
private boolean stopTest = false; // Should test terminate?
private boolean isMonitor = false;
private int sampleCount = 1;
private int bytes = 0; // Allows override of sample size in case sampler does not want to store all the data
private volatile int groupThreads = 0; // Active threads in this thread group
private volatile int allThreads = 0; // Active threads in all thread groups
// TODO do contentType and/or dataEncoding belong in HTTPSampleResult instead?
private final static String TOTAL_TIME = "totalTime"; // $NON-NLS-1$
private static final boolean startTimeStamp
= JMeterUtils.getPropDefault("sampleresult.timestamp.start", false); // $NON-NLS-1$
static {
if (startTimeStamp) {
log.info("Note: Sample TimeStamps are START times");
} else {
log.info("Note: Sample TimeStamps are END times");
}
log.info("sampleresult.default.encoding is set to " + DEFAULT_ENCODING);
}
public SampleResult() {
time = 0;
}
/**
* Construct a 'parent' result for an already-existing result, essentially
* cloning it
*
* @param res
* existing sample result
*/
public SampleResult(SampleResult res) {
//TODO - why not just copy all the fields? Do we need the calculations that some of the set() methods perform?
//TODO - why are the following not copied:
// assertionResults, bytes, idleTime, latency, parent,pauseTime,resultFileName,sampleCount,samplerData,saveConfig
// stopTest, stopThread, subResults,threadName
setStartTime(res.getStartTime());
setEndTime(res.getStartTime());
// was setElapsed(0) which is the same as setStartTime=setEndTime=now
setSampleLabel(res.getSampleLabel());
setRequestHeaders(res.getRequestHeaders());
setResponseData(res.getResponseData());
setResponseCode(res.getResponseCode());
setSuccessful(res.isSuccessful());
setResponseMessage(res.getResponseMessage());
setDataType(res.getDataType());
setResponseHeaders(res.getResponseHeaders());
setContentType(res.getContentType());
setDataEncoding(res.getDataEncodingNoDefault());
setURL(res.getURL());
setGroupThreads(res.getGroupThreads());
setAllThreads(res.getAllThreads());
addSubResult(res); // this will add res.getTime() to getTime().
}
public boolean isStampedAtStart() {
return startTimeStamp;
}
/**
* Create a sample with a specific elapsed time but don't allow the times to
* be changed later
*
* (only used by HTTPSampleResult)
*
* @param elapsed
* time
* @param atend
* create the sample finishing now, else starting now
*/
protected SampleResult(long elapsed, boolean atend) {
long now = currentTimeInMs();
if (atend) {
setTimes(now - elapsed, now);
} else {
setTimes(now, now + elapsed);
}
}
/**
* Create a sample with specific start and end times for test purposes, but
* don't allow the times to be changed later
*
* (used by StatVisualizerModel.Test)
*
* @param start
* start time
* @param end
* end time
*/
public static SampleResult createTestSample(long start, long end) {
SampleResult res = new SampleResult();
res.setStartTime(start);
res.setEndTime(end);
return res;
}
/**
* Create a sample with a specific elapsed time for test purposes, but don't
* allow the times to be changed later
*
* @param elapsed -
* desired elapsed time
*/
public static SampleResult createTestSample(long elapsed) {
long now = currentTimeInMs();
return createTestSample(now, now + elapsed);
}
/**
* Allow users to create a sample with specific timestamp and elapsed times
* for cloning purposes, but don't allow the times to be changed later
*
* Currently used by OldSaveService, CSVSaveService and StatisticalSampleResult
*
* @param stamp -
* this may be a start time or an end time
* @param elapsed
*/
public SampleResult(long stamp, long elapsed) {
stampAndTime(stamp, elapsed);
}
private static long sampleNsClockInMs() {
return nanoTime() / 1000000;
}
// Helper method to get 1 ms resolution timing.
public static long currentTimeInMs() {
if (haveNanoTime()) {
long elapsedInMs = sampleNsClockInMs() - referenceTimeNsClock;
return referenceTimeMsClock + elapsedInMs;
} else {
return System.currentTimeMillis();
}
}
// Helper method to maintain timestamp relationships
private void stampAndTime(long stamp, long elapsed) {
if (startTimeStamp) {
startTime = stamp;
endTime = stamp + elapsed;
} else {
startTime = stamp - elapsed;
endTime = stamp;
}
timeStamp = stamp;
time = elapsed;
}
/*
* For use by SaveService only.
*
* @param stamp -
* this may be a start time or an end time
* @param elapsed
*/
public void setStampAndTime(long stamp, long elapsed) {
if (startTime != 0 || endTime != 0){
throw new RuntimeException("Calling setStampAndTime() after start/end times have been set");
}
stampAndTime(stamp, elapsed);
}
/**
* Method to set the elapsed time for a sample. Retained for backward
* compatibility with 3rd party add-ons.
* It is assumed that the method is only called at the end of a sample
* and that timeStamps are end-times
*
* Also used by SampleResultConverter when creating results from files.
*
* Must not be used in conjunction with sampleStart()/End()
*
* @deprecated use sampleStart() and sampleEnd() instead
* @param elapsed
* time in milliseconds
*/
public void setTime(long elapsed) {
if (startTime != 0 || endTime != 0){
throw new RuntimeException("Calling setTime() after start/end times have been set");
}
long now = currentTimeInMs();
setTimes(now - elapsed, now);
}
public void setMarked(String filename) {
if (files == null) {
files = new HashSet();
}
files.add(filename);
}
public boolean isMarked(String filename) {
return files != null && files.contains(filename);
}
public String getResponseCode() {
return responseCode;
}
private static final String OK = Integer.toString(HttpURLConnection.HTTP_OK);
/**
* Set response code to OK, i.e. "200"
*
*/
public void setResponseCodeOK(){
responseCode=OK;
}
public void setResponseCode(String code) {
responseCode = code;
}
public boolean isResponseCodeOK(){
return responseCode.equals(OK);
}
public String getResponseMessage() {
return responseMessage;
}
public void setResponseMessage(String msg) {
responseMessage = msg;
}
public void setResponseMessageOK() {
responseMessage = "OK"; // $NON-NLS-1$
}
public String getThreadName() {
return threadName;
}
public void setThreadName(String threadName) {
this.threadName = threadName;
}
/**
* Get the sample timestamp, which may be either the start time or the end time.
*
* @see #getStartTime()
* @see #getEndTime()
*
* @return timeStamp in milliseconds
*/
public long getTimeStamp() {
return timeStamp;
}
public String getSampleLabel() {
return label;
}
/**
* Get the sample label for use in summary reports etc.
*
* @param includeGroup whether to include the thread group name
* @return the label
*/
public String getSampleLabel(boolean includeGroup) {
if (includeGroup) {
StringBuffer sb = new StringBuffer(threadName.substring(0,threadName.lastIndexOf(" "))); //$NON-NLS-1$
return sb.append(":").append(label).toString(); //$NON-NLS-1$
}
return label;
}
public void setSampleLabel(String label) {
this.label = label;
}
public void addAssertionResult(AssertionResult assertResult) {
if (assertionResults == null) {
assertionResults = new ArrayList();
}
assertionResults.add(assertResult);
}
/**
* Gets the assertion results associated with this sample.
*
* @return an array containing the assertion results for this sample.
* Returns empty array if there are no assertion results.
*/
public AssertionResult[] getAssertionResults() {
if (assertionResults == null) {
return EMPTY_AR;
}
return (AssertionResult[]) assertionResults.toArray(new AssertionResult[0]);
}
public void addSubResult(SampleResult subResult) {
String tn = getThreadName();
if (tn.length()==0) {
tn=Thread.currentThread().getName();//TODO do this more efficiently
this.setThreadName(tn);
}
subResult.setThreadName(tn);
if (subResults == null) {
subResults = new ArrayList();
}
subResults.add(subResult);
// Extend the time to the end of the added sample
setEndTime(Math.max(getEndTime(), subResult.getEndTime()));
// Include the byte count for the added sample
setBytes(getBytes() + subResult.getBytes());
subResult.setParent(this);
}
/**
* Add a subresult read from a results file.
*
* As for addSubResult(), except that the fields don't need to be accumulated
*
* @param subResult
*/
public void storeSubResult(SampleResult subResult) {
if (subResults == null) {
subResults = new ArrayList();
}
subResults.add(subResult);
subResult.setParent(this);
}
/**
* Gets the subresults associated with this sample.
*
* @return an array containing the subresults for this sample. Returns an
* empty array if there are no subresults.
*/
public SampleResult[] getSubResults() {
if (subResults == null) {
return EMPTY_SR;
}
return (SampleResult[]) subResults.toArray(new SampleResult[0]);
}
public void configure(Configuration info) {
time = info.getAttributeAsLong(TOTAL_TIME, 0L);
}
/**
* Sets the responseData attribute of the SampleResult object.
*
* If the parameter is null, then the responseData is set to an empty byte array.
* This ensures that getResponseData() can never be null.
*
* @param response
* the new responseData value
*/
public void setResponseData(byte[] response) {
responseData = response == null ? EMPTY_BA : response;
}
/**
* Sets the responseData attribute of the SampleResult object.
*
* @param response
* the new responseData value (String)
*
* @deprecated - only intended for use from BeanShell code
*/
public void setResponseData(String response) {
responseData = response.getBytes();
}
/**
* Gets the responseData attribute of the SampleResult object.
* <p>
* Note that some samplers may not store all the data, in which case
* getResponseData().length will be incorrect.
*
* Instead, always use {@link #getBytes()} to obtain the sample result byte count.
* </p>
* @return the responseData value (cannot be null)
*/
public byte[] getResponseData() {
return responseData;
}
/**
* Gets the responseData of the SampleResult object as a String
*
* @return the responseData value as a String, converted according to the encoding
*/
public String getResponseDataAsString() {
try {
return new String(responseData,getDataEncodingWithDefault());
} catch (UnsupportedEncodingException e) {
log.warn("Using platform default as "+getDataEncodingWithDefault()+" caused "+e);
return new String(responseData);
}
}
public void setSamplerData(String s) {
samplerData = s;
}
public String getSamplerData() {
return samplerData;
}
/**
* Get the time it took this sample to occur.
*
* @return elapsed time in milliseonds
*
*/
public long getTime() {
return time;
}
public boolean isSuccessful() {
return success;
}
public void setDataType(String dataType) {
this.dataType = dataType;
}
public String getDataType() {
return dataType;
}
/**
* Set Encoding and DataType from ContentType
* @param ct - content type (may be null)
*/
public void setEncodingAndType(String ct){
if (ct != null) {
// Extract charset and store as DataEncoding
// N.B. The meta tag:
// <META http-equiv="content-type" content="text/html; charset=foobar">
// is now processed by HTTPSampleResult#getDataEncodingWithDefault
final String CS_PFX = "charset="; // $NON-NLS-1$
int cset = ct.toLowerCase(java.util.Locale.ENGLISH).indexOf(CS_PFX);
if (cset >= 0) {
// TODO - assumes charset is not followed by anything else
String charSet = ct.substring(cset + CS_PFX.length());
// Check for quoted string
if (charSet.startsWith("\"")){ // $NON-NLS-1$
setDataEncoding(charSet.substring(1, charSet.length()-1)); // remove quotes
} else {
setDataEncoding(charSet);
}
}
if (isBinaryType(ct)) {
setDataType(BINARY);
} else {
setDataType(TEXT);
}
}
}
// List of types that are known to be binary
private static final String[] BINARY_TYPES = {
"image/", //$NON-NLS-1$
"audio/", //$NON-NLS-1$
"video/", //$NON-NLS-1$
};
/*
* Determine if content-type is known to be binary, i.e. not displayable as text.
*
* @param ct content type
* @return true if content-type is of type binary.
*/
private static boolean isBinaryType(String ct){
for (int i = 0; i < BINARY_TYPES.length; i++){
if (ct.startsWith(BINARY_TYPES[i])){
return true;
}
}
return false;
}
/**
* Sets the successful attribute of the SampleResult object.
*
* @param success
* the new successful value
*/
public void setSuccessful(boolean success) {
this.success = success;
}
/**
* Returns the display name.
*
* @return display name of this sample result
*/
public String toString() {
return getSampleLabel();
}
/**
* Returns the dataEncoding or the default if no dataEncoding was provided
*
* @deprecated use getDataEncodingWithDefault() or getDataEncodingNoDefault() as needed.
*/
public String getDataEncoding() {
if (dataEncoding != null) {
return dataEncoding;
}
return DEFAULT_ENCODING;
}
/**
* Returns the dataEncoding or the default if no dataEncoding was provided
*/
public String getDataEncodingWithDefault() {
if (dataEncoding != null && dataEncoding.length() > 0) {
return dataEncoding;
}
return DEFAULT_ENCODING;
}
/**
* Returns the dataEncoding or the default if no dataEncoding was provided
*/
public String getDataEncodingNoDefault() {
return dataEncoding;
}
/**
* Sets the dataEncoding.
*
* @param dataEncoding
* the dataEncoding to set, e.g. ISO-8895-1, UTF-8
*/
public void setDataEncoding(String dataEncoding) {
this.dataEncoding = dataEncoding;
}
/**
* @return whether to stop the test
*/
public boolean isStopTest() {
return stopTest;
}
/**
* @return whether to stop this thread
*/
public boolean isStopThread() {
return stopThread;
}
/**
* @param b
*/
public void setStopTest(boolean b) {
stopTest = b;
}
/**
* @param b
*/
public void setStopThread(boolean b) {
stopThread = b;
}
/**
* @return the request headers
*/
public String getRequestHeaders() {
return requestHeaders;
}
/**
* @return the response headers
*/
public String getResponseHeaders() {
return responseHeaders;
}
/**
* @param string -
* request headers
*/
public void setRequestHeaders(String string) {
requestHeaders = string;
}
/**
* @param string -
* response headers
*/
public void setResponseHeaders(String string) {
responseHeaders = string;
}
/**
* @return the full content type - e.g. text/html [;charset=utf-8 ]
*/
public String getContentType() {
return contentType;
}
/**
* Get the media type from the Content Type
* @return the media type - e.g. text/html (without charset, if any)
*/
public String getMediaType() {
return JOrphanUtils.trim(contentType," ;").toLowerCase(java.util.Locale.ENGLISH);
}
/**
* @param string
*/
public void setContentType(String string) {
contentType = string;
}
/**
* @return idleTime
*/
public long getIdleTime() {
return idleTime;
}
/**
* @return the end time
*/
public long getEndTime() {
return endTime;
}
/**
* @return the start time
*/
public long getStartTime() {
return startTime;
}
/*
* Helper methods N.B. setStartTime must be called before setEndTime
*
* setStartTime is used by HTTPSampleResult to clone the parent sampler and
* allow the original start time to be kept
*/
protected final void setStartTime(long start) {
startTime = start;
if (startTimeStamp) {
timeStamp = startTime;
}
}
protected void setEndTime(long end) {
endTime = end;
if (!startTimeStamp) {
timeStamp = endTime;
}
if (startTime == 0) {
log.error("setEndTime must be called after setStartTime", new Throwable("Invalid call sequence"));
// TODO should this throw an error?
} else {
time = endTime - startTime - idleTime;
}
}
private void setTimes(long start, long end) {
setStartTime(start);
setEndTime(end);
}
/**
* Record the start time of a sample
*
*/
public void sampleStart() {
if (startTime == 0) {
setStartTime(currentTimeInMs());
} else {
log.error("sampleStart called twice", new Throwable("Invalid call sequence"));
}
}
/**
* Record the end time of a sample and calculate the elapsed time
*
*/
public void sampleEnd() {
if (endTime == 0) {
setEndTime(currentTimeInMs());
} else {
log.error("sampleEnd called twice", new Throwable("Invalid call sequence"));
}
}
/**
* Pause a sample
*
*/
public void samplePause() {
if (pauseTime != 0) {
log.error("samplePause called twice", new Throwable("Invalid call sequence"));
}
pauseTime = currentTimeInMs();
}
/**
* Resume a sample
*
*/
public void sampleResume() {
if (pauseTime == 0) {
log.error("sampleResume without samplePause", new Throwable("Invalid call sequence"));
}
idleTime += currentTimeInMs() - pauseTime;
pauseTime = 0;
}
/**
* When a Sampler is working as a monitor
*
* @param monitor
*/
public void setMonitor(boolean monitor) {
isMonitor = monitor;
}
/**
* If the sampler is a monitor, method will return true.
*
* @return true if the sampler is a monitor
*/
public boolean isMonitor() {
return isMonitor;
}
/**
* For the JMS sampler, it can perform multiple samples for greater degree
* of accuracy.
*
* @param count
*/
public void setSampleCount(int count) {
sampleCount = count;
}
/**
* return the sample count. by default, the value is 1.
*
* @return the sample count
*/
public int getSampleCount() {
return sampleCount;
}
/**
* Returns the count of errors.
*
* @return 0 - or 1 if the sample failed
*/
public int getErrorCount(){
return success ? 0 : 1;
}
public void setErrorCount(int i){// for reading from CSV files
// ignored currently
}
/*
* TODO: error counting needs to be sorted out after 2.3 final.
* At present the Statistical Sampler tracks errors separately
* It would make sense to move the error count here, but this would
* mean lots of changes.
* It's also tricky maintaining the count - it can't just be incremented/decremented
* when the success flag is set as this may be done multiple times.
* The work-round for now is to do the work in the StatisticalSampleResult,
* which overrides this method.
* Note that some JMS samplers also create samples with > 1 sample count
* Also the Transaction Controller probably needs to be changed to do
* proper sample and error accounting.
* The purpose of this work-round is to allow at least minimal support for
* errors in remote statistical batch mode.
*
*/
/**
* In the event the sampler does want to pass back the actual contents, we
* still want to calculate the throughput. The bytes is the bytes of the
* response data.
*
* @param length
*/
public void setBytes(int length) {
bytes = length;
}
/**
* return the bytes returned by the response.
*
* @return byte count
*/
public int getBytes() {
return bytes == 0 ? responseData.length : bytes;
}
/**
* @return Returns the latency.
*/
public long getLatency() {
return latency;
}
/**
* Set the time to the first response
*
*/
public void latencyEnd() {
latency = currentTimeInMs() - startTime - idleTime;
}
/**
* This is only intended for use by SampleResultConverter!
*
* @param latency
* The latency to set.
*/
public void setLatency(long latency) {
this.latency = latency;
}
/**
* This is only intended for use by SampleResultConverter!
*
* @param timeStamp
* The timeStamp to set.
*/
public void setTimeStamp(long timeStamp) {
this.timeStamp = timeStamp;
}
private URL location;
public void setURL(URL location) {
this.location = location;
}
public URL getURL() {
return location;
}
/**
* Get a String representation of the URL (if defined).
*
* @return ExternalForm of URL, or empty string if url is null
*/
public String getUrlAsString() {
return location == null ? "" : location.toExternalForm();
}
/**
* @return Returns the parent.
*/
public SampleResult getParent() {
return parent;
}
/**
* @param parent
* The parent to set.
*/
public void setParent(SampleResult parent) {
this.parent = parent;
}
public String getResultFileName() {
return resultFileName;
}
public void setResultFileName(String resultFileName) {
this.resultFileName = resultFileName;
}
public int getGroupThreads() {
return groupThreads;
}
public void setGroupThreads(int n) {
this.groupThreads = n;
}
public int getAllThreads() {
return allThreads;
}
public void setAllThreads(int n) {
this.allThreads = n;
}
}
The table below shows all metrics for SampleResult.java.




