Saturday, October 30, 2010

Workbench not coming while running UI tests for eclipse plugins in Hudson CI in windows

We planned to do CI setup for a project that involved eclipse plugins and decided to go to tycho for achieving that. The reason is simple as we were bit familiar with Maven and also saw that configuring to use tycho is easy (atleast we haven't used Ant before, so PDE build with Ant tasks, the usual way, is not gonna be easy as well).
This mini article is not about tycho but about overcoming the hurdle you might face when running eclipse UI integration tests written via WindowTester when setting up CI in Hudson in windows machine.

We first wrote a windows batch that does this -


a. Checkout projects from SVN
b. Trigger maven build, that builds plugins, runs unit tests followed by UI tests (that requires a launched workbench).

Tycho is brilliant is bringing up workbench right before running tests so things were going fine.
But when we moved to Hudson to set up, all happened except bringing up workbench. However an eclipse instance was created which was evident as seen in Task Manager but somehow workbench didn't come up which failed all UI tests.

Googling and googling finally fetched solutions in form of posts - UI tests in a CI env  - here, here and there and though they are not directly related to stated problem, the concept applies..

Read them? Fine, so what was the problem really?
We used to do the Hudson setup in a remote box which we used to login via mstsc console. As mentioned in above posts, doing remote login itself would lock the desktop and hence Hudson won't be able to interact natively with OS to bring up the workbench. This won't occur if you configure Hudson directly in your local machine i.e. when you logged directly into the machine where you are configuring Hudson. But this won't be the case as usually we configure Hudson in a remote box or one in a CI farm..

These are the points to note
a. Have a VNC server installed in the machine where Hudson has to be configured. We used RealVNC free edition.
b. Now in the remote machine (where we just installed VNC) where Hudson has to be configured disconnect all user sessions. Do it by going to Task Manager -> Users. No entry should be present and just disconnect all users. This implies that the machine should not be a normal box which is shared among users. Better disable remote session for the box.
c. Now remember this 'never use mstsc console to launch Hudson instance'. So connect to remote machine via VNC viewer installed in your local box. (you should give something like hostname:display to connect)
d. Once connected via VNC viewer, launch Hudson via command prompt; yes, not via Windows Service!
e. Now just trigger the build from local box or the remote box itself and see the workbench being shown up!

We haven't done any configuration in Hudson itself so far and things will be fine unless you would like have multiple builds being done in parallel by Hudson in same above machine and each build having to run UI tests as well..
Interesting..
Actually we came to know about a Hudson plugin named XVnc to satisfy exactly this purpose, but wait, we didn't play with it, as luckily we got a dedicated box for our project - so only one build at a time - so no prob..
The notion X protocol that the plugin talks about is specific to Linux based systems so not sure how easy to set it up in windows. We also contacted the plugin creator and got that the plugin was tested only in Linux systems (atleast until the time of this writing) but it doesn't mean that its not possible to set it up in windows. However we heard that minor tweaking might be required to see that the scripts that the plugin executes are intact in windows based machines too.. Anyways, hope we get a chance to experiment that too..

Monday, October 25, 2010

Adding test suites to a test suite in Junit 3.x

Normally in a junit 3.x test suite we will add test classes (that has our test methods) as entries. 
As an example,

public class AllTests {

    public static Test suite() {

        TestSuite suite = new TestSuite(
                "All tests wrapped in a suite");
        // $JUnit-BEGIN$
        suite.addTestSuite(SampleTest.class);
        suite.addTestSuite(AnotherSampleTest.class);
        // $JUnit-END$
        return suite;
    }

}

But what if we want to put several test suites into a master test suite.
It can be done in this way:

public static Test suite() throws Exception {
         TestSuite suite = new TestSuite(
                "Master test suite that has all test suites");
        // $JUnit-BEGIN$
        suite.addTest(AllTests.suite());
        suite.addTest(AnotherAllTests.suite());       
        // $JUnit-END$
        return suite;
    }


And last but not least, you can mix and match both.

Thursday, September 2, 2010

Eclipse plugin/OSGI err: Validation failed : Missing constraint - Import-Package: x.y.z; version=".."

You might encounter this while dealing with eclipse plugins in eclipse EDE.
For sample while launching as Eclipse Application or Junit Plug-in test.

This is because of validation (automatically trigged) upon launch.
a. Goto Run/Debug Configuration -> Eclipse Application (say) -> your configuration name
b. In the right side you will see many tabs named Main, Arguments, Plug-ins etc.
Select Plug-ins
c. At the bottom you will see item 'Validate plug-ins automatically prior to launching' checked.
d. Though un checking it might resolve the problem temporarily (at launch) its not a real solution
e. To resolve it, click 'Add Required Plugins' at the right. It will automatically add required bundles if available. Now manually do 'Validate Plug-ins' and validation will pass.

Sunday, August 22, 2010

GWT error - com.google.gwt.user.client.rpc.ServiceDefTarget $NoServiceEntryPointSpecifiedException: Service implementation URL not specified

Note that the solution depends on the GWT version. I was using GWT 2.0+

Just ensure that service relative path is mentioned in your client service interface via annotation

com.google.gwt.user.client.rpc.RemoteServiceRelativePath

An example,

@RemoteServiceRelativePath("sampleService")
public interface SampleService extends RemoteService {
..
}

If you want to understand why 
or
if you using older version of GWT then the annotation won't be available for you so 
here is the answer.

This is mentioned in GWT dev guide under 'Common pitfall' but i didn't read it earlier,
"When running your RPC call, development mode displays an excaption NoServiceEntryPointSpecifiedException: Service implementation URL not specified. This error means that you did not specify a @RemoteServiceRelativePath in your service interface, and you also did not manually set target path by calling ServiceDefTarget.setServiceEntryPoint()."
    Also note this one that's closely related to above one,
    "If invoking your RPC call fails with a 404 StatusCodeException, your web.xml may be misconfigured. Make sure you specified a @RemoteServiceRelativePath and that the <url-pattern> specified in your web.xml matches this value, prepended with the location of your GWT output directory within the war directory."

    For every annotation definition given above, corresponding entry for service impl should be given in web deployment descriptor i.e web.xml. As an example,

       <servlet>
            <servlet-name>sampleServlet</servlet-name>
            <servlet-class>samples.gwt.SampleServiceImpl</servlet-class>
        </servlet>

        <servlet-mapping>
            <servlet-name>sampleServlet</servlet-name>
            <url-pattern>/sample-gwt-module/sampleService</url-pattern>
        </servlet-mapping>
     
    where


     sample-gwt-module

    is the (alternate) name of the sample GWT module as defined in module definition as


    <module rename-to='addressbookmain'>

    GWT error: 'samples.gwt.Model' is not assignable to 'com.google.gwt.user.client.rpc.IsSerializable' or 'java.io.Serializable' nor does it have a custom field serializer (reached via samples.gwt.Model)


    This could really be because of multiple reasons and i have listed solution pertaining to my case here.

    See if the class in err i.e. (samples.gwt.Model here) implements
    java.io.Serializable; 


    i did and this solved the prob in my case. If err still persists, before further analysis you could ensure that following are intact though these might not be directly related.

      Make sure the class (samples.gwt.Model here) that could not be assigned to RPC is defined in shared package (per GWT convention it is the package with leaf folder in name of 'shared' for eg. 'samples.gwt.shared') that's visible to both server and client.
    The point is the class should not only be defined in client package (say samples.gwt.client) that's translated to javascript finally and not visible to server part.
    (and as a note, you should/would have mentioned this path in corresponding module definition XML as <source path='shared'/>)

     Also if the class in err i.e. is defined in GWT module A (say) and the RPC service class in error is one that's present in module B (say), in this case, ensure that module A is inherited in module B XML definition
    via inherit tag.
    eg. 
    <inherits name='samples.gwt.A'/>

    Hope this helps.


    GWT error - Unable to find 'Sample.gwt.xml' on your classpath; could be a typo, or maybe you forgot to include a classpath entry for source


    How to solve the error in question?

    The solution is in the err message itself, thanks to GWT.
    Though the exact cause depends on your environment, following addresses common scenarios

    a. If the module definition XML (i.e. 'Sample.gwt.xml' here) is in the same GWT module that you are compiling via GWT compiler (or running in development mode) then check if the desired xml has been put in package that's just before above your client package. Importantly the module definition should be in the source path so that it falls in the GWT module's classpath.
     i.e. if your client package is 
    samples.gwt.client
    then Sample.gwt.xml should go into 
    samples.gwt

    b. If the module definition XML is in a dependent module that you have inherited in your parent (or main) module definition Main.gwt.xml (say) then ensure that the logical name of inherited module definition XML mentioned in <inherit> tag is correct

    i.e. you should have 
    <inherits name='samples.gwt.Sample'/> 
    in 
    Main.gwt.xml

    This logical name is irrespective of the alternate name, if any, that you have given to 'Sample.gwt.xml' like

    <module rename-to='sample-alt-name'>

    Also to ensure the trivial case, if you are using IDE check that dependent module exists in Project -> Build Path
    and if you use Maven then the dependent module should have been mentioned in <dependency> tag of parent project. 
    Hope this helps.





    GWT error - Deferred binding result type should not be abstract (or) Rebind result must be a class



    When you encounter following GWT error message

    either 

    'Deferred binding result type should not be abstract'

    in hosted or development mode

    or

    'Rebind result must be a class'

    upon GWT compilation

    then mostly it means that your GWT client service interface didn't extend the required marker interface 

    com.google.gwt.user.client.rpc.RemoteService

    So change your service from 

    interface SampleService{
         ..
    }

    to

    import com.google.gwt.user.client.rpc.RemoteService;

    interface SampleService extends RemoteService {
         ..
    }

    Hope this helps. Thanks to this post that helped me initially.