de.tsl2.nano.h5.NanoH5Unit Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tsl2.nano.h5 Show documentation
Show all versions of tsl2.nano.h5 Show documentation
TSL2 Framework Html5 Extensions (WebServer, Html5Presentation, RuleCover, BeanConfigurator, LogicTable-Sheet, Expression-Descriptors for Actions, Rules, URLs, Queries)
package de.tsl2.nano.h5;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.lang.Thread.UncaughtExceptionHandler;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Stack;
import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlButton;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import de.tsl2.nano.action.IAction;
import de.tsl2.nano.bean.BeanContainer;
import de.tsl2.nano.bean.def.Bean;
import de.tsl2.nano.bean.def.BeanCollector;
import de.tsl2.nano.bean.def.BeanDefinition;
import de.tsl2.nano.core.ENV;
import de.tsl2.nano.core.Main;
import de.tsl2.nano.core.ManagedException;
import de.tsl2.nano.core.Messages;
import de.tsl2.nano.core.exception.ExceptionHandler;
import de.tsl2.nano.core.util.ConcurrentUtil;
import de.tsl2.nano.core.util.ENVTestPreparation;
import de.tsl2.nano.core.util.FileUtil;
import de.tsl2.nano.core.util.NetUtil;
import de.tsl2.nano.core.util.StringUtil;
import de.tsl2.nano.core.util.Util;
import de.tsl2.nano.h5.navigation.EntityBrowser;
import de.tsl2.nano.persistence.DatabaseTool;
import de.tsl2.nano.persistence.Persistence;
import de.tsl2.nano.serviceaccess.Authorization;
/**
* ONLY TO BE EXTENDED BY JUNIT TESTS! USES JUNIT+HTMLUNIT
* @author Tom, Thomas Schneider
* @version $Revision$
*/
public abstract class NanoH5Unit implements ENVTestPreparation {
protected static final int DEFAULT_H2_PORT = 9092;
protected static final String BTN_LOGIN_OK = PersistenceUI.ACTION_LOGIN_OK;
protected static final String BTN_RESET = ".reset";
protected static final String BTN_DELETE = ".delete";
protected static final String BTN_CANCEL = IAction.CANCELED;
protected static final String BTN_NEW = ".new";
protected static final String BTN_EXPORT = ".export";
protected static final String BTN_PRINT = ".print";
protected static final String BTN_BACK = ".back";
protected static final String BTN_FORWARD = ".forward";
protected static final String BTN_SEARCH = ".search";
protected static final String BTN_SHUTDOWN = ".shutdown";
protected static final String BTN_OPEN = ".open";
protected static final String BTN_ADMINISTRATION = ".administration";
protected static final String BTN_SELECTALL = ".selectall";
protected static final String BEANCOLLECTORLIST = (BeanCollector.class.getSimpleName()
+ Messages.getString("tsl2nano.list")).toLowerCase();
protected boolean nanoAlreadyRunning;
protected int port = -1;
protected String getServiceURL(boolean nextFreePort) {
return "http://localhost:" + (port == -1 && nextFreePort ? port = NetUtil.getNextFreePort(Main.DEFAULT_PORT) : port == -1 ? port = Main.DEFAULT_PORT : port);
}
protected int dbPort() {
return DEFAULT_H2_PORT;
}
public void setUp() {
setUpUnit("h5");
}
public void setUpUnit(String moduleShort) {
// tearDownAfter(250000);
System.setProperty("tsl2nano.offline", "true");
System.setProperty(ENV.KEY_TESTMODE, "true");
System.setProperty("app.stop.allow.system.exit", "false");
nanoAlreadyRunning = Boolean.getBoolean("app.server.running");
NanoH5UnitPlugin.setEnabled(!nanoAlreadyRunning);
ENVTestPreparation.super.setUp(moduleShort);
if (!nanoAlreadyRunning) {
// GenericLocalBeanContainer.initLocalContainer();
setPersistenceConnectionPort();
DatabaseTool.runDBServerDefault(); //in the test it seems not enough (forks?) to let nanoh5 start h2 internally....
// ENV.setProperty("app.database.internal.run", true);
ENV.setProperty("service.url", getServiceURL(!nanoAlreadyRunning));
startApplication();
ConcurrentUtil.waitFor(()->NetUtil.isOpen(port));
} else {
setPersistenceConnectionPort();
// DatabaseTool.runDBServerDefault(); //in the test it seems not enough (forks?) to let nanoh5 start h2 internally....
System.out.println("NanoH5TestBase: nanoAlreadyRunning=true ==> trying to connect to external NanoH5");
}
// ConcurrentUtil.sleep(20000); //otherwise the nano-server is not started completely on parallel testing
}
protected void setPersistenceConnectionPort() {
try {
Persistence persistence = Persistence.current();
String url = persistence.getConnectionUrl().replace(String.valueOf(DEFAULT_H2_PORT), String.valueOf(dbPort()));
persistence.setConnectionUrl(url);
persistence.setDatabase(Persistence.DEFAULT_DATABASE);
persistence.save();
} catch (IOException e) {
ManagedException.forward(e);
}
}
/** WORKAROUND FOR SUREFIRE/FAILSAFE failing on not stopping fork */
private void tearDownAfter(long millis) {
ConcurrentUtil.doAfterWait(millis, "tearDown after " + millis + " ms", () -> {this.tearDown(); return null;});
}
public void tearDown() {
if (webClient != null)
webClient.close();
if (NetUtil.isOpen(port))
shutdownNanoHttpServer();
if (NetUtil.isOpen(dbPort()))
DatabaseTool.shutdownDBServerDefault();
// ENVTestPreparation.removeCaches();
Bean.clearCache();
BeanContainer.reset();
}
protected void startApplication() {
startApplication(getTestEnv(), String.valueOf(port));
}
protected static void startApplication(String...args) {
System.setProperty("file.encoding", "UTF-8");
System.setProperty("sun.jnu.encoding", "UTF-8");
System.setProperty("JAVA_OPTS", "-Xmx512m -Djava.awt.headless -agentlib:jdwp=transport=dt_socket,address=8787,server=y,suspend=n");
System.setProperty("tsl2nano.offline", "true");
System.setProperty("websocket.use", "false");
System.setProperty("app.show.startpage", "false");
ConcurrentUtil.startDaemon(new Runnable() {
@Override
public void run() {
new Loader().start(NanoH5.class.getName(), args);
// Main.startApplication(NanoH5.class, null, args);
}
});
}
private WebClient webClient;
protected HtmlPage runWebClient() {
return runWebClient(getServiceURL(!nanoAlreadyRunning));
}
protected HtmlPage runWebClient(String serviceURL) {
HtmlPage page = null;
webClient = new WebClient();
webClient.getOptions().setJavaScriptEnabled(true);
webClient.getOptions().setTimeout(1200000); //20min
webClient.getOptions().setPrintContentOnFailingStatusCode(true);
webClient.getOptions().setThrowExceptionOnScriptError(false);
webClient.getOptions().setCssEnabled(false);
webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
// webClient.getOptions().setRedirectEnabled(true);
try {
page = webClient.getPage(serviceURL);
} catch (FailingHttpStatusCodeException | IOException e) {
ManagedException.forward(e);
}
if (page == null)
fail("web client can't get first page on " + serviceURL
+ "Please stop any running NanoH5 application on this port!");
return page;
}
protected HtmlPage submit(HtmlPage page, String buttonName) throws Exception {
System.out.println("htmlUnit testing button: " + buttonName);
try {
HtmlButton htmlButton = (HtmlButton) page.getElementById(buttonName);
if (htmlButton == null) {
throw new IllegalArgumentException("button " + buttonName + " not found! page:\n\t" + page.asXml());
}
page = htmlButton.click();
page.getWebClient().waitForBackgroundJavaScript(1000);
return page;
} catch (Exception e) {
List exceptions = ((ExceptionHandler)ENV.get(UncaughtExceptionHandler.class)).getExceptions();
String pageName = page.getBody().getId();
String buttonHandleError = "error on clicking button: '" + buttonName + "' on page '" + pageName + "'\n\n"
+ StringUtil.toFormattedString(exceptions, -1);
String asXml = "\n" + page.asXml();
FileUtil.writeBytes(asXml.getBytes(), ENV.getTempPath() + "page-failed.html", false);
System.out.println(buttonHandleError);
ManagedException.forward(e);
return page;
}
// return form.getInputByName(buttonName).click();
}
protected HtmlPage back(HtmlPage page) throws Exception {
page.getWebClient().getWebWindows().get(0).getHistory().back();
return (HtmlPage) page;//.refresh();
}
protected HtmlPage crudBean(HtmlPage page) throws Exception {
String pageId = page.getBody().getId(); //thats not the best solution - perhaps a bean has a translated name
if (Util.isEmpty(pageId))
throw new IllegalStateException("pageId is empty!");
String beanName = StringUtil.toFirstLower(pageId);
if (BeanDefinition.getBeanDefinition(beanName).isVirtual()) {
System.out.println("beanname was translated....ignoring");
return submit(page, BTN_CANCEL);
}
String beanList = beanName + Messages.getString("tsl2nano.list").toLowerCase();
//TODO: check pages with with saved last current state
page = submit(page, beanList + BTN_SEARCH);
page = submit(page, beanList + BTN_FORWARD);
page = submit(page, beanList + BTN_BACK);
submit(page, beanList + BTN_PRINT);
page = back(page);
submit(page, beanList + BTN_EXPORT);
page = back(page);
page = submit(page, beanList + BTN_NEW);
if (page.getElementById(BTN_CANCEL) == null)
return back(page); //workaround
page = submit(page, BTN_CANCEL);
// page = submit(page, beanName + ".save");
// page = submit(page, beanList + BTN_DELETE);
// page = submit(page, beanName + BTN_RESET);
return page;
}
/*
* conveniences to create a testable nanoh5 application + session
*/
public static NanoH5Session createApplicationAndSession(String name, Serializable... instances) throws IOException, UnknownHostException {
return createApplicationAndSession(name, Arrays.stream(instances).map(i -> Bean.getBean(i)).toArray(Bean[]::new));
}
// public static NanoH5Session createApplicationAndSession(String name, Class...classes) throws IOException, UnknownHostException {
// return createApplicationAndSession(name, Arrays.stream(classes).map(c -> BeanDefinition.getBeanDefinition(c)).toArray(BeanDefinition[]::new));
// }
public static NanoH5Session createApplicationAndSession(String name, BeanDefinition...beandefs) throws IOException, UnknownHostException {
NanoH5 server = new NanoH5();
// NanoH5Session session = (NanoH5Session) new PrivateAccessor(server).call("createSession", NanoH5Session.class
// , new Class[] {InetAddress.class}, InetAddress.getLocalHost());
Stack> nav = new Stack>();
nav.addAll((List) Arrays.asList(beandefs));
EntityBrowser entities = new EntityBrowser("test", nav);
entities.next(null);
NanoH5Session session = NanoH5Session.createSession(server, InetAddress.getLocalHost()
, entities, Thread.currentThread().getContextClassLoader()
, Authorization.create(name, false), new HashMap());
return session;
}
protected void shutdownNanoHttpServer() {
shutdownNanoHttpServer(FileUtil.userDirFile(ENV.getTempPath() + "instance-id.txt"));
}
protected void shutdownNanoHttpServer(File idFile) {
if (!idFile.exists())
return;
String id = FileUtil.getFileString(idFile.getAbsolutePath());
String cmdShutdown = "/" + id + "-shutdown";
String url = getServiceURL(false) + cmdShutdown;
try {
NetUtil.browse(url, System.out);
} catch (Exception e) {
System.out.println("couldn't shutdown nanohttp server on: " + url + " exception: " + e.toString());
}
}
}