Come fare integration test su un plugin per Jira 3.13.4

Quando si tratta di voler scrivere test di integrazione per il vostro meraviglioso plugin per Jira 3.13.4 (l’ultima versione di Jira, in attesa che la 4.0 esca dalla beta), ci si imbatte in una serie di problemi.
Dopo qualche indagine, sono riuscito a risolverli tutti, e mi accingo a condividere la soluzione adottata, nella speranza che possa servire a qualcun altro (anche a me stesso tra qualche mese…).

Premetto che stiamo sviluppato il plugin usando maven2, che per questo genere di cose è davvero molto comodo.
Se avete qualche dubbio, ecco due riferimenti:

Il pom.xml generato da maven usando l’archetipo per plugin di Jira contiene una sezione “properties” che, all’inizio, si presenta così:
<properties>
<atlassian.plugin.key>
com.sourcesense.jira.plugin.MyWonderfulPluginToSaveTheWorld
</atlassian.plugin.key>

<!– JIRA version –>

<atlassian.product.version>3.13</atlassian.product.version>

<!– JIRA functional test library version –>

<atlassian.product.test-lib.version>3.13</atlassian.product.test-lib.version>

<!– JIRA data version –>

<atlassian.product.data.version>3.13</atlassian.product.data.version>

</properties>

Qui trovate una descrizione di queste properties, assieme ai loro valori di default.

Ecco un estratto:

“atlassian.product.version” – version of the Atlassian product to compile and test against.

“atlassian.product.data.version” – version of the test resource bundle that contains the basic Atlassian product configuration data for the integration test environment. These versions mimic the actual Atlassian product versions. However we might only modify and release the relevant projects for the reasons of non-backwards compatibility of the new versions of Atlassian products. Therefore not every version of Atlassian products will have a corresponding version of the resource bundle.

La property “atlassian.product.test-lib.version” non è documentata, e per capire il suo significato dovete chiedere a Google, che vi rispondera’ con questa utile pagina.

“atlassian.product.test-lib.version” – The version of the testing library to use, as a general recommendation you should at least use version 2.0 or higher as it exposes more of the page’s content and provides quite a few extra helper classes to aid in your testing.

Benissimo, quindi io che sto facendo un plugin per la versione 3.13.4 di Jira, sostituisco questo valore nelle tre properties del POM

<properties>
 ...
    <atlassian.product.version>3.13.4</atlassian.product.version>
    <atlassian.product.test-lib.version>3.13.4</atlassian.product.test-lib.version>
    <atlassian.product.data.version>3.13.4</atlassian.product.data.version>
 </properties>

Detto, fatto.
Mi manca solo di creare il mio primo test di integrazione, rigorosamente nel package che inizia con “it”.

 package it.com.sourcesense.jira.plugin;

 import com.atlassian.jira.webtests.JIRAWebTest;

 public class JiraTest extends JIRAWebTest {

    public JiraTest(String name) {
      super(name);
    }

    public void setUp() {
      super.setUp();
      restoreDataWithLicense("JiraDataForTest.xml", ENTERPRISE_KEY);
   }

   public void testVerySimple() throws Exception {
      assertTextPresent("This JIRA site is for demonstration purposes only");
   }
 }

E copiare il dump esportato da Jira per avere qualche dato di test (JiraDataForTest.xml) nel folder src/test/xml/ del progetto del plugin.

A questo punto non mi resta che lanciare il seguente comando nella home della progetto

mvn integration-test

e aspettare con pazienza che maven scarichi quel Terabyte di jar di cui dichiara di aver bisogno.

Primo problema: la console di mvn mi dice

 [INFO] [jar:jar]
 [INFO] Building jar:
        /private/tmp/HelloWorldPlugin/target/MyWonderfulPluginToSaveTheWorld-1.0-SNAPSHOT.jar
 [INFO] [antrun:run {execution: generate-integration-test-config}]
 [INFO] Executing tasks
 [touch] Creating
  /private/tmp/MyWonderfulPluginToSaveTheWorld/target/test-classes/localtest.properties
 [propertyfile] Updating property file:
  /private/tmp/MyWonderfulPluginToSaveTheWorld/target/test-classes/localtest.properties
 [INFO] Executed tasks
 [INFO] [antrun:run {execution: pre-integration-test-user-ant-tasks}]
 [INFO] Executing tasks
 [INFO] Executed tasks
 [INFO] [atlassian-test-harness:start-fisheye {execution: start-fisheye}]
 [INFO] Skipping fisheye; startService is set to false
 [INFO] [atlassian-test-harness:start-confluence {execution: start-confluence}]
 [INFO] Skipping confluence; startService is set to false
 [INFO] [atlassian-test-harness:start-jira {execution: start-jira}]
 [INFO] Output log is set to /private/tmp/MyWonderfulPluginToSaveTheWorld/target/jira/output.log

E si blocca lì.
Vado a vedere il log segnalato nell’ultima riga della console, e scopro una pletora di eccezioni:

2009-07-07 16:11:19,568 main ERROR
[com.atlassian.license.LicenseManager] Exception getting license: java.lang.RuntimeException: contactLicense was null
 at org.picocontainer.defaults.DecoratingComponentAdapter.getComponentInstance(DecoratingComponentAdapter.java:42)
 at org.picocontainer.defaults.SynchronizedComponentAdapter.getComponentInstance(SynchronizedComponentAdapter.java:35)
 ...

Indago, guardo su Google, niente.
Provo allora a sostituire 3.13.4 con 3.13.2 nelle tre properties del POM

<properties>
    ...
   <atlassian.product.version>3.13.2</atlassian.product.version>
   <atlassian.product.test-lib.version>3.13.2</atlassian.product.test-lib.version>
   <atlassian.product.data.version>3.13.2</atlassian.product.data.version>
</properties>

E rilancio “mvn integration-test”.
Stavolta l’errore è più chiaro: fallisce il ripristino del dump JiraDataForTest.xml nell’istanza di Jira 3.13.2 che viene avviata da maven, perchè la versione del dump è stata fatta con la 3.13.4, una versione successiva alla 3.13.2, e quindi Jira si rifiuta da caricarla. Eccheccavolo.

Vi risparmio tutte le combinazioni di numeri di versione che ho provato a mettere nel POM, senza successo, e vado dritto verso la soluzione.
Ecco il pom.xml che funziona

<properties>
 ...
 <atlassian.product.version>3.13.2</atlassian.product.version>
 <atlassian.product.test-lib.version>3.13.4</atlassian.product.test-lib.version>
 <atlassian.product.data.version>3.13.2</atlassian.product.data.version>
 </properties>

L’altra cosa da fare è modificare i dump di Jira che vorrete usare per i vostri test, in modo da far credere a Jira che sta importando una versione compatibile del dump.
Per fare questo dovete:

1. Aprire il dump xml di Jira che usate per i test (nel nostro caso JiraDataForTest.xml)

2. Cercare l’occorrenza di questa property

<OSPropertyEntry id="12345"
   entityName="jira.properties"
   entityId="1"
   propertyKey="jira.version.patched"
   type="5"/>

Per essere sicuri basta che cerchiate la parola “jira.version.patched”

3. Prendere nota dell’id di questa propery (es 12345) e cercare l’occorrenza di una OSPropertyString con lo stesso id

<OSPropertyString id="12345" value="354"/>

Ecco, quel valore (354) rappresenta la build version di Jira, che per la 3.13.4 è proprio 354.

4. Sostituire il valore 354 con 335, che è la build versione di Jira 3.13.2 e salvare l’xml

5. Rilanciare il test.

Tutto dovrebbe filare liscio ora…

 $ mvn integration-test
 ...
 ...
 [INFO] [jar:jar]
 [INFO] Building jar:
    /Users/pietrodibello/Documents/workspace/MyWonderfulProjectToSaveTheWorld/MyWonderfulPluginToSaveTheWorld/
    target/MyWonderfulPluginToSaveTheWorld-1.0-SNAPSHOT.jar
 [INFO] [antrun:run {execution: generate-integration-test-config}]
 [INFO] Executing tasks
 [propertyfile] Updating property file:
   /Users/pietrodibello/Documents/workspace/MyWonderfulProjectToSaveTheWorld/MyWonderfulPluginToSaveTheWorld/
   target/test-classes/localtest.properties
 [INFO] Executed tasks
 [INFO] [antrun:run {execution: pre-integration-test-user-ant-tasks}]
 [INFO] Executing tasks
 [INFO] Executed tasks
 [INFO] [atlassian-test-harness:start-fisheye {execution: start-fisheye}]
 [INFO] Skipping fisheye; startService is set to false
 [INFO] [atlassian-test-harness:start-confluence {execution: start-confluence}]
 [INFO] Skipping confluence; startService is set to false
 [INFO] [atlassian-test-harness:start-jira {execution: start-jira}]
 [INFO] Output log is set to
   /Users/pietrodibello/Documents/workspace/MyWonderfulProjectToSaveTheWorld/MyWonderfulPluginToSaveTheWorld/target/jira/output.log
 [INFO] Finished with jira goal
 [INFO] [atlassian-test-harness:start-bamboo {execution: start-bamboo}]
 [INFO] Skipping bamboo; startService is set to false
 [INFO] [surefire:test {execution: acceptance_tests}]
 [INFO] Surefire report directory:
   /Users/pietrodibello/Documents/workspace/MyWonderfulProjectToSaveTheWorld/MyWonderfulPluginToSaveTheWorld/target/surefire-reports

 -------------------------------------------------------
 T E S T S
 -------------------------------------------------------
 Running it.com.sourcesense.jira.plugin.JiraTest
 .
 . Started it.com.sourcesense.jira.plugin.JiraTest.test. Wed Jul 08 14:30:44 CEST 2009
 going to page secure/admin/XmlRestore!default.jspa
 Asserting text present: Your project has been successfully imported
 Asserting text present: This JIRA site is for demonstration purposes only
 .
 . Finished it.com.sourcesense.jira.plugin.JiraTest.test. Wed Jul 08 14:30:54 CEST 2009
 . The test ran in 10.542 seconds
 . The test suite has been running for 10.536 seconds
 . Max Mem : 66650112 Total Mem : 2727936 Free Mem : 268968
 . ______________________________
 Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 11.045 sec

 Results :

 Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

 [INFO] ------------------------------------------------------------------------
 [INFO] BUILD SUCCESSFUL
 [INFO] ------------------------------------------------------------------------
 [INFO] Total time: 44 seconds
 [INFO] Finished at: Wed Jul 08 14:30:55 CEST 2009
 [INFO] Final Memory: 32M/254M
 [INFO] ------------------------------------------------------------------------

Evviva, barra verde!!

Come generare il report HTML dei test eseguiti con Jmeter

Problema: “Ho problemi con il report html dei test jmeter generato dalla trasformazione XSL indicata dalla documentazione di Jmeter (versione 2.3.4). Infatti nel report html si hanno due comportamenti anomali:

  • la prima riga è sempre raddoppiata, ovvero presente due volte (e vabbè, passi)
  • le colonne che indicano i tempi massimi e minimi non sono valorizzate (NaN)”

Soluzione: “Il problema è nella versione di Xalan inclusa di default nel JRE 1.5 e 1.6 di java. Si deve usare Xalan-J 2.4.1”

Descrizione più dettagliata:

Tutto è nato con dei test di carico e performance che stiamo eseguendo in questo periodo.
Jmeter, di cui usiamo la versione 2.3.4, esporta il report del test plan in formato XML (o CSV se specificato). Per convertirlo in un HTML più comodamente fruibile si deve effettuare una trasformazione XSL, e per fortuna Jmeter mette a disposizione degli stylesheet apposta per questo (si trovano nel folder /extras dell’installazione di Jmeter).

Detto, fatto. Il comando che eseguo dovrebbe essere (ad esempio)

java org.apache.xalan.xslt.Process
  -IN jmeterResults.xml
  -XSL ~/work/jakarta-jmeter-2.3.4/extras/jmeter-results-report_21.xsl
  -OUT jmeterResults.html

Purtroppo questa trasformazione non funziona, o meglio, produce un HTML incompleto (vedi sezione “Problema”).

Dopo diversi tentativi, ho scoperto la soluzione, grazie ad un commento a questo post: usando la versione 2.4.1 di Xalan-J l’HTML prodotto è completo.

Per la cronaca, per lanciare la trasformazione XSL a linea di comando specificando una propria versione di Xalan, basta fare così

java
  -cp xalan-2.4.1.jar org.apache.xalan.xslt.Process
  -IN log.jtl
  -XSL ../extras/jmeter-results-report_21.xsl
  -OUT foo.html



E in ant (cosa che interessava me in particolare, perchè lanciavamo jmeter da ant)

<xslt
  in="${scenario.target.path}/scenario-result.xml"
  out="${scenario.target.path}/AggregateReport.html"
  style="${jmeter.home}/extras/jmeter-results-report_21.xsl"
  classpath="${basedir}/../xalan-2.4.1.jar" />