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

jadex.base.test.ComponentTestSuite Maven / Gradle / Ivy

Go to download

Jadex bridge is a base package for kernels and platforms, i.e., it is used by both and provides commonly used interfaces and classes for active components and their management.

There is a newer version: 4.0.267
Show newest version
package jadex.base.test;

import java.awt.BorderLayout;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

import org.junit.runner.RunWith;
import org.junit.runners.AllTests;

import jadex.base.IPlatformConfiguration;
import jadex.base.Starter;
import jadex.base.test.impl.ComponentLoadTest;
import jadex.base.test.impl.ComponentStartTest;
import jadex.base.test.impl.ComponentTest;
import jadex.base.test.util.STest;
import jadex.bridge.IErrorReport;
import jadex.bridge.IExternalAccess;
import jadex.bridge.IResourceIdentifier;
import jadex.bridge.modelinfo.IArgument;
import jadex.bridge.modelinfo.IModelInfo;
import jadex.bridge.service.annotation.Timeout;
import jadex.bridge.service.search.ServiceQuery;
import jadex.bridge.service.types.factory.SComponentFactory;
import jadex.bridge.service.types.library.ILibraryService;
import jadex.commons.SReflect;
import jadex.commons.SUtil;
import jadex.commons.TimeoutException;
import jadex.commons.future.Future;
import junit.framework.TestResult;
import junit.framework.TestSuite;


/**
 * Execute multiple component tests in a test suite.
 */
@RunWith(AllTests.class)
public class ComponentTestSuite extends TestSuite implements IAbortableTestSuite
{
	//-------- constants --------
	
	/** Run all tests on the same platform. */
	// Set to true for old behavior (speeds up old BDI tests)
	public static final boolean	SAME_PLATFORM	= true;
	
//	/**
//	 *  The default test platform arguments.
//	 */
//	public static final String[]	DEFARGS	= new String[]
//	{
//		"-platformname", "testcases_*",
////		"-kernels", "\"all\"",	// Required for old hudson build, otherwise wrong bdi kernel is used as dependencies are not in correct order
//		"-simulation", "true",
//		"-asyncexecution", "true",
////		"-libpath", "new String[]{\""+root.toURI().toURL().toString()+"\"}",
////		"-logging", "true",
////		"-logging", path.toString().indexOf("bdiv3")!=-1 ? "true" : "false",
//		"-logging_level", "java.util.logging.Level.WARNING",
////		"-debugfutures", "true",
////		"-nostackcompaction", "true",
//		"-gui", "false",
//		"-awareness", "false",
//		"-saveonexit", "false",
//		"-welcome", "false",
//		"-autoshutdown", "false",
//		"-opengl", "false",
//		"-cli", "false",
////		"-persist", "true", // for testing persistence
////		"-deftimeout", "-1",
//		"-printsecret", "false",
//		"-superpeerclient", "false",
//		"-wstransport", "false",
//		"-relaytransport", "false",
////		"-tcptransport", "false"
//		// Hack!!! include ssl transport if available
////		"-ssltcptransport", (SReflect.findClass0("jadex.platform.service.message.transport.ssltcpmtp.SSLTCPTransport", null, ComponentTestSuite.class.getClassLoader())!=null ? "true" : "false"),  
//	};

	//-------- attributes --------
	
	/** Indicate when the suite is aborted due to excessive run time. */
	public boolean	aborted;
	
	/** The platform. */
	protected IExternalAccess	platform;
	
	/** The class loader. */
	protected ClassLoader	classloader;
	
	/** The timeout (if any). */
	protected long	timeout;
	
	/** The timeout timer (if any). */
	protected Timer	timer;
	
	//-------- constructors --------

	/**
	 * Create a component test suite for components contained in class directories on the class path (i.e. not jars).
	 * @param excludes	Files to exclude (if a pattern is contained in file path).
	 */
	public ComponentTestSuite(String[] excludes) throws Exception
	{
		this(findClassDirectories(), null, excludes);
	}
	
	/**
	 * Create a component test suite for components contained in a given path.
	 * @param projectDir	The project directory.
	 * @param excludes	Files to exclude (if a pattern is contained in file path).
	 */
	public ComponentTestSuite(String projectDir, String[] excludes, boolean includeTestClasses) throws Exception
	{
		this(new File[][]{SUtil.findOutputDirs(projectDir, includeTestClasses)}, null, excludes);
	}

	/**
	 * Create a component test suite for components contained in a given path.
	 * @param projectDir	The project directory.
	 * @param tests	The tests (full qualified names) to include. Includes all, if null.
	 * @param excludes	Files to exclude (if a pattern is contained in file path). 
	 */
	public ComponentTestSuite(String projectDir, String[] tests, String[] excludes, boolean includeTestClasses) throws Exception
	{
		this(new File[][]{SUtil.findOutputDirs(projectDir, includeTestClasses)}, tests, excludes);
	}
	
	/**
	 * Create a component test suite for components contained in a given path.
	 * @param root	The class path root corresponding to the path.
	 * @param excludes	Files to exclude (if a pattern is contained in file path). 
	 */
//	public ComponentTestSuite(File[] root, String[] excludes) throws Exception
//	{
//		this(root, root, excludes);
//	}
	
	/**
	 * Create a component test suite for components contained in a given path.
	 * @param roots The paths to search for testcases in and to load classes from.
	 * @param tests	The tests (full qualified names) to include. Includes all, if null.
	 * @param excludes	Files to exclude (if a pattern is contained in file path). 
	 */
	public ComponentTestSuite(File[][] roots, String[] tests, String[] excludes) throws Exception
	{
		this(roots, tests, excludes, true, true, true);
//		this(roots, tests, excludes, true, false, false);
	}
	
	/**
	 * Create a component test suite for components contained in a given path.
	 * @param roots The paths to search for testcases in and to load classes from.
	 * @param tests	The tests (full qualified names) to include. Includes all, if null.
	 * @param excludes	Files to exclude (if a pattern is contained in file path). 
	 * @param test	Run test components.
	 * @param load	Include broken components (will cause test failure if any). Also shows loadable, but not startable components as succeeded tests.
	 * @param start	Try starting components, which are no test cases.
	 */
	public ComponentTestSuite(File[][] roots, String[] tests, String[] excludes, boolean test, boolean load, boolean start) throws Exception
	{
		this(null, roots, tests, excludes, test, load, start);
	}
	
	protected void startTimer()
	{
		final Thread	runner	= Thread.currentThread();

		if(timeout!=Timeout.NONE && timeout>0)
		{
			timer	= new Timer(true);
			timer.schedule(new TimerTask()
			{
				@SuppressWarnings("deprecation")	// for Thread.stop()
				public void run()
				{
					aborted	= true;
					System.out.println("Aborting test suite "+getName()+" due to excessive run time (>"+timeout+" ms).");
					//if(!SReflect.isAndroid())
					{
						try
						{
							runner.stop();
							// Broken in Java 11, method removed.
							//runner.stop(new RuntimeException("Aborting test suite "+getName()+" due to excessive run time (>"+timeout+" ms)."));
						}
						catch(UnsupportedOperationException e)
						{
							runner.stop();
						}
					}
					/*else
					{
						System.err.println("Aborting test suite "+getName()+" due to excessive run time (>"+timeout+" ms).");
						System.exit(1);
					}*/
				}
			}, timeout);
		}
	}

	/**
	 * Create a component test suite for components contained in a given path.
	 * @param args	The platform arguments.
     * @param roots The paths to search for testcases in and to load classes from.
	 *              Grouped by project, e.g. proj1/build/classes and proj1/build/resources
	 *              should be both at index [0] of this array.
	 * @param tests	The tests (full qualified names) to include. Includes all, if null.
	 * @param excludes	Files to exclude (if a pattern is contained in file path).
	 * @param runtests	Run test components.
	 * @param load	Include broken components (will cause test failure if any).
	 * @param start	Try starting components, which are no test cases.
	 */
	public ComponentTestSuite(String[] args, File[][] roots, String[] tests, String[] excludes, final boolean runtests, final boolean load, final boolean start) throws Exception
	{
		super(roots[0][0].toString());
		
//		/* Attempt to extract user command line args. */
//		String cmdline = System.getProperty("sun.java.command");
////		System.out.println("COMMAND: " + cmdline);
//		if (cmdline != null)
//		{
//			String[] cmdlinetokens = cmdline.split(" ");
//			List cmdargs = new ArrayList();
//			for (int i = 1; i < cmdlinetokens.length; ++i)
//			{
//				if (cmdlinetokens[i].length() > 0)
//					if ("-version".equals(cmdlinetokens[i]))
//						break;
//					else
//						cmdargs.add(cmdlinetokens[i]);
//			}
//			int len = args != null? args.length : 0;
//			len += cmdargs.size();
//			String[] newargs = new String[len];
//			int pos = 0;
//			if (args != null)
//			{
//				System.arraycopy(args, pos, newargs, pos, args.length);
//				pos += args.length;
//			}
//			for (String cmdarg : cmdargs)
//				newargs[pos++] = cmdarg;
//			args = newargs;
//		}
//		
		IPlatformConfiguration conf = STest.getLocalTestConfig(getName());	// Avoid dependencies to created platforms
		//conf.getExtendedPlatformConfiguration().setDebugFutures(true);
		
		
		// Initial timeout for starting platform.
		// Use larger timeout so we can reduce default timeout on build slave
		this.timeout	= Starter.getScaledDefaultTimeout(null, 10);
		startTimer();

		if (tests != null) 
		{
			for (int i = 0; i < tests.length; i++) 
			{
				tests[i] = tests[i].replace('.', File.separatorChar);
			}
		}

		// Tests must be available after constructor execution.

//		System.out.println("start platform");
		platform	= Starter.createPlatform(conf, args).get();
//		this.timeout	= Starter.getDefaultTimeout(platform.getComponentIdentifier());
//		System.out.println("end platform");
//		ServiceQuery cmsquery = new ServiceQuery<>(IComponentManagementService.class);
//		IComponentManagementService cms = platform.searchService(cmsquery).get();
		ServiceQuery lsquery = new ServiceQuery<>(ILibraryService.class);
		ILibraryService libsrv	= platform.searchService(lsquery).get();

		// Only works with x-rids hack or maven dependency service, because rms cannot use default classloader for decoding application messages.
//		final IResourceIdentifier	rid	= null;
		long ctimeout = Starter.getDefaultTimeout(platform.getId());	// Start with normal timeout for platform startup/shutdown.

		IResourceIdentifier[] rids = new IResourceIdentifier[roots.length];
		for (int projectIndex=0; projectIndex < roots.length; projectIndex++) 
		{
			File[] project = roots[projectIndex];
			IResourceIdentifier	parentRid	= null;
			for(int rootIndex=0; rootIndex scanForTestCases = getAllFiles(project[rootIndex]);
				this.timeout = Starter.getScaledDefaultTimeout(platform.getId(), 1 + 0.05 * scanForTestCases.size()); // Timeout
																																			// for
				startTimer();
//				Logger.getLogger("ComponentTestSuite").info("Scanning for testcases: " + project[rootIndex] + " (scan timeout: " + timeout + ")");
				for(String abspath : scanForTestCases)
				{
					boolean exclude = false;
					boolean include = (tests == null);

					for(int i = 0; !exclude && excludes != null && i < excludes.length; i++)
					{
						exclude = abspath.indexOf(excludes[i]) != -1;
					}

					for(int i = 0; !include && i < tests.length; i++)
					{
						include = abspath.indexOf(tests[i]) != -1;
					}

					if(!exclude && include)
					{
						try
						{
							IResourceIdentifier rid = rids[projectIndex];

							if((SComponentFactory.isLoadable(platform, abspath, null, rid).get()).booleanValue())
							{
								boolean startable = SComponentFactory.isStartable(platform, abspath, null, rid).get().booleanValue();
								IModelInfo model = SComponentFactory.loadModel(platform, abspath, rid).get();
								boolean istest = false;
								if(model != null && model.getReport() == null && startable)
								{
									IArgument[] results = model.getResults();
									for(int i = 0; !istest && i < results.length; i++)
									{
										if(results[i].getName().equals("testresults") && Testcase.class.equals(results[i].getClazz().getType(libsrv.getClassLoader(rid).get(), model.getAllImports())))
										{
											istest = true;
										}
									}
								}

								if(istest)
								{
//									System.out.print(".");
									if(runtests)
									{
										ComponentTest test = SAME_PLATFORM ? new ComponentTest(platform, model, this) : new ComponentTest(STest.getLocalTestConfig(abspath), args, roots, platform, model, this);
										test.setName(abspath);
										addTest(test);
										if(ctimeout == Timeout.NONE || test.getTimeout() == Timeout.NONE)
										{
											ctimeout = Timeout.NONE;
										}
										else
										{
											ctimeout += test.getTimeout();
										}
									}
								}
								else if(startable && model.getReport() == null)
								{
//									System.out.print(".");
									if(start)
									{
										ComponentStartTest test = new ComponentStartTest(platform, model, this);
										test.setName(abspath);
										addTest(test);
										if(ctimeout == Timeout.NONE)
										{
											ctimeout = Timeout.NONE;
										}
										else
										{
											// Delay instead of timeout as start
											// test should be finished after
											// that.
											ctimeout += test.getTimeout();
										}
									}
								}
								else if(load)
								{
//									System.out.print(".");
									ComponentLoadTest test = new ComponentLoadTest(model, model.getReport());
									test.setName(abspath);
									addTest(test);
								}
							}
						}
						catch(final RuntimeException e)
						{
							if(e instanceof TimeoutException)
							{
								throw e;
							}
							
							else if(load)
							{
								@SuppressWarnings("serial")
								ComponentLoadTest test = new ComponentLoadTest(abspath, new IErrorReport()
								{
									public String getErrorText()
									{
										StringWriter sw = new StringWriter();
										e.printStackTrace(new PrintWriter(sw));
										return "Error loading model: " + sw.toString();
									}

									public String getErrorHTML()
									{
										return getErrorText();
									}

									public Map getDocuments()
									{
										return null;
									}
								});
								test.setName(abspath);
								addTest(test);
							}
						}
					}
				}

				stopTimer();
				Future.DEBUG = originalDebug;
//				Logger.getLogger("ComponentTestSuite").info("Finished Building Suite for " + project[rootIndex] + ", cumulated execution timeout is: " + ctimeout);
			}
		}
		this.timeout = ctimeout;
	}

	protected void	stopTimer()
	{
		if(timer!=null)
		{
			timer.cancel();
			timer	= null;
		}
	}

	protected List getAllFiles(File root)
	{
		List result = new ArrayList();

		/*if(SReflect.isAndroid())
		{
			try
			{
				// Scan for resource files in .apk
				String	template	= root.toString().replace('.', '/');
				ZipFile	zip	= new ZipFile(root);
				Enumeration< ? extends ZipEntry>	entries	= zip.entries();
				while(entries.hasMoreElements())
				{
					ZipEntry	entry	= entries.nextElement();
					String name	= entry.getName();
					if(name.startsWith(template))
					{
						result.add(name);
//						System.out.println("Found potential Testcase: "+name);
					}
				}
				zip.close();

				// Scan for classes in .dex
				Enumeration dexEntries = SUtil.androidUtils().getDexEntries(root);
				String nextElement;
				while(dexEntries.hasMoreElements())
				{
					nextElement = dexEntries.nextElement();
					if(nextElement.toLowerCase().startsWith(root.toString().toLowerCase()))
//						&& nextElement.toLowerCase().split("\\.").length  (path.toString().split("\\.").length +1))
					{
						if(!nextElement.matches(".*\\$.*"))
						{
							// path-style identifier needed for Factories, but android doesn't use a classical classpath
							nextElement = nextElement.replaceAll("\\.", "/") + ".class";
							result.add(nextElement);
//							System.out.println("Found potential Testcase: " + nextElement);
						}
					}
				}

			}
			catch (IOException e)
			{
				e.printStackTrace();
			}
		}
		else*/
		{
			List	todo	= new LinkedList();
//			if(path.toString().indexOf("micro")!=-1)
			todo.add(root);

			while(!todo.isEmpty())
			{
				File	file	= (File)todo.remove(0);
				final String	abspath	= file.getAbsolutePath();
	//			System.out.println("todo: "+abspath);

				if(file.isDirectory())
				{
					File[]	subs	= file.listFiles();
					todo.addAll(Arrays.asList(subs));
				}
				else
				{
					result.add(abspath);
				}
			}
		}

		return result;
		
	}

	/**
	 *  Indicate when the suite is aborted due to excessive run time.
	 */
	public boolean isAborted()
	{
		return aborted;
	}
	
	/**
	 *  Overridden for pre and post code.
	 */
	public void run(TestResult result)
	{
		startTimer();
		if(timer==null)
		{
			this.timer	= new Timer(true);
		}
		timer.scheduleAtFixedRate(new TimerTask()
		{
			public void run()
			{
				System.out.println("Memory: free="+SUtil.bytesToString(Runtime.getRuntime().freeMemory())
					+", max="+SUtil.bytesToString(Runtime.getRuntime().maxMemory())
					+", total="+SUtil.bytesToString(Runtime.getRuntime().totalMemory()));
			}
		}, 0, 30000);

		super.run(result);

		cleanup(result);
	}
	
	/**
	 *  Called after test suite is finished.
	 */
	protected void	cleanup(TestResult result)
	{
		try
		{
			//System.out.println("SUITE KILLING PLATFORM: "+getName());
			platform.killComponent().get(Starter.getDefaultTimeout(platform.getId()), true);
			//System.out.println("SUITE KILLED PLATFORM: "+getName());
		}
		catch(Exception e)
		{
			//System.out.println("SUITE FAILED KILLING PLATFORM: "+getName()+", "+e);
			e.printStackTrace();
			result.addError(this, e);
		}
		platform	= null;
		
		//System.out.println("SUITE CLEARING AWT: "+getName());
		if(!clearAWT())
			System.out.println("SUITE FAILED CLEANING AWT: "+getName());
		//System.out.println("SUITE CLEARED AWT: "+getName());
		
		stopTimer();
	}
	
	/**
	 *  Workaround for AWT/Swing memory leaks.
	 */
	public static boolean	clearAWT()
	{
		return !SReflect.HAS_GUI || internalClearAWT();
	}

	/**
	 *  Get the class loader.
	 */
	public ClassLoader getClassLoader()
	{
		return classloader;
	}
	
	/**
	 *  Find class directories on classpath.
	 */
	public static File[][]	findClassDirectories()
	{
		Set	dirs	= new LinkedHashSet();
		collectClasspathDirectories(ComponentTestSuite.class.getClassLoader(), dirs);
		File[][]	ret	= new File[dirs.size()][];
		
		int	i=0;
		for(File dir: dirs)
		{
			ret[i++]	= new File[]{dir};
		}
		return ret;
	}

	/**
	 *  Collect all directory URLs belonging to a class loader.
	 */
	protected static void	collectClasspathDirectories(ClassLoader classloader, Set set)
	{
		assert classloader!=null;
		
		if(classloader.getParent()!=null)
		{
			collectClasspathDirectories(classloader.getParent(), set);
		}
		
		if(classloader instanceof URLClassLoader)
		{
			URL[] urls = ((URLClassLoader)classloader).getURLs();
			for(int i=0; i	disposed	= new Future();
		final Semaphore sem = new Semaphore(0);
		
		SwingUtilities.invokeLater(new Runnable()
		{
			public void run()
			{
				javax.swing.Timer	t	= new javax.swing.Timer(100, new ActionListener()
				{
					public void actionPerformed(ActionEvent e)
					{
						final JFrame f	= new JFrame("dummy");
						f.getContentPane().add(new JButton("Dummy"), BorderLayout.CENTER);
						f.pack();
						f.setVisible(true);
						
						javax.swing.Timer	t	= new javax.swing.Timer(100, new ActionListener()
						{
							public void actionPerformed(ActionEvent e)
							{
								f.dispose();
								javax.swing.Timer	t	= new javax.swing.Timer(100, new ActionListener()
								{
									public void actionPerformed(ActionEvent e)
									{
//										System.out.println("cleanup dispose");
										KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
										sem.release();
//										disposed.setResult(null);
									}
								});
								t.setRepeats(false);
								t.start();

							}
						});
						t.setRepeats(false);
						t.start();
					}
				});
				t.setRepeats(false);
				t.start();
			}
		});
		
//		disposed.get(new ThreadSuspendable(), BasicService.getDefaultTimeout());
//		disposed.get(new ThreadSuspendable(), 30000);
//		disposed.get(30000);
		try
		{
			return sem.tryAcquire(30000, TimeUnit.MILLISECONDS);
		}
		catch (InterruptedException e)
		{
			return false;
		}
		
//		// Another bug not releasing the last drawn window.
//		// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6857676
//		
//		try
//		{
//			Class clazz	= Class.forName("sun.java2d.pipe.BufferedContext");
//			Field	field	= clazz.getDeclaredField("currentContext");
//			field.setAccessible(true);
//			field.set(null, null);
//		}
//		catch(Throwable e)
//		{
//			e.printStackTrace();
//		}

	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy