/*
* JBoss, Home of Professional Open Source.
* Copyright 2009, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.jopr.jsfunit;
import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.*;
import java.io.IOException;
import java.util.*;
import org.jboss.logging.*;
import org.apache.cactus.ServletTestCase;
import org.jboss.jsfunit.framework.WebClientSpec;
import org.jboss.jsfunit.jsfsession.JSFClientSession;
import org.jboss.jsfunit.jsfsession.JSFServerSession;
import org.jboss.jsfunit.jsfsession.JSFSession;
import javax.faces.application.FacesMessage;
//import org.jboss.jmx.adaptor.rmi.RMIAdaptor; // Needs dependency: jmx-adaptor-plugin
import java.util.regex.Pattern;
import org.jboss.profileservice.spi.ProfileService;
import org.jboss.profileservice.spi.NoSuchDeploymentException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.apache.commons.lang.StringUtils;
import org.jboss.deployers.spi.management.ManagementView;
import org.jboss.managed.api.*;
import org.jboss.metatype.api.values.MetaValue;
import org.jboss.metatype.api.values.SimpleValueSupport;
import org.jboss.jopr.jsfunit.exceptions.EmbJoprTestException;
import org.jboss.jopr.jsfunit.exceptions.HtmlElementNotFoundException;
import org.jboss.jopr.jsfunit.util.EmbJoprTestToolkit;
import org.jboss.jopr.jsfunit.util.jaas.SecuredProfileServiceAccess;
/**
* This is the base test class for Embedded Jopr test cases.
* It supplies access to a JSFClientSession object and a JSFServerSession
* object. It also provides methods that make it easier to access some
* commonly used UI components.
*
* @author Farah Juma
* @author Ondrej Zizka
* @author Stan Silvert
*/
public abstract class EmbjoprTestCase extends ServletTestCase implements EmbJoprTestConstants {
protected final Logger log = Logger.getLogger(this.getClass().getName());
protected EmbJoprTestToolkit ejtt;
protected boolean isJBoss4;
protected WebClient webClient;
protected JSFClientSession client;
protected JSFServerSession server;
public static final String LOGIN_USERNAME = "admin";
public static final String LOGIN_PASSWORD = "admin";
public String getLoginUser() { return LOGIN_USERNAME; }
public String getLoginPass() { return LOGIN_PASSWORD; }
// Tab Menu IDs
public static final String SUMMARY_TAB = "summaryTab";
public static final String METRICS_TAB = "metricsTab";
public static final String CONFIGURATION_TAB = "configurationTab";
public static final String CONTROL_TAB = "controlTab";
public static final String CONTENT_TAB = "contentTab";
public static final String RESOURCE_CONFIGURATION_FORM = "resourceConfigurationForm";
public JSFClientSession getClient() { return client; }
public JSFServerSession getServer() { return server; }
private long testStartTime;
/**
* Start a JSFUnit session by logging in to the main page. Note that
* because setUp() is called before each test, a new HttpSession will be
* created each time a test is run.
*/
@Override
public void setUp() throws IOException, EmbJoprTestException
{
// Announce this test in the JBoss log.
log.info("========================================================================================");
log.info(" Setting up test "+this.getClass().getName()+"#"+this.getName());
log.info("========================================================================================");
// Save the startup time.
this.testStartTime = System.currentTimeMillis();
// JVM version
log.info("Java version: "+System.getProperty("java.version") + "," +
" vendor: " +System.getProperty("java.vendor"));
log.info("Java home: " +System.getProperty("java.home"));
// JBoss AS version
String version = Package.getPackage("org.jboss.system.server")
.getImplementationVersion();
log.info("Detected AS version: " + version);
isJBoss4 = version.startsWith("4");
// Browser branch and version
BrowserVersion browserVersion = BrowserVersion.FIREFOX_3;
String browserProp = System.getProperty("htmlunit.browser");
if( "ff3".equals(browserProp) || "firefox3".equals(browserProp) ){
browserVersion = BrowserVersion.FIREFOX_3;
}else
if( "ff2".equals(browserProp) || "firefox2".equals(browserProp) ){
browserVersion = BrowserVersion.FIREFOX_2;
}else
if( "ie7".equals(browserProp) || "internetexplorer7".equals(browserProp) ){
browserVersion = BrowserVersion.INTERNET_EXPLORER_7_0;
}else
if( "ie6".equals(browserProp) || "internetexplorer6".equals(browserProp) ){
browserVersion = BrowserVersion.INTERNET_EXPLORER_6_0;
}
log.info("Simulating browser: "+browserVersion.getNickName() + "('htmlunit.browser' sysprop: "+browserProp+")");
// Initial JSF request
WebClientSpec wcSpec = new WebClientSpec("/", browserVersion);
// This is temporary because embedded Jopr can't find /js/rhq.js
wcSpec.getWebClient().setThrowExceptionOnFailingStatusCode(true);
// Always press OK for confirm dialogs
wcSpec.getWebClient().setConfirmHandler(new SimpleConfirmHandler(true));
wcSpec.setInitialRequestStrategy(new JoprLoginStrategy( this.getLoginUser(), this.getLoginPass())); // logs in
this.webClient = wcSpec.getWebClient();
JSFSession jsfSession = new JSFSession(wcSpec);
this.client = jsfSession.getJSFClientSession();
this.server = jsfSession.getJSFServerSession();
this.ejtt = new EmbJoprTestToolkit(client, server);
this.ejtt.setCurrentTest(this);
}
@Override
protected void tearDown() throws Exception {
// Clean up.
this.webClient.closeAllWindows();
this.webClient.getCache().clear();
this.webClient.getCookieManager().clearCookies();
this.webClient = null;
this.client = null;
this.server = null;
// Denounce this test in the JBoss log.
log.info("------ END OF TEST "+this.getName()+" - took "+((System.currentTimeMillis() - this.testStartTime)/1000)+" seconds. -------");
}
/**
* Need a standard JSFUnit API to replace this code
*/
public HtmlAnchor getNavTreeLink(String linkLabel)
{
return getLinkInsideForm("navTreeForm", linkLabel);
}
/**
* Get the "Delete" button in the resources data table that corresponds
* to the resource given by resourceName.
*/
public HtmlButtonInput getDeleteButton(String formId, String resourceName)
{
HtmlAnchor link = getLinkInsideForm(formId, resourceName);
// The id will look like "resourceSummaryForm:dataTable:2:resourceName"
// I need the row number. (2 in the above example)
String id = link.getIdAttribute();
String[] idElements = id.split(":");
String row = idElements[idElements.length - 2];
// resourceSummaryForm:dataTable:2:removeButton
return (HtmlButtonInput)client.getElement(formId + ":dataTable:" + row + ":removeButton");
}
/**
* Finds a <a> tag inside a form that has a particular label.
*/
public HtmlAnchor getLinkInsideForm(String formId, String linkLabel)
{
HtmlForm form = (HtmlForm)client.getElement(formId);
List links = form.getByXPath(".//a"); // get all <a> tags inside form
for (Iterator i = links.iterator(); i.hasNext();)
{
HtmlAnchor link = (HtmlAnchor)i.next();
String linkText = link.getTextContent();
linkText = linkText.trim(); // ignore any leading or trailing spaces
if (linkText.equals(linkLabel)) return link;
}
throw new IllegalStateException("Link for '"+ linkLabel +"' not found in form #"+formId);
}
/**
* Finds the arrow icon in the nav tree that corresponds to the resource
* given by resourceName. This method is used to expand tree nodes
* (eg. "Web Applications (WAR)", "Datasources", etc.) in the
* navigation tree.
*/
public ClickableElement getNavTreeArrow(String resourceName) throws EmbJoprTestException {
// Tree.Item JS object can be still loading.
ejtt.navTree.waitUntilReady(100, 15);
// After expanding some node, it's children are loaded using AJAX.
// Here, we wait for the node with given label to appear in the nav tree.
ejtt.navTree.waitUntilNodeLoadedByAjax(resourceName, 200, 10);
HtmlAnchor link = getNavTreeLink(resourceName);
String id = link.getIdAttribute();
// An example id is: "navTreeForm:navTree:81:82:83:84::typeSummaryLink"
// The icon's id would be: "81:82:83:84::typeSummary:handle:img:collapsed"
int index = id.lastIndexOf("Link");
id = id.substring(0, index) + ":handle";
return (ClickableElement)client.getElement(id);
}
/**
* Expand the nav tree arrow for the given resource.
*/
public void expandNavTreeArrow(String resourceName) throws IOException, EmbJoprTestException {
// Expand the tree node
ClickableElement resourceArrow = getNavTreeArrow(resourceName);
resourceArrow.click();
}
/**
* Click on the given nav tree link.
*/
public void clickNavTreeLink(String resourceName) throws IOException {
HtmlAnchor resourceLink = getNavTreeLink(resourceName);
resourceLink.click();
}
/**
* Finds the value of the given metric in the given metrics
* data table.
*/
public String getMetricValueFromTable(String metricName,
String tableId) {
// Get the metrics data table
HtmlTable metricsTable = (HtmlTable)client.getElement(tableId);
if( null == metricsTable )
throw new IllegalStateException("Metrics table with ID '"+tableId+"' not found.");
List<HtmlTableRow> rows = metricsTable.getRows();
// Find the appropriate metric and return its value
for(Iterator i = rows.iterator(); i.hasNext();) {
HtmlTableRow row = (HtmlTableRow)i.next();
HtmlTableCell metric = row.getCell(0);
if(metric.asText().equals(metricName)) {
String id = metric.getIdAttribute();
// An example id is: dataTable:0:j_id118:2:j_id119
// We would need: dataTable:0:j_id118:2:measurementValue
return ((HtmlTableCell)client.getElement(id.substring(0, id.lastIndexOf(":"))
+ ":measurementValue")).asText();
}
}
throw new IllegalStateException("Value of '"+metricName+"' not found.");
}
/**
* Takes a Properties object, takes their names
* and calls getFormPropertiesValues( Collection<String> ).
*/
public Properties getFormPropertiesValues( Properties propsTemplate ){
return getFormPropertiesValues(EmbJoprTestToolkit.stringPropertyNames(propsTemplate));
}
/**
* Takes a list of properties to load
* and returns a Properties object filled with their values.
*/
public Properties getFormPropertiesValues( Collection<String> propsToLoad ){
Properties props = new Properties();
//for( String propName : EmbJoprTestToolkit.stringPropertyNames(propsToLoad) )
for( String propName : propsToLoad )
{
HtmlInput input = getConfigFormInput(propName);
String propValue = getFormInputValueAsText(input);
props.setProperty(propName, propValue);
}
return props;
}
/**
* fillOutForm sets the values of input boxes and "Yes/No" radio
* buttons on a resource configuration page using the given values.
*
* @param properties maps property names (eg. "jndi-name",
* "min-pool-size", etc.) to property values
*/
public void fillOutForm(Map<String, String> properties, String formName) {
Iterator itr = properties.keySet().iterator();
// Set each property
while(itr.hasNext()) {
String propertyName = (String)itr.next();
// Make sure the input is enabled
HtmlInput input = enableOrDisableFormInput(propertyName,
Boolean.TRUE,
formName);
assertFalse("Could not enable: " + propertyName, input.isDisabled());
setFormInput(input, properties.get(propertyName));
}
}
/** Convert Properties to Map and call fillOutForm(Map). */
public void fillOutForm(Properties props) {
Map<String,String> map = new HashMap<String,String>(props.size());
for( String propName : EmbJoprTestToolkit.stringPropertyNames(props) ) {
map.put(propName, props.getProperty(propName));
}
fillOutForm(map, RESOURCE_CONFIGURATION_FORM);
}
/** Check if the form is filled according to given Properties. */
public void checkForm(Properties props)
{
boolean foundNonMatching = false;
StringBuilder sb = new StringBuilder("Non-matching properties: \n");
for( String propName : EmbJoprTestToolkit.stringPropertyNames(props) ) {
HtmlInput input = getConfigFormInput(propName);
String expected = props.getProperty(propName);
String actual = getFormInputValueAsText(input);
if( StringUtils.equals(expected, actual) ) continue;
foundNonMatching = true;
sb.append( propName+": expected '"+expected+"', found '"+actual+"'\n");
}
if( foundNonMatching ){
fail( sb.toString() );
}
}
/** Looks for a form input of given property. */
public HtmlInput getConfigFormInput( String propertyName )
{
HtmlForm form = (HtmlForm)client.getElement("resourceConfigurationForm");
HtmlInput input = (HtmlInput)form.getFirstByXPath(".//input[@ondblclick='//"
+ propertyName + "']");
assertNotNull("Form input for property '"+ propertyName +"' not found.", input);
return input;
}
/** Looks for an enable/disable checkbox corresponding to this input element. */
public HtmlCheckBoxInput getCheckBoxForInput( HtmlInput input ){
boolean isRadioButton = input.getTypeAttribute().equals("radio");
String id = input.getId();
String xpath;
if(isRadioButton) {
xpath = ".//input[@onclick=\"setInputUnset(document.getElementById('"+ id
+ "'), this.checked);setInputUnset(document.getElementById('"
+ id.substring(0, id.lastIndexOf(":")) + ":1'), this.checked);\"]";
} else {
xpath = ".//input[@onclick=\"setInputUnset(document.getElementById('"
+ id + "'), this.checked);\"]";
}
HtmlCheckBoxInput checkBox = (HtmlCheckBoxInput)input.getEnclosingForm().getFirstByXPath(xpath);
return (HtmlCheckBoxInput) checkBox;
}
/**
* Attempt to enable or disable the given input box or "Yes/No" radio button
* that corresponds to the given property name on a resource configuration
* page. Return the enabled/disabled input element.
* If the input box/radio button does not have an enable/disable checkbox,
* return the input element as is.
*/
public HtmlInput enableOrDisableFormInput(String propertyName, Boolean enableInput, String formName) {
HtmlForm form = (HtmlForm)client.getElement(formName);
if( null == form ){
// Wrapped. Don't want to add "throws Html..." all over the project.
throw new RuntimeException(new HtmlElementNotFoundException(
"Element " + formName + " not found. Page dumped.", this));
}
HtmlInput input = (HtmlInput)form.getFirstByXPath(".//input[@ondblclick='//"
+ propertyName + "']");
assertNotNull("Form input for property '" + propertyName + "' not found.", input);
boolean isRadioButton = input.getTypeAttribute().equals("radio");
String id = input.getId();
String xpath;
// Look for an enable/disable checkbox corresponding to this
// input element.
if(isRadioButton) {
List<HtmlInput> propertyButtons = (List<HtmlInput>)form.getByXPath(".//input[@ondblclick='//" + propertyName
+ "' and @type='radio']");
int numButtons = propertyButtons.size();
xpath = ".//input[@onclick=\"";
for(int i = 0; i < numButtons; i++) {
xpath = xpath + "setInputUnset(document.getElementById('"
+ id.substring(0, id.lastIndexOf(":")) + ":" + i + "'), this.checked);";
}
xpath = xpath + "\"]";
} else {
xpath = ".//input[@onclick=\"setInputUnset(document.getElementById('"
+ id + "'), this.checked);\"]";
}
HtmlInput checkBox = (HtmlInput)form.getFirstByXPath(xpath);
if(checkBox != null) {
//checkBox.setChecked(!enableInput);
boolean isChecked = checkBox.isChecked();
if(isChecked == enableInput) {
try {
checkBox.click();
} catch (Exception e) {
log.error("Could not click on the checkbox for: " + propertyName);
}
}
}
return input;
}
/**
* Set the given input box or "Yes/No" radio button to the given value.
*/
public void setFormInput(HtmlInput input, String propertyValue) {
boolean isRadioButton = input.getTypeAttribute().equals("radio");
if(isRadioButton) {
// Check the appropriate button
if(propertyValue.equals("false")) {
// Get the "No" radio button.
String id = input.getId();
input = (HtmlInput)client.getElement(
id.substring(0, id.lastIndexOf(":")) + ":1");
}
else{
// Multiple choices - find the appropriate radio button.
String inputName = input.getNameAttribute();
DomNode node = input.getFirstByXPath(
"./ancestor::form//input[@name='"+inputName+"' and @value='"+propertyValue+"']");
//DomNode node = input.getOneHtmlElementByAttribute("input", "value", propertyValue);
if( null == node ){
throw new IllegalArgumentException(
"HTML Radio input of name '"+inputName+"' and value '"+propertyValue+"' not found.");
}
input = (HtmlInput)node;
}
input.setChecked(Boolean.TRUE);
} else {
input.setValueAttribute(propertyValue);
}
}
/**
* Returns the value of HTML input.
* @returns
* If the input is marked as unset, returns "unset".
* For radios, returns the value of the checked radio.
* For others, simply returns value attribute.
*/
public String getFormInputValueAsText(HtmlInput input) {
HtmlCheckBoxInput checkbox = getCheckBoxForInput(input);
if( checkbox.isChecked() )
return "unset";
boolean isRadioButton = input.getTypeAttribute().equals("radio");
if(!isRadioButton){
return input.getValueAttribute();
}
else {
HtmlRadioButtonInput radio = (HtmlRadioButtonInput)input;
// Multiple choices - find the appropriate radio button.
String inputName = input.getNameAttribute();
String xPath = ".//input[@name='"+ inputName +"']";
List<HtmlInput> radios = (List<HtmlInput>) input.getEnclosingForm().getByXPath(xPath);
for (HtmlInput htmlInput : radios) {
if( htmlInput.isChecked() ){
return htmlInput.getValueAttribute();
}
}
return null;
}
}
/**
* Check that the given messages occur on the client side and server side.
* Uses checkClientAndServerMessages( String, String, FacesMessage.Severity ),
* kept for backwards compat.
*/
public void checkClientAndServerMessages(String expectedClientMsg,
String expectedServerMsg,
boolean isErrorMsg)
{
FacesMessage.Severity expectedSeverity;
if(isErrorMsg) {
expectedSeverity = FacesMessage.SEVERITY_ERROR;
} else {
expectedSeverity = FacesMessage.SEVERITY_INFO;
}
checkClientAndServerMessages(expectedClientMsg, expectedServerMsg, expectedSeverity);
}
/**
* Check that the given messages with given severity
* occur on the client side and server side.
*/
public void checkClientAndServerMessages(String expectedClientMsg,
String expectedServerMsg,
FacesMessage.Severity expectedSeverity ) {
// Check that the expected message appears on the server side
assertTrue("Expected message not found in faces messages (no messages in Faces)",
server.getFacesMessages().hasNext());
FacesMessage message = server.getFacesMessages().next();
assertTrue("Expected message: " + expectedServerMsg + " Actual: "+ message.getDetail(),
message.getDetail().contains(expectedServerMsg));
if( ! message.getDetail().contains(expectedServerMsg) ){
//throw new EmbJoprTestException( "Expected message: " + expectedServerMsg + " Actual: "+ message.getDetail(), this);
String fileName = this.getName() + "-msgCheck.html";
try {
ejtt.dumpPage( fileName );
} catch (IOException ex) { log.error(ex.toString()); }
fail( "\nExpected message: [" + expectedServerMsg + "]\nActual: ["+ message.getDetail() + "]\nPage dumped to '"+fileName+"'." );
}
assertEquals("Incorrect message severity. Message: "+message.getSummary(), expectedSeverity, message.getSeverity());
// Check that the expected message appears on the client side
assertTrue("This expected message was not found on the page: " + expectedClientMsg,
client.getPageAsText().contains(expectedClientMsg));
}
/**
* Check that the given messages occur on the client side and server side.
* Given strings are treated as regular expressions to match.
*/
public void checkClientAndServerMessagesRegExp(String expectedClientMsgRE,
String expectedServerMsgRE,
boolean isErrorMsg)
{
// In Faces
assertTrue(server.getFacesMessages().hasNext());
FacesMessage message = server.getFacesMessages().next();
if(isErrorMsg) {
assertTrue(FacesMessage.SEVERITY_ERROR.equals(message.getSeverity()));
} else {
assertTrue(FacesMessage.SEVERITY_INFO.equals(message.getSeverity()));
}
assertTrue( Pattern.matches( expectedServerMsgRE, message.getDetail() ) );
// On page
String pageText = client.getPageAsText();
assertTrue( Pattern.matches(expectedClientMsgRE, pageText) );
}
/**
* Refresh the content under the given nav tree node.
*/
public void refreshTreeNode(String nodeName) throws EmbJoprTestException {
try {
// Collapse and then expand the nav tree node
ClickableElement nodeArrow = getNavTreeArrow(nodeName);
nodeArrow.click();
nodeArrow = getNavTreeArrow(nodeName);
nodeArrow.click();
} catch (IOException e) {
throw new EmbJoprTestException("An error occurred when trying " +
"to collapse and then expand the nav tree " +
"arrow for " + nodeName, e);
}
}
/**
* Finds a row in the "details table" using the text in the Name column
* and returns the text from the Value column.
* @param name
* @return
*/
public String getDetailsRowValue(String name) throws EmbJoprTestException {
HtmlDivision contentDiv = (HtmlDivision) client.getElement("content");
List<?> valueTDs = contentDiv.getByXPath(
".//div[@class='tabmenubox']//td[contains(text(),'"+name+"']/following-sibling::td[1]");
//assertTrue( name + " row not found.", valueTDs.size() == 1 );
if( valueTDs.size() == 1 )
throw new EmbJoprTestException( name + " row not found." );
String value = ((HtmlTableCell) valueTDs).getTextContent();
return value;
}
/**
* Returns the content element - <div id="content"> - which contains whole page.
* Good as a start point for XPath queries - other elements usually have generated IDs.
* Assertion fails if the element is not found.
* @return
*/
public HtmlElement getContentElement() throws EmbJoprTestException {
HtmlElement contentElement = (HtmlElement)client.getElement("content");
//assertNotNull("Content <div> not found.", contentElement);
if( null == contentElement )
throw new EmbJoprTestException( "Content <div> not found." );
return contentElement;
}
/**
* Convenience method, calls getElementsByXPath() with content element.
* @param sXPath
* @return
*/
public List<? extends HtmlElement> getElementsByXPath(String sXPath ) throws EmbJoprTestException {
//return (List<? extends HtmlElement>) getContentElement().getByXPath(sXPath);
return getElementsByXPath( getContentElement(), sXPath );
}
/**
* Retuns a list of elements chosen by XPath, with the given element as context node.
* @param xPathContextElement
* @param sXPath
* @return
*/
public List<? extends HtmlElement> getElementsByXPath(
HtmlElement xPathContextElement, String sXPath )
throws EmbJoprTestException
{
if( null == xPathContextElement ){
throw new EmbJoprTestException("Given XPath context element is null.");
}
return (List<? extends HtmlElement>) xPathContextElement.getByXPath(sXPath);
}
/**
* Returns the first element in the list returned by getElementsByXPath(String sXPath ).
* @param sXPath
* @returns The first of elements found, or null when XPath expr. found none.
*/
public HtmlElement findFirstElementByXPath( HtmlElement xPathContext, String sXPath ) throws EmbJoprTestException {
List<? extends HtmlElement> elementsByXPath = getElementsByXPath(xPathContext, sXPath);
if( elementsByXPath.size() == 0 ){
//
// Exception is better - will get the stack trace.
//fail("XPath expression found no elements: "+sXPath);
return null;
}
return elementsByXPath.get(0);
}
/**
* The same as findFirstElementByXPath(), only throws an exception when no element was found.
* Returns the first element in the list returned by getElementsByXPath(String sXPath ).
* @param sXPath
* @returns The first of elements found.
* @throws XPathException when the expression found no elements.
*/
public HtmlElement getFirstElementByXPath( HtmlElement xPathContext, String sXPath )
throws EmbJoprTestException
{
HtmlElement e = findFirstElementByXPath(xPathContext, sXPath);
if( null == e ){
throw new EmbJoprTestException("XPath expression found no elements: "+sXPath);
}
return e;
}
/**
* Convenience method - calls getFirstElementByXPath() with content div as context.
* @param sXPath
* @return
*/
public HtmlElement getFirstElementByXPath( String sXPath ) throws EmbJoprTestException{
return getFirstElementByXPath( getContentElement(), sXPath );
}
/**
* Retrieves an input element from a named row of a table in a form.
* Supposes that the form is in the "tabmenubox" or "notabmenubox" div.
* @param sRowName
* @return
* @throws org.jboss.jopr.jsfunit.AssertException
*/
public HtmlInput getFormInputByRowName(String sRowName) throws EmbJoprTestException {
try {
HtmlInput input = (HtmlInput) getFirstElementByXPath(
getTabMenuBoxElement(),
".//td[contains(text(),'"+sRowName+"')]/following-sibling::td[@class='property-value-cell']//input"
);
if( null == input ){
throw new EmbJoprTestException("Input for value "+sRowName+" not found.");
}
return input;
}
catch(EmbJoprTestException ex){
//throw new AssertException("Row with name \""+sRowName+"\" not found.", ex);
throw ex;
}
}
/**
* Retrieves a named row of a table in the "right side of the page".
* Supposes that the table is in the "tabmenubox" or "notabmenubox" div.
* Uses getTabMenuBoxElement() to get that div.
* @param sRowName
* @return
* @throws org.jboss.jopr.jsfunit.AssertException
*/
public HtmlTableRow getRowByName(String sRowName) throws EmbJoprTestException {
HtmlTableRow row = (HtmlTableRow) getFirstElementByXPath(
getTabMenuBoxElement(),
".//td[contains(string(),'"+sRowName+"')]/ancestor::tr" );
if( null == row ){
throw new EmbJoprTestException("Row with label "+sRowName+" not found.");
}
return row;
}
/**
* Returns the element which contains the "right side of the page".
* <div class="tabmenubox"> element exists on each page that shows resource's details.
* <div class="notabmenubox"> element exists on each page with form for resource's properties editation.
* @return
* @throws org.jboss.jopr.jsfunit.AssertException
*/
public HtmlElement getTabMenuBoxElement() throws EmbJoprTestException {
return getFirstElementByXPath(".//div[@class='tabmenubox' or @class='notabmenubox']");
}
/**
* Returns an integer part of the beginning of the given string.
* @param s
* @return Integer with the value of numerical part of the string,
* or null if there are no digits at the beginning.
*/
public Integer integerFromString(String s) {
int pos;
for( pos = 0; pos < s.length(); pos++ ){
char ch = s.charAt(0);
if( '0' > ch || ch > '9' )
break;
}
if( pos == 0 )
return null;
try{
int val = Integer.parseInt( s.substring( 0, pos ) );
return val;
}catch( NumberFormatException ex ){
return null;
}
}
/**
* Checks whether given string looks like a double in terms of Java's Double,
* i.e. /<digit>+(\.<digit>+)?/
* @param value The string to check.
* @returns true if the
*/
public static boolean looksLikeDouble(String value) {
try{
Double.parseDouble(value);
}catch(NumberFormatException ex){
return false;
}
return true;
}
/**
* Returns true if the string looks like a double with unit, i.e. 123.45kg
*/
public static boolean looksLikeDoubleWithUnit(String value) {
return value.matches("([0-9]+\\.[0-9]+)[a-zA-Z]{0,3}");
}
/**
* If both expected and actual string look like a double,
* returns normalized double (with a decimal dot);
* Otherwise, returns original actual value.
* @param expected
* @param actual
*/
public static String normalizeIfDoubleExpected(String expected, String actual) {
//return looksLikeDouble(expected) ? actual.replace(',', '.') : actual;
if( !looksLikeDouble(expected) )
return actual;
String converted = actual.replace(',', '.');
return looksLikeDouble(converted) ? converted : actual;
}
/** Converts a decimal number in either english or german notation to Java-like double. */
public static String normalizeIfNumber( String val ){
if( null == val )
return null;
boolean isNumeric = val.matches("([0-9][0-9\\., ]+[0-9])[a-zA-Z]{0,3}");
if( !isNumeric )
return val;
// TODO: Normalize numbers with units (1.5m)
String val2 = val.replace(",", "");
// English notation - 1,322.51
if( EmbjoprTestCase.looksLikeDoubleWithUnit(val2) )
return val2;
// Still can be numbe: 1 358,84
val2 = val.replace(" ", "");
val2 = val.replace(" ", "").replace(',', '.');
if( EmbjoprTestCase.looksLikeDoubleWithUnit(val2) )
return val2;
return val;
}
/**
* Transform the given map of Strings to MetaValues into a
* map of Strings to Strings.
*/
protected static Map<String, String> formatPropertiesMap(Map<String, MetaValue> propertiesMap) {
Map<String, String> formattedPropertiesMap = new HashMap<String, String>();
for(String propertyName : propertiesMap.keySet()) {
SimpleValueSupport propertyMetaValue = (SimpleValueSupport)propertiesMap.get(propertyName);
String propertyStringValue = propertyMetaValue.getValue().toString();
formattedPropertiesMap.put(propertyName, propertyStringValue);
}
return formattedPropertiesMap;
}
/**
* Check the properties for a particular managed component.
*
* @param expectedProperties maps property names to expected values
* @param componentName - the name of the ManagedComponent
* @param type - the component type
*/
protected void checkComponentProperties(Map<String, MetaValue> expectedProperties, String componentName,
ComponentType type) throws Exception {
checkComponentProperties(expectedProperties, componentName, type, true);
}
/**
* Check the properties for a particular managed component.
*
* @param expectedProperties maps property names to expected values
* @param componentName - the name of the ManagedComponent
* @param type - the component type
*/
protected void checkComponentProperties(Map<String, MetaValue> expectedProperties, String componentName,
ComponentType type, boolean secured) throws Exception {
Map<String, MetaValue> actualProperties = getComponentProperties(componentName, type, secured);
// Verify that the property values are correct
for(String propertyName : expectedProperties.keySet()) {
assertEquals("Incorrect value for '" + propertyName + "'",
expectedProperties.get(propertyName),
actualProperties.get(propertyName));
}
}
/**
* Create a map of property names to property values for a particular component. Unsecured.
*/
protected Map<String, MetaValue> getComponentProperties(String componentName,
ComponentType type) throws Exception {
return getComponentProperties(componentName, type, true);
}
/**
* Create a map of property names to property values for a particular component.
*/
protected Map<String, MetaValue> getComponentProperties(String componentName,
ComponentType type, boolean secured) throws Exception
{
ManagedComponent component = getManagedComponent(componentName, type, secured);
assertNotNull("The returned component was null; Name: "+componentName, component);
assertEquals(componentName, component.getName());
Map<String, ManagedProperty> actualProperties = component.getProperties();
Map<String, MetaValue> propertiesMap = new HashMap<String, MetaValue>();
ManagedProperty prop;
// Create a map of Strings to MetaValues
for(String propertyName : actualProperties.keySet()) {
prop = actualProperties.get(propertyName);
propertiesMap.put(propertyName, prop.getValue());
}
return propertiesMap;
}
/**
* Create a map of property names to property values for a particular
* component. The desired property names are given by specificProperties.
* (This is useful when we need to check the values of some specific properties
* only - eg. the configuration tests)
*/
protected Map<String, MetaValue> getSpecificComponentProperties(String componentName,
ComponentType type,
String specificProperties[]) throws Exception {
return getSpecificComponentProperties(componentName, type, specificProperties, true);
}
/**
* Create a map of property names to property values for a particular
* component. The desired property names are given by specificProperties.
* (This is useful when we need to check the values of some specific properties
* only - eg. the configuration tests)
*/
protected Map<String, MetaValue> getSpecificComponentProperties(String componentName,
ComponentType type,
String specificProperties[],
boolean secured) throws Exception {
ManagedComponent component = getManagedComponent(componentName, type, secured);
assertNotNull("The returned component was null", component);
assertEquals(componentName, component.getName());
Map<String, ManagedProperty> actualProperties = component.getProperties();
Map<String, MetaValue> propertiesMap = new HashMap<String, MetaValue>();
ManagedProperty prop;
// Create a map containing only the specified properties
for(int i = 0; i < specificProperties.length; i++) {
String propertyName = specificProperties[i];
prop = actualProperties.get(propertyName);
propertiesMap.put(propertyName, prop.getValue());
}
return propertiesMap;
}
/**
* Return a ManagedComponent, given the component name and type.
*/
protected ManagedComponent getManagedComponent(String componentName,
ComponentType type) throws Exception {
return getManagedComponent(componentName, type, true);
}
/**
* Return a ManagedComponent, given the component name and type.
* @param secured If true, uses JAAS secured access to ProfileService etc.
*/
protected ManagedComponent getManagedComponent(String componentName,
ComponentType type, boolean secured) throws Exception {
// Get the ManagedComponent
ManagementView mgtView = getCurrentProfileView( secured );
ManagedComponent component = mgtView.getComponent(componentName, type);
return component;
}
/**
* Return whether or not the given deployment is deployed.
*
* @param deployment - the deployment we are interested in
*/
protected boolean isDeployed(String deployment) throws Exception {
return isDeployed(deployment, true);
}
/**
* Return whether or not the given deployment is deployed.
*
* @param deployment - the deployment we are interested in
* @param secured If true, JAAS secured ManagementView is used.
*/
protected boolean isDeployed(String deployment, boolean secured) throws Exception {
deployment = deployment.replace("/", System.getProperty("file.separator"));
ManagementView currentProfileView = getCurrentProfileView(secured);
ManagedDeployment managedDeployment = null;
try {
managedDeployment = currentProfileView.getDeployment(deployment);
} catch (NoSuchDeploymentException e) {
return false;
}
return managedDeployment != null;
}
/**
* Get the profile service.
*/
protected ProfileService getProfileService( boolean secured ){
return secured ? getProfileServiceSecured() : getProfileService();
}
protected ProfileService getProfileServiceSecured()
{
try {
return SecuredProfileServiceAccess.getInstance().getProfileService();
} catch (NamingException ex) {
// Farah's methods don't propagate exceptions -> report and swallow.
log.error("Can't get secured ProfileService: " + ex.toString(), ex);
return null;
}
}
protected ProfileService getProfileService()
{
ProfileService profileService = null;
InitialContext initialContext;
try {
initialContext = new InitialContext();
} catch (NamingException e) {
log.error("Unable to get an InitialContext to JBoss AS 5", e);
return null;
}
try {
profileService = (ProfileService) initialContext.lookup("ProfileService");
} catch (NamingException e) {
log.error("Could not find ProfileService Name on JBoss AS 5", e);
} catch (Exception e) {
log.error("Exception thrown when looking up ProfileService on JBoss AS 5", e);
}
return profileService;
}
/**
* Get the current profile view.
* @param secured If true, returns JAAS profile view of secured profile service.
*/
protected ManagementView getCurrentProfileView( boolean secured ){
return secured ? getCurrentProfileView() : getCurrentProfileViewUnsecured();
}
/**
* Get the current profile view.
*/
protected ManagementView getCurrentProfileView(){
try {
ManagementView view = SecuredProfileServiceAccess.getInstance().getManagementView();
view.load();
return view;
} catch (NamingException ex) {
log.error("Can't get ManagementView: "+ex);
return null;
}
}
protected ManagementView getCurrentProfileViewUnsecured()
{
ProfileService profileService = getProfileService();
ManagementView currentProfileView = profileService.getViewManager();
try {
currentProfileView.load();
} catch (Exception e) {
log.error("Could not find default Profile in Current Profile View", e);
}
return currentProfileView;
}
}