htmlunit javascript performance - performance

I made a performance test of htmlunit against selenium with firefoxdriver and firefox 21.
The performance test was made on my windows7 machine through Eclipse.
When both have javascript disabled, the performance is the same. When both have javascript turned on htmlunit 2.12 is 150% slower than firefox.
I imagine that this is due the superiority of the spidermonkey engine on rhino.
Is there a way to configure rhino that it will be faster?
Is there anpther way we can speed htmlunit up?
package utils;
import java.io.IOException;
import java.net.MalformedURLException;
import java.text.DateFormat;
import java.util.Date;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxProfile;
import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
public class PerformanceTest {
public static void main(String[] args) {
String[] urls = new String[] {
...
};
Date beforeSelenium = new Date();
System.out.println("Going to run selenium");
testSelenium(urls);
Date afterSelenium = new Date();
Date beforehtmlUnit= new Date();
System.out.println("Going to run htmlunit");
testHtmlUnit(urls);
Date afterhtmlUnit = new Date();
System.out.println(
DateFormat.getTimeInstance(DateFormat.LONG).format(beforeSelenium));
System.out.println(
DateFormat.getTimeInstance(DateFormat.LONG).format(afterSelenium));
System.out.println(
DateFormat.getTimeInstance(DateFormat.LONG).format(beforehtmlUnit));
System.out.println(
DateFormat.getTimeInstance(DateFormat.LONG).format(afterhtmlUnit));
}
public static void testSelenium(String[] urls) {
WebDriver driver = new FirefoxDriver();
int i=0;
for(String url:urls) {
i++;
System.out.println(i);
// And now use this to visit Google
driver.get(url);
String str = driver.getPageSource();
System.out.println(str);
}
driver.close();
}
public static void testHtmlUnit(String[] urls) {
WebClient client = new WebClient(BrowserVersion.FIREFOX_17);
client.getOptions().setJavaScriptEnabled(true);
client.getOptions().setRedirectEnabled(true);
client.getOptions().setThrowExceptionOnScriptError(false);
client.getOptions().setCssEnabled(true);
client.getOptions().setUseInsecureSSL(true);
client.getOptions().setThrowExceptionOnFailingStatusCode(false);
int i=0;
for(String url:urls) {
i++;
System.out.println(i);
// And now use this to visit Google
HtmlPage page;
try {
page = client.getPage(url);
String str = page.asText();
System.out.println(str);
} catch (FailingHttpStatusCodeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

HtmlUnit use a modified, repacked Rhino JavaScript engine. By default is used a interpreter mode. You can enable JavaScript optimization. Then the JavaScript will be compiled to Java byte code.
WebClient webClient = new WebClient();
JavaScriptEngine sriptEngine = webClient.getJavaScriptEngine();
HtmlUnitContextFactory factory = sriptEngine.getContextFactory();
Context context = factory.enterContext();
context.setOptimizationLevel(9);
But this must not speed up your page. It can also slow down it.

The JS engine is the major problem on HtmlUnit performance.
There are some options:
Change Rhino Optimization Settings
Write Rhino Optimized Javascript (hardly it will be enough).
Adapt an external engine (like Chromium).
Wait for Nashorn.
Switch to PhantomJs.

Related

Mockito Unit Test with HTTPUrlConnection

I wrote code in our Spring Boot 2 application to make a third-party API call with HTTPUrlConnection.
public String loginApi(LoginDTO loginDto)
{
String responseData = null;
HttpURLConnection conn = null;
try {
link = authBaseUrl + loginUrl;
url = new URL(link);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty(CONTENT_TYPE, MEDIA_TYPE);
String body = getAuth0LoginDto(loginDto);
// =====================
// For POST only - START
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
os.write(body.getBytes(StandardCharsets.UTF_8));
os.flush();
os.close();
// For POST only - END
// ====================
try (BufferedReader br = (conn.getResponseCode() >= 400
? new BufferedReader(new InputStreamReader(conn.getErrorStream()))
: new BufferedReader(new InputStreamReader(conn.getInputStream())))) {
StringBuilder everything = new StringBuilder();
String output = null;
while ((output = br.readLine()) != null) {
everything.append(output);
}
responseData = everything.toString();
}
} catch (JsonProcessingException e) {
throw new Auth0Exception("Could not create Auth0 Login Body", e);
} catch (IOException e) {
throw new Auth0Exception("Error with Login API", e);
} finally {
if (conn != null) {
conn.disconnect();
}
}
return responseData;
}
Now, I am very much used to doing real integration testing, where I make a real call to the web-service and check the results.
I am now being asked to use strictly Mockito, not PowerMockito, not EasyMock, to create mocking tests, and I have never done that before. My knowledge of Mockito is weak also since I haven't used it in a very long time.
So, I know it has been asked before, and I have really searched on the internet, and I really haven't found a full piece of code as an example. I see code snippets which leaves me with pieces missing, and I am not knowledgeable enough to add those parts myself.
I know this code actual implementation works fine, and the integration test works fine also. But, what I have seen before is that some users are being told they need to change their client code in order to make the mockito tests work.
If I don't get the mocking tests working for HTTPUrlConnection, then I'll be forced to switch over to RestTemplate and Mocking since my co-worker insists we use RestTemplate anyway.
Thanks!
Since you have asked for a small example which does not make sense but should show the idea:
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.HttpURLConnection;
import java.net.URL;
public class App {
public int status(URL url) {
HttpURLConnection urlConnection = null;
try {
urlConnection = create(url);
return urlConnection.getResponseCode();
} catch (IOException e) {
throw new UncheckedIOException(e);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
}
HttpURLConnection create(URL url) throws IOException {
return (HttpURLConnection) url.openConnection();
}
}
I would implement this with a spy and as I recommended a mocked HttpURLConnection:
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
#ExtendWith(MockitoExtension.class)
class AppTest {
#Spy
App app;
#Mock
HttpURLConnection connection;
#Test
void status() throws IOException {
int expected = 200;
doReturn(connection).when(app).create(any());
doReturn(expected).when(connection).getResponseCode();
URL url = new URL("http://www.google.ats");
int status = app.status(url);
Assertions.assertEquals(expected, status);
}
}

Extracting information from XML-Files by URL-Source takes a lot of time

I would like to extract specific information from 108 Xml files. The general source is also a XML-File with further URLs as resources.
XML-Source
The static method getURL() extracts the URLs in order to set them as URL-paths within a for loop in the main method. The programm works, but it takes approx. 5 minutes to get the data from all files. Any ideas how to increase the performance?
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.Namespace;
import org.jdom2.filter.Filters;
import org.jdom2.input.SAXBuilder;
import org.jdom2.xpath.XPathExpression;
import org.jdom2.xpath.XPathFactory;
public class XmlReader2 {
public static void main(String[] args) throws IOException {
for (int i = 0; i < getURL().size(); i++) {
URL url = new URL(getURL().get(i));
try {
Document doc = new SAXBuilder().build(url);
final String getDeath = String
.format("//ns:teiHeader/ns:profileDesc/ns:particDesc/ns:listPerson/ns:person/ns:death");
XPathExpression<Element> xpath = XPathFactory.instance().compile(getDeath, Filters.element(), null,
Namespace.getNamespace("ns", "http://www.tei-c.org/ns/1.0"));
String test;
for (Element elem : xpath.evaluate(doc)) {
test = elem.getValue();
if (elem.getAttributes().size() != 0) {
test = elem.getAttributes().get(0).getValue();
}
System.out.println(elem.getName() + ": " + test);
}
} catch (org.jdom2.JDOMException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static List<String> getURL() throws IOException {
List<String> urlList = new ArrayList<>();
URL urlSource = new URL("http://www.steinheim-institut.de:80/cgi-bin/epidat?info=resources-mz1");
try {
Document doc = new SAXBuilder().build(urlSource);
final String getURL = String.format("/collection");
XPathExpression<Element> xpath = XPathFactory.instance().compile(getURL, Filters.element());
int i = 0;
for (Element elem : xpath.evaluate(doc)) {
while (i != elem.getChildren().size()) {
String url = elem.getChildren().get(i).getAttributes().get(1).getValue();
// System.out.println(url);
urlList.add(url);
i++;
}
}
} catch (org.jdom2.JDOMException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return urlList;
}
}
A delay of this order may be caused by fetching files from the web. Find a tool for monitoring HTTP requests issued from your machine to see what is going on. Look in particular for requests for common W3C files such as the XHTML DTD: because these files are requested so often, W3C deliberately injects a delay into the process to encourage people to use local copies of the files. If it turns out that this is the problem, there are various techniques you can use to access cached local copies.
Having said that, I'm puzzled by the logic of your code. The method getURL() appears to fetch and parse the document at http://www.steinheim-institut.de:80/cgi-bin/epidat?info=resources-mz1 every time it is called, and yet you are calling it within a loop, even using getURL().size() as your terminating condition.

JMeter - Access variables used in Java

I'm new to JMeter. I've a Java code which I've imported as JAR file. There is a variable called output, in which the result is in which the output is received and is printed. I want to access that variable from Jmeter Beanshell. Can anyone help me out with that?
My Java code is as follows:
package co.in;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class RestClientGet_Validate {
// http://localhost:8080/RESTfulExample/json/product/get
public static void main(String[] args) {
try {
URL url = new URL("http://172.16.2.192:8080/pivot_service_1.0/service/validate");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
if (conn.getResponseCode() != 200) {
throw new RuntimeException("Failed : HTTP error code : "
+ conn.getResponseCode());
}
BufferedReader br = new BufferedReader(new InputStreamReader(
(conn.getInputStream())));
String output;
System.out.println("Output from Server .... \n");
while ((output = br.readLine()) != null) {
System.out.println(output);
response = output;
}
conn.disconnect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
First of all, be informed that you can execute the request using JMeter's HTTP Request sampler and obtain the output using Regular Expression Extractor
If you're looking for a way to re-use your existing Java code in JMeter scripting test elements:
You need to change return type of your function to String, to wit replace
public static void main(String[] args)
with
public static String main()
You need to add return statement at the end of your function like:
return output;
Once done place the .jar to JMeter Classpath and restart JMeter to pick it up
If everything goes well you should be able to access the value in Beanshell like:
String output = co.in.RestClientGet_Validate.main();
Also be aware that starting from JMeter 3.1 it is recommended to switch to JSR223 Test Elements and Groovy language for scripting so consider migrating from Beanshell ASAP.

Launch browser automatically after spring-boot webapp is ready

How do I launch a browser automatically after starting the spring boot application.Is there any listener method callback to check if the webapp has been deployed and is ready to serve the requests,so that when the browser is loaded , the user sees the index page and can start interacting with the webapp?
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
// launch browser on localhost
}
Below code worked for me:
#EventListener({ApplicationReadyEvent.class})
void applicationReadyEvent() {
System.out.println("Application started ... launching browser now");
browse("www.google.com");
}
public static void browse(String url) {
if(Desktop.isDesktopSupported()){
Desktop desktop = Desktop.getDesktop();
try {
desktop.browse(new URI(url));
} catch (IOException | URISyntaxException e) {
e.printStackTrace();
}
}else{
Runtime runtime = Runtime.getRuntime();
try {
runtime.exec("rundll32 url.dll,FileProtocolHandler " + url);
} catch (IOException e) {
e.printStackTrace();
}
}
}
#SpringBootApplication
#ComponentScan(basePackageClasses = com.io.controller.HelloController.class)
public class HectorApplication {
public static void main(String[] args) throws IOException {
SpringApplication.run(HectorApplication.class, args);
openHomePage();
}
private static void openHomePage() throws IOException {
Runtime rt = Runtime.getRuntime();
rt.exec("rundll32 url.dll,FileProtocolHandler " + "http://localhost:8080");
}
}
You could do it by some java code. I am not sure if spring boot has something out of the box.
import java.awt.Desktop;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
public class Browser {
public static void main(String[] args) {
String url = "http://www.google.com";
if(Desktop.isDesktopSupported()){
Desktop desktop = Desktop.getDesktop();
try {
desktop.browse(new URI(url));
} catch (IOException | URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
Runtime runtime = Runtime.getRuntime();
try {
runtime.exec("xdg-open " + url);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
I've recently been attempting to get this working myself, I know it's been a while since this question was asked but my working (and very basic/simple) solution is shown below. This is a starting point for anyone wanting to get this working, refactor as required in your app!
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.awt.*;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
openHomePage();
}
private static void openHomePage() {
try {
URI homepage = new URI("http://localhost:8080/");
Desktop.getDesktop().browse(homepage);
} catch (URISyntaxException | IOException e) {
e.printStackTrace();
}
}
}
If you package the application as a WAR file, configure an application server, like Tomcat, and restart the configured application server through your IDE, IDEs can automatically open a browser-tab.
If you want to package your application as a JAR file, your IDE will not be able to open a web browser, so you have to open a web browser and type the desired link(localhost:8080). But in the developing phase, taking these boring steps might be very tedious.
It is possible to open a browser with Java programming language after the spring-boot application gets ready. You can use the third-party library like Selenium or use the following code snippet.
The code snippet to open a browser
#EventListener({ApplicationReadyEvent.class})
private void applicationReadyEvent()
{
if (Desktop.isDesktopSupported())
{
Desktop desktop = Desktop.getDesktop();
try
{
desktop.browse(new URI(url));
} catch (IOException | URISyntaxException e)
{
e.printStackTrace();
}
} else
{
Runtime runtime = Runtime.getRuntime();
String[] command;
String operatingSystemName = System.getProperty("os.name").toLowerCase();
if (operatingSystemName.indexOf("nix") >= 0 || operatingSystemName.indexOf("nux") >= 0)
{
String[] browsers = {"opera", "google-chrome", "epiphany", "firefox", "mozilla", "konqueror", "netscape", "links", "lynx"};
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < browsers.length; i++)
{
if (i == 0) stringBuffer.append(String.format("%s \"%s\"", browsers[i], url));
else stringBuffer.append(String.format(" || %s \"%s\"", browsers[i], url));
}
command = new String[]{"sh", "-c", stringBuffer.toString()};
} else if (operatingSystemName.indexOf("win") >= 0)
{
command = new String[]{"rundll32 url.dll,FileProtocolHandler " + url};
} else if (operatingSystemName.indexOf("mac") >= 0)
{
command = new String[]{"open " + url};
} else
{
System.out.println("an unknown operating system!!");
return;
}
try
{
if (command.length > 1) runtime.exec(command); // linux
else runtime.exec(command[0]); // windows or mac
} catch (IOException e)
{
e.printStackTrace();
}
}
}
Using Selenium to open a browser
To use the selenium library add the following dependency to your pom.xml file.
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
Then in your main class, add the following code snippet.
#EventListener({ApplicationReadyEvent.class})
private void applicationReadyEvent()
{
String url = "http://localhost:8080";
// pointing to the download driver
System.setProperty("webdriver.chrome.driver", "Downloaded-PATH/chromedriver");
ChromeDriver chromeDriver = new ChromeDriver();
chromeDriver.get(url);
}
Notice: It is possible to use most of the popular browsers like FirefoxDriver, OperaDriver, EdgeDriver, but it is necessary to download browsers' drivers beforehand.
Runtime rt = Runtime.getRuntime();
try {
rt.exec("cmd /c start chrome.exe https://localhost:8080");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
The code above worked for me. Change chrome.exe to the browser of your choice and Url to to your choice.
Note: You must include the scheme - http or https, and the browser you choose must me installed, else your app will run without opening the browser automatically.
Works only for windows though.

How to register my custom MessageBodyReader in my CLIENT?

Maybe somebody can help me find out how to solve this.
I am using jersey-apache-client 1.17
I tried to use Jersey client to build a standalone application (no Servlet container or whatever, just the Java classes) which communicates with a RESTFUL API, and everything worked fine until I tried to handle the mediatype "text/csv; charset=utf-8" which is a CSV stream sent by the server.
The thing is that I can read this stream with the following code:
InputStreamReader reader = new InputStreamReader(itemExportBuilder
.get(ClientResponse.class).getEntityInputStream());
Csv csv = new Csv();
Input input = csv.createInput(reader);
try {
String[] readLine;
while ((readLine = input.readLine()) != null) {
LOG.debug("Reading CSV: {}", readLine);
}
} catch (IOException e) {
e.printStackTrace();
}
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
But I'd like to encapsulate it and put it into a MessageBodyReader. But after writing this code, I just can't make the client use the following class:
package client.response;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.Provider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#Provider
public class ItemExportMessageBodyReader implements MessageBodyReader<ItemExportResponse> {
private static final Logger LOG = LoggerFactory.getLogger(ItemExportMessageBodyReader.class);
private static final Integer SKU = 0;
private static final Integer BASE_SKU = 1;
public boolean isReadable(Class<?> paramClass, Type type, Annotation[] annotations,
MediaType mediaType) {
LOG.info("Cheking if content is readable or not");
return paramClass == ItemExportResponse.class && !mediaType.isWildcardType()
&& !mediaType.isWildcardSubtype()
&& mediaType.isCompatible(MediaType.valueOf("text/csv; charset=utf-8"));
}
public ItemExportResponse readFrom(Class<ItemExportResponse> paramClass, Type paramType,
Annotation[] paramArrayOfAnnotation, MediaType paramMediaType,
MultivaluedMap<String, String> paramMultivaluedMap, InputStream entityStream)
throws IOException, WebApplicationException {
InputStreamReader reader = new InputStreamReader(entityStream);
Csv csv = new Csv();
Input input = csv.createInput(reader);
List<Item> items = new ArrayList<Item>();
try {
String[] readLine;
while ((readLine = input.readLine()) != null) {
LOG.trace("Reading CSV: {}", readLine);
Item item = new Item();
item.setBaseSku(readLine[BASE_SKU]);
items.add(item);
}
} catch (IOException e) {
LOG.warn("Item export HTTP response handling failed", e);
} finally {
try {
input.close();
} catch (IOException e) {
LOG.warn("Could not close the HTTP response stream", e);
}
}
ItemExportResponse response = new ItemExportResponse();
response.setItems(items);
return response;
}
}
The following documentation says that the preferred way of making this work in a JAX-RS client to register the message body reader with the code below:
Using Entity Providers with JAX-RS Client API
Client client = ClientBuilder.newBuilder().register(MyBeanMessageBodyReader.class).build();
Response response = client.target("http://example/comm/resource").request(MediaType.APPLICATION_XML).get();
System.out.println(response.getStatus());
MyBean myBean = response.readEntity(MyBean.class);
System.out.println(myBean);
Now the thing is that I can't use the ClientBuilder. I have to extend from a specific class which constructs the client another way, and I have no access to change the construction.
So when I receive the response from the server, the client fails with the following Exception:
com.sun.jersey.api.client.ClientHandlerException: A message body reader for Java class client.response.ItemExportResponse, and Java type class client.response.ItemExportResponse, and MIME media type text/csv; charset=utf-8 was not found
Any other way to register my MessageBodyReader?
OK. If anybody would bump into my question I solved this mystery by upgrading from Jersey 1.17 to version 2.9. The documentation I linked above also covers this version not the old one, this is where the confusion stems from.
Jersey introduced backward INCOMPATIBLE changes starting from version 2, so I have no clue how to configure it in version 1.17.
In version 2 the proposed solution worked fine.

Resources