Skip to content

Commit

Permalink
#535: No measurements after resetting the web client (#536)
Browse files Browse the repository at this point in the history
* When resetting the Web client, make sure the JavaScript engine and Web connection are recreated using XLT classes.

* Renamed setUp methods to avoid confusion with regular setter methods.
  • Loading branch information
jowerner authored Nov 21, 2024
1 parent ed53f2e commit 6eb3df7
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 65 deletions.
159 changes: 98 additions & 61 deletions src/main/java/com/xceptance/xlt/engine/XltWebClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -314,38 +314,9 @@ public XltWebClient(final BrowserVersion browserVersion, final boolean javaScrip
cssMode = CssMode.getMode(props.getProperty("com.xceptance.xlt.css.download.images"));

// JavaScript
if (javaScriptEngineEnabled)
{
// setup JavaScript engine
int optimizationLevel = props.getProperty("com.xceptance.xlt.js.compiler.optimizationLevel", -1);
if (optimizationLevel < -1 || optimizationLevel > 9)
{
XltLogger.runTimeLogger.warn("Property 'com.xceptance.xlt.js.compiler.optimizationLevel' is set to an invalid value. Will use -1 instead.");
optimizationLevel = -1;
}

final boolean takeMeasurements = props.getProperty("com.xceptance.xlt.js.takeMeasurements", false);

setJavaScriptEngine(new XltJavaScriptEngine(this, optimizationLevel, takeMeasurements));
getOptions().setJavaScriptEnabled(props.getProperty("com.xceptance.xlt.javaScriptEnabled", false));
getOptions().setThrowExceptionOnScriptError(props.getProperty("com.xceptance.xlt.stopTestOnJavaScriptErrors", false));

// setup JavaScript debugger
if (props.getProperty("com.xceptance.xlt.js.debugger.enabled", false))
{
setJavaScriptDebuggerEnabled(true);

// create JS beautifying response processor only when needed
if (props.getProperty("com.xceptance.xlt.js.debugger.beautifyDownloadedJavaScript", true))
{
jsBeautifier = new JSBeautifingResponseProcessor();
}
}
}
else
{
getOptions().setJavaScriptEnabled(false);
}
getOptions().setJavaScriptEnabled(props.getProperty("com.xceptance.xlt.javaScriptEnabled", false));
getOptions().setThrowExceptionOnScriptError(props.getProperty("com.xceptance.xlt.stopTestOnJavaScriptErrors", false));
configureJavaScriptEngine(props);

// default user authentication
final String userName = props.getProperty("com.xceptance.xlt.auth.userName");
Expand Down Expand Up @@ -448,36 +419,30 @@ public XltWebClient(final BrowserVersion browserVersion, final boolean javaScrip
getOptions().setHistorySizeLimit(historySizeLimit);

// set web connection
final WebConnection underlyingWebConnection;
if (props.getProperty("com.xceptance.xlt.http.offline", false))
{
// we are in offline mode and return fixed responses
underlyingWebConnection = new XltOfflineWebConnection();
}
else
{
final String client = props.getProperty("com.xceptance.xlt.http.client");
final boolean collectTargetIpAddress = ((XltPropertiesImpl) props).collectUsedIpAddress();
if ("okhttp3".equals(client))
{
final boolean http2Enabled = props.getProperty("com.xceptance.xlt.http.client.okhttp3.http2Enabled", true);
underlyingWebConnection = new OkHttp3WebConnection(this, http2Enabled, collectTargetIpAddress);
}
else
{
// the default connection
underlyingWebConnection = new XltApacheHttpWebConnection(this, collectTargetIpAddress);
}
}
configureWebConnection(props);

XltLogger.runTimeLogger.debug("Using web connection class: " + underlyingWebConnection.getClass().getName());
// load key/trust material for client/server authentication
configureKeyStore(props);
configureTrustStore(props);
}

final XltHttpWebConnection connection = new XltHttpWebConnection(this, underlyingWebConnection);
setWebConnection(connection);
/**
* {@inheritDoc}
*/
@Override
public void reset()
{
super.reset();

// load key/trust material for client/server authentication
setUpKeyStore(props);
setUpTrustStore(props);
final XltProperties props = XltProperties.getInstance();

// create a new instance of "our" JavaScript engine if needed
configureJavaScriptEngine(props);

// create a new instance of "our" web connection
configureWebConnection(props);

pageLocalCache.clear();
}

/**
Expand Down Expand Up @@ -2059,14 +2024,86 @@ else if (s.equals("resync"))
}
}

/**
* Sets up the JavaScript engine to be used by this web client.
*
* @param props
* the configuration
*/
private void configureJavaScriptEngine(final XltProperties props)
{
if (isJavaScriptEngineEnabled())
{
// setup JavaScript engine
int optimizationLevel = props.getProperty("com.xceptance.xlt.js.compiler.optimizationLevel", -1);
if (optimizationLevel < -1 || optimizationLevel > 9)
{
XltLogger.runTimeLogger.warn("Property 'com.xceptance.xlt.js.compiler.optimizationLevel' is set to an invalid value. Will use -1 instead.");
optimizationLevel = -1;
}

final boolean takeMeasurements = props.getProperty("com.xceptance.xlt.js.takeMeasurements", false);

setJavaScriptEngine(new XltJavaScriptEngine(this, optimizationLevel, takeMeasurements));

// setup JavaScript debugger
if (props.getProperty("com.xceptance.xlt.js.debugger.enabled", false))
{
setJavaScriptDebuggerEnabled(true);

// create JS beautifying response processor only when needed
if (props.getProperty("com.xceptance.xlt.js.debugger.beautifyDownloadedJavaScript", true))
{
jsBeautifier = new JSBeautifingResponseProcessor();
}
}
}
}

/**
* Sets up the web connection to be used by this web client.
*
* @param props
* the configuration
*/
private void configureWebConnection(final XltProperties props)
{
final WebConnection underlyingWebConnection;
if (props.getProperty("com.xceptance.xlt.http.offline", false))
{
// we are in offline mode and return fixed responses
underlyingWebConnection = new XltOfflineWebConnection();
}
else
{
final String client = props.getProperty("com.xceptance.xlt.http.client");
final boolean collectTargetIpAddress = ((XltPropertiesImpl) props).collectUsedIpAddress();
if ("okhttp3".equals(client))
{
final boolean http2Enabled = props.getProperty("com.xceptance.xlt.http.client.okhttp3.http2Enabled", true);
underlyingWebConnection = new OkHttp3WebConnection(this, http2Enabled, collectTargetIpAddress);
}
else
{
// the default connection
underlyingWebConnection = new XltApacheHttpWebConnection(this, collectTargetIpAddress);
}
}

XltLogger.runTimeLogger.debug("Using web connection class: " + underlyingWebConnection.getClass().getName());

final XltHttpWebConnection connection = new XltHttpWebConnection(this, underlyingWebConnection);
setWebConnection(connection);
}

/**
* Sets up the key store with the client key to be used by this web client. The store is read from a file specified
* in the test suite configuration.
*
* @param props
* the configuration
*/
private void setUpKeyStore(final XltProperties props)
private void configureKeyStore(final XltProperties props)
{
final String storeFilePath = props.getProperty("com.xceptance.xlt.tls.keyStore.file");
if (StringUtils.isNotBlank(storeFilePath))
Expand All @@ -2086,7 +2123,7 @@ private void setUpKeyStore(final XltProperties props)
* @param props
* the configuration
*/
private void setUpTrustStore(final XltProperties props)
private void configureTrustStore(final XltProperties props)
{
final String storeFilePath = props.getProperty("com.xceptance.xlt.tls.trustStore.file");
if (StringUtils.isNotBlank(storeFilePath))
Expand Down
36 changes: 32 additions & 4 deletions src/test/java/com/xceptance/xlt/engine/XltWebClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@

import org.htmlunit.BrowserVersion;
import org.htmlunit.MockWebConnection;
import org.htmlunit.WebConnection;
import org.htmlunit.WebResponse;
import org.htmlunit.javascript.AbstractJavaScriptEngine;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
Expand Down Expand Up @@ -203,16 +205,42 @@ private void checkBrowserVersion(final String key, final BrowserVersion expected
}
}

@Test
public void testReset()
{
try (final XltWebClient webClient = new XltWebClient(BrowserVersion.BEST_SUPPORTED, true))
{
// prevalidation
final WebConnection webConnection = webClient.getWebConnection();
final AbstractJavaScriptEngine<?> javaScriptEngine = webClient.getJavaScriptEngine();

Assert.assertEquals("Unexpected WebConnection class", XltHttpWebConnection.class, webConnection.getClass());
Assert.assertEquals("Unexpected JavaScriptEngine class", XltJavaScriptEngine.class, javaScriptEngine.getClass());

// reset
webClient.reset();

// validate that web connection and javascript engine are still XLT classes, but different objects
final WebConnection newWebConnection = webClient.getWebConnection();
final AbstractJavaScriptEngine<?> newJavaScriptEngine = webClient.getJavaScriptEngine();

Assert.assertEquals("Unexpected WebConnection class", XltHttpWebConnection.class, newWebConnection.getClass());
Assert.assertEquals("Unexpected JavaScriptEngine class", XltJavaScriptEngine.class, newJavaScriptEngine.getClass());

Assert.assertNotEquals("WebConnection is the same as before", webConnection, newWebConnection);
Assert.assertNotEquals("JavaScriptEngine is the same as before", javaScriptEngine, newJavaScriptEngine);
}
}

/**
* Response processor which simple stores the request URLs.
*/
static class URLCollector implements ResponseProcessor
{
/**
* Collected URLs.
* This has to be a synchronized set because some of the processing runs in another thread and hence
* we might experiencene false sharing otherwise, mainly because a response processor is not designed
* to be a data collector
* Collected URLs. This has to be a synchronized set because some of the processing runs in another thread and
* hence we might experiencene false sharing otherwise, mainly because a response processor is not designed to
* be a data collector
*/
private final Set<URL> urls = Collections.synchronizedSet(new HashSet<URL>());

Expand Down

0 comments on commit 6eb3df7

Please sign in to comment.