All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.tsl2.nano.h5.NanoH5Unit Maven / Gradle / Ivy

Go to download

TSL2 Framework Html5 Extensions (WebServer, Html5Presentation, RuleCover, BeanConfigurator, LogicTable-Sheet, Expression-Descriptors for Actions, Rules, URLs, Queries)

There is a newer version: 2.5.2
Show newest version
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());
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy