[embjopr-commits] EMBJOPR SVN: r245 - in trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit: as5 and 1 other directories.

embjopr-commits at lists.jboss.org embjopr-commits at lists.jboss.org
Thu Mar 19 23:26:13 EDT 2009


Author: ozizka at redhat.com
Date: 2009-03-19 23:26:13 -0400 (Thu, 19 Mar 2009)
New Revision: 245

Modified:
   trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/AppConstants.java
   trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/EmbjoprTestCase.java
   trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/as5/EarTest.java
   trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/as5/WarTest.java
   trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/util/ActiveConditionChecker.java
   trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/util/EmbJoprTestToolkit.java
Log:
WAR tests created, EAR tests updated, EJTT updates.
EmbjoprTestCase: getNavTreeLink() - changed ID of the Delete button - "resourceSummaryForm:" prepended

Modified: trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/AppConstants.java
===================================================================
--- trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/AppConstants.java	2009-03-20 03:11:17 UTC (rev 244)
+++ trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/AppConstants.java	2009-03-20 03:26:13 UTC (rev 245)
@@ -30,6 +30,7 @@
 
 
 
+
 		/**
 		 * Information about deployable types -
 		 * navigation tree labels, archive extensions, 
@@ -38,18 +39,22 @@
 		public enum DeployableTypes {
 
 			// Mandatory: first, fourth
-			EAR(AppConstants.NAV_EAR, ".ear", null, "application/ear"),
-			WAR(AppConstants.NAV_WAR, ".war", null, "application/war"),
-			EJB(AppConstants.NAV_EJB, ".jar", null, "	application/java-archive"),
-			SAR(AppConstants.NAV_SAR, ".sar", "-service.xml", "application/sar"),
-			RAR(AppConstants.NAV_RAR, ".rar", null, "application/rar"),
-			MC_BEAN(AppConstants.NAV_MC, "",  null, "application/java-archive");
+			// Nav tree link label, testdata/$dir, extension, suffix, mime type.
+			EAR(AppConstants.NAV_EAR,  "ear",  ".ear", null, "application/ear"),
+			WAR(AppConstants.NAV_WAR,  "war",  ".war", null, "application/war"),
+			EJB(AppConstants.NAV_EJB,  "ejb",  ".jar", null, "	application/java-archive"),
+			SAR(AppConstants.NAV_SAR,  "sar",  ".sar", "-service.xml", "application/sar"),
+			RAR(AppConstants.NAV_RAR,  "rar",  ".rar", null, "application/rar"),
+			MC_BEAN(AppConstants.NAV_MC, "mc", "",    null, "application/java-archive");
 
 			// -- Fields --
 
 			protected final String navTreeLabel;
 			public String getNavTreeLabel() {			return navTreeLabel;		}
 
+			protected final String dataDir;
+			public String getDataDir() {			return dataDir;		}
+
 			protected final String extension;
 			public String getExtension() {			return extension;		}
 
@@ -61,13 +66,17 @@
 
 
 
+
 			// -- Constructors --
 
 			private DeployableTypes(
-							String navTreeLabel, String extension,
+							String navTreeLabel,
+							String dataDir,
+							String extension,
 							String suffix, String mimeType)
 			{
 				this.navTreeLabel = navTreeLabel;
+				this.dataDir = dataDir;
 				this.extension = extension;
 				this.suffix = suffix;
 				this.mimeType = mimeType;
@@ -75,8 +84,8 @@
 
 
 		}// enum DeployableTypes
+		
 
-
 		/** Several ways how to deploy / undeploy. */
 		public enum DeploymentMeans {
 			VIA_EMBJOPR,
@@ -98,14 +107,19 @@
     public static final String NAV_WAR = "Web Application (WAR)s";
 
 		public static final String EAR_MALFORMED_APP_FILENAME = "malformed-application-xml.ear";
+		public static final String WAR_FILENAME_MALFORMED_APP = "malformed-web-xml.war";
 
     // Test Archives
     public static final String BASIC_JAR = "deployment-ejb.jar";
     public static final String BASIC_EAR = "eardeployment.ear";
 		public static final String EAR_UNPACKED = "unpacked-ear1.ear";
 		public static final String EAR_UNPACKED_ZIP = "unpacked-ear1.ear.zip";
+
     public static final String BASIC_WAR = "hellothere.war";
+		public static final String WAR_UNPACKED = "unpacked-web1.war";
+		public static final String WAR_UNPACKED_ZIP = "unpacked-web1.war.zip";
 
+
     // Defaults
     public static final String[] WAR_DEFAULTS = new String[]{
 			"ROOT.war", "invoker.war",

Modified: trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/EmbjoprTestCase.java
===================================================================
--- trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/EmbjoprTestCase.java	2009-03-20 03:11:17 UTC (rev 244)
+++ trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/EmbjoprTestCase.java	2009-03-20 03:26:13 UTC (rev 245)
@@ -155,7 +155,8 @@
         String id = link.getIdAttribute(); 
         String[] idElements = id.split(":");
         String row = idElements[idElements.length - 2];
-        return (HtmlButtonInput)client.getElement("dataTable:" + row + ":removeButton");
+				// resourceSummaryForm:dataTable:2:removeButton
+        return (HtmlButtonInput)client.getElement("resourceSummaryForm:dataTable:" + row + ":removeButton");
     }
 
     /**
@@ -173,9 +174,7 @@
             if (linkText.contains(linkLabel)) return link;
         }
 
-        throw new IllegalStateException("Link for '" 
-                                        + linkLabel 
-                                        + "' not found.");
+        throw new IllegalStateException("Link for '"+ linkLabel +"' not found.");
     }
     
     /**

Modified: trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/as5/EarTest.java
===================================================================
--- trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/as5/EarTest.java	2009-03-20 03:11:17 UTC (rev 244)
+++ trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/as5/EarTest.java	2009-03-20 03:26:13 UTC (rev 245)
@@ -434,7 +434,7 @@
 
 
 	/**
-	 * Changes EAR configuration, and checks whether the changes were saved.
+	 * Changes EAR configuration, and verifies that the changes were NOT saved.
 	 *
 	 * FAILS because some of the values are read-only.  EMBJOPR-96
 	 */
@@ -457,8 +457,8 @@
 
 			// Load properties (we will use their names).
 			Properties propsToSet = new Properties();
-			String filePath = ejtt.getTestDataDir()+"/ear/"+"ear-conf-basic.properties";
-			propsToSet.load(new FileInputStream( filePath ));
+			String propsFilePath = ejtt.getTestDataDir()+"/ear/"+"ear-conf-basic.properties";
+			propsToSet.load(new FileInputStream( propsFilePath ));
 
 			// Get the current properties.
 			Properties propsOriginal = getFormPropertiesValues( propsToSet );
@@ -485,9 +485,7 @@
 
 
 	/**
-	 * Changes EAR configuration, and checks whether the changes were saved.
-	 *
-	 * FAILS because some of the values are read-only.  EMBJOPR-96
+	 * Redeploys EAR.
 	 */
 	public void testEarRedeployment() throws IOException, EmbJoprTestException {
 
@@ -526,9 +524,9 @@
 	/**
 	 * Deploys exploded EAR and checks whether it is reported as exploded.
 	 *
-	 * FAILS: EMBJOPR-95
+	 * DISABLED - Badly written test, to be fixed. TODO: Hot-deploy
 	 */
-	public void testUnzippedEarReportedAsExploded() throws IOException, EmbJoprTestException {
+	public void DISABLEDtestUnzippedEarReportedAsExploded() throws IOException, EmbJoprTestException {
 
 		// Deploy the EAR.
 		String earFilePath = ejtt.getTestDataDir() + "/ear/"+BASIC_EAR;
@@ -665,7 +663,7 @@
 		}
 		finally {
 			// Delete the EAR dir.
-			deleteFromDeployDir(EAR_UNPACKED_ZIP);
+			deleteFromDeployDir(EAR_UNPACKED);
 		}
 	}
 
@@ -845,7 +843,7 @@
 
 
 
-	// TODO: Move to utils
+	// TODO: Moved to EJTT, remove from here.
 	private void deleteFromDeployDir( String deployableName ) throws IOException{
 
 		String deployDir = ejtt.getDeployDir();

Modified: trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/as5/WarTest.java
===================================================================
--- trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/as5/WarTest.java	2009-03-20 03:11:17 UTC (rev 244)
+++ trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/as5/WarTest.java	2009-03-20 03:26:13 UTC (rev 245)
@@ -22,36 +22,43 @@
 
 package org.jboss.jopr.jsfunit.as5;
 
+import javax.faces.context.FacesContext;
+import javax.servlet.http.HttpServletRequest;
+import com.gargoylesoftware.htmlunit.WebClient;
+import org.jboss.jopr.jsfunit.util.EmbJoprTestToolkit.*;
+
 import org.jboss.jopr.jsfunit.*;
 import com.gargoylesoftware.htmlunit.html.*;
-import java.io.IOException;
+import java.io.*;
+import java.util.Properties;
+import javax.faces.application.FacesMessage;
 import junit.framework.Test;
 import junit.framework.TestSuite;
-import javax.faces.context.FacesContext;
-import javax.servlet.http.HttpServletRequest;
-import com.gargoylesoftware.htmlunit.WebClient;
-import java.io.File;
-import java.io.FileNotFoundException;
-import org.jboss.jopr.jsfunit.exceptions.ActionNotAvailableException;
-import org.jboss.jopr.jsfunit.exceptions.HtmlElementNotFoundException;
+import org.apache.commons.lang.math.RandomUtils;
+import org.jboss.jopr.jsfunit.exceptions.*;
+import org.jboss.jopr.jsfunit.util.ActiveConditionChecker;
+import org.jboss.jopr.jsfunit.util.DescribedCondition;
+import org.jboss.jopr.jsfunit.util.EmbJoprTestToolkit.*;
+import org.w3c.dom.Node;
 
-
-
 /**
  * This class contains tests for testing the EmbJopr Application
  * Management Functions for Web Components with JBoss AS 5.
- * 
- * @author Shelly McGowan
  *
+ * Most tests currently fail because of 
+ * JBAS-6640: Undeploying and deploying the same WAR in short time fails.
  */
 public class WarTest extends ApplicationTestBaseAS5 {
 
+	public static final int DEPLOY_UP_STATE_WAIT_CHECK_INTERVAL = 6000;
+	public static final int DEPLOY_UP_STATE_WAIT_CHECK_RETRIES = 50;
+
+	
+
 	/**
-	  * @return the suite of tests being tested
-	*/
-
-	public static Test suite()
-	{
+	 * @return the suite of tests being tested
+	 */
+	public static Test suite() {
 		return new TestSuite(WarTest.class);
 	}
 
@@ -90,6 +97,10 @@
 			HtmlPage page = (HtmlPage)webClient.getPage("http://localhost:" + port + "/hellothere/hello.jsp");
 			assertTrue(page.asText().contains("HELLO WORLD"));
 
+		}
+		finally {
+			//undeployWAR(BASIC_WAR);
+
 			// Undeploy the WAR
 			HtmlButtonInput deleteButton = getAppDeleteButton(BASIC_WAR);
 			deleteButton.click();
@@ -98,14 +109,598 @@
 			// reason, JBoss doesn't undeploy the MBeans
 			// JBAS-XXXX
 			//assertFalse(isWarDeployed(BASIC_WAR));
+
 		}
+	}
+
+
+
+
+
+
+	public void DISABLEDtestBadWarRedeploy() throws IOException, HtmlElementNotFoundException, ActionNotAvailableException {
+
+		try {
+			String filePath = ejtt.getTestDataDir() + "/war/"+AppConstants.WAR_FILENAME_MALFORMED_APP;
+			deployWAR(filePath);
+
+			checkClientAndServerMessages("Failed to create Resource", "Failed to create Resource", true);
+		}
 		finally {
 			undeployWAR(BASIC_WAR);
 		}
 	}
 
 
+
+
+
+
+
+	public void testNavigationToWar() throws IOException, HtmlElementNotFoundException, ActionOutOfSyncException, ActionNotAvailableException, EmbJoprTestException, InterruptedException, ActionOutOfSyncException
+	{
+
+		// JBossAS Servers node
+		NavTreeNode nodeServers = ejtt.getNavTree().getNodeByLabel("JBossAS Servers");
+		nodeServers.click();
+
+		{
+			String headerText = "JBossAS Server";
+
+			assertTrue("Page doesn't contain the header: "+headerText,
+							client.getPageAsText().contains(headerText));
+
+			assertTrue("EmbJopr should list at least one server (the one it is running on)" +
+							" and that should be in the UP sate.",
+							client.getPageAsText().contains("UP"));
+			// Check whether the server is listed. If not, Exception is thrown.
+			ContentTableRow row =
+							ejtt.getTabMenu().getTabContentBox().getTableUnderHeader("JBoss Application Server")
+							.getFirstRowContainingLink("JBoss App Server:default");
+			// Click the server link
+			//HtmlAnchor link row.getLinkByLabel("JBoss App Server:default");
+			Node firstLink = row.getCellByColumnName("Name").getElementsByTagName("a").item(0);
+			if( null == firstLink || !(firstLink instanceof HtmlAnchor) )
+				throw new HtmlElementNotFoundException("Can't find the server link.");
+
+			((HtmlAnchor)firstLink).click();
+		}
+
+		// JBoss App Server:${config} node
+		{
+			String pageText = client.getPageAsText();
+
+			String headerText = "JBoss App Server:default";
+			assertTrue("Page doesn't contain the header: "+headerText,
+							pageText.contains(headerText));
+
+			headerText = "General Properties";
+			assertTrue("Page doesn't contain the header: "+headerText,
+							pageText.contains(headerText));
+
+			// TODO: This page reports "Version:5.0 CR1" - EMBJOPR-77
+
+			ejtt.getNavTree().getNodeByLabel("Applications").click();
+
+		}
+
+
+		// Applications node
+		{
+			// Whooo-hooo! So much to click through!
+
+			ejtt.getTabMenu().clickTab("Summary");
+
+			// TODO: Pagination options: EMBJOPR-78
+			// resourceDataScroller.xhtml, TableManager.java, "pageSizes".
+
+
+			// There's at least one Application with State == UP.
+			//ContentTable table = ejtt.getTabMenu().getTabContentBox().getTableUnderHeader("Different types of Applications");
+			HtmlTable tableElement = (HtmlTable)client.getElement("categorySummaryForm:dataTable");
+			ContentTable table = ejtt.getTabMenu().getTabContentBox().getTable(tableElement);
+			ContentTableRow row = table.getFirstRowContainingText("UP");
+
+			// Go further - try to click on any Application that is up.
+			HtmlAnchor link = row.getFirstLinkFromColumn("Name");
+			link.click();
+		}
+
+
+		{
+			// Go back to applications Sumary screen.
+			ejtt.getNavTree().getNodeByLabel("Applications").click();
+		}
+
+
+		// Concrete appliction node.
+		{
+
+			// Deploy the WAR.
+			String filePath = ejtt.getTestDataDir() + "/war/"+BASIC_WAR;
+			deployWarRepeatedly( filePath );
+
+			ejtt.getNavTree().getNodeByLabel(NAV_WAR).click();
+
+			// Get to the app through listing.
+			log.debug("Looking for row with: "+BASIC_WAR);
+
+			// Commented out: we would have to click trough pages.
+			//ContentTableRow row = ejtt.getDefaultContentTable().getFirstRowContainingLink(BASIC_WAR);
+			ContentTableRow row = ejtt.getTabMenu().getTabContentBox()
+							.findLinkRowInDataTableUsingPagination(BASIC_WAR);
+
+			assertTrue("Page doesn't list "+BASIC_WAR+" in Summary tab.", row != null );
+
+			 // Go to the summary through listed item.
+			row.getLinkByLabel(BASIC_WAR).click();
+			/**/
+
+			
+			// Other way to get to app: through nav tree.
+			ejtt.getNavTree().getNodeArrow(NAV_WAR).click();
+			ejtt.navTree.waitUntilNodeLoadedByAjax(BASIC_WAR, 500, 15);
+			ejtt.navTree.getNodeByLabel(BASIC_WAR).click();
+			/**/
+
+
+			// Check that we have the summary tab for the selected WAR.
+			assertTrue( "WAR name "+BASIC_WAR+" not found in the content box.",
+				ejtt.getTabMenu().getTabContentBox().getElement().getTextContent().contains(BASIC_WAR) );
+
+			// Go to the summary through nav tree node.
+			NavTreeNode appNode = ejtt.getNavTree().getNodeByLabel(NAV_WAR);
+			if( !appNode.isExpanded() ){
+				log.info("Expanding.");
+				appNode.getArrowLink().click();
+				Thread.sleep(2000);
+			}
+			ejtt.getNavTree().getNodeByLabel(BASIC_WAR).click();
+			// Check that we have the summary tab for the selected WAR.
+			ejtt.getTabMenu().getTabContentBox().getElement().getTextContent().contains(BASIC_WAR);
+
+			undeployWAR(BASIC_WAR);
+
+		}
+
+
+	}// testNavigationToWar()
+
+
+
+
+
+
+
 	/**
+	 * Tests the values shown in the Summary tab of WAR.
+	 *
+	 *  FAILS because of:  EMBJOPR-110
+	 */
+	public void testWarSummaryTab() throws EmbJoprTestException, IOException, Exception {
+
+		final int DEPLOY_TIMEOUT_SEC = 120;
+
+		// Deploy the WAR
+		String appFilePath = System.getProperty(SYSPROP_TESTDATA_DIR) + "/war/"+BASIC_WAR;
+		deployWarRepeatedly( appFilePath );
+
+		try {
+
+			// Wait until the WAR appears...
+			// Should be present when the page is reloaded.
+			// TODO: Replace with waitUntil~()
+			new ActiveConditionChecker(new DescribedCondition("WAR appears in Summary tab list") {
+				public boolean isTrue() throws Exception {
+					// Refresh, then check.
+					ejtt.getNavTree().getNodeByLabel(NAV_WAR).click();
+					ContentTableRow appRow = ejtt.getDefaultContentTable().findFirstRowContainingLink(BASIC_WAR);
+					return null != appRow;
+				}
+			}).dumpPageOnTimeout(this).throwOnTimeout().waitWithTimeout(2000, 5);
+			/**/
+
+
+			ContentTableRow appRow = ejtt.getDefaultContentTable().getFirstRowContainingLink(BASIC_WAR);
+
+			// Wait until the Status is "UP".
+			// TODO: Replace with ActiveConditionChecker.
+			int maxLoops = DEPLOY_TIMEOUT_SEC;
+			do {
+				String statusText = appRow.getCellTextByColumnName("Status");
+				log.debug("WAR Status: "+statusText);
+				if( "UP".equals(statusText) )
+					break;
+
+				// Refresh page after 1 second.
+				ejtt.getNavTree().getNodeByLabel(NAV_WAR).click();
+				appRow = ejtt.getDefaultContentTable().getFirstRowContainingLink(BASIC_WAR);
+
+				// We don't want an infinite loop by mistake.
+				if( maxLoops-- <= 0 ){
+					throw new EmbJoprTestException("WAR "+BASIC_WAR+" not UP after "+DEPLOY_TIMEOUT_SEC+" seconds.");
+				}
+			} while( true );
+
+			// FAILS because of EMBJOPR-80.
+			appRow.getLinkByLabel(BASIC_WAR).click();
+
+
+			// Check the values in info table(s)
+
+			// General Properties
+			HtmlTable genpropTable = ejtt.getTabMenu().getTabContentBox().getTableUnderHeader("General Properties").getElement();
+			ContentInfoTable infoTable = ejtt.getContentInfoTable( genpropTable );
+			Properties props = infoTable.getProperties();
+			log.info("General Properties: "+props.toString());
+
+			assertEquals(BASIC_WAR, props.getProperty("Name").trim());
+			//assertEquals("?", props.getProperty("Version")); // TODO: Where does RHQ get the version from?
+
+
+			// Resource Traits
+			infoTable = ejtt.getContentInfoTable(
+							ejtt.getTabMenu().getTabContentBox().getTableUnderHeader("Resource Traits").getElement() );
+			props = infoTable.getProperties();
+			log.info("Resource Traits: "+props.toString());
+			log.debug("Path: "+props.getProperty("Path"));///
+
+
+			String path = ejtt.getDeployDir()+"/"+BASIC_WAR;
+			assertEquals(path, props.getProperty("Path").trim());
+			assertEquals("no", props.getProperty("Exploded?").trim());
+
+			// Metrics Summary
+			HtmlTable summaryTable = ejtt.getTabMenu().getTabContentBox().getTableUnderHeader("Metrics Summary").getElement();
+			infoTable = ejtt.getContentInfoTable(summaryTable);
+			// (nothing here yet)
+
+
+		}
+		finally {
+			// Undeploy the WAR
+			undeployWAR( BASIC_WAR );
+		}
+
+	}// testWarSummary()
+
+
+
+
+
+
+
+	/**
+	 * Changes WAR configuration, and checks whether the changes were saved.
+	 *
+	 * FAILS because some of the values are read-only.  EMBJOPR-96
+	 */
+	public void testWarConfigurationTab() throws IOException, EmbJoprTestException, HtmlElementNotFoundException, Exception {
+
+		// Deploy the WAR.
+		String filePath = ejtt.getTestDataDir() +"/war/"+ BASIC_WAR;
+		deployWarRepeatedly( filePath );
+
+		try {
+
+			ejtt.getNavTree().getNodeByLabel(NAV_WAR).click();
+			ejtt.deployment.waitActivelyForDeployment(DeployableTypes.WAR, BASIC_WAR, DEPLOY_UP_STATE_WAIT_CHECK_INTERVAL, DEPLOY_UP_STATE_WAIT_CHECK_RETRIES, this);
+
+			// Navigate to the Configuration tab
+			ContentTableRow appRow = ejtt.getDefaultContentTable().getFirstRowContainingLink(BASIC_WAR);
+			appRow.getLinkByLabel(BASIC_WAR).click();
+			ejtt.tabMenu.clickConfigurationTab();
+
+			// Read properties.
+			Properties props = new Properties();
+			String propsFilePath = ejtt.getTestDataDir()+"/war/"+"war-conf-basic.properties";
+			props.load(new FileInputStream( propsFilePath ));
+
+
+			// Set the configuration options and Save
+			fillOutForm(props);
+			//ejtt.getTabMenu().getTabContentBox().getButtonByLabel("Save");
+			ejtt.getClickableByID("resourceConfigurationForm:saveButton").click();
+
+
+			// Check whether the properties were saved.
+			ejtt.tabMenu.clickConfigurationTab();
+
+			// TODO: We don't see the success message! EMBJOPR-89
+			//checkClientAndServerMessages("successfully", "successfully", false);
+
+			// FAILS because some of the values are read-only.  EMBJOPR-96
+			checkForm(props);
+
+			// TODO: Finish when the properties are marked read-only.
+
+		}
+		finally {
+			undeployWAR(BASIC_WAR);
+		}
+
+	}
+
+
+
+
+
+	/**
+	 * Changes WAR configuration, and verifies that the changes were NOT saved.
+	 *
+	 * FAILS because some of the values are read-only.  EMBJOPR-96
+	 */
+	public void testWarConfigurationTabCancel() throws IOException, EmbJoprTestException {
+
+		// Deploy the WAR.
+		String filePath = ejtt.getTestDataDir() +"/war/"+ BASIC_WAR;
+		deployWarRepeatedly( filePath );
+
+		try {
+
+			ejtt.getNavTree().getNodeByLabel(NAV_WAR).click();
+			ejtt.deployment.waitActivelyForDeployment(DeployableTypes.WAR, BASIC_WAR,
+							DEPLOY_UP_STATE_WAIT_CHECK_INTERVAL, DEPLOY_UP_STATE_WAIT_CHECK_RETRIES, this);
+
+			// Navigate to the Configuration tab
+			ContentTableRow row = ejtt.getDefaultContentTable().getFirstRowContainingLink(BASIC_WAR);
+			row.getLinkByLabel(BASIC_WAR).click();
+			ejtt.tabMenu.clickConfigurationTab();
+
+
+			// Load properties (we will use their names).
+			Properties propsToSet = new Properties();
+			String propsFilePath = ejtt.getTestDataDir()+"/war/"+"war-conf-basic.properties";
+			propsToSet.load(new FileInputStream( propsFilePath ));
+
+			// Get the current properties.
+			Properties propsOriginal = getFormPropertiesValues( propsToSet );
+
+
+			// Set the configuration options and CANCEL
+			fillOutForm( propsToSet );
+			ejtt.getClickableByID("resourceConfigurationForm:cancelButton").click();
+
+
+			// TODO: We should get back to Conf tab automatically: EMBJOPR-100
+			ejtt.tabMenu.clickConfigurationTab();
+
+			// Now check whether the values are the same as before editing.
+			checkForm( propsOriginal );
+
+		}
+		finally {
+			undeployWAR(BASIC_WAR);
+		}
+
+	}
+
+
+
+
+	/**
+	 * Redeploys WAR.
+	 *
+	 * Fails because of:  EMBJOPR-109
+	 */
+	public void testWarRedeployment() throws IOException, EmbJoprTestException {
+
+		// Deploy the WAR.
+		String appFilePath = ejtt.getTestDataDir() +"/war/"+ BASIC_WAR;
+		deployWarRepeatedly( appFilePath );
+
+		try {
+
+			ejtt.getNavTree().getNodeByLabel(NAV_WAR).click();
+			ejtt.deployment.waitActivelyForDeployment(DeployableTypes.WAR, BASIC_WAR, DEPLOY_UP_STATE_WAIT_CHECK_INTERVAL, DEPLOY_UP_STATE_WAIT_CHECK_RETRIES, this);
+
+			// Navigate to the Configuration tab
+			ContentTableRow row = ejtt.getDefaultContentTable().getFirstRowContainingLink(BASIC_WAR);
+			row.getLinkByLabel(BASIC_WAR).click();
+			ejtt.tabMenu.clickContentTab();
+
+			String xPath = ".//table//input[@type='file']";
+			HtmlFileInput fileInput = ejtt.tabMenu.getTabContentBox().getElement().getFirstByXPath(xPath);
+			fileInput.setValueAttribute(appFilePath);
+			xPath = ".//table//input[@type='submit']";
+			HtmlSubmitInput submit = ejtt.tabMenu.getTabContentBox().getElement().getFirstByXPath(xPath);
+			submit.click();
+
+		}
+		finally {
+			DebugUtils.writeFile("target/redeployment.html", client.getPageAsText());///
+			undeployWAR(BASIC_WAR);
+		}
+
+	}
+
+
+
+	/**
+	 * Deploys exploded WAR and checks whether it is reported as exploded.
+	 *
+	 * DISABLED - Badly written test, to be fixed. TODO: Hot-deploy
+	 */
+	public void DISABLEDtestUnzippedWarReportedAsExploded() throws IOException, EmbJoprTestException {
+
+		// Deploy the WAR.
+		String WARFilePath = ejtt.getTestDataDir() + "/war/"+BASIC_WAR;
+		deployWarRepeatedly( WARFilePath );
+
+		try {
+			// Wait for WAR to be deployed and UP
+			ejtt.getNavTree().getNodeByLabel(NAV_WAR).click();
+			ejtt.deployment.waitActivelyForDeployment(DeployableTypes.WAR, BASIC_WAR, DEPLOY_UP_STATE_WAIT_CHECK_INTERVAL, DEPLOY_UP_STATE_WAIT_CHECK_RETRIES, this);
+
+			// Click the WAR link 
+			ejtt.getTabMenu().getTabContentBox().getFirstTable()
+							.getFirstRowContainingText(BASIC_WAR).getFirstLinkFromColumn("Name").click();
+
+			DebugUtils.writeFile("target/res_traits.html", client.getPageAsText());///
+
+			ContentTable table = ejtt.getTabMenu().getTabContentBox().getTableUnderHeader("Resource Traits");
+			ContentInfoTable infoTable = ejtt.getTabMenu().getTabContentBox().getContentInfoTable(table.getElement());
+			Properties props = infoTable.getProperties();
+			log.info("Resource Traits: "+props.toString());
+			log.debug("Exploded?: "+props.getProperty("Exploded?"));
+
+			assertEquals("'Exploded?' should be 'yes'", "yes", props.getProperty("Exploded?")/*.toLowerCase()*/ );
+
+		}
+		finally {
+			undeployWAR(BASIC_WAR);
+		}
+
+	}
+
+
+
+
+	/**
+	 * Checks WAR metrics tab.
+	 */
+	public void testWarMetricsTab() throws IOException, EmbJoprTestException {
+
+		// Deploy the WAR.
+		String WARFilePath = ejtt.getTestDataDir() + "/war/"+BASIC_WAR;
+		deployWarRepeatedly( WARFilePath );
+
+		try {
+
+			ejtt.getNavTree().getNodeByLabel(NAV_WAR).click();
+			ejtt.deployment.waitActivelyForDeployment(DeployableTypes.WAR, BASIC_WAR, DEPLOY_UP_STATE_WAIT_CHECK_INTERVAL, DEPLOY_UP_STATE_WAIT_CHECK_RETRIES, this);
+
+			// Navigate to the Metrics tab
+			ContentTableRow row = ejtt.getDefaultContentTable().getFirstRowContainingLink(BASIC_WAR);
+			row.getLinkByLabel(BASIC_WAR).click();
+			ejtt.tabMenu.clickMetricsTab();
+
+			// Resource Traits
+
+			// Check the Path.
+			HtmlTable tbl = ejtt.getTabMenu().getTabContentBox().
+							getTableUnderHeader("Trait Values").getElement();
+			ContentInfoTable infoTable = ejtt.getContentInfoTable( tbl );
+			Properties props = infoTable.getProperties();
+
+			String path = ejtt.getDeployDir()+"/"+BASIC_WAR;
+			assertEquals(path, props.getProperty("Path").trim());
+
+
+		}
+		finally {
+			undeployWAR(BASIC_WAR);
+		}
+
+	}
+
+
+	/**
+	 * Changes WAR configuration, and checks whether the changes were saved.
+	 *
+	 * FAILS because some of the values are read-only.  EMBJOPR-96
+	 */
+	public void testWarMetricsTabRefreshButton() throws IOException, EmbJoprTestException, HtmlElementNotFoundException, Exception {
+
+		// Deploy the WAR.
+		String WARFilePath = ejtt.getTestDataDir() + "/war/"+BASIC_WAR;
+		deployWarRepeatedly( WARFilePath );
+
+		try {
+
+			ejtt.getNavTree().getNodeByLabel(NAV_WAR).click();
+			ejtt.deployment.waitActivelyForDeployment(DeployableTypes.WAR, BASIC_WAR,
+							DEPLOY_UP_STATE_WAIT_CHECK_INTERVAL, DEPLOY_UP_STATE_WAIT_CHECK_RETRIES, this);
+
+			// Navigate to the Metrics tab
+			ContentTableRow row = ejtt.getDefaultContentTable().getFirstRowContainingLink(BASIC_WAR);
+			row.getLinkByLabel(BASIC_WAR).click();
+			ejtt.tabMenu.clickMetricsTab();
+
+			// Click the Refresh button.
+			// Can this change to submit? Perhaps set an ID and use ejtt.getClickableById().
+			ejtt.tabMenu.getTabContentBox().getButtonByLabel("Refresh").click();
+
+			// Check that we are still on the right tab.
+			assertTrue("Metrics tab is active", ejtt.tabMenu.isTabActive("Metrics") );
+			assertTrue("Page contains WAR name", client.getPageAsText().contains(BASIC_WAR) );
+			assertTrue("Page contains 'Refresh'", client.getPageAsText().contains("Refresh") );
+
+		}
+		finally {
+			undeployWAR(BASIC_WAR);
+		}
+
+	}
+
+
+	/**
+	 * Deploys an exploded WAR application.
+	 *
+	 * FAILS when undeploying, because:
+	 *
+org.jboss.jopr.jsfunit.exceptions.EmbJoprTestException: Couldn't delete following files:
+  /home/ondra/work/JOPRembedded/embjopr-svn-trunk/jsfunit/target/jboss5x/deploy/unpacked-web1.war
+
+	at org.jboss.jopr.jsfunit.util.EmbJoprTestToolkit$Deployment.deleteDirectory(EmbJoprTestToolkit.java:1662)
+	at org.jboss.jopr.jsfunit.util.EmbJoprTestToolkit$Deployment.deleteFromDeployDir(EmbJoprTestToolkit.java:1652)
+	at org.jboss.jopr.jsfunit.as5.WarTest.testDeployUnpackedWar(WarTest.java:663)
+	 *
+	 * TODO:  Catch exceptions in finally and log them only (in all tests),
+	 *        to get the eventual real exception from the try block.
+	 *
+	 * TODO:  Think up how to simulate hot-undeploy.
+	 *				Should we rename it to other dir and then delete?
+	 *
+	 *        Perhaps it just still didn't process the deployed war when trying to undeploy?
+	 *				  "Condition 'WAR unpacked-web1.war appears in embjopr as deployed' not satisfied,
+	 *           0 retries left. Leaving the wait loop."
+	 *        Should we wait more? Or is it caused by failures of some previous tests?
+	 *
+	 */
+	public void testDeployUnpackedWar() throws IOException, EmbJoprTestException {
+
+
+		// Deploy the unpacked WAR.
+		// We have to use hotdeploy - can't upload a directory.
+		log.info("Unzipping war/"+WAR_UNPACKED_ZIP);
+		ejtt.deployment.unzipToDeployDir("war/"+WAR_UNPACKED_ZIP, "");
+
+		try {
+			// Loop, wait for the app to appear.
+			log.info("Waiting for WAR to appear.");
+			ejtt.deployment.waitActivelyForDeployment(DeployableTypes.WAR, WAR_UNPACKED,
+						DEPLOY_UP_STATE_WAIT_CHECK_INTERVAL, DEPLOY_UP_STATE_WAIT_CHECK_RETRIES, this);
+
+
+			ejtt.getNavTree().getNodeByLabel(NAV_WAR).click();
+
+			ContentTableRow row = ejtt.getDefaultContentTable().getFirstRowContainingLink(WAR_UNPACKED);
+
+			// TODO: Finish
+
+			// TODO: Check whether Exploded?:  yes.  EMBJOPR-95
+
+			// TODO: DeploymentUtils, DeployableTypes, isAvailable enum inner classes
+
+			// TODO: Preliminary test - check system properties, their validity, java version, etc.
+		}
+		finally {
+			// Delete the WAR dir.
+			ejtt.deployment.deleteFromDeployDir(WAR_UNPACKED);
+		}
+	}
+
+
+
+
+
+
+
+
+
+
+	/**
 	 * Deploys WAR.
 	 */
 	private void deployWAR( String warFilePath )
@@ -128,28 +723,91 @@
 		fileInput.setContentType("application/war");
 		fileInput.setValueAttribute(warFilePath);
 		client.click("createContentForm:addButton");
+
+		// Log server message.
+		ejtt.logServerMessage();
+
+		// Todo: Write some waitUntilDeployed().
 		ejtt.sleep( 2000 );
 
 	}
 
 
+
+	/**
+	 * Deploys WAR; if fails, waits 5 seconds and re-tries; this is repeated 3 times.
+	 */
+	private void deployWarRepeatedly( final String warFilePath )
+					throws IOException, HtmlElementNotFoundException, EmbJoprTestException
+	{
+
+		try {
+
+			// Try it 3x in 5 second interval.
+			new ActiveConditionChecker( new DescribedCondition("WAR '"+warFilePath+"' succesfuly deployed") {
+				public boolean isTrue() throws Exception {
+					deployWAR(warFilePath);
+					if( server.getFacesMessages().hasNext() ){
+						FacesMessage msg = server.getFacesMessages().next();
+						if( msg.getSeverity() == FacesMessage.SEVERITY_INFO )
+							return true;
+						else
+							ejtt.logServerMessage("Deployment error: ");
+					}
+					return false;
+				}
+			}).dumpPageOnTimeout(this).throwOnTimeout().waitWithTimeout(5000, 3);
+
+		}
+		catch( Exception ex ){
+			throw new EmbJoprTestException(ex.getMessage());
+		}
+
+
+	}// deployWarRepeatedly()
+
+
+	/**
+	 * Undeploys war.
+	 *
+	 * TODO: When tested, merge to EJTT.Deployment.
+	 */
 	private void undeployWAR( String warFileName )
 					throws IOException, HtmlElementNotFoundException, ActionNotAvailableException
 	{
 
 		// Navigate to Enterprise Archives
-		ejtt.getNavTree().getNodeLink(NAV_EAR).click();
+		ejtt.getNavTree().getNodeLink(NAV_WAR).click();
 
 		ejtt.getTabMenu().clickSummaryTab();
 
-		HtmlButtonInput deleteButton = getAppDeleteButton( warFileName );
-		deleteButton.click();
+		/// DEBUG dump
+		//String dumpFile = "undeploy"+RandomUtils.nextInt()+".html";
+		//log.debug("Dumping page to: "+dumpFile);
+		//DebugUtils.writeFile(dumpFile, client.getPageAsText());
 
+		//HtmlButtonInput deleteButton = getAppDeleteButton( warFileName ).click();
+
+		// Find the row containing the deployable. Use the pagination if needed.
+		ContentTableRow appRow = ejtt.getTabMenu().getTabContentBox().
+						findLinkRowInDataTableUsingPagination(warFileName);
+
+		/// DEBUG dump
+		//log.debug("Dumping page to: "+dumpFile+"2");
+		//DebugUtils.writeFile(dumpFile+"2", client.getPageAsText());
+
+		if( null == appRow ){
+			log.warn("Can't find row with WAR to undeploy: "+warFileName);
+			return;
+		}
+
+		appRow.getButtonByLabel("Delete").click();
+
 		// Log the message (with prefix of potential warning)
 		ejtt.logServerMessage("Something went wrong with undeploy: ");
 
-		// Sleep for 3 sec. TODO: write some waitForUndeployed()
-		ejtt.sleep( 3000 );
+		// Sleep for 3 sec. TODO: write some waitForUndeployed(), as negation of opposite.
+		ejtt.sleep( 2000 );
 
 	}
 

Modified: trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/util/ActiveConditionChecker.java
===================================================================
--- trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/util/ActiveConditionChecker.java	2009-03-20 03:11:17 UTC (rev 244)
+++ trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/util/ActiveConditionChecker.java	2009-03-20 03:26:13 UTC (rev 245)
@@ -3,6 +3,7 @@
 import org.jboss.jopr.jsfunit.*;
 import org.apache.commons.lang.StringUtils;
 import org.jboss.jopr.jsfunit.exceptions.EmbJoprTestException;
+import org.jboss.jsfunit.jsfsession.JSFClientSession;
 import org.jboss.logging.*;
 
 
@@ -17,9 +18,12 @@
 	Condition condition;
 	private boolean dumpPageOnTimout = false;
 	private boolean throwExceptionOnTimout = false;
-	private EmbjoprTestCase test;
 
+	// Used when dumping the page in case of exceeded timeout.
+	private String dumpFileName;
+	private JSFClientSession client;
 
+
 	public ActiveConditionChecker(Condition condition) {
 		this.condition = condition;
 	}
@@ -31,9 +35,20 @@
 		log.info("Waiting for condition: "+condition.getDescription());
 
 		while( retries-- > 0 ){
-			if( this.condition.isTrue() )
+			if( this.condition.isTrue() ){
+				log.info("  Condition '"+condition.getDescription()+"' satisfied.");
 				return true;
-			log.info("  Condition not satisfied, "+retries+" left. Sleeping for "+msInterval+" ms.");
+			}
+
+			if( retries <= 0){
+				log.info("  Condition '"+condition.getDescription()+"' not satisfied, "
+								+retries+" retries left. Leaving the wait loop.");
+				break;
+			}
+
+
+			log.info("  Condition '"+condition.getDescription()+"' not satisfied, "
+							+retries+" retries left. Sleeping for "+msInterval+" ms.");
 			try {
 				Thread.sleep(msInterval);
 			} catch (InterruptedException ex){
@@ -46,7 +61,8 @@
 		if( this.dumpPageOnTimout ){
 			try {
 				// Since this is still inner class, we could use 'this'.
-				DebugUtils.writeFile("target/"+test.getName()+".html", test.getClient().getPageAsText());///
+				log.info("Dumping page text to: "+this.dumpFileName);
+				DebugUtils.writeFile("target/"+this.dumpFileName, this.client.getPageAsText());///
 			} catch (Exception ex) { log.error("Can't dump page.", ex); }
 		}
 
@@ -67,8 +83,15 @@
 
 	// This has nothing to do with condition checking, but is convenient shorthand...
 	public ActiveConditionChecker dumpPageOnTimeout(EmbjoprTestCase test) {
+		if( null == test ) return this;
+		return dumpPageOnTimeout( test.getName()+".html", test.getClient() );
+	}
+
+	// This has nothing to do with condition checking, but is convenient shorthand...
+	public ActiveConditionChecker dumpPageOnTimeout(String dumpFileName, JSFClientSession client) {
 		this.dumpPageOnTimout = true;
-		this.test = test;
+		this.dumpFileName = dumpFileName;
+		this.client = client;
 		return this;
 	}
 

Modified: trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/util/EmbJoprTestToolkit.java
===================================================================
--- trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/util/EmbJoprTestToolkit.java	2009-03-20 03:11:17 UTC (rev 244)
+++ trunk/jsfunit/src/test/java/org/jboss/jopr/jsfunit/util/EmbJoprTestToolkit.java	2009-03-20 03:26:13 UTC (rev 245)
@@ -6,17 +6,27 @@
 import com.gargoylesoftware.htmlunit.Page;
 import java.util.*;
 
+import java.util.logging.Level;
 import org.jboss.jopr.jsfunit.exceptions.*;
 import com.gargoylesoftware.htmlunit.html.*;
 import com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.net.URL;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
 import javax.faces.application.FacesMessage;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.math.NumberUtils;
 import org.jboss.jopr.jsfunit.AppConstants;
+import org.jboss.jopr.jsfunit.AppConstants.DeployableTypes;
+import org.jboss.jopr.jsfunit.DebugUtils;
+import org.jboss.jopr.jsfunit.EmbjoprTestCase;
 import org.jboss.jsfunit.jsfsession.*;
 import org.jboss.logging.Logger;
 import org.mozilla.javascript.NativeFunction;
@@ -385,18 +395,19 @@
 	 */
 	public class TabMenu {
 
-		public TabContentBox getTabContentBox() throws HtmlElementNotFoundException {
-
+		public TabContentBox getTabContentBox() throws HtmlElementNotFoundException
+		{
 			HtmlElement contentElement = (HtmlElement) client.getElement("content");
-			HtmlElement tabContentBox = (HtmlElement) contentElement.getFirstByXPath("div[@class='tabmenubox']");
+			String xPath = "div[@class='tabmenubox' or @class='notabmenubox']";
+			HtmlElement tabContentBox = (HtmlElement) contentElement.getFirstByXPath(xPath);
 			if( null == tabContentBox )
-				throw new HtmlElementNotFoundException("Tab content box not found using div[@class='tabmenubox'] XPath");
+				throw new HtmlElementNotFoundException("Tab content box not found using XPath: "+xPath);
 
 			return new TabContentBox(tabContentBox);
 		}
 
-		public ClickableElement getTabByLabel( String label ) throws HtmlElementNotFoundException {
-
+		public ClickableElement getTabByLabel( String label ) throws HtmlElementNotFoundException
+		{
 			DomElement element = (DomElement)client.getElement("tabmenu");
 			String xPath = "ul/li/span[normalize-space(string())='"+label+"'] | ul/li/a[normalize-space(string())='"+label+"']";
 			ClickableElement tabContent = element.getFirstByXPath(xPath);
@@ -406,10 +417,10 @@
 				throw new HtmlElementNotFoundException("Tab '"+label+"' not found using XPath '"+xPath+"'");
 
 			return tabContent;
-
 		}
 
-		public ClickableElement getTabByID( String tabID ) throws HtmlElementNotFoundException {
+		public ClickableElement getTabByID( String tabID ) throws HtmlElementNotFoundException
+		{
 			ClickableElement element = (ClickableElement)client.getElement(tabID);
 			if( null == element )
 				throw new HtmlElementNotFoundException("Tab with id '"+tabID+"' not found, perhaps disabled?");
@@ -536,6 +547,7 @@
 
 
 
+
 	/**
 	 * Inner class for manipulation with tab content box.
 	 */
@@ -564,13 +576,18 @@
 		 * Unfortunately, headers are not H2 or similar, but DIV class="instructionalText".
 		 * To be revised later.
 		 */
-		public ContentTable getTableUnderHeader( String headerText ) throws ActionOutOfSyncException
+		public ContentTable getTableUnderHeader( String headerText ) throws ActionOutOfSyncException, HtmlElementNotFoundException
 		{
 			checkIfStillValid();
 
 			String xPath = "*[contains(normalize-space(), '"+headerText+"')]/following::table";
 			// [@id='resourceSummaryForm:dataTable'] - is this reliable?
 			HtmlTable tableElement = (HtmlTable) element.getFirstByXPath(xPath);
+			if( null == tableElement ){
+				throw new HtmlElementNotFoundException(
+								"Table under header '"+headerText+"' not found using XPath: "+xPath);
+			}
+
 			return new ContentTable(tableElement);
 		}
 
@@ -637,10 +654,59 @@
 		}
 
 
+		/**
+		 *  Tries to find a data table row with given deployable, using pagination if needed.
+		 * @returns  The row wrapper if found, or null.
+		 */
+		public ContentTableRow findLinkRowInDataTableUsingPagination(String label)
+						throws HtmlElementNotFoundException, IOException
+		{
+
+			ContentTableRow row = null;
+
+			if( null == getTabMenu().getTabContentBox().getPagination().getPageContols() ){
+				log.debug("No page controls present - that probably means that only single page is listed.");
+			}
+			else{
+				log.debug("Number of pages: "+getTabMenu().getTabContentBox().getPagination().getPageCount());
+			}
+
+
+			int currentPage = 1;
+
+			// For all pages...
+			do {
+				HtmlTable tableElm = (HtmlTable) client.getElement("resourceSummaryForm:dataTable");
+				if( null == tableElm ){
+					throw new HtmlElementNotFoundException(
+									"Data table not found (looking for ID 'resourceSummaryForm:dataTable'");
+				}
+
+				ContentTable table = new ContentTable(tableElm);
+				row = table.findFirstRowContainingText(label);
+
+				// Did we find?
+				if( null != row )
+					break;
+				else
+					log.debug("Row with '"+label+"' not present on page "+currentPage+".");
+
+			} while (
+					// Infinite loop prevention.
+					currentPage++ < 20
+					// Pagination is not rendered if not needed.
+					&& null != getTabMenu().getTabContentBox().getPagination().getPageContols()
+					// goNext() returns true if there's a next page to go.
+					&& getTabMenu().getTabContentBox().getPagination().goNext()
+			);
+
+			return row;
+		}
+
+
 	}// inner class TabContentBox
 
 
-
 	/**
 	 * Contains convenience methods for accessing content tables in EmbJopr.
 	 */
@@ -656,6 +722,8 @@
 		 * Creates a data table wrapper for the given table element.
 		 */
 		public ContentTable( HtmlTable element ) {
+			if( null == element )
+				throw new IllegalArgumentException("null given as element for ContentTable.");
 			this.element = element;
 		}
 
@@ -708,15 +776,30 @@
 
 			// TODO: Escape the single quotes. By doubling?
 			// http://books.google.com/books?id=jzqFMlM0gb0C&pg=PA308&lpg=PA308&dq=xquery+escape+quote&source=bl&ots=DIKQ92AhHh&sig=A7adGlif6jfYKtJXGc4eZbXYeCQ&hl=cs&ei=LYCcSYKLO5ir-gazwfjtBA&sa=X&oi=book_result&resnum=8&ct=result
-			String xPath = ".//tr[contains(string(), '"+text+"')]";
+			//String xPath = ".//tr[contains(string(), '"+text+"')]";
+			String xPath = ".//tr[.//*[contains(string(), '"+text+"')]]";
 			HtmlTableRow elm = (HtmlTableRow) element.getFirstByXPath(xPath);
 			if( null == elm )
 				throw new HtmlElementNotFoundException(xPath);
 			return new ContentTableRow(elm, this);
 		}
 
+		/**  Same as getFirstRowContainingText(), only returns null if row is not found. */
+		public ContentTableRow findFirstRowContainingText( String text )
+						throws HtmlElementNotFoundException
+		{
+			if( 0 == element.getRowCount() )
+				return null;
 
+			String xPath = ".//tr[.//*[contains(string(), '"+text+"')]]";
+			HtmlTableRow elm = (HtmlTableRow) element.getFirstByXPath(xPath);
+			if( null == elm )
+				return null;
+			return new ContentTableRow(elm, this);
+		}
 
+
+
 		/**
 		 * Returns wrapper of the table row which contains a link with given label,
 		 * or null when the no such row is found.
@@ -853,19 +936,26 @@
 		}
 
 		/**
-		 * Parses the content of the table for properties.
-		 * @return
+		 * Parses the content of the table properties.
+		 * @returns Set of properties extracted from rows
+		 *          whose plain text has the 'Name: Value' format.
 		 */
 		public Properties getProperties()
 		{
 			Properties props = new Properties();
 
 			// The template has label in span/strong and the value as text in td.
-			String xPath = ".//tr/td[span/strong]";
+			String xPath = ".//tr/td[span/strong | strong]";
+			//String xPath = ".//tr/td[span/strong] | .//tr/td[.//strong]";
 			List<HtmlTableCell> cells  = (List<HtmlTableCell>) this.getElement().getByXPath(xPath);
 			for( HtmlTableCell cell : cells ){
-				String[] parts = cell.getTextContent().split(":");
-				props.put(parts[0], parts[1]);
+				String cellText = cell.getTextContent();
+				String[] parts = cellText.split(":");
+				if( parts.length != 2 ){
+					log.warn("Cell text not in format 'Name: Value': "+cellText);
+					continue;
+				}
+				props.setProperty(parts[0].trim(), parts[1].trim());
 			}
 			return props;
 		}
@@ -906,7 +996,7 @@
 		public ClickableElement getButtonByLabel( String label ) throws HtmlElementNotFoundException
 		{
 			String xPath = ".//input[@type='button' and normalize-space(@value) = '"+label+"']" +
-							" || .//button[normalize-space() = '"+label+"']";
+							" | .//button[normalize-space() = '"+label+"']";
 			HtmlElement elm = this.element.getFirstByXPath(xPath);
 			if( null == elm )
 				throw new HtmlElementNotFoundException("Can't find the button using xPath: "+xPath);
@@ -1010,14 +1100,21 @@
 		private static final String ID_PAGE_SIZE_SELECT = "categorySummaryForm:currentPageSize";
 		private static final String ID_PAGINATION_TOTAL_ITEMS = "paginationTotalItems";
 
-		public HtmlDivision getPageContols(){
-			return (HtmlDivision) client.getElement(ID_PAGE_CONTROLS);
+		/** Returns the HTML element of the bar with "First | Prev | 1 2 | Next Last" controls. */
+		public HtmlDivision getPageContols() throws HtmlElementNotFoundException {
+			//return (HtmlDivision) client.getElement(ID_PAGE_CONTROLS);
+			return (HtmlDivision) getTabMenu().getTabContentBox().getElement()
+							.getFirstByXPath(".//*[contains(@id, 'SummaryForm:dataTableScroller')]");
 		}
 
-		public HtmlSelect getPageSizeSelect(){
-			return (HtmlSelect) client.getElement(ID_PAGE_SIZE_SELECT);
+		/** Returns the HTML Select element of page size selection. */
+		public HtmlSelect getPageSizeSelect() throws HtmlElementNotFoundException {
+			//return (HtmlSelect) client.getElement(ID_PAGE_SIZE_SELECT);
+			return (HtmlSelect) getTabMenu().getTabContentBox().getElement()
+							.getFirstByXPath(".//select[contains(@id, 'SummaryForm:currentPageSize')]");
 		}
 
+		/** Returns total items count, taken from the "Total: N" element. */
 		public int getTotalItemsCount() throws ActionNotAvailableException
 		{
 			Element e = client.getElement(ID_PAGINATION_TOTAL_ITEMS);
@@ -1087,7 +1184,7 @@
 			return !getGoPage(pageNumber).getStyleAttribute().contains("-inact");
 		}
 
-		public int getPageCount(){
+		public int getPageCount() throws HtmlElementNotFoundException {
 			String xPath = ".//td[ count(./*) = 0  and  normalize-space() > 0 ]";
 			List<?> elements = getPageContols().getByXPath(xPath);
 			return elements.size();
@@ -1135,6 +1232,17 @@
 	public HtmlAnchor getLinkInsideForm(String formId, String linkLabel) throws HtmlElementNotFoundException
 	{
 		HtmlForm form = (HtmlForm)client.getElement(formId);
+		if( null == form ){
+			/// Dump the page
+			String normID = StringUtils.replaceChars(formId, "\\/.: ", "-----");
+			String dumpFileName = "target/formNotFound-"+ formId +".html";
+			log.debug("Dumping page to file: "+dumpFileName);
+			try { DebugUtils.writeFile(dumpFileName, client.getPageAsText()); }
+			catch (Exception ex) { log.warn("getLinkInsideForm(): "+ ex.toString()); }
+
+			throw new HtmlElementNotFoundException("Form element of given ID not found: "+formId);
+		}
+
 		String xPath = ".//a[contains(normalize-space(), '"+linkLabel+"')]";
 		HtmlAnchor link = form.getFirstByXPath(xPath);
 		if( null == link )
@@ -1147,11 +1255,12 @@
 
 	/** Calls Thread.sleep(ms), ignores the InterruptedException. */
 	@SuppressWarnings("empty-statement")
-	public static void sleep( int ms ) {
+	public void sleep( int ms ) {
 		try {
-			Thread.sleep(3000);
+			Thread.sleep(ms);
 		} catch (InterruptedException ex) {
-			; // We don't care, that's the purpose of this method.
+			log.warn("EJTT.sleep() interrupted.");
+			// We don't care more, that's the purpose of this method.
 		}
 	}
 
@@ -1224,26 +1333,16 @@
 	}
 
 
+	public final Deployment deployment = new Deployment();
 
 	public class Deployment {
 
 		// TODO: Shortcuts:
 		/*
-		private void deployWAR( String warFilePath ){
-
-		}
-
-		private void undeployWAR( String warFileName ){
-
-		}
-
-		private void deployEAR( String warFilePath ){
-
-		}
-
-		private void undeployEAR( String warFileName ){
-
-		}
+		private void deployWAR( String warFilePath ){}
+		private void undeployWAR( String warFileName ){}
+		private void deployEAR( String warFilePath ){}
+		private void undeployEAR( String warFileName ){}
 		// Etc. */
 
 
@@ -1253,7 +1352,7 @@
 		 *
 		 * @param type  Type of the deployable - EAR, SAR, WAR, ...
 		 */
-		private void deployViaEmbJopr( AppConstants.DeployableTypes type, String filePath )
+		public void deployViaEmbJopr( AppConstants.DeployableTypes type, String filePath )
 					throws IOException, HtmlElementNotFoundException
 		{
 			if( !(new File(filePath)).exists())
@@ -1283,7 +1382,7 @@
 		 *
 		 * @param type  Type of the deployable - EAR, SAR, WAR, ...
 		 */
-		private void undeployViaEmbJopr( AppConstants.DeployableTypes type, String fileName )
+		public void undeployViaEmbJopr( AppConstants.DeployableTypes type, String fileName )
 						throws IOException, HtmlElementNotFoundException, ActionNotAvailableException, ActionOutOfSyncException
 		{
 
@@ -1306,12 +1405,292 @@
 		}// undeployViaEmbJopr()
 
 
-	}
+		// TODO: The following was copied from EarTest.java; remove from there.
 
 
 
+		/** Convenience method, setting mustBeUP to true. */
+		public boolean isDeployedAccordingToEmbJopr( DeployableTypes type, String deployableName )
+				throws HtmlElementNotFoundException, IOException, ActionNotAvailableException{
+			return isDeployedAccordingToEmbJopr( type, deployableName, true );
+		}
 
+		/**
+		 * Returns true if EmbJopr lists a deployable of given type and name,
+		 * and it's State is UP; false otherwise.
+		 */
+		public boolean isDeployedAccordingToEmbJopr( 
+						DeployableTypes type, String deployableName, boolean mustBeUP )
+				throws HtmlElementNotFoundException, IOException, ActionNotAvailableException
+		{
+			// Refresh / go to the appropriate page.
+			getNavTree().getNodeByLabel( type.getNavTreeLabel() ).click();
 
+			// Pagination
+			//int totalItemsCount = getTabMenu().getTabContentBox().getPagination().getTotalItemsCount();
+
+			/*
+			ContentTableRow appRow = null;
+
+			// Search trough all pages.
+			int currentPage = 1;
+			do {
+				appRow = getDefaultContentTable().findFirstRowContainingLink(deployableName);
+				if( null != appRow ){
+					break;
+				}else{
+					log.debug("Row with "+deployableName+" not present on page "+currentPage+".");
+				}
+			} while( currentPage++ < 20 && getTabMenu().getTabContentBox().getPagination().goNext() );
+
+			*/
+
+			// Find the row containing the deployable. Use the pagination if needed.
+			ContentTableRow appRow = getTabMenu().getTabContentBox().
+							findLinkRowInDataTableUsingPagination(deployableName);
+
+			if( null == appRow ){
+				log.debug("Row with '"+deployableName+"' not found.");
+				return false;
+			}
+
+			if( !mustBeUP ){
+				// Not needed to be UP; we found it, thus return true.
+				return true;
+			}
+
+			String statusText = appRow.getCellTextByColumnName("Status");
+			if( "UP".equals(statusText) ){
+				return true;
+			}else{
+				log.debug("Row with "+deployableName+" has Status == '"+statusText+"' != UP.");
+				return false;
+			}
+
+		}// isDeployedAccordingToEmbJopr()
+
+
+
+		/**
+		 * Waits for the deployable to be in the UP State.
+		 *
+		 * @param type  Type of deployable - EAR, WAR, SAR, ...
+		 * @param name  Name of the deployable, like 'hello.war'.
+		 */
+		public void waitActivelyForDeployment(
+							final DeployableTypes type, final String name,
+							int intervalMS, int retries
+						)
+						throws EmbJoprTestException, IOException
+		{
+			waitActivelyForDeployment(type, name, intervalMS, retries, null);
+		}
+
+		/**
+		 * Waits for the deployable to be in the UP State.
+		 *
+		 * @param type  Type of deployable - EAR, WAR, SAR, ...
+		 * @param name  Name of the deployable, like 'hello.war'.
+		 */
+		public void waitActivelyForDeployment(
+							final DeployableTypes type, final String name,
+							int intervalMS, int retries,
+							EmbjoprTestCase test // used for page dump
+						)
+						throws EmbJoprTestException, IOException
+		{
+			try {
+				//final EmbJoprTestToolkit selfEjtt = getEjtt();
+
+				String conditionDesc = type.name()+" "+name+" appears in embjopr as deployed";
+				ActiveConditionChecker checker =
+				new ActiveConditionChecker(new DescribedCondition(conditionDesc) {
+
+					int callsMade = 0;
+
+					public boolean isTrue() throws HtmlElementNotFoundException, IOException, ActionNotAvailableException {
+						// Refresh the page if this is not the first call.
+						if (callsMade++ > 0) {
+							selfEjtt.refreshPage();
+						}
+						// If found, return true.
+						return isDeployedAccordingToEmbJopr(type, name);
+						// If found, return true.
+					}
+				}).throwOnTimeout();
+
+				if( null != test )
+					checker.dumpPageOnTimeout(test);
+
+				boolean deployedSuccessfuly = checker.waitWithTimeout( intervalMS, retries );
+			}
+			catch( EmbJoprTestException ex ){ throw ex; }
+			catch( IOException ex ){ throw ex; }
+			// Wrap all exceptions to EmbJoprTestException.
+			catch( Exception ex ){
+				throw new EmbJoprTestException("Exception thrown while actively waiting for condition.", ex);
+			}
+		}
+
+
+		
+		/**
+		 * Returns true if there's a file of the given name in server's deploy dir;
+		 * false otherwise.
+		 */
+		private boolean isDeployedAccordingToFileSystem( DeployableTypes type, String name )
+		{
+			String deployPath = getDeployDir();
+			String fileName = deployPath+"/"+name;
+			return (new File(fileName)).exists();
+		}
+
+		private void undeployViaFileSystem( String name ) throws EmbJoprTestException{
+			String deployPath = getDeployDir();
+			String fileName = deployPath+"/"+name;
+			File fileToDelete = new File(fileName);
+
+			if( !fileToDelete.exists() )
+				throw new EmbJoprTestException("Deployable doesn't exist: "+fileName);
+
+			if(fileToDelete.isFile()){
+				if( !fileToDelete.delete() ){
+					throw new EmbJoprTestException("Unable to delete: "+fileName);
+				}
+			}else if(fileToDelete.isDirectory()){
+				deleteDirectory(fileToDelete);
+			}
+
+		}// isDeployedAccordingToFileSystem()
+
+
+
+		/**
+		 * Unzips given archive from testdata dir to server's deploy/ dir.
+		 * @param relativeArchivePath  Path of the archive relative to testdata dir.
+		 * @param relativeDestDir      Path of the destination dir relative to deploy dir.
+		 */
+		public void unzipToDeployDir( String relativeArchivePath, String relativeDestDir )
+						throws FileNotFoundException, IOException
+		{
+
+			String destDir = getTestDataDir()+"/"+relativeDestDir;
+			String archivePath = getTestDataDir()+"/"+relativeArchivePath;
+
+			log.info("Unzipping '"+archivePath+"' to '"+destDir+"'.");
+
+			unzipArchive( archivePath, destDir );
+		}
+
+
+
+		/**
+		 * Unzips archive from the given path to the given destination dir.
+		 */
+		public void unzipArchive(String archivePath, String destDir)
+						throws FileNotFoundException, IOException
+		{
+
+			FileInputStream fis = new FileInputStream( archivePath );
+			ZipInputStream zin = new ZipInputStream(new BufferedInputStream(fis));
+
+			ZipEntry entry;
+			while( null != (entry = zin.getNextEntry()) ){
+
+				if(entry.isDirectory()) {
+					// Assume directories are stored parents first then children.
+					log.info("Extracting directory: " + entry.getName());
+					// This is not robust, just for demonstration purposes.
+					(new File(destDir +"/"+ entry.getName())).mkdir();
+					continue;
+				}
+
+				log.info("Extracting file: " + entry.getName());
+
+				final int BUFFER = 2048;
+				FileOutputStream fos = new FileOutputStream( destDir +"/"+ entry.getName());
+				BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER);
+
+				int count;
+				byte[] data = new byte[BUFFER];
+				while ((count = zin.read(data, 0, BUFFER)) != -1) {
+					 dest.write(data, 0, count);
+				}
+				dest.flush();
+				dest.close();
+				zin.closeEntry();
+
+			}
+
+			zin.close();
+
+		}
+
+
+
+
+		public void deleteFromDeployDir( String deployableName ) throws IOException, EmbJoprTestException{
+
+			String deployDir = getDeployDir();
+
+			File dirToDelete = new File( deployDir, deployableName);
+
+			// Just not to delete something accidentally...
+			// For tests:
+			// /.../embjopr-svn-trunk/jsfunit/target/jboss5x/deploy/unpacked-web1.war.zip
+			/*if( ! dirToDelete.getCanonicalPath().contains("/server/") )
+				throw new EmbJoprTestException( "Path to deployable doesn't contain '/server/': "
+				+dirToDelete.getCanonicalPath() );
+			/**/
+
+			// Check if not outside deploy dir.
+			if( !dirToDelete.getCanonicalPath().startsWith( deployDir ) )
+				throw new IllegalArgumentException(
+								" The resulting path is outside deploy dir: "+dirToDelete.getCanonicalPath());
+
+			log.info("Deleting '"+dirToDelete.getPath()+"'...");
+			deleteDirectory( dirToDelete );
+		}
+
+
+
+		public /*static*/ void deleteDirectory(File path) throws EmbJoprTestException
+		{
+			List<String> undeletableFiles = new ArrayList();
+			deleteDirectory(path, undeletableFiles);
+			if( !undeletableFiles.isEmpty() ){
+				throw new EmbJoprTestException("Couldn't delete following files: \n  "+
+								StringUtils.join(undeletableFiles, "\n  ") + "\n");
+			}
+		}
+
+		public /*static*/ void deleteDirectory(File path, List<String> undeletableFiles)
+		{
+			if( path.exists() ) {
+				File[] files = path.listFiles();
+				for(int i=0; i<files.length; i++) {
+					 if(files[i].isDirectory()) {
+						 deleteDirectory(files[i], undeletableFiles );
+					 }
+					 else {
+						 if( !files[i].delete() ){
+							 undeletableFiles.add(files[i].getAbsolutePath());
+						 }
+					 }
+				}
+			}
+			if( ! path.delete() )
+				undeletableFiles.add( path.getAbsolutePath() );
+		}
+
+
+	}// class Deployment
+
+
+
+
+
+
 	// TODO
 	protected class JMXDeploymentInfo {
 




More information about the embjopr-commits mailing list