001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 020package org.tynamo.test; 021 022import static com.gargoylesoftware.htmlunit.WebAssert.assertTextNotPresent; 023import static com.gargoylesoftware.htmlunit.WebAssert.assertTextPresent; 024import static org.testng.Assert.assertNotNull; 025import static org.testng.Assert.assertTrue; 026import static org.testng.Assert.fail; 027 028import java.io.File; 029import java.io.IOException; 030import java.net.Socket; 031import java.util.List; 032 033import org.eclipse.jetty.server.Connector; 034import org.eclipse.jetty.server.Handler; 035import org.eclipse.jetty.server.Server; 036import org.eclipse.jetty.server.handler.DefaultHandler; 037import org.eclipse.jetty.server.handler.HandlerCollection; 038import org.eclipse.jetty.server.nio.SelectChannelConnector; 039import org.eclipse.jetty.util.resource.ResourceCollection; 040import org.eclipse.jetty.webapp.WebAppContext; 041import org.testng.annotations.BeforeClass; 042 043import com.gargoylesoftware.htmlunit.ElementNotFoundException; 044import com.gargoylesoftware.htmlunit.WebClient; 045import com.gargoylesoftware.htmlunit.html.HtmlForm; 046import com.gargoylesoftware.htmlunit.html.HtmlInput; 047import com.gargoylesoftware.htmlunit.html.HtmlPage; 048// import org.eclipse.jetty.server.nio.SelectChannelConnector; 049 050public abstract class AbstractContainerTest 051{ 052 protected static PauseableServer server; 053 054 public static int port = 8180; 055 056 protected static String BASEURI = "http://localhost:" + port + "/"; 057 058 protected final WebClient webClient = new WebClient(); 059 060 static String errorText = "You must correct the following errors before continuing"; 061 062 @BeforeClass 063 public void startContainer() throws Exception 064 { 065 if (server == null) 066 { 067 String reserveNetworkPort = System.getProperty("reserved.network.port"); 068 069 if (reserveNetworkPort != null) 070 { 071 port = Integer.valueOf(reserveNetworkPort); 072 BASEURI = "http://localhost:" + port + "/"; 073 } else { 074 // adapted from http://stackoverflow.com/questions/434718/sockets-discover-port-availability-using-java 075 // arbitrarily try next ten ports 076 int maxPort = port + 10; 077 for (port = port; port < maxPort; port++) { 078 Socket sock = null; 079 try { 080 // Check if port is open by trying to connect as a client 081 sock = new Socket("localhost", port); 082 sock.close(); 083 continue; 084 } catch (Exception e) { 085 if (sock != null) sock = null; 086 if (e.getMessage().contains("refused")) { 087 break; 088 } 089 throw new RuntimeException("Couldn't find an available port to run the functional test server", e); 090 } 091 } 092 093 } 094 095 096 server = new PauseableServer(); 097 Connector connector = new SelectChannelConnector(); 098 connector.setPort(port); 099 server.setConnectors(new Connector[]{connector}); 100 101 HandlerCollection handlers = new HandlerCollection(); 102 handlers.setHandlers(new Handler[]{buildContext(), new DefaultHandler()}); 103 server.setHandler(handlers); 104 server.start(); 105 assertTrue(server.isStarted()); 106 } 107 } 108 109 /** 110 * Non-abstract hook method (with a default implementation) to allow subclasses to provide their own WebAppContext instance. 111 * @return a WebAppContext 112 */ 113 public WebAppContext buildContext() 114 { 115 WebAppContext context = new WebAppContext("src/main/webapp", "/"); 116 if (new File("src/test/webapp").exists()) { 117 ResourceCollection resourceCollection = new ResourceCollection(new String[]{"src/main/webapp", "src/test/webapp"}); 118 context.setBaseResource(resourceCollection); 119 } 120 121 /** 122 * like -Dorg.eclipse.jetty.webapp.parentLoaderPriority=true 123 * Sets the classloading model for the context to avoid an strange "ClassNotFoundException: org.slf4j.Logger" 124 */ 125 context.setParentLoaderPriority(true); 126 return context; 127 } 128 129 public void pauseServer(boolean paused) 130 { 131 if (server != null) server.pause(paused); 132 } 133 134 public static class PauseableServer extends Server 135 { 136 public synchronized void pause(boolean paused) 137 { 138 try 139 { 140 if (paused) for (Connector connector : getConnectors()) 141 connector.stop(); 142 else for (Connector connector : getConnectors()) 143 connector.start(); 144 } catch (Exception e) 145 { 146 } 147 } 148 } 149 150 /** 151 * Verifies that the specified xpath is somewhere on the page. 152 * 153 * @param page 154 * @param xpath 155 */ 156 protected void assertXPathPresent(HtmlPage page, String xpath) 157 { 158 String message = "XPath not present: " + xpath; 159 List list = page.getByXPath(xpath); 160 if (list.isEmpty()) fail(message); 161 assertNotNull(list.get(0), message); 162 } 163 164 /** 165 * Verifies that the specified xpath does NOT appear anywhere on the page. 166 * 167 * @param page 168 * @param xpath 169 */ 170 protected void assertXPathNotPresent(HtmlPage page, String xpath) 171 { 172 if (!page.getByXPath(xpath).isEmpty()) fail("XPath IS present: " + xpath); 173 } 174 175 176 protected HtmlPage clickLink(HtmlPage page, String linkText) 177 { 178 try 179 { 180 return (HtmlPage) page.getAnchorByText(linkText).click(); 181 } catch (ElementNotFoundException e) 182 { 183 fail("Couldn't find a link with text '" + linkText + "' on page " + page); 184 } catch (IOException e) 185 { 186 fail("Clicking on link '" + linkText + "' on page " + page + " failed because of: ", e); 187 } 188 return null; 189 } 190 191 protected HtmlPage clickButton(HtmlPage page, String buttonId) throws IOException 192 { 193 return page.getHtmlElementById(buttonId).click(); 194 } 195 196 protected HtmlPage clickButton(HtmlForm form, String buttonValue) throws IOException 197 { 198 try 199 { 200 return form.<HtmlInput>getInputByValue(buttonValue).click(); 201 } catch (ElementNotFoundException e) 202 { 203 try 204 { 205 return form.getButtonByName(buttonValue).click(); 206 } catch (ElementNotFoundException e1) 207 { 208 fail("Couldn't find a button with text/name '" + buttonValue + "' on form '" + form.getNameAttribute() + 209 "'"); 210 } 211 } 212 return null; 213 } 214 215 protected void assertErrorTextPresent(HtmlPage page) 216 { 217 assertTextPresent(page, errorText); 218 } 219 220 protected void assertErrorTextNotPresent(HtmlPage page) 221 { 222 assertTextNotPresent(page, errorText); 223 } 224 225}