Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
SpecRunner - Acceptance Test Driven Development Tool
Copyright (C) 2011-2016 Thiago Santos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
*/
package org.specrunner.htmlunit;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
import org.specrunner.SRServices;
import org.specrunner.context.IContext;
import org.specrunner.context.IDestructable;
import org.specrunner.features.IFeatureManager;
import org.specrunner.htmlunit.listeners.PageListener;
import org.specrunner.listeners.IListenerManager;
import org.specrunner.plugins.ActionType;
import org.specrunner.plugins.ENext;
import org.specrunner.plugins.PluginException;
import org.specrunner.plugins.core.AbstractPluginScoped;
import org.specrunner.plugins.type.Command;
import org.specrunner.result.IResultSet;
import org.specrunner.result.status.Success;
import org.specrunner.reuse.IReusable;
import org.specrunner.reuse.IReuseManager;
import org.specrunner.reuse.core.AbstractReusable;
import org.specrunner.util.UtilLog;
import org.specrunner.util.expression.UtilExpression;
import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.Cache;
import com.gargoylesoftware.htmlunit.DefaultCredentialsProvider;
import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
import com.gargoylesoftware.htmlunit.ProxyConfig;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.WebClientOptions;
import com.gargoylesoftware.htmlunit.WebConnection;
import com.gargoylesoftware.htmlunit.WebResponse;
/**
* This plugin creates an HTML browser and add it to the test context with a
* default name, or a given name. It means you can have more then one browser in
* the same specification.
*
* @author Thiago Santos
*
*/
public class PluginBrowser extends AbstractPluginScoped {
/**
* Default browser name. To set a different name use the attribute
* 'name=<name>'.
*/
public static final String BROWSER_NAME = "browser";
/**
* Feature to set browser version.
*/
public static final String FEATURE_VERSION = PluginBrowser.class.getName() + ".version";
/**
* The browser version.
*/
private String version = "CHROME";
/**
* Feature to set host (for proxies).
*/
public static final String FEATURE_HOST = PluginBrowser.class.getName() + ".host";
/**
* The host.
*/
private String host;
/**
* Feature to set port (for proxies).
*/
public static final String FEATURE_PORT = PluginBrowser.class.getName() + ".port";
/**
* The port.
*/
private Integer port;
/**
* Feature to set user name, if the browser requires authentication.
*/
public static final String FEATURE_USERNAME = PluginBrowser.class.getName() + ".username";
/**
* The username.
*/
private String username;
/**
* Feature to set password, if the browser requires authentication.
*/
public static final String FEATURE_PASSWORD = PluginBrowser.class.getName() + ".password";
/**
* The password.
*/
private String password;
/**
* Set default browser http timeout.
*/
public static final String FEATURE_HTTPTIMEOUT = PluginBrowser.class.getName() + ".httptimeout";
/**
* The browser http timeout. Default is '0'.
*/
private Integer httptimeout = 0;
/**
* Feature to set browser connection type.
*/
public static final String FEATURE_CONNECTION = PluginBrowser.class.getName() + ".connection";
/**
* IWebConnection type to be used.
*/
private String connection;
/**
* Connection instance.
*/
private Class extends IWebConnection> connectionType;
/**
* Default browser cache (class name) setting feature.
*/
public static final String FEATURE_CACHE = PluginBrowser.class.getName() + ".cache";
/**
* Cache cache class to be used.
*/
private String cache;
/**
* Cache instance.
*/
private Cache cacheInstance;
/**
* Feature to set browser cached option (true/false).
*/
public static final String FEATURE_CACHED = PluginBrowser.class.getName() + ".cached";
/**
* The cache status. Default is 'true'.
*/
private Boolean cached = true;
/**
* Feature to enable browser recording.
*/
public static final String FEATURE_RECORDING = PluginBrowser.class.getName() + ".recording";
/**
* Recording status. Default is "DEBUG log enabled".
*/
private Boolean recording = UtilLog.LOG.isDebugEnabled();
/**
* Feature to set web driver reuse.
*/
public static final String FEATURE_REUSE = PluginBrowser.class.getName() + ".reuse";
/**
* The reuse status.
*/
private Boolean reuse = false;
/**
* Creates a browser.
*/
public PluginBrowser() {
setName(BROWSER_NAME);
}
/**
* The browser version. Valid values are those in BrowserVersion class.
* Default is "FIREFOX_24".
*
* @return The HtmlUnit browser version.
*/
public String getVersion() {
return version;
}
/**
* Set the browser version.
*
* @param version
* The version.
*/
public void setVersion(String version) {
this.version = version;
}
/**
* Gets the host for proxy settings. Default is null, to use a proxy set
* 'host' an 'port' attributes.
*
* @return The proxy host.
*/
public String getHost() {
return host;
}
/**
* Sets the host.
*
* @param host
* The host.
*/
public void setHost(String host) {
this.host = host;
}
/**
* Gets the port for proxy settings. Default is null, to use a proxy set
* 'host' and 'port' attributes.
*
* @return The proxy port.
*/
public Integer getPort() {
return port;
}
/**
* Sets the port.
*
* @param port
* The port.
*/
public void setPort(Integer port) {
this.port = port;
}
/**
* Gets username for authentication. Default is null, to use authentication
* set 'username' and 'password' attributes.
*
* @return The username.
*/
public String getUsername() {
return username;
}
/**
* Sets the username.
*
* @param username
* The username.
*/
public void setUsername(String username) {
this.username = username;
}
/**
* Gets the password for authentication. Default is null, to use
* authentication set 'username' and 'password' attributes.
*
* @return The password.
*/
public String getPassword() {
return password;
}
/**
* Sets the password.
*
* @param password
* The password.
*/
public void setPassword(String password) {
this.password = password;
}
/**
* Gets the default browser Http timeout. This timeout is passed to HtmlUnit
* and it uses it as Socket connection time limitation. Default is '0',
* which is infinite.
*
* @return The timeout.
*/
public Integer getHttptimeout() {
return httptimeout;
}
/**
* Sets the HTTP timeout.
*
* @param httptimeout
* The timeout.
*/
public void setHttptimeout(Integer httptimeout) {
this.httptimeout = httptimeout;
}
/**
* Gets the web connection type, valid values are classes which implements
* com.gargoylesoftware.htmlunit.WebConnection. Default is
* null.
*
* @return The connection instance class.
*/
public String getConnection() {
return connection;
}
/**
* Sets the connection class.
*
* @param connection
* The connection.
*/
public void setConnection(String connection) {
this.connection = connection;
}
/**
* Gets the cache type, valid values are classes which extend
* com.gargoylesoftware.htmlunit.Cache. Default is null.
*
* @return The cache class.
*/
public String getCache() {
return cache;
}
/**
* Sets the cache class name.
*
* @param cache
* The cache class name.
*/
public void setCache(String cache) {
this.cache = cache;
}
/**
* Gets if the browser uses a cache strategy. Default is false, to enable
* cache set 'cache' attribute to true.
*
* @return The cache status.
*/
public Boolean getCached() {
return cached;
}
/**
* Set cached version.
*
* @param cached
* The cached status.
*/
public void setCached(Boolean cached) {
this.cached = cached;
}
/**
* Gets if the browser will take a snapshot after each action or assertion.
* Default is true.
*
* @return The recording status.
*/
public Boolean getRecording() {
return recording;
}
/**
* Set recording status.
*
* @param recording
* The status.
*/
public void setRecording(Boolean recording) {
this.recording = recording;
}
/**
* Gets the reuse status. If reuse is true, the browser can be reused by
* multiple tests if the browser name is the same.
*
* @return The reuse status.
*/
public Boolean getReuse() {
return reuse;
}
/**
* Set reuse status.
*
* @param reuse
* The reuse status.
*/
public void setReuse(Boolean reuse) {
this.reuse = reuse;
}
@Override
public ActionType getActionType() {
return Command.INSTANCE;
}
@Override
@SuppressWarnings("unchecked")
public void initialize(IContext context) throws PluginException {
super.initialize(context);
IFeatureManager fm = SRServices.getFeatureManager();
fm.set(FEATURE_VERSION, this);
if (host == null) {
fm.set(FEATURE_HOST, this);
}
if (port == null) {
fm.set(FEATURE_PORT, this);
}
if (username == null) {
fm.set(FEATURE_USERNAME, this);
}
if (password == null) {
fm.set(FEATURE_PASSWORD, this);
}
fm.set(FEATURE_HTTPTIMEOUT, this);
if (connection == null) {
fm.set(FEATURE_CONNECTION, this);
}
if (cache == null) {
fm.set(FEATURE_CACHE, this);
}
if (cached == null) {
fm.set(FEATURE_CACHED, this);
}
fm.set(FEATURE_RECORDING, this);
fm.set(FEATURE_REUSE, this);
if (connection != null) {
try {
connectionType = (Class extends IWebConnection>) Class.forName(connection);
} catch (ClassNotFoundException e) {
throw new PluginException("Connection class '" + connection + "' not found, or is not a subtype of " + WebConnection.class.getName() + ".", e);
}
}
if (cache != null) {
try {
Class extends Cache> cacheType = (Class extends Cache>) Class.forName(cache);
cacheInstance = cacheType.newInstance();
} catch (ClassNotFoundException e) {
throw new PluginException("Cache class '" + cache + "' not found, or is not a subtype of " + Cache.class.getName() + ".", e);
} catch (Exception e) {
throw new PluginException("Cache class '" + cache + "' instance could not be created.", e);
}
}
}
@Override
@SuppressWarnings("serial")
public ENext doStart(IContext context, IResultSet result) throws PluginException {
try {
IListenerManager fac = SRServices.get(IListenerManager.class);
if (recording) {
fac.add(new PageListener(getName()));
} else {
fac.remove(getName());
}
IReuseManager reusables = SRServices.get(IReuseManager.class);
if (reuse) {
Map cfg = new HashMap();
cfg.put("version", version);
cfg.put("name", getName());
IReusable> reusable = reusables.get(getName());
if (reusable != null && reusable.canReuse(cfg)) {
reusable.reset();
saveGlobal(context, getName(), reusable.getObject());
result.addResult(Success.INSTANCE, context.peek());
if (UtilLog.LOG.isInfoEnabled()) {
UtilLog.LOG.info("Browser (" + getName() + ") reused.");
}
return ENext.DEEP;
}
}
BrowserVersion bVersion = null;
try {
bVersion = (BrowserVersion) UtilExpression.evaluate(BrowserVersion.class.getName() + "." + version, context, false);
} catch (Exception e) {
throw new PluginException("The plugin version " + version + " is invalid.", e);
}
if (UtilLog.LOG.isInfoEnabled()) {
UtilLog.LOG.info("Browser named '" + getName() + "' version '" + bVersion.getNickname() + "'.");
}
final WebClient client = new WebClient(bVersion);
// change web connection
if (connectionType != null) {
WebConnection connectionInstance = null;
try {
Constructor extends WebConnection> constr = connectionType.getConstructor(WebClient.class);
connectionInstance = constr.newInstance(client);
} catch (Exception e) {
connectionInstance = connectionType.newInstance();
}
client.setWebConnection(connectionInstance);
}
setDefaultClientBehaviors(client);
// synchronize Ajax calls
client.setAjaxController(new NicelyResynchronizingAjaxController());
WebClientOptions options = client.getOptions();
options.setUseInsecureSSL(true);
if (host != null && port != null) {
ProxyConfig config = new ProxyConfig(host, port);
if (UtilLog.LOG.isInfoEnabled()) {
UtilLog.LOG.info("Browser named '" + getName() + "' proxy '" + host + ":" + port + "'.");
}
options.setProxyConfig(config);
}
if (username != null && password != null) {
DefaultCredentialsProvider provider = new DefaultCredentialsProvider();
provider.addCredentials(username, password);
client.setCredentialsProvider(provider);
if (UtilLog.LOG.isInfoEnabled()) {
UtilLog.LOG.info("Browser named '" + getName() + "' credentials '" + username + "|" + password + "'.");
}
}
if (cached || cacheInstance != null) {
if (UtilLog.LOG.isInfoEnabled()) {
UtilLog.LOG.info("Browser named '" + getName() + "' cached.");
}
Cache cacheLocal = null;
if (cacheInstance == null) {
if (UtilLog.LOG.isInfoEnabled()) {
UtilLog.LOG.info("Using default cache.");
}
cacheLocal = new Cache() {
@Override
protected boolean isCacheableContent(WebResponse response) {
String type = response.getContentType();
boolean dynamic = ("".equals(type) || "text/html".equals(type)) && !super.isCacheableContent(response);
if (UtilLog.LOG.isInfoEnabled()) {
String url = response.getWebRequest().getUrl().toString();
UtilLog.LOG.info("Dynamic '" + type + "' = " + dynamic + ", loaded in " + response.getLoadTime() + "mls, URL: " + url + ".");
}
return !dynamic;
}
};
} else {
if (UtilLog.LOG.isInfoEnabled()) {
UtilLog.LOG.info("Using customized cache '" + cacheInstance.getClass() + "'.");
}
cacheLocal = cacheInstance;
}
client.setCache(cacheLocal);
} else {
if (UtilLog.LOG.isInfoEnabled()) {
UtilLog.LOG.info("Browser named '" + getName() + "' not cached.");
}
}
options.setTimeout(httptimeout);
if (UtilLog.LOG.isInfoEnabled()) {
UtilLog.LOG.info("Browser named '" + getName() + "' bound to '" + client + "'.");
}
save(context, client);
result.addResult(Success.INSTANCE, context.peek());
if (reuse) {
if (UtilLog.LOG.isInfoEnabled()) {
UtilLog.LOG.info("WebClient reuse enabled.");
}
reusables.put(getName(), new AbstractReusable(getName(), client) {
@Override
public boolean canReuse(Map extra) {
Object localVersion = extra.get("version");
Object nameVersion = extra.get("name");
return localVersion != null && localVersion.equals(version) && nameVersion != null && nameVersion.equals(getName());
}
@Override
public void reset() {
if (UtilLog.LOG.isInfoEnabled()) {
UtilLog.LOG.info("WebClient recycling '" + getName() + "'.");
}
client.close();
if (UtilLog.LOG.isInfoEnabled()) {
UtilLog.LOG.info("WebClient '" + getName() + "' windows reset.");
}
}
@Override
public void release() {
if (UtilLog.LOG.isInfoEnabled()) {
UtilLog.LOG.info("WebClient '" + getName() + "' windows release.");
}
}
});
}
return ENext.DEEP;
} catch (Exception e) {
throw new PluginException(e);
}
}
/**
* Save client on context.
*
* @param context
* A context.
* @param client
* A client.
*/
protected void save(IContext context, final WebClient client) {
if (reuse) {
saveGlobal(context, getName(), client);
} else {
// not reuse mean close resources on context destroy
saveGlobal(context, getName(), new IDestructable() {
@Override
public Object getObject() {
return client;
}
@Override
public void destroy() {
client.close();
}
});
}
}
/**
* Set common properties.
*
* @param client
* The client to be set.
*/
protected void setDefaultClientBehaviors(final WebClient client) {
// print content on error
WebClientOptions options = client.getOptions();
options.setPrintContentOnFailingStatusCode(true);
options.setThrowExceptionOnFailingStatusCode(false);
options.setThrowExceptionOnScriptError(false);
// some handlers are logging without test log enabled, fixing.
client.setCssErrorHandler(new OptimizedCssErrorHandler());
client.setIncorrectnessListener(new OptimizedIncorrectnessListener());
}
}