Creating application under UI test [message #1603689] |
Fri, 06 February 2015 10:28 |
Jerome Joslet Messages: 6 Registered: February 2015 |
Junior Member |
|
|
Hello,
I've issued some problem to create my RCP Application under an UI Test framework. After some investiguation and try, I think there is a problem for IApplication creation in many UI testing framework. Here is some more details.
In the class org.eclipse.equinox.internal.app.EclipseAppHandle which is the one that is used to instantiate Eclipse IApplication when Eclipse run, the following codes is used to instantiate an IApplication from the Extension Registry (It's not exactly that since I've simplified the code by removing some methods, but Eclipse really does something like that) :
IExtension applicationExtension = Platform.getExtensionRegistry().getExtension(Platform.PI_RUNTIME, Platform.PT_APPLICATIONS, applicationToRun);
IConfigurationElement[] configs = applicationExtension.getConfigurationElements();
if (configs.length == 0) throw new RuntimeException(NLS.bind(Messages.application_invalidExtension, getApplicationDescriptor().getApplicationId()));
return configs[0].createExecutableExtension("run");
While many UI test launcher that I've seen :
- PDE test : org.eclipse.pde.internal.junit.runtime.NonUIThreadTestApplication
- SWTBot test : org.eclipse.swtbot.eclipse.core.UITestApplication and org.eclipse.swtbot.eclipse.junit.headless.UITestApplication
- Tycho : org.eclipse.tycho.surefire.osgibooter.AbstractUITestApplication
- And maybe more ...
use the following snippet to instantiate the IApplication under test:
IExtension extension = Platform.getExtensionRegistry().getExtension(Platform.PI_RUNTIME, Platform.PT_APPLICATIONS, applicationToRun);
Assert.isNotNull(extension, "Could not find IExtension for application: " + applicationToRun);
IConfigurationElement[] elements = extension.getConfigurationElements();
if (elements.length > 0) {
IConfigurationElement[] runs = elements[0].getChildren("run"); //$NON-NLS-1$
if (runs.length > 0) {
Object runnable = runs[0].createExecutableExtension("class"); //$NON-NLS-1$
if (runnable instanceof IApplication)
return runnable;
}
}
Which have not really the same effect... The problem is when you use a Factory (IExecutableExtension, IExecutableExtensionFactory) to create your IApplication instance.
Here is a concrete example, I have an application declaration like that :
<extension id="rcp-application" point="org.eclipse.core.runtime.applications">
<application thread="main">
<run class="com.test.DiFramework">
<parameter name="class" value="org.eclipse.equinox.app.IApplication"></parameter>
<parameter name="named" value="rcp-application-sample"></parameter>
</run>
</application>
</extension>
com.test.DiFramework implements IExecutableExtension, IExecutableExtensionFactory to retrieve the class instance given in parameter with the given @Named annotation (it uses a DI Framework to instantiate this class).
This example runs correctly under Eclipse but I'm unable to create this application under a test framesork since my executable extension never get the parameter and therefore cannot instantiate the class using my DI framework.
In EclipseAppHandle the IExecutableExtension#setInitializationData receives a Map as data with the class and named parameter but not in the UI Test Framework. The code for this feature is in the method Object org.eclipse.core.internal.registry.ConfigurationElement.createExecutableExtension(String attributeName).
Am I doing something wrong with IExecutableExtension, IExecutableExtensionFactory since I think I respect this API contract ?
If not, I think many UI Test framework has a bug in the way they create the IApplication under test and they should use the same code as EclipseAppHandler does.
I hope I've posted this at the right place since it impacts many Eclipse projects, if not, I'll move the topic or fill a bug somewhere if necessary.
Thanks in advance for response.
Jérôme
|
|
|
Re: Creating application under UI test [message #1611899 is a reply to message #1603689] |
Wed, 11 February 2015 17:37 |
Eclipse User |
|
|
|
Quote:This example runs correctly under Eclipse but I'm unable to create this application under a test framesork since my executable extension never get the parameter and therefore cannot instantiate the class using my DI framework.
In EclipseAppHandle the IExecutableExtension#setInitializationData receives a Map as data with the class and named parameter but not in the UI Test Framework.
What is the Map in the UI test situation? Could you post your code for your DiFramework?
Those snippets should work: the createExecutableExtension() is all handled by the extension registry and there should not be any difference.
I'm not sure where you're seeing the @Named though; I think you mean the "named" parameter?
Sounds to me like you're missing one of your plugins carrying the "named" lookup data from your launch configuration.
Brian.
|
|
|
Re: Creating application under UI test [message #1619369 is a reply to message #1611899] |
Mon, 16 February 2015 14:34 |
Jerome Joslet Messages: 6 Registered: February 2015 |
Junior Member |
|
|
Quote:What is the Map in the UI test situation?
In the case of the UI framework, I receive null as the data parameter of the method void org.eclipse.core.runtime.IExecutableExtension.setInitializationData(IConfigurationElement config, String propertyName, Object data) throws CoreException
I can't post link to the JavaDoc since I've posted less than 5 messages ... so bad
Quote:Could you post your code for your DiFramework?
Here is my code (I've simplified it a bit for this post). It uses Guice to instantiate class.
public class DiFramework implements IExecutableExtension, IExecutableExtensionFactory {
// -- parsing constants
private final static String CLASS_NAME_PARAMETER = "class";
private final static String NAMED_PARAMETER = "named";
/**
* Value from initialization
*/
private IConfigurationElement configuration;
private Object data;
private IContributor contributor;
@Override
public void setInitializationData(final IConfigurationElement config, final String name, final Object data) {
// -- keep initialization value for further uses
this.configuration = config;
this.data = data;
this.contributor = configuration.getContributor();
}
@Override
public Object create() throws CoreException {
// -- resolve bundle
Bundle bundle = ContributorFactoryOSGi.resolve(contributor);
// -- retrieve key
Key<?> key = retrieveKey(bundle, configuration, data);
// -- create instance
return retrieveInjector(bundle).getInstance(key);
}
/**
* Retrieve key from initialization value
*
* @param bundle the bundle
* @param config the configuration element used to trigger this execution.
* It can be queried by the executable extension for specific configuration properties
* @param data adapter data in the form of a {@link String}, a {@link Hashtable}, or <code>null</code>.
*
* @return an {@link Injector} {@link Key}
*
* @throws CoreException if class name cannot be found or cannot be loaded
*/
private Key<?> retrieveKey(Bundle bundle, IConfigurationElement config, Object data) throws CoreException {
// Retrieve class name and named
//
String className = null;
String named = null;
// 1. try to query data
//
// -- data is a string
if (data instanceof String) {
className = data.toString();
}
// -- data is a table
else if (data instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, String> table = (Map<String, String>) data;
// -- retrieve value, will be null if no mapping
className = table.get(CLASS_NAME_PARAMETER);
named = table.get(NAMED_PARAMETER);
}
// 2. try the id of the config element
//
if (className == null) {
if (config.getAttribute("id") != null) {
className = config.getAttribute("id");
log.debug("Found class name from config id '{}'", className);
}
}
// -- class name not found
if (className == null) {
throw newCoreException("Unable to find a class name from configuration");
}
// -- load class
final Class<?> clazz;
try {
clazz = bundle.loadClass(className);
}
catch (final InvalidRegistryObjectException e) {
throw newCoreException(e);
}
catch (final ClassNotFoundException e) {
throw newCoreException(e);
}
// -- forge key
return named != null ? Key.get(clazz, Names.named(named)) : Key.get(clazz);
}
}
Quote:Those snippets should work: the createExecutableExtension() is all handled by the extension registry and there should not be any difference.
You're right, there should be no difference if each consumer call the same code, which is not the case. As I've said in my previous post, EcliseAppHandle call createExecutableExtension on the run parameter and UI Testing frameworks call it on the class parameter of the first run children.
It works correctly when my application is launched as an Eclipse Application but not when it's launched under an UI Test tools.
I'll try to reproduce this with a simple application so you can try it.
|
|
|
|
Re: Creating application under UI test [message #1621808 is a reply to message #1619405] |
Wed, 18 February 2015 04:27 |
Eclipse User |
|
|
|
The 'data' argument is a bit confusing. It's only non-null if the attribute in question has additional information other than the class name. For example, a ViewPart:
<extension point="org.eclipse.ui.views">
<view id="xxx" class="my.ViewPart:special info" />
</extension>
the "data" for "class" would be "special info".
In your case, I believe you want to use the IConfigurationElement from the setInitializationData() call (which will be the <view> element in the above) and examine its child elements.
Brian.
|
|
|
|
Re: Creating application under UI test [message #1624069 is a reply to message #1623627] |
Thu, 19 February 2015 14:39 |
Eclipse User |
|
|
|
Interesting -- I've never used that second form for specifying extension-adapters, and never think of it. Sorry for being obtuse! You're completely right: it looks like a deviation that's since spread. Feel like opening bugs against the specific components?
You can work around it by having your factory check to see what attribute was used to obtain it. If "class" and your data==null then you know it's from the UITest approach and you'll need to look at the child elements.
Brian.
|
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.03680 seconds