Estendere Selenium per validare pagine web, parte 2

Nel precedente articolo abbiamo visto come sia semplice fare delle chiamate XmlhttpRequest da Selenium testando il tutto sul css validator.

In un’ottica di automatizzare i test di selenium con Hudson (vedi plugin), potremmo pensare anche di salvare o di inviare per email il report generato da guardare in un secondo momento.

Per fare ciò invece di chiamare direttamente il validator potremmo chiamare un proxy scritto in PHP (o in un altro linguaggio) che:

  1. prende in input l’indirizzo della pagina da validare, l’indirizzo email e il tipo di validazione (CSS21, CSS3 ecc)
  2. chiama il validator e ottiene il report in xml
  3. salva il report in html e invia l’html per email (usando un file xslt per fare la trasformazione da xml a html)
  4. restituisca il report xml.

Andiamo a vedere dunque il comando da selenium:

storeLocation entry
checkCss ${entry} validity, email=emidiostani@gmail.com, profile=CSS21
verifyExpression ${validity} true

Come potete vedere una volta memorizzato l’indirizzo della pagina corrente nella variable entry, passiamo tale indirizzo al comando checkCss che restituisce il valore della variabile validity e prende come opzioni l’email e il profile (magari è meglio spostarli nella colonna di centro in futuro). Verifichiamo alla fine che il valore della variabile validity sia true.

Andiamo a vedere il codice (vi risparmio la funzione chiama WebService che abbiamo già visto nel precedente articolo):

Selenium.prototype.doCheckCss = function( uri, names ){

 var email = "";
 var profile = "";
 var array = names.split(',');
 for (var i = 0; i < array.length; i++){
 var name = array[i].trim();
 if(name.substr(0,5)=="email"){
 LOG.info( 'email = ' + name);
 var email_array = name.split('=');
 email = email_array[1];
 }
 else if(name.substr(0,7)=="profile"){
 LOG.info( 'profile = ' + name);
 var profile_array = name.split('=');
 profile = profile_array[1];
 }
 }

 var params = [
 {
 "param" : "uri",
 "value" : uri,
 },
 {
 "param" : "email",
 "value" : email,
 },
 {
 "param" : "profile",
 "value" : profile,
 },
 ];

 var lista = "";
 for(var i=0; i<params.length; i++){
 lista +="&" + params[i].param + "=" + encodeURIComponent(params[i].value);
 }

 var proxycss ="http://192.39.226.51/proxycss.php?";
 var indirizzo = proxycss+lista;
 LOG.info( 'indirizzo = ' + indirizzo);

 var responseXML = chiamaWebService(indirizzo);
 LOG.info( 'response = ' + responseXML);

 for (var i = 0; i < array.length; i++){
 var name = array[i].trim();
 if(name.substr(0,5)!="email" && name.substr(0,7)!="profile"){
 var name2 = "m:"+name;
 LOG.info( 'name2 = ' + name2);
 storedVars[name] = responseXML.getElementsByTagName(name2)[0].firstChild.nodeValue;
 LOG.info( 'callWebService: returned [' + storedVars[name] + ']' );
 }
 }
};

Nella prima parte estraiamo le opzioni email e profile da inserire insieme all’indirizzo (uri) nell’array params.

Concateniamo poi i parametri all’inidirizzo del proxy che contattiamo con la chiamaWebService (notate l’indirizzo ip che ovviamente dovete cambiare).

Estraiamo infine dalla risposta xml i parametri che abbiamo passato (ad eccezione di email e profile) da memorizzare nell’array associativo storedVars (predefinito per Selenium).

Ci resta da vedere il proxy php che dunque deve ricevere uri, email e profile e intrinsecamente:

  1. l’indirizzo della css validator (più altri parametri impliciti)
  2. il path del file xslt da applicare
  3. il path del report da salvare

Ed ecco il codice:

<?php

$uri = trim($_REQUEST['uri']);
$profile = trim(strtolower($_REQUEST['profile']));
$email = trim(strtolower($_REQUEST['email']));
$css = "http://192.39.226.51:8081/css-validator/validator?";
$usermedium = "all";
$warning = "1";
$lang = "en";
$output = "soap12";

if($profile =='')
 $profile="css21";
$address = $css."uri=".$uri."&profile=".$profile."&usermedium=".$usermedium."&warning=".$warning."&lang=".$lang."&output=".$output;
$result = file_get_contents($address);

$XSL = new DOMDocument();
$XSL->load( '/var/www/rest_style_css.xslt', LIBXML_NOCDATA);
$xslt = new XSLTProcessor();
$xslt->importStylesheet( $XSL );
$XML = new DOMDocument();
$XML->loadXML( $result );
$html = $xslt->transformToXML( $XML );

$dir = "reports/css/";
$report = "css-report-". date("H:i:s").".html";
$pathmyFile = "/var/www/".$dir.$report;
$fh = fopen($pathmyFile, 'w') or die("can't open file");
fwrite($fh, $html);
fclose($fh);

if($email !=''){
 $to = $email;
 $subject = 'CSS validation';
 $addresstomyfile = "<a href=http://".$_SERVER['SERVER_ADDR']."/".$dir.$report.">".$report."</a>";
 $message = "Report generated: ".$addresstomyfile." on ".date("j F, Y, g:i a")."\n".$html;
 $headers  = "From: Selenium Server<selenium.server@gmail.com>\r\n";
 $headers .= 'MIME-Version: 1.0' . "\r\n";
 $headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";
 mail($to, $subject, $message, $headers);
}

header('Content-type: text/xml');
echo $result;
?>

Si suppone dunque che:

  1. avete  la libreria xml e xsl per php (riavviate apache dopo averla installata)
  2. avete creato la cartella reports/css sotto la var/www
  3. avete creato un file xslt (che trovate alla fine dell’articolo) nella var/www
  4. abbiate una applicazione come sendmail che è in ascolto per mandare email

Il codice è facile da leggere:

  • una volta estratti i parametri li concateniamo per chiamare il validator con il metodo file_get_content(),
  • convertiamo il file xml ottenuto in html tramite il file xslt
  • salviamo tale file nella cartella reports/css
  • se l’email era stata passata come opzione allora mandiamo email l’html ottenuto
  • restituiamo (possiamo vedere anche tramite browser) il risultato xml

Potremmo in futuro passare solo una parte del risultato xml per risparmiare banda usata.

Ora potete fare lo stesso con w3c validator (su Ubuntu installate w3c-markup-validator), rss validator (ho testato in remoto ma non installato), l’achecker per l’accessibilità (che potete traquillamente installare (vi consiglio da svn).

File xslt da usare:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:m="http://www.w3.org/2005/07/css-validator" version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="html" encoding="UTF-8"/>
 <xsl:template match="m:cssvalidationresponse">
 <html>
 <head>
 <title>CSS report</title>
 </head>
 <body>
 <table width="100%">
 <TR bgcolor="#f7f3fd">
 <TD colspan="6">Analyzed web page address:
 <a href="{m:uri}" onclick="popup('{m:uri}; return false;')" title="{m:uri}" target="_new">
 <xsl:value-of select="m:uri" />
 </a>
 </TD>
 </TR>
 <TR bgcolor="#f7f3fd">
 <TD colspan="3"><B>Errors</B></TD>
 </TR>
 <TR bgcolor="#f7f3fd">
 <TD><B>Line</B></TD>
 <TD><B>Error Type</B></TD>
 <TD><B>Context</B></TD>
 <TD><B>Error Subtype</B></TD>
 <TD><B>Skipped String</B></TD>
 <TD><B>Message</B></TD>
 </TR>
 <xsl:for-each select="m:result/m:errors/m:errorlist/m:error">
 <tr>
 <xsl:if test="(position() mod 2 = 1)">
 <xsl:attribute name="bgcolor">#EEEEFF</xsl:attribute>
 </xsl:if>
 <TD><xsl:value-of select="m:line" /></TD>
 <TD><xsl:value-of select="m:errortype" /></TD>
 <TD><xsl:value-of select="m:context" /></TD>
 <TD><xsl:value-of select="m:errorsubtype" /></TD>
 <TD><xsl:value-of select="m:skippedstring" /></TD>
 <TD><xsl:value-of select="m:message" /></TD>
 </tr>
 </xsl:for-each>
 </table>
 <br/>
 <table width="100%">
 <TR rowspan="4" bgcolor="#f7f3fd">
 <TD width="10%"><B>Warnings</B></TD>
 </TR>
 <TR bgcolor="#f7f3fd">
 <TD width="10%"><B>Line</B></TD>
 <TD width="10%"><B>Level</B></TD>
 <TD width="70%"><B>Message</B></TD>
 <TD width="10%"><B>Context</B></TD>
 </TR>
 <xsl:for-each select="m:result/m:warnings/m:warninglist/m:warning">
 <tr>
 <xsl:if test="(position() mod 2 = 1)">
 <xsl:attribute name="bgcolor">#EEEEFF</xsl:attribute>
 </xsl:if>
 <TD width="10%"><xsl:value-of select="m:line" /></TD>
 <TD width="10%"><xsl:value-of select="m:level" /></TD>
 <TD width="70%"><xsl:value-of select="m:message" /></TD>
 <TD width="10%"><xsl:value-of select="m:context" /></TD>
 </tr>
 </xsl:for-each>
 </table>
 </body>
 </html>
 </xsl:template>
</xsl:stylesheet>

Testare applicazioni web con Selenium e Hudson

La fase di test di una applicazione è una di quelle più delicate in quanto dovrebbe cominciare (almeno il design) non appena i requisiti funzionali di una applicazione sono definiti. E’ difficile perchè entrano in gioco diversi fattori dall’usabilità di una applicazione all’architettura della applicazione stessa.

Normalmente in applicazioni Java avete Junit (o TestNG o ancora Nunit per applicazioni .NET) come libreria che vi permette di creare unit test per la vostra applicazione. In questa maniera avete modo di verificare che le vostre classi fanno il loro dovere. Per rendere poi gli unit test automatici potete usare continuous integration server come Hudson i quali non appena compilano il vostro codice permettono anche di eseguirli.

Se però sviluppate una applicazione con interfaccia web vi servirebbe uno strumento che vi permette di simulare il comportamento di un utente (cosa alquanto difficile) o comunque che dimostri che i requisiti funzionali dell’applicazione siano rispettati. Si parla di requisiti come:

  • se l’utente si vuole loggare sul sito web:
    • egli clicca sul link per accedere sulla pagina di login
    • digita username e password
    • clicca sul pulsante di login
    • appare una stringa dove esce il nome utente o comuque una pagina di benvenuto
    • l’attesa tra la pressione del pulsante login e il caricamento della pagina di benvenuto non deve essere più di tot secondi
  • se l’utente vuole cercare una risorsa nel sito web:
    • egli digita una parola chiave nell’apposito form
    • clicca sul pulsante cerca
    • visualizza, se esistono, pagine che contengono quella parola chiave

Rimane ovvio che il requisito del login più restringente è quello sul tempo di attesa, esso dovrebbe dipendere dall’achitettura software (accesso al database, uso di cookie ecc), mentre sulla ricerca non è sempre vero che inserendo una parola chiave riusciamo a trovare qualcosa.

Selenium è un software scritto per testare interfacce web che di base si presenta come una estensione per Firefox (Selenium IDE) o ancora come server (Selenium RC) per automatizzare i test e lanciare istanze di browser per eseguire i test stessi.

Selenium IDE in pratica permette di scrivere test tramite una comoda interfaccia web. Questi test in realtà vengono salvati come pagine html che contengono una semplice tabella come la seguente:

New Test
open /ig?hl=it
type q selenium
clickAndWait btnG
verifyTextPresent Selenium web application testing system
clickAndWait link=Selenium web application testing system
clickAndWait link=Documentation
clickAndWait link=Selenium-IDE

Questo test in particolare esegue la ricerca su http://www.google.it della parola “selenium”, verifica che tra i risultati compare la scritta “Selenium web application testing system”, clicca sul link e accede alla sezione documentazione sul Selenium-IDE. I comandi (scritti in Selenese :-) ) sono di semplice comprensione (accettano da 1 a 2 parametri) e possono essere generati automaticamente dal Selenium IDE utilizzando la modalità Record che registra l’attività utente sul sito web e modificati manualmente in ogni momento. Esistono diversi comandi che permettono per esempio:

  • di simulare il doppio click
  • di simulare la pressione di un tasto
  • di simulare il mouse sopra un particolare oggetto (evento OnMouseOver)
  • di fermare l’esecuzione del test per un determinato tempo
  • di rimuovere i cookie
  • di catturare lo screenshot di una pagina
  • di salvare e caricare variabili
  • ecc

Capite bene però che, leggendo il test precedente, il test può fallire per diversi motivi (il link documentazione è stato cambitato ad esempio) e non esistono condizioni per dire “se questa condizione fallisce allora verifica quest’altra”. Inoltre si vorrebbe verificare se gli stessi test sono validi su diversi browser e magari rendere la procedura più automatica possibile.

Ecco per cui è stato realizzato Selenium RC, un server java che rimane in ascolto di chiamate da client scritti in diversi linguaggi (Java, C#, Perl, PHP, Python, Ruby) ed esegue i test lanciando istanze di browser come Firefox, Internet Explorer, Safari e Opera.

Un esempio di test in Java sarebbe:

package com.example.tests;

import com.thoughtworks.selenium.*;
import java.util.regex.Pattern;

public class NewTest extends SeleneseTestCase {
    public void setUp() throws Exception {
        setUp("http://www.google.com/", "*firefox");
    }
      public void testNew() throws Exception {
          selenium.open("/");
          selenium.type("q", "selenium");
          selenium.click("btnG");
          selenium.waitForPageToLoad("30000");
          assertTrue(selenium.isTextPresent("Results * for selenium"));
    }
}

Il codice è anche qui di facile comprensione, occorre leggersi con comodo le API da usare. Quindi magari ora potreste pensare di includere il codice in Junit o Nunit test per esempio da essere eseguiti automaticamente da un continuous integration server.

Hudson in particolare ha 2 plugin di cui uno apposito per Selenium RC e permette di generare i report, alternativamente esiste un Ant task. La cosa interessante è che partono direttamente dall’html senza passare ai test scritti in Java (a voi la scelta).

Il problema concreto è quindi non tanto usare i comandi quanto identificare l’oggetto su cui eseguire il comando, infatti potete usare attributi Id, attributi Name, DOM, Xpath, CSS sta a voi vedere dove usare una tecnica o l’altra perchè per esempio in talune applicazioni gli attributi Id sono generati dinamicamente e non potete di conseguenza creare i test.

Sul sito di Selenium trovate molta documentazione dallo screencast, al forum, bug tracker e al wiki.

Sul sito di Refcardz trovate una scheda riassuntiva.

Qualche nota interessante:

Buon test e buon anno a tutti !

Webclient for SVN, Hudson e Artifactory

Salve a tutti, in questi giorni mi sono addentrato ancora nel mondo del continuous integration perchè sto lavorando su un progetto in Java, gestito in outsourcing, dove aiuto un gruppo di sviluppatori ad utilizzare strumenti di sviluppo che facilitano il lavoro quali un sistema di continuos integration.

Sono partito da un progetto con subversion installato su una macchina e so che nel progetto usano Jboss con JDK 1.5 (ancora non so perchè)

Su un’altra macchina remota vado e installo JDK 1.5.0.22, Ant 1.7.1, Maven 2.2.1 (fino ad ora (2 mesi di progetto) hanno usato solo Ant e vorrebbero passare a Maven), Jboss 5.1.0, Webclient for SVN 3.1.0 e Artifactory 2.1.2.

Piccola nota: volevo usare Sventon ma l’ultima versione aveva problemi con le librerie e le precedenti mi davano anch’esse problemi.

Non sapete cosa è Artifactory ??? Allora è possibile che siete ancora freschi su Maven (non è che io non lo sia :-) )

Artifactory è una applicazione web che permette di gestire repository Maven, sviluppata in Java e rilasciata con licenza LGPL 3.0. L’applicazione è realizzata da JFrog Ltd, una società privata isreliana.

Strutturalmente si poggia su Apache Jackrabbit per l’implemetazione delle specifiche JSR 170 per il cosiddetto Java Content Repository (anche altri content manager come Nuxeo si appoggiano su Jackrabbit).

Piccola nota: la JSR 170 (rilasciata nel 2005) è seguita dalla JSR 283 da poco rilasciata (25 Settempre 2009) ed entrambe sono condotte da David Nuescheler, CTO della società svizzera Day Software.

Inoltre Artifactory si basa su Apache Lucene per indicizzare i file e Apache Wicket per l’interfaccia utente.

Ora l’applicazione è rilasciata come standalone ma esiste la versione war che può essere deployata su un application server e quindi l’ho messa su Jboss insieme ad Hudson e Webclient for SVN (questi 2 li ho poi legati con il plugin di hudson per Polarion che permette di linkare la lista di file modificati ai file presenti sul webclient e si possono anche vedere le differenze con le versioni precedenti).

La struttura è basata anche su database, di default Apache Derby ma che può essere cambiato (vedi anche qui).

A parte il fatto che Artifactory permette di base una autenticazione LDAP, quello che lascia senza parole è la semplicità di uso (andrebbe confrontato con Nexus ma non ne ho tempo, di sicuro nella versione base manca LDAP (anche se ho scoperto di recente che esiste un plugin di terze parti) e di sicuro gli sviluppatori hanno realizzato una bella guida a maven e un plugin per Eclipse). Una volta andato su

http://localhost:8080/artifactory

e loggato, sono andato sul pannello amministrativo e nella sezione repository ho creato un repository locale dove fare il deploy dei propri jar file e un repository virtuale in cui aggiungo quello locale più tutti i remoti quali quello di Maven, Jboss ecc ecc. Fatto ! Ora potete generare anche la sezione del file settings.xml da aggiungere nel vostro progetto Maven.

Per una vecchia guida vi rimando qui. Per un confronto con Nexus e Archiva vi rimando a questo link (attenzione è scritto dallo stesso autore della guida su Artifactory ma sembra serio)

Buon maven a tutti !

Nota: Webclient for SVN si basa su Subversion 1.4 (con versioni successive ho avuto problemi perchè usa un SVNKit vecchio che non posso aggiornare perchè c’è una particolare classe non più presente nelle ultime versioni), potete trovare Subversion 1.4 qui:

http://downloads-guests.open.collab.net/servlets/ProjectDocumentList?folderID=6

Redmine: non solo bug tracking

Cercavo un sistema web di bug tracking e avevo già notato Trac e lo consideravo per via dei suoi innumerrevoli plugin il migliore, tuttavia il caso della vita vuole che scopro Redmine principalmente per 3 ragioni:

  • supporto multiprogetto cosa che Trac sembra non avere (in tal caso si dovrebbbero creare più istanze di Trac)
  • dipendenza tra bug, cosa che Trac sembra non avere
  • possibilità di inviare un bug anche tramite email, non so se Trac ha questa funzionalità.

Googlando trovo Redmine che a sorpresa vedo gestire più revision control systems (SVN, CVS, GIT, Bazaar, Mercurial, Darcs), supporta LDAP ed è multilinguaggio.

Redmine è scritto in Ruby on Rails ed rilasciato con licenza GPL.

Per poterlo provare esiste una demo:

http://demo.redmine.org/

oppure installarlo velocemente in locale con lo stack Bitnami:

http://bitnami.org/stack/redmine

Una volta loggati l’interfaccia risulta pulita, in alto a sinistra vedere My Page (issue assegnati a voi), Projects (per creare o vedere i vostri progetti), Administrations (dove potete gestire utenti e ruoli, assegnare i ruoli alle atttività di Bug, Feature o Support), impostare lo stile del sito, notifiche email, autenticazione LDAP.

Una delle caratteristiche interessanti è il diagramma di Gantt che si viene a creare per ogni progetto per ogni bug aggiunto in tal modo si può avere una visione di insieme di come sta evolvendo il progetto. Potete salvare il diagramma in PDF e PNG. Avete comunque una visione a calendario.

Tra i progetti che usano Redmine trovate Ruby, Lighttpd, Typo3 e PHPBB

Piccola nota:Esiste un plugin per Hudson.

Lascio a voi il piacere di scoprire il resto! Ovviamente se avete una vostra esperienza con Redmine fatemi sapere!

Raccogliere dati sul repository Subversion: WebSVN e StatSVN

Probabilmente in molti hanno provato a configurare Apache per poter vedere un repository di Subversion con una delle classiche configurazioni come la seguente che ho realizzato su di un server a disposizione:

<Location /svn/repos>
   DAV svn
   SVNPath /home/svn/repos
   AuthType Basic
   AuthName "Subversion Repository"
   AuthUserFIle /home/emidio/.htpasswd
   Require valid-user
</Location>

configurazione che va messo in /etc/apache2/mods-available/dav_svn.conf dove /home/svn/repos è il vero e proprio repository subversion mentre .htpasswd contiene il file utenti/password per l’autenticazione. Per maggiori informazioni leggete la pagina di manuale.

Cosi se poi andate su htttp://localhost/svn/repos potete scorrere il vostro repository usando il browser e conoscendo solo lo stato dell’ultima revisione.

Oggi vi presento 2 strumenti interessanti a chi ha un progetto condiviso con Subversion: WebSVN e StatSVN.

WebSVN è una applicazione PHP (richiede minimo PHP 4.3.0) rilasciata con licenza GPL che vi permette di monitorare, tramite pagine web la struttura del vostro repository Subversion (richiede minimo SVN 1.2.0).

In pratica potete vedere l’ultima revisione del progetto, autore e log message sul lato sinistro e sulla destra potete scorrere tra le cartelle e file del repository che potete monitorare tramite RSS feed.

Cartelle e file sono indicati dal loro numero di revisione; selezionando un file vedete la sua ultima revisione ma se cliccate su View Log ad esempio vedete la lista delle sue revisioni che potete vedere una per una (Details) o confrontare tramite una piacevole interfaccia grafica.

Eccovi un link dove viene spiegato in breve come installarlo su Linux (l’ho testato su Ubuntu 8.10). Per Subversion ho anche usato questo link. In pratica dovete copiarlo nella cartella /var/www servita da Apache e cambiare il file di configurazione puntando a subversion (/usr/bin) e alla cartella padre del repository di Subversion (nel mio caso avendo il repository in /home/svn/repos ho indicato il path /home/svn).

Per abilitare gli RSS feed dovete settare i permessi della cartella /var/www/websvn/cache a 777 (ho provato 700 e 770 ma mi dava problemi di permessi).

La cosa carina è che avete il syntax highlighting (l’ho provato su codice PHP, file CSS, file javascript, perl) che è basato di default su GeSHI che supporta molti linguaggi altrimenti potete usare Enscript 1.6 o superiore (insieme a Sed) che deve essere già installato sul sistema.

Ulteriori info le trovate in locale  su: http://localhost/websvn/doc/install.html

StatSVN è invece una applicazione Java (file jar compresso in un file zip di appena 2.4 mega) rilasciata con licenza LGPL che genera statistiche dettagliate sul repository subversion. Arrivato il 22 maggio scorso alla versione 0.5.0, StatSVN ha ora la possibilità di essere usato tramite Twitter.

La cosa interessante che ho notato nel manuale è che si può integrare con Bugzilla, Mantis e Trac.

Il sommario delle statistiche lo vedete dalla pagina principale index.html che vi mostra:

  • quando è stato generato il report
  • ultima revisione
  • su che periodo si basa
  • numero totale di file
  • numero totale di linee di codice
  • numero di sviluppatori
  • un collegamento a Twitter
  • un menu che mostra maggiori dettagli
  • il grafico sommario delle linee di codice
  • la tag cloud delle parole usate nei messaggi di log
  • la struttura gerarchica delle directory, dove per ognuna vedete il numero di file e le linee di codice contenuti.

Nota: I grafici sono realizzati tramite JFreeChart.

Nel menu dei dettagli vedete ad esempio, quante linee di codice ha scritto un particolare autore, il numero di commit per ora e giorno della settimana,i log dei commit, che tipi di file ci sono ordinati per loro numero (1o file php, 4 xml ecc.) e quante linee di codice in media ci sono per ogni tipo, lista dei file più grandi e più revisionati, tabella e grafico a torta delle dimensioni delle cartelle e tanto altro.

Per vedere una demo subito andate a questo link oppure potete vedere anche la demo su progetti come Ant, Apache Synapse, Apache Continuum, Ruby.

Non c’è in pratica installazione (ha bisogno almeno di SVN 1.3) dove lanciarlo nel seguente modo come indicato nel manuale:

svn co svn://server/repo/trunk/modulename
svn log -v –xml > logfile.log
java -jar /path/to/statsvn.jar /path/to/module/logfile.log /path/to/module

In pratica dovete fare un checkout del progetto, generare il file di log e sulla base del path indicato eseguire il file statsvn.jar.

Sarebbe bello però rendere automatica la procedura ed ecco che ho pensato a come integrarlo con Hudson e ho notato che qualcuno ci ha provato ma senza successo, io ho ripreso la sua configurazione e l’ho leggermente modificata.

Ho copiato prima di tutto il file statsvn.jar nella cartella lib di Apache Ant in modo che sia raggiungibile dalla variabile di ambiente ANT_HOME che punta alla directory di Ant.

Poi sono andato nel file build.xml della mia applicazione in Netbeans e ho notato che importa il file build-impl.xml che ha al suo interno una lunga serie di target. Tra le dipendenze del target default ho aggiunto statsvn-clean, statsvn e alla fine del file (prima della chiusura del tag </project>) ho aggiunto:

<taskdef name=”statsvn” classname=”net.sf.statsvn.ant.StatSvnTask”/>

<!– output directory for reports –>
<property name=”StatSVNReportDir” value=”statsvn”/>

<target name=”statsvn-clean” description=”resets to a clean state”>
<delete dir=”${StatSVNReportDir}” failonerror=”no”/>
</target>

<target name=”statsvn” description=”Does SVN repository statistics.”>
<echo message=”Metrics: running statsvn …”/>

<delete file=”${StatSVNReportDir}/svn-log.xml” />
<mkdir dir=”${StatSVNReportDir}” />

<exec executable=”svn” dir=”${src.dir}” output=”${StatSVNReportDir}/svn-log.xml” searchpath=”true” >
<arg line=”log –xml –verbose” />
</exec>

<statsvn
log=”${StatSVNReportDir}/svn-log.xml”
path=”..”
outputDir=”${StatSVNReportDir}/html” />

</target>

Ho poi fatto il commit di questo file sul repository SVN e così Hudson (che è impostato per fare il polling di Subversion) lo cattura e, poichè è impostato di fare il build periodicamente, mi genera anche la cartella statsvn (vedi proprietà StatSVNReportDir sopra) dell’ultimo build con tutte le descrizioni dettagliate. Come vedete come path gli ho indicato “..” per specificare la root del progetto in quanto non tutti i file del progetto si trovano nella cartella src come, ad esempio, le pagine jsp che normalmente le trovate nella cartella web.

A questo punto non mi resta che augurarvi buone statistiche !

Nota: ho usato Subversion 1.6.2, Hudson 1.296 e Ant 1.7.0

Sperimentando con Netbeans, Glassfish, Hudson e Subversion

Ho cominciato a scrivere qualche applicazione web con Netbeans 6.1 (penso di migrare presto (magari anche oggi) alla versione 6.5) e ho preso ad esempio il tutorial:

http://www.netbeans.org/kb/docs/web/quickstart-webapps.html

Il tutorial spiega come creare un paio di pagine Jsp facendo uso di una classe java usata come java bean, benchè dicono che richiede Netbeans 6.5 io ho usato tranquillamente Netbeans 6.1. Inoltre, durante il wizard, dovete specificare dove si trova Glassfish; ho preferito usare la mia istanza di Glassfish 2.1 scaricato a parte.

A parte ciò era mia intenzione di installare un server subversion e farne il polling tramite Hudson.

Ho trovato questo tutorial che spiega passo passo come prendere confidenza con Subversion; il tutorial suggerisce per Mac OS X di prendere Subversion da qui. Il pacchetto include Subversion 1.6.2 client e server (una volta installato potete provare i comandi svn –version e svnserve –version). Subversion mi si è installato in /opt/subversion/bin e non /usr/local/bin come descritto nella pagina di Collabnet; dovete quindi aggiungere il path /opt/subversion/bin nella variabile di ambiente PATH (che ho specificato nel file .bash_profile che si trova nella cartella utente).

Dopo aver giocato con il tutorial ho cercato subito di connettere Netbeans e Subversion e ho impostato in Preferences->Miscellaneous-> Versioning -> Subversion il path /opt/subversion/bin lasciando le altre impostazioni inalterate.

Inoltre ho poi cliccato con il tasto destro del mouse sulla cartella del progetto e sono nel menu contestuale sono andato in Versioning ->Import into Subversion Repository dove dovete specificare più che altro il path del repository che nel mio caso era:

file:///Users/emidiostani/SVNrep

(ho usato il repository creato con il tutorial su subversion)

Durante il wizard ho avuto un errore del tipo:

Expected FS format between ‘2’; found format ‘4’

che ho risolto facendo l’upgrade del plugin per subversion dalla versione 1.3 alla 1.3.1, difatti se andate nel repository (nel mio caso la cartella SVNrep) c’è il file /db/format che dice la versione del db interna è 4, in pratica non c’è accordo da tra client in netbeans e il server (noto che in Netbeans 6.5 potrebbe esserci lo stesso problema, vedere qui).

Sono poi andato su Hudson (versione 1.296) che vuole l’URL del repository e allora nella cartella di subversion ho lanciato il comando:

svnserve -d

che esegue il server che rimane in ascolto di default sulla porta 3690 (lo potete vedere da shell con il comando netstat -ant -p tcp). Ho trovato una breve descrizione di svnserve qui.

Cosi poi su Hudson ho inserito l’URL:

svn://localhost/Users/emidiostani/SVNrep

quando poi sono andato a specificare, nel form Build, il target file da compilare ho messo:

./HelloWeb/build.xml

che il target file che Netbeans mi aveva creato al momento del progetto.

Succede però che quando eseguo il build su Hudson esso mi genera un errore del tipo:

BUILD FAILED
/Users/emidiostani/.hudson/jobs/Test/workspace/SVNrep/HelloWeb/nbproject/build-impl.xml:188: The Java EE server classpath is not correctly set up. Your active server type is J2EE.
Either open the project in the IDE and assign the server or setup the server classpath manually.
For example like this:
ant -Duser.properties.file=<path_to_property_file> (where you put the property “j2ee.platform.classpath” in a .properties file)
or ant -Dj2ee.platform.classpath=<server_classpath> (where no properties file is used)

Total time: 0 seconds
Finished: FAILURE

questo accade perchè nel file HelloWeb/nbproject/build-impl.xml alla riga 188 esiste la riga:

<fail unless=”j2ee.platform.classpath”>

ecc ecc.

in pratica non trova la directory delle librerie di glassfish, questo l’ho scoperto semplicemente aggiungendo:

<echo>using ${j2ee.platform.classpath}</echo>

subito dopo quella riga e compilando direttamente da Netbeans.

Ovviamente Hudson non può sapere questa informazione che arriva direttamente dalle impostazioni di Netbeans e perciò per arrangiare ho messo nella casella Properties la voce:

j2ee.platform.classpath=/Users/emidiostani/Desktop/glassfish/lib/

e così sono riuscito a compilare.

In pratica leggendo poi in questo post, si capisce che la variable j2ee.platform.classpath è settata in HelloWeb/nbproject/private/private.properties file che non viene caricato nel repository (potete notarlo nel workspace di Hudson) e di conseguenza Hudson non la trova. L’autore del post suggerisce di settare la variabile nel file HelloWeb/nbproject/project.properties invece di settarla in Hudson perchè se pensate bene è una variabile statica che dovrebbe essere inclusa in diversi progetti in hudson e sarebbe giusto fissarla a monte.

Comunque come ho tempo rifaccio il tutto su Netbeans 6.5.

Buona giornata !

Note su Hudson e CruiseControl

In uno dei recenti progetti sto valutando con un mio collega la possibilità di fornire come servizio l’uso di uno strumento di Continuous Integration.

Attualmente stiamo hostando diversi progetti Java (30), PHP (10), Python (6) e Javascript(6), C++ (4) più altri minimi progetti; di conseguenza ho cominciato a valutare strumenti Java tra cui Hudson, CruiseControl e Apache Continuum per poi vedere quale è il più indicato per progetti in PHP e Python.

Nota: Avevo già provato Apache Continuum ma non mi aveva dato una grande impressione.

Guardando sul sito JavaPowerTools , Wakkaleo, SOA World Magazine, Eclipse Community Survey 2009 e partecipando al Devoxx si nota come Hudson e CruiseControl sono i preferiti.

Se diamo uno sguardo a strumenti di continuous integration per PHP ritroviamo in pratica Xinc e PHPUnderControl, quest’ultimo si basa su CruiseControl e include strumenti come PHPUnit, PhpDocumentor e PHP_CodeSniffer.

Se quindi consideriamo CruiseControl + PHPUnderControl si copre una grossa percentuale di progetti. CruiseControl e Hudson hanno comunque il supporto a Phing per progetti in PHP ma PHPUnderControl è alettante.

Vediamo quali strumenti esistono per Python:

Development in Python

Link

Buildbot, a python continuous integration tool http://buildbot.net/trac
It explains how to integrate Hudson and Python (but an internal link explains the same thing with CruiseControl with PyUnit). For Hudson there is a plugin that uses Pylint http://redsolo.blogspot.com/2007/11/hudson-embraces-python.html
Python Ant task (Pydoc generation) http://www.rpstechnologies.net/PyAntTasks.html

http://www.ibm.com/developerworks/opensource/library/os-ecant/

Python Doxygen integration http://internetducttape.com/2007/03/20/automatic_documentation_python_doxygen/
Pylint (errors in python code – command line) http://www.logilab.org/857

It claims to be more advanced of PyChecker, also Netbeans Python Early Access seems to use it, see:

http://www.netbeans.org/kb/docs/python/temperature-converter.html#08

Also PyDev (Eclipse plugin) has a support for PyLint, see

http://pydev.sourceforge.net/pylint.html

Eric Python IDE has a plugin for Pylint, see:

http://eric-ide.python-projects.org/index.html

PyChecker (error in python code – command line) http://pychecker.sourceforge.net/

Used by Stani Python Editor, see:

http://pythonide.blogspot.com/

PyFlakes (error in python code – command line) http://divmod.org/trac/wiki/DivmodPyflakes
Figleaf (code coverage – command line) http://darcs.idyll.org/~t/projects/figleaf/doc
General notes http://www.doughellmann.com/articles/CompletelyDifferent-2008-03-linters/index.html

Sfortunatamente vediamo che esiste in pratica solo Buildbot che non puo’ essere integrato con CruiseControl o Hudson ma esiste un plugin, più per Hudson che per CruiseControl, che aiuta ad integrare Python con gli altri tools.

Dall’altro lato abbiamo un Python Ant Task e qualche strumento a linea di comando che possono essere usati con Ant e quindi una facile integrazione con CruiseControl e Hudson.

Riguardo Javascript al momento l’unico Javascript unit test che sembra integrabile con Ant per eseguire unit test è JsUnit.

Riguardo a C++ notiamo che in Hudson ci sono 2 plugin (CCCC e CppUnit) mentre su CruiseControl sembra che non ci sia niente (solo questo link). Tuttavia ho trovato un Ant task per C++ che permette di scegliere tra diversi compilatori.

Per quanto riguarda i generatori di documentazione ritroviamo:

Document generator

Link

Javadoc

http://java.sun.com/j2se/javadoc/

Doxygen

http://www.stack.nl/~dimitri/doxygen/

PhpDocumentor

http://www.phpdoc.org/

Pydoc

http://docs.python.org/library/pydo

JsDoc Toolkit

http://code.google.com/p/jsdoc-toolkit-ant-task

Per C++ di solito viene usato Doxygen. Per Javascript potete notare JsDoc Toolkit per cui esiste il rispettivo Ant task.

Sarebbe bene anche includere software che fanno analisi statica del codice per fare debug del codice tra questi ritroviamo dal sito JavaPowerTools:

Java Analyzer Code Style

Vote – Number of votes

Checkstyle

3,37/5 – 90

PMD

3,63/5 – 84

Findbugs

3,69/5 – 83

Dobbiamo dire che Doxygen e questi strumenti (più Cobertura) sono integrati come plugin su Hudson tuttavia essi sono disponibili come Ant task e quindi integrabili con CruiseControl:

Plugins

Link

Checkstyle

http://checkstyle.sourceforge.net/anttask.html

Findbugs

http://findbugs.sourceforge.net/manual/anttask.html

Cobertura

http://cobertura.sourceforge.net/anttaskreference.html

PMD

http://pmd.sourceforge.net/ant-task.html

Doxygen

http://ant-doxygen.blogspot.com/

Per C++ ho notato che esiste Cppcheck to do static code analysis. Qui ho trovato come usarlo, in pratica è un eseguibile (esiste exe e deb)  che si puo’ facilmente integrare.

Per Javascript ho notato che esiste Yasca strumento a linea di comando che si integra con diversi strumenti visti prima (tra questi Javascript Lint e CppCheck) e genera diversi report.

Ultime note:

  • abbiamo notato che Gforge AS (quindi non la nostra versione community), ha un plugin per CruiseControl.
  • Gforge ha poi un sistema di gestione delle richieste di supporto (ticket) non tanto carino e sarebbe possible rimpiazzarlo con Trac che ha tra i suoi plugin proprio il supporto per CruiseControl e Hudson.
  • Abbiamo notato che Jboss e Linkedin fanno uso di Hudson (stiamo parlando di soli progetti Java).
  • Quelli di Apache usano sia Hudson che Continuum :-)
  • Stefane Fermigier, CEO di Nuxeo, afferma di usare Hudson e Glassfish come application server.
  • Installando Hudson per prova si vede subito la possibilità di usarlo su più nodi per scalabilità o semplicemente perchè alcuni progetti richiedono sistemi operativi diversi mentre sembra per CruiseControl non esiste una perfetta integrazione. Entrambi comunque propongono JNLP come connessione.
  • Occorre considerare l’integrazione con LDAP. Per Hudson un post interessante è qui.
  • Trovata una tabella comparativa.
  • Trovato un documento comparativo pubblicato il 2 gennaio 2009

Ora credo ci sia da scegliere anche perchè ho notato in rete che la gente lamenta il fatto che CruiseControl vada opportunatamente configurato tramite file XML mentre Hudson tramire interfaccia grafica e gli sviluppatori migrano nel tempo a Hudson.

//