Wednesday, October 28, 2015

Unit Testing of AngularJS in Spring MVC maven project using Jasmine, PhantomJS, and Jenkins CI

This post is about some links on how to perform unit testing of angularjs in spring MVC project. One typical setup is with Jasmine and phantomjs.

Some general descriptions of these tools: jasmine is a behavior-driven development framework for testing javascript, phantomjs is a headless browser, which can be invoked on Jenkins CI to run unit testing of angularjs (Jenkins CI is a continuous integration server that supports building and testing of software projects)

POM setup


Firstly includes the following in your maven POM file

<properties>
<angularjs.version>1.4.3-1</angularjs.version>
<phantomjs.outputDir>${java.io.tmpdir}/phantomjs</phantomjs.outputDir>
</properties>

<build>
  <pluginManagement>
        <plugins>
            <!--This plugin's configuration is used to store Eclipse m2e settings 
                only. It has no influence on the Maven build itself. -->
            <plugin>
                <groupId>org.eclipse.m2e</groupId>
                <artifactId>lifecycle-mapping</artifactId>
                <version>1.0.0</version>
                <configuration>
                    <lifecycleMappingMetadata>
                        <pluginExecutions>
                            <pluginExecution>
                                <pluginExecutionFilter>
                                <groupId>com.github.klieber</groupId>
              <artifactId>phantomjs-maven-plugin</artifactId>
                                    <versionRange>
                                        [0.7,)
                                    </versionRange>
                                    <goals>
                                        <goal>install</goal>
                                    </goals>
                                </pluginExecutionFilter>
                                <action>
                                    <ignore></ignore>
                                </action>
                            </pluginExecution>
                        </pluginExecutions>
                    </lifecycleMappingMetadata>
                </configuration>
            </plugin>
        </plugins>
    </pluginManagement>

<plugins>

<plugin>
          <groupId>com.github.klieber</groupId>
          <artifactId>phantomjs-maven-plugin</artifactId>
          <version>0.7</version>
          <executions>
            <execution>
              <goals>
                <goal>install</goal>
              </goals>
            </execution>
          </executions>
          <configuration>
            <version>1.9.7</version>
          </configuration>
        </plugin>
   <plugin>
     <groupId>com.github.searls</groupId>
     <artifactId>jasmine-maven-plugin</artifactId>
     <version>2.0-alpha-01</version>
     <executions>
       <execution>
         <goals>
           <goal>test</goal>
         </goals>
       </execution>
     </executions>
     
  
     
     <configuration>
       <additionalContexts>
         <context>
           <contextRoot>/lib</contextRoot>
           <directory>${project.build.directory}/generated-resources/unit/ml/js</directory>
         </context>
       </additionalContexts>
       <skipTests>true</skipTests>
       <preloadSources>
          <source>/webjars/jquery/2.1.3/jquery.min.js</source>
     <source>/webjars/bootstrap/3.3.5/js/bootstrap.min.js</source>
     <source>/webjars/angularjs/${angularjs.version}/angular.min.js</source>
     <source>/webjars/angularjs/${angularjs.version}/angular-route.min.js</source>
     <source>/webjars/angularjs/${angularjs.version}/angular-animate.min.js</source>
    
      <source>/webjars/angularjs/${angularjs.version}/angular-mocks.js</source>
       </preloadSources>
       <jsSrcDir>${project.basedir}/src/main/resources/js</jsSrcDir>
       <jsTestSrcDir>${project.basedir}/src/test/resources/js</jsTestSrcDir>
       <webDriverClassName>org.openqa.selenium.phantomjs.PhantomJSDriver</webDriverClassName>
      <webDriverCapabilities>
     <capability>
      <name>phantomjs.binary.path</name>
      <value>${phantomjs.binary}</value>
     </capability>
    </webDriverCapabilities>
     </configuration>
   </plugin>
  </plugins>

  
<build>  


In the <plugins> section two plugins, namely jasmine and phantomjs maven plugins are added. The jasmine plugin is for jasmine to be used for unit testing and the phantomjs will download the phantomjs executable into a tmp folder so that it can be invoked to run the unit testing by Jenkins. The phantomjs maven plugin is very useful in that when the project is fetched by Jenkins CI to perform testing, the machine running Jenkins CI may not have phantomjs pre-installed. With the phantomjs maven plugin and the "install" goal specified in it, the Jenkins will search locally whether a copy of phantomjs is available in the specified phantomjs.outputDir folder, if not, it will download from the internet and put it in the phantomjs.outputDir folder, and after that the plugin set the phantomjs.binary parameter automatically, so that Jenkins CI knows where to find the phantomjs executable.

The org.eclipse.m2e lifecycle-mapping specified in the <pluginManagement> is used to stop Eclipse from complaining m2e cannot under the "install" goal specified in the phantomjs maven plugin. It does not have any effect on maven when it builds and run the project.

Implement Jasmine and spring unit testing codes


For this, there is already a nice article on how to do it here at:

https://spring.io/blog/2015/05/19/testing-an-angular-application-angular-js-and-spring-security-part-viii

Therefore I won't repeat it.

Tuesday, October 27, 2015

Building Asynchronous RESTful Services With Spring MVC and Guava

Recently I was working some asynchronous RESTful services in the Spring MVC framework in which i am thinking of using Guava to reduce the effort in development. After failing to find any good reference on using Guava with Spring MVC's asynchronous RESTful operation, I decide to do it by trial and error. In the end, it turned out to be quite easy. This post shows how to develop asynchronous RESTful services with spring mvc and google's Guava library.

Firstly includes the dependencies for Guava in your spring MVC project.

Implementation using Guava in Spring MVC


Now write a simple spring service something like the one below:


import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;

import java.util.concurrent.Callable;
import java.util.concurrent.Executors;

import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class MyLongRunningServiceImpl extends MyLongRunningService {
   private ListeningExecutorService service;
 
   public MyLongRunningService(){
     service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
   }

   public ListenableFuture<Date> doLongRunningProcess(final int milliseconds){
 ListenableFuture<date> future = service.submit(new Callable<date>() {
            public Date call() throws Exception {
                Thread.sleep(milliseconds
                return new Date();
            }
        });

 return future;
   }
}

As shown in the code above the service has a method which delay a number user-specified milliseconds before returning a Date object. Next write a simple controller that autowires with the service:


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.async.DeferredResult;


@Controller
public class MyLongRunningController {
  @Autowired
  private MyLongRunningService service;

  @RequestMapping(value="/longRun", method = RequestMethod.GET)
 public @ResponseBody DeferredResult<Date> doLongRunningProcess(){
  
  DeferredResult<Date> deferredResult = new DeferredResult<>();

   
  logger.info("start long running process");
  
  
  ListenableFuture<Date> future = service.doLongRunningProcess(60000);
  
  Futures.addCallback(future, new FutureCallback<Date>(){

   @Override
   public void onFailure(Throwable throwable) {
    logger.error("long running process failed", throwable);

   }

   @Override
   public void onSuccess(Date res) {
    logger.info("long running process returns");
    
     
    deferredResult.setResult(res);
   }
   
  });
  
  
  return deferredResult;
 }
}

This completes the coding part. There are two notes apart from the above implementation in order to make the asynchronous RESTful service to work:

<async-supported>true</async-supported>


The first thing is that the user needs to add in the following XML element into their web.xml configuration

<async-supported>true</async-supported>

This should be put under both <servlet> section (for the servlet which contains the spring controller above) as well as the <filter> section of the "org.springframework.web.filter.DelegatingFilterProxy"

asyncTimeout

If you are using Tomcat server as the servlet and http container for your spring MVC, that the asyncTimeout need to be added into the <Connector> element of the /conf/server.xml in tomcat directory, so that async services won't be terminated before tomcat's timeout, e.g.,

<Connector asyncTimeout="60000" ... >

If you are using javascript to interact with the asynchronous RESTful services, you may also need to specify the timeout property (e.g., in the $http of angularjs) so that the http call will not terminate before the asynchronous service call is completed.

Install Nide on CentOS

One headache i have is with the use of vi on command line of VM to edit complex script. I recently found the alternative of using Nide. Nide is a web-based editor which allows user to remotely view and edit files in a VM using a web interface. this post shows a step-by-step installation guide on how to make it run on centos or scientific linux

Install nodejs in VM

To install nodejs on centos, run the following commands:

> cd /opt
> wget http://nodejs.org/dist/v0.10.30/node-v0.10.30.tar.gz
> tar xvzf node-v0.10.30.tar.gz
> cd node-v0.10.30
> ./configure
> sudo yum install gcc gcc-c++
> make
> make-install

Now run the following command to see if it is installed:

> node --version

Install npm in VM

To install npm, run the following commands 
> curl -SL https://rpm.nodesource.com/setup | bash -

Run the following command to see if it is installed:

> npm --version

Install nide

Run the following command to install nide

> npm install -g nide

Run nide in VM


After nide is installed, before proceed to launch it, the first thing is to make sure that the port that it listen can be accessible from VM, if not run some command like the following to open the port (in this case, it is port 80):

> iptables -I INPUT 5 -i eth0 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT

One more thing to make sure before the launching is to make sure that the node_modules in which nide is installed have the proper permission, by running the following command:

> sudo chown -R $USER /usr/local/lib/node_modules

Now, one can launch the nide at port 80 using the following command:

> nide init -p 80

And you can go to your local machine, and enter the address "http://[VM-IP]" (where VM-IP is the ip address of the VM, since you are running nide at port 80 here, no need to add the port number). Now you are free to view and edit files in your VM.

Saturday, October 17, 2015

Eclipse Tomcat: class path resource [properties/server-${spring.profiles.active}.properties] cannot be opened because it does not exist

Today I encounter this error when working on a spring project in eclipse when trying to start the tomcat server on the spring mvc project:

"class path resource [properties/server-${spring.profiles.active}.properties] cannot be opened because it does not exist"

The issues turned out to be that the spring project has two properties files: namely server-dev.properties and server-production.properties. The project define a property "spring.profiles.active" which need to be supplied to the tomcat server when launching the spring mvc project so that the proper properties file can be loaded. The problem occurred because i was did not specify the argument when launching the project. To resolve this, double click the tomcat server instance in the "Servers" window in Eclipse and click the "Overview" tab. In the "Overview" tab, click "Open launch configuration" link. In the "Edit Configuration" dialog opened, click the "Arguments" tab, and append the following to the "VM arguments" textbox:

-Dspring.profiles.active=dev


Thursday, October 15, 2015

Scentific Linux / CentOS: investigate system error

Some simple commands to check system errors in centos or scentific linux:

To check the list of errors:
> grep -i error /var/log/messages

To check login:
> tail --lines=200 /var/log/secure

To check when the system is shutdown:
> grep -i shutdown /var/log/messages

Under centos the /var/log/messages is equivalent to /var/log/syslog in Ubuntu

Eclipse: Black tooltip background when running eclipse on centos and scentific linux

I have been use eclipse for java development but recently i migrated the eclipse over from centos and scentific linux, now the eclipse running on centos and scentific linux have a black tooltip when user hover over the codes. The problem seems to be related to GTK which eclipse use.

Solution:
Create a "start.sh" in the eclipse root folder, make it executable. then put the following two lines in the files:

export SWT_GTK3=0
./eclipse

Now launch the "start.sh" instead of "eclipse" executable.

While the above solution seems to temporarily solve the black tooltip problem for me, eclipse will occasionally crash due to issues button size cannot be determined. Today, my colleague comes up with a better solution which is to replace the default desktop environment in centos with the xfce http://www.xfce.org/. This completely remove the issue with black tooltip background in eclipse.

Wednesday, October 14, 2015

Nexus: Maven pulls everything but the main jar of drools and jboss through POM dependency

I encountered an error in the eclipse in which maven was not able to pull jar files as specified in the pom file related to the drools.6.3.0.Final. The library files are pulled from a local Nexus repository in which both the jboss public proxy has been setup and added in the mirrors of the local maven settings.xml file.

The problem turned out to be that the pom file in the folder '/root/.m2/repository/org/jboss/dashboard-builder/dashboard-builder-bom/6.3.0.Final/" is named as " dashboard-builder-bom-6.3.0.Final.pom.lastUpdated" instead of "
dashboard-builder-bom-6.3.0.Final.pom". 

After renamed the pom file back and do a maven force update on the project in eclipse the error was gone.

Tuesday, October 13, 2015

Redis: Running redis server in docker container and access it from Windows host

Start the boot2docker on Windows host, run the following commands to create a container instance:

> docker run -i -t -p 6379:6379 --name=redis ubuntu bash

Note that the "-p 6379:6379" expose the port 6379 (which is the port on which redis server run by default) of the docker container as the port of the docker vm, so that it can be accessed from the Windows host. In the "redis" container, run the following command to install the necessary tools for building redis:

> sudo apt-get update
> sudo apt-get upgrade
> sudo apt-get install build-essential
> sudo apt-get install tk8.5 tcl8.5
> sudo apt-get install wget

In the "redis" container, run the following command to download and build the redis

> cd /opt
> wget http://download.redis.io/redis-stable.tar.gz
> tar xvzf redis-stable.tar.gz
> cd redis-stable
> make distclean
> make test

In the "redis" container, run the following command to start running the redis server:
> cd /opt/redis-stable/src
> ./redis-server

Open a console windows on the Windows host and type the following command to find out the boot2docker ip address:

> boot2docker ip

which should return something like 192.168.59.103  (Note that the address 192.169.59.103 is the ip address of the docker vm, which by default the docker container is mapped to)

Now start a redis client from the Windows console windows (if you have not downloaded the redis client binary, can download it from https://github.com/ServiceStack/redis-windows) by entering the following command line in the console of the Windows host:

> cd [your-redis-windows-binary-directory]
> redis-cli.exe -h 192.168.59.103

That's it. This is the link to some C# demo code (using the ServiceStack.Redis library via nuget) which connect to the redis server running in the docker container:

https://dl.dropboxusercontent.com/u/113201788/Redis/RedisDemoCSharp.zip