Oct
21
2009

(ITA) - TESTING & Magnolia

Prima di chiedersi come si fa a testare, occorre chiedersi “cosa” testare e perchè.
Se il perchè può essere ovvio, il “cosa” no e spesso è la chiave di volta per dei test di successo.

Cosa NON testare:

- funzionalità “core” di Magnolia: per queste ci affidiamo ad un prodotto, si spera che sia testato
- funzionalità “core” di Java / Tomcat / Loadbalancer / Sistemi di rete, ecc… non è compito dei test applicativi testare queste cose

Cosa vale la pena di testare

- funzionalità di business logic
- grafica
- interazioni via browser
- integrazioni con sistemi legacy / esterni
- scritture / letture / interazioni con dati da fonti esterne
- tutto quello che viene costruito “sopra” il mattoncino Magnolia

In un progetto Java, ci sono principalmente due modi per effettuare test:

1) Test in fase di build
2) Continuos Integration [3]

Mentre la seconda modalità prevede l’utilizzo di un ambiente di test separato, integrazione con SVN, definizione rigorosa di suite di test, ecc… (ovvero, è al momento troppo costoso!) si può procedere con la prima modalità.

In fase di build si possono quindi fare test di due tipi:
1) Test funzionali, puramente java-based
2) Test di “container”, ovvero simulando il deploy dell’artifact in un container (tomcat)

La suite di test da utilizzare è TestNG [1]. In alternativa è possibile ad esempio utilizzare JUnit, che si integra anch’essa con Surefire.
I test sono da effettuare in fase di build (Maven build).
Per utilizzare testNG è sufficiente dichiarare questa dipendenza all’interno del parent POM:

<dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>5.8</version>
    <scope>test</scope>
    <classifier>jdk15</classifier>
</dependency>

ed utilizzare il plugin

<build>
	<plugins>
		...
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-surefire-plugin</artifactId>
			<version>2.4.3</version>
		</plugin>
		...
	</plugins>
<build>

I test saranno eseguiti dal plugin Surefire come test TestNG.
Per ulteriori informazioni su Surefire e TestNG vedi [2]

A questo punto occorre chiedersi cosa è possibile testare con un’ambiente di questo tipo a disposizione.
Sicuramente è possibile testare i metodi di utility, le integrazioni con sistemi esterni (lettura di feed RSS, accesso a DB, ecc..).
L’unica cosa a cui bisogna porre attenzione è lo “scope” del test.
Un test eseguito in fase di build di un modulo altro non può testare che le funzionalità esclusive del modulo stesso o le integrazioni del modulo con l’ambiente di deploy.
Non è possibile testare le interazioni del modulo con altri moduli.

Es1: vorrei testare la spedizione di una newsletter

artifact: example-magnolia-newsletter.jar
metodo da testare: NewsletterUtil.sendNewsletter(recipientList, newsletterIstance, delay);
presupposti: occorre avere a disposizione l’architettura dei server / servizi da utilizzare per spedire la newsletter

OK, è testabile.

Es2: vorrei testare la spedizione di una newsletter LEGGENDO gli indirizzi dal DMS Alfresco, utilizzando il modulo example-magnolia-dms.jar

artifact: example-magnolia-newsletter.jar
metodo da testare: NewsletterUtil.sendNewsletter(DMSUtil.getRecipient(id), newsletterIstance, delay);
presupposti: occorre avere a disposizione l’architettura dei server / servizi da utilizzare per spedire la newsletter

NON è testabile, a meno di non avere un ambiente di test “reale” –> Continuos Integration

Vi è un altro tipo di test, particolare dell’ambiente di sviluppo di Magnolia.
E’ possibile effettuare dei test automatici che simulano l’interazione della nostra applicazione con un browser.
Per fare questo occorre utilizzare Selenium [4].
Selenium si compone di due parti, la parte server (o grid) ha il compito di eseguire in un browser i comandi che la parte client invia tramite connessione TCP su porta 4444 (default).

Gli step da percorrere sono i seguenti:
1) Configurare l’utilizzo di Surefire e TestNG
2) Far partire Selenium Remote Command in fase di pre-integration-test [5]. (* perchè in questa fase?)
3) Far partire un container nel quale “deployare” l’applicazione web
4) DEPLOY -> Magnolia + Modulo
5) Eseguire i test Selenium
6) Spegnere il container e il server Selenium

-> 1) Vedi sopra (Surefire + TestNG)
-> 2) Occorre utilizzare un plugin (selenium-maven-plugin), in fase di pre-integration-test

<build>
	<plugins>
		...
		<plugin>
			<groupId>org.codehaus.mojo</groupId>
			<artifactId>selenium-maven-plugin</artifactId>
			<executions>
				<!-- start Selenium server before test execution -->
        		<execution>
           			<id>start</id>
           			<phase>pre-integration-test</phase>
           			<goals>
               			<goal>start-server</goal>
           			</goals>
           			<configuration>
               			<background>true</background>
               			<logOutput>true</logOutput>
						<multiWindow>true</multiWindow>
           			</configuration>
        		</execution>
        		<!-- stop Selenium server after test execution -->
        		<execution>
           			<id>stop</id>
           			<phase>post-integration-test</phase>
           			<goals>
               			<goal>stop-server</goal>
           			</goals>
        		</execution>
    		</executions>
		</plugin>
		...
	</plugins>
</build>

-> 3) Per far partire Tomcat (il container di riferimento per la piattaforma) occorre utilizzare l’ennesimo plugin (cargo-maven-plugin), in fase di pre-integration-test

<build>
	<plugins>
		...
		<plugin>
			<inherited>true</inherited>
			<groupId>org.codehaus.cargo</groupId>
			<artifactId>cargo-maven2-plugin</artifactId>
			<configuration>
 
				<!-- Container configuration -->
				<container>
				<containerId>tomcat6x</containerId>
					<!-- container.home: indica dove andare a prendere i file originari di tomcat -->
					<home>c:/dev/apache-tomcat/apache-tomcat-6.0.20</home>
					<output>${project.build.directory}/cargo/tomcat.log</output>
					<log>${project.build.directory}/cargo/cargo.log</log>
				</container>
 
				<!-- Configuration to use with the above container -->
				<configuration>
					<!-- configuration.home: indica dove far girare il container -->
					<home>${project.build.directory}/tomcat/container</home>
					<properties>
						<cargo.servlet.port>8090</cargo.servlet.port><!-- utilizzare 8090, in quanto è possibile avere altre istanze attive -->
						<cargo.logging>high</cargo.logging>
						<cargo.jvmargs>${heap.pre} ${heap.max} ${permsize}</cargo.jvmargs>
					</properties>
				</configuration>
 
				<!--  
					By default the Maven2 plugin will wait after the container is started. 
					It means that you have to either press Ctrl-C or to run cargo:stop from another shell to stop it. 
					If you are using Cargo to automate your functional tests, you'll want the plugin 
					not to wait so that you can execute your tests after the container is started. 
					To achieve this simply specify <wait>false</wait> in the Cargo's configuration in your pom.xml.
				-->
				<wait>false</wait>
			</configuration>
 
			<executions>
				<!-- start container before tests execution -->
				<execution>
					<id>start-container</id>
					<phase>pre-integration-test</phase>
					<goals>
						<goal>start</goal>
						<goal>deploy</goal>
					</goals>
				</execution>
 
				<!-- stop container before tests execution -->
				<execution>
					<id>stop-container</id>
					<phase>post-integration-test</phase>
					<goals>
						<goal>stop</goal>
					</goals>
				</execution>
			</executions>
		</plugin>
		...
	</plugins>
</build>

-> 4) Questa è la fase più delicata. Una volta partito tomcat occorre deployare all’interno webapp Magnolia, possibilimente già installata e con licenza EE, e occorre deployare al suo interno il modulo in questione.
Per fare questo ci sono due opzioni:
A) Procedere con un deploy configurato in cargo:

modificare:

		<!-- start container before tests execution -->
		<execution>
			<id>start-container</id>
			<phase>pre-integration-test</phase>
			<goals>
				<goal>start</goal>
				<goal>deploy</goal>
			</goals>
		</execution>

in:

		<!-- start container before tests execution -->
		<execution>
			<id>start-container</id>
			<phase>pre-integration-test</phase>
			<goals>
				<goal>start</goal>
				<goal>deploy</goal>
			</goals>
			<configuration>
				<deployer>
					<deployables>
						<deployable>
							<group-id>com.example.magnolia</group-id>
							<artifactId>magnoliaAuthor</artifactId>
							<type>war</type>
							<pingURL>http://localhost:8090/magnoliaAuthor/.magnolia/pages/adminCentral.html?mgnlUserId=superuser&amp;mgnlUserPSWD=superuser</pingURL>
							<pingTimeout>180000</pingTimeout>
							<properties>
								<context>magnoliaAuthor</context>
							</properties>
						</deployable>	
					</deployables>
				</deployer>
			</configuration>
		</execution>

in questo modo, il WAR identificato dal gruppo Maven indicato verrà deployato all’interno del container.
Rimane ancora il problema di integrare il progetto attualmente in fase di build con il file WAR e di eseguire l’installazione di Magnolia.

B) Procedere con un deploy “manuale”, mediato da task ant

è possibile definire un task ant da eseguire in una qualunque fase di esecuzione di una maven build.

<build>
			<plugins>
				...
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-antrun-plugin</artifactId>
					<executions>
						<execution>
							<id>copyModule</id>
							<phase>pre-integration-test</phase>
							<configuration>
								<tasks>
									<echo>Copy module ${project.build.finalName}.jar</echo>
									<copy 
										file="target/${project.build.finalName}.jar"
										todir="../magnoliaAuthor-integrationTest/src/main/magnoliaAuthor/WEB-INF/lib"
										overwrite="true" />
								</tasks>
							</configuration>
							<goals>
								<goal>run</goal>
							</goals>
						</execution>
 
						<!-- cancella il file dopo i test -->					
						<execution>
							<id>deleteModule</id>
							<phase>post-integration-test</phase>
							<configuration>
								<tasks>
									<echo>Delete module  ${project.name}</echo>
									<delete>
										<fileset 
											dir="../magnoliaAuthor-integrationTest/src/main/magnoliaAuthor/WEB-INF/lib"
										    includes="${project.build.finalName}*.jar" />
									</delete>
								</tasks>
							</configuration>
							<goals>
								<goal>run</goal>
							</goals>
						</execution>
					</executions>
				</plugin>
				...
			</plugins>
		</build>

A questo punto occorre modificare Cargo, in modo da caricare la webapp di integration:

		<configuration>
			<deployer>
				<deployables>
					<deployable>
						<type>war</type>
						<location>../magnoliaAuthor-integrationTest/src/main/magnoliaAuthor</location>
						<pingURL>http://localhost:8080/magnoliaAuthor/demo-project.html?mgnlUserId=superuser&amp;mgnlUserPSWD=superuser</pingURL>
						<pingTimeout>180000</pingTimeout>
					</deployable>
				</deployables>
			</deployer>
		</configuration>

La webapp sarà quindi deployata non più come war, ma come semplice “copia e incolla” di cartella e conterrà al suo interno il file da testare.

-> 5) I test partono e se contengono invocazioni remote a Selenium queste saranno eseguite e si vedrà “apparire” sullo schermo un browser che eseguirà i comandi richiesti.
-> 6) Le dichiarazioni dei plugin precedenti contengono due fasi di esecuzione: quella relativa alla fase “post-integration-test” avviene dopo aver eseguito i test.

PUNTI APERTI:

è possibile partire dalla empty webapp di magnolia e utilizzare un cargo che carica:
- empty webapp CE (versione X)
- moduli EE dichiarati per la versione (X)
- modulo aggiuntivo da testare
- effettua l’installazione del repository
- effettua il caricamento della licenza
?

E’ possibile / ha senso avere un WAR di test collegato ad un repository di test, in modo da evitare la fase di installazione?

NB: per testare funzionalità core di Magnolia e precisamente legate a:
- Content
- Context
- HierarchyManager
è possibile utilizzare delle classi di mockup (http://www.easymock.org) che facilitano l’interazione con questi oggetti.
Vedere [7]

————————————————
[1] http://testng.org
[2] http://maven.apache.org/plugins/maven-surefire-plugin/testng.html
[3] http://en.wikipedia.org/wiki/Continuous_integration
[4] http://seleniumhq.org
[5] http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Lifecycle_Reference
[6] http://mojo.codehaus.org/selenium-maven-plugin/
[7] http://wiki.magnolia-cms.com/display/DEV/Testing+Magnolia

0
Jun
24
2009

Repairing a “missing child” error on Magnolia 3.6.3

This little article is related to Magnolia 3.6.3 but it uses magnolia-tools, a common tool for any >3.5 version of Magnolia.

Case description
At tomcat start-up an error message, thrown by SearchIndexer says:

ERROR org.apache.jackrabbit.core.query.OnWorkspaceInconsistency OnWorkspaceInconsistency.java(handleMissingChildNode:57) 18.06.2009 16:38:38 Node /news/latest/2009/04/18 (16a3070f-5297-435b-b04b-304b889cb26d) has missing child 'latestnews-77811' (19d83f35-05cd-4f81-ace6-81477039fe61)
ERROR org.apache.jackrabbit.core.RepositoryImpl RepositoryImpl.java(getWorkspaceInfo:733) 18.06.2009 16:38:38 Unable to initialize workspace 'data'
javax.jcr.RepositoryException: Error indexing workspace: Error indexing workspace: Error indexing workspace

The approach of forcing consistency check within Jackrabbit configuration was not helpful, because Jackrabbit can fix missing references, but not missing nodes.

With a good help of our friend (Jan) we manage to fix this, althought some data has been lost.

1) Do a full backup, anyway
2) In this case, the affected workspace is “data”, so we created a /tmp folder within Magnolia AdminInterface
3) We moved the “father” on /tmp, again within AdminInterface
4) We deployed magnolia-tools (version 1.0.5) jar in webapp/WEB-INF/lib folder.
5) We copied the /bin folder of magnolia-tools on webapp folder
6) Now, to avoid time consumption, we commented out the “SearchIndexer” part on webapp/repositories/magnolia/workspaces/data/workspace.xml file
7) with tomcat stopped, we launch this from the /bin folder:

sh ./removenode --uuid 16a3070f-5297-435b-b04b-304b889cb26d --workspace
data --webapp /var/lib/tomcat5/webapps/magnoliaAuthor > log 2>&1

where 16a3070f-5297-435b-b04b-304b889cb26d is the node’s uuid of the parent of the missing node (missing node uuid = 19d83f35-05cd-4f81-ace6-81477039fe61).

Now the parent is removed and Magnolia can bootstrap fine!

8 and final step) Uncomment worskpace.xml and decide if remove the /bin folder, for security purpose.

0
Jun
02
2009

CSS Training Course

Being called to teach CSS techniques, I’ve decided to add a post here which can contains all references I’ll found over this topic.

* Most of this resources are in italian because it is the course spoken lanaguage, sorry.

First of all, PPT slides I’ve made for Politecnico di Milano CSS Crash Course, on 2006.
CSS basic course (PDF)
CSS basic course, samples (PDF)

Italian resources:
HTML.it CSS basic course
- printable version
HTML.it CSS layout course
- printable version
html.net css tutorial

English resources:
W3Schools CSS tutorial
Free CSS Templates (400+ free templates)
Layout Gala: 1 markup, 40 templates
Intensivstation
Ironmyers - Layout generator
MyCelly.com
DynamicDrive

Frameworks:
A good article speaking about CSS frameworks
BlueprintCSS - Maybe the first CSS framework
Top 12 (11?) CSS Frameworks

Tools:
MenuMatic: a dynamic MooTools based menu engine

0
May
26
2009

How to install Windows XP over Acer Aspire 7738G

The Acer Aspire 7738G notebook is shipped with Windows Vista Home Premium SO.
A friend of mine bought this (good) notebook but wanted to downgrade to Windows XP.
The first thing I made is to check if drivers are available:

http://www.acer.com –> Support –> Drivers –> … –> YES! They are!

So download all of them and extract on a USB Key (you can also burn a CD).
Then, the second thing is to find a solution for the AHCI Controller.

To properly boot WIndows XP CD, first enter the BIOS and change SATA Controller Mode from AHCI to IDE. In this way, a normal Windows XP boot CD can load, otherwise you have 2 options:

1) Download SATA HCI Drivers (see below), create a driver floppy disk and on Windows XP boot start, hit F6 and load custom driver
2) Using nLite create your own Windows XP copy with AHCI driver already preloaded.

Method 1 requires a floppy driver, I have none! Method 2 is time consuming, so I prefer to try another way.

After enabled IDE mode for SATA drivers, I installed Windows XP as usual: the only thing to take care is to use the “C” partition, the “Acer” one, because the “E” partition and the “unnamed” partition contains recovery information, so avoid to touch them.

Wait until Windows load…

At this point we need to enable the AHCI SATA mode.
Download the latest version of Intel Matrix Storage Manager here:

http://www.intel.com/support/it/chipsets/imsm/

Since we want to change drivers of a boot hard drive, a standard installation would not have success. So we need a little more work.

Unpack with “-a” command line option: cmd > iata88cd.exe -a

It will unpack all files under “Program Files > Intel > Matrix Storage Manager”.
Look for the folder “Driver”, or Driver64 if you need drivers for 64 bit.
Copy iaStor.sys from this folder to C:\Windows\System32\Drivers folder, overwriting the existing one.

Now, open Device Manager (Control Panel > System > third tab) and select the Intel(R) ICH9M/M-E 2 port … 2928 controller.
Right click, update drivers.
Force to load drivers from the Matrix Storage Manager Driver folder and select the iaahci.inf file. Click next and select the right controller, in this case it is the Intel(R) ICH9M/M-E.
Windows now says that the driver can be harmful, but trust me and go on.
When installation is finished, reboot the system WITHOUT touching the second controller (292D).

Now enable from the BIOS the AHCI mode.

Windows should start well and now it will let you install the standard Intel Matrix Storage Manager installation procedure.
Reboot the system and now you have only one AHCI enabled controller!

NOTES:
At one moment I have tried also to follow another procedure, with a little regedit phase.
I’ve launched this code from a hci.reg file:

Windows Registry Editor Version 5.00
 
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_8086&dev_2922&cc_0106]
"Service"="iaStor"
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
 
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\iaStor]
"Type"=dword:00000001
"Start"=dword:00000000
"Group"="SCSI miniport"
"ErrorControl"=dword:00000001
"ImagePath"="system32\\drivers\\iaStor.sys"
"tag"=dword:00000019
"DisplayName"="Intel AHCI Controller"
 
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\iaStor\Parameters]
"queuePriorityEnable"=dword:00000000
 
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\iaStor\Enum]
"0"="PCI\\VEN_8086&DEV_2922&SUBSYS_B0051458&REV_02\\3&13c0b0c5&0&FA"
"Count"=dword:00000001
"NextInstance"=dword:00000001

USEFUL LINKS:
- Some details on Acer Aspire 7738g
- Intel Matrix Storage Manager
- HWUpgrade forum (italian) speaking about it
- English forum speaking about it

0
May
22
2009

Building a modular component for Magnolia - Part 1

Let’s say: I would like to have  on my site a html component which let me see next days weather forecast.

This component can be configured for each instance (e.g.: on home I would like to see a summary and on other pages I would like to see a detailed forecast).

This component can also answer to specific parameters (e.g.: ?showTime=true / ?forecastDate=2009.05.23).

Ok, we are ready to start!

01 - Build an empty component

Create a new Java class, call it WeatherStation.java

package com.mycompany.magnolia.modules;
 
import javax.servlet.http.HttpServletRequest;
import info.magnolia.cms.core.Content;
 
public class WeatherStation {
 
  public WeatherStation((HttpServletRequest request, Content config)){
    //...
    System.out.println("component weather instantiated!");
  }
 
}

Now, create a new paragraph renderer, WeatherStationParagraphRenderer.java:

package com.mycompany.magnolia.modules;
 
import javax.servlet.http.HttpServletRequest;
import info.magnolia.cms.core.Content;
 
public class WeatherStationParagraphRenderer implements ParagraphRenderer{
 
  //...
 
  public void render(Content content, Paragraph paragraph, Writer out) throws IOException {
 
  //...
 
  HttpServletRequest request = ((WebContext)ctx).getRequest();
  WeatherStation weatherStationComponent = new WeatherStation (request, content);
 
  //..
  }
 
}

This because we want to “emulate” a MVC lifecycle, instantiating object outside the rendering JSP templates.

At this point we can log-in to Magnolia AdminCentral and configure a paragraph, making it pointing to the right paragraphRenderer (add one or use one you can edit, not the default one). Remember to add a paragraph and a dialog too.

config

Click on this picure to enlarge.

The corresponding eclipse project structure is the following:

eclipse-config

To complete, this is the code inside main.jsp

<%@ taglib prefix="cms" uri="cms-taglib"%>
<cms:editBar editLabel="Edit" moveLabel="Move" deleteLabel="Delete" showParagraphName="true" />
 
<p>Weather station is alive</p>

and inside weatherStationTest.jsp

<%@ taglib prefix="cms" uri="cms-taglib"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 
<html>
	<head>
		<cms:links />
		<title>Test Weather Station</title>
	</head>
	<body>
		<p>Ready for testing</p>
		<cms:newBar contentNodeCollectionName="mainAreaComponents" paragraph="weather-station" newLabel="Add" />
 
		<cms:contentNodeIterator contentNodeCollectionName="mainAreaComponents">
			<cms:includeTemplate />
		</cms:contentNodeIterator>
	</body>
</html>

Ok, if everything is done correctly you can add a new page, add a template and add all Magnolia standard taglibs to handle paragraph instantiation:

website

And the output should be that:
ready

Of course, on the log file you should see the message: component weather instantiated!

0
Mar
06
2009

Too many open files!

While testing Magnolia CMS 4.0 RC4 on my Ubuntu Linux, I’ve encounter this error in catalina.out

  java.io.FileNotFoundException: /home/matteo/software/magnolia/magnolia-enterprise-4.0-rc4/apache-tomcat-5.5.27/webapps/magnoliaAuthor/repositories/magnolia/workspaces/config/db/seg0/cd1.dat (Too many open files)

Magnolia, by default, uses Derby database, a filesystem based ones, which opens a large amount of files.
I’ve solved this issue changing file limit by editing /etc/sysctl.conf and set fs.file-max to 400000 AND setting this line

  tomcatservice hard nofile 5000

in /etc/security/limits.conf. I needed to restart the session and everything works fine!

0
Feb
17
2009

Ok, let’s start!

Hi all, a little introduction just to break the ice.

This is the first post in this blog. My name is Matteo Pelucco, I’m a Computer Science Engineer and I like to work around the field of CMS (Content Management System). This blog would like to be a sort of “daily diary” of my IT activities, I hope that my notes can help somebody out here looking for help.

I want to start simply saying…

1
2
3
4
5
    public class HelloWorld {
      public static void main(String[] args) {
        System.out.println("Hello World!");
      }
    }

And good reading…

0