Added by Jonathan Nolen, last edited by Jonathan Nolen on Dec 17, 2007  (view change)

Labels:

plugins plugins Delete
testing testing Delete
Enter labels to add to this page:
Wait Image 
Looking for a label? Just start typing.

Atlassian plugins depend on Maven 2 for running their test suites. This is advantageous because all plugins are always tested the same way, and because Bamboo, our continuous integration server, can do likewise.

Building a suite of tests for your plugin is extremely important. We're big believers in Test Driven Development, and we think that writing tests as you go is one of the best ways to ensure you build a high-quality and functional application. Additionally, having a comprehensive suite of tests means that other developers in the community (or even Atlassian developers) can jump in and collaborate on your plugin without fear of breaking anything inadvertently.

Our products are always moving forward. We enhance and change things. We move or deprecate APIs. A plugin that works perfectly in Confluence 2.5 might change in Confluence 2.6, in subtle or profound ways. That's the primary reason that we run the Developer Bamboo Server – to alert us to any changes that might break plugins. When those breakages occur, we might be able to go back and do things another way that preserves compatibility. Or, at the very least, we can notify developers in advance of a new release about what has changed. Continuous Integration is a crucial safeguard, and it depends largely on a comprehensive test suite to alert us when things break.

Unit Tests

The first tests you should write for your plugin are unit tests. Unit tests are designed to exercise individual chunks of your code in isolation. To run unit tests, the default maven 'test' command works:

> mvn clean test

For examples of unit tests, take a look at the Confluence Chart Plugin test or the JIRA Fisheye Plugin tests.

Integration, or Functional, Tests

Integration Testing is designed to test your code inside the the Atlassian product. The goal is confirm that the plugin functionality works as designed, and is compatible with various versions of the product. To achieve this goal, Maven will actually deploy your plugin to a running version of JIRA or Confluence and then run tests that you write to exercise its functionality. To run integration tests, the command is:

> mvn clean integration-test

When you run this command, Maven will start up a new instance of JIRA or Confluence, running inside Tomcat, and install some default data into it: things like a license, database configuration, and an admin account. This will save you the effort of having to set up the product each time. It's important to note that the license installed is a unique one: it is perpetually valid, but only for a period of three hours (which should be more than enough time to run your tests.) Should you keep going longer than three hours, the license system will lock you out, and you'll need to restart it to proceed.

For examples of integration tests, take a look at the JIRA Fisheye Plugin tests. A Confluence example is forthcoming.

Skipping tests

To skip the various test phases, add one of the following options to your Maven command:

> -Dmaven.test.skip=true - skips both unit and integration tests
> -Dmaven.test.unit.skip=true - skips unit tests
> -Dmaven.test.it.skip=true - skips integration tests

Notes

Oftentimes, your functional tests will need to set up the product in a particular state. You may wish to do this by creating an XML export of JIRA or Confluence data in a known state, and importing that data at the beginning of your tests. XML data that is usually imported by the tests into the running product should be placed in src/test/xml/ directory provided.

Packages containing integration tests should start with it. For instance:

  • it.com.atlassian.jira.plugins.fisheye
  • it.com.atlassian.jira.plugins.calendar

This is due to inability of Maven to discriminate unit tests from integration tests. This will be resolved in the coming Maven 2.1 and we will take care of the migration for you then.

System Properties

The following system properties are available to control the behaviour of the integration test harness:

  • tomcat.installer.url - path to the tomcat zip file to install. Default: http://repository.atlassian.com/maven2/org/apache/tomcat/apache-tomcat/5.5.20/apache-tomcat-5.5.20-jdk14.zip
  • cargo.wait - if this is set to true tomcat will be started up and then cargo suspends allowing you to manually access this JIRA from the browser.
  • confluence.version / jira.version - version of JIRA to compile and test against. default is 3.10.2
  • confluence.data.version / jira.data.version - version of the test resource bundle that contains the basic JIRA configuration data for the integration test environment. These versions mimic the actual JIRA versions. However we might only modify and release this project for the reasons of non-backwards compatibility of the new versions of JIRA. Therefore not every version of JIRA will have a corresponding version of the resource bundle. By default this is set to 3.10.2 which should be migrated and work correctly with the newer versions.
  • jira.test-lib.version - version of jira-func-tests JAR to compile and test against. default is 3.10-DEV (JIRA only).
  • confluence.url / jira.url - base URL for this instance of JIRA. Default: http://localhost:$http.port/jira/
  • http.port - port on which this instance of JIRA will be accessible on. Default: 8989
  • rmi.port

Debugging your failing tests

All of the necessary output generated by tests will be found under target subdirectory of your module. The following files are useful places to look at dire times:

  • surefire-reports/*.txt - a log file per test class of failed tests (both unit tests and functional tests)
  • cargo.log - the log file of cargo trying to deploy jira and start or stop the tomcat
  • output.log - the log file of tomcat and jira to which the plugin is deployed for functional testing

I am trying to write an integration test for my JIRA plugin, but things are not working out very well. I first manually setup a JIRA instance with 1 project and 1 issue in that project (running under mvn -Pplugin-debug).
I then exported the data to xml and wrote a unit test like this:

public class DatabaseValuesCFTest extends JIRAWebTest
{
	public DatabaseValuesCFTest( String s )
	{
		super( s );
	}

	public void setUp()
	{
		Locale.setDefault( Locale.US );
		super.setUp();
		restoreData( "database-values-plugin-it-data.xml" );		
	}

	public void testEditing()
	{
		gotoIssue("TST-1");
	}
}

However, this gives the following error:

Running it.org.deblauwe.jira.plugin.databasevalues.DatabaseValuesCFTest
Test testEditing started at Tue Apr 01 21:07:21 CEST 2008
Setting up JIRA ... 
Asserting text present: You must specify the backup path.
Setting up JIRA ... 
Asserting text present: Invalid license key specified.
--------------------------------------------------------------------------------------------------------
--------- HTML dump from:
java.lang.RuntimeException
	at com.atlassian.jira.webtests.WebTestCaseWrapper.dumpResponse(WebTestCaseWrapper.java:1115)
	at com.atlassian.jira.webtests.WebTestCaseWrapper.assertTextPresent(WebTestCaseWrapper.java:178)
	at com.atlassian.jira.webtests.JIRAWebTest.setupJIRA(JIRAWebTest.java:478)
	at com.atlassian.jira.webtests.JIRAWebTest.init(JIRAWebTest.java:450)
	at com.atlassian.jira.webtests.JIRAWebTest.setUp(JIRAWebTest.java:434)
	at it.org.deblauwe.jira.plugin.databasevalues.DatabaseValuesCFTest.setUp(DatabaseValuesCFTest.java:20)
	at junit.framework.TestCase.runBare(TestCase.java:125)
	at junit.framework.TestResult$1.protect(TestResult.java:106)
	at junit.framework.TestResult.runProtected(TestResult.java:124)
	at junit.framework.TestResult.run(TestResult.java:109)
	at junit.framework.TestCase.run(TestCase.java:118)
	at junit.framework.TestSuite.runTest(TestSuite.java:208)
	at junit.framework.TestSuite.run(TestSuite.java:203)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:324)
	at org.apache.maven.surefire.junit.JUnitTestSet.execute(JUnitTestSet.java:213)
	at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:138)
	at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:125)
	at org.apache.maven.surefire.Surefire.run(Surefire.java:132)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:324)
	at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:290)
	at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:818)

My default Locale is not English, so I tried to specify it before the setUp() happens, but it does not seem to make a difference. I get the same error.

Hi,

I faced same problem yesterday. I fixed it simply adding

<jvmargs>-Duser.language=en</jvmargs>
tag between my build properties.

Where exactly do you specify this in the pom.xml?

Within project/properties element.

Hi,
I have also problem with integration tests. They gives me following error into output.log file:

2008-04-07 21:42:10,812 main ERROR [web.action.util.JiraLicenseUtils] The current license is too old (Tue Aug 22 07:00:00 CEST 2006) to run this version (3.12 - Wed Nov 28 00:00:00 CET 2007) of JIRA.

Do yo know what is wrong? I expected that the licence will be installed by integration test framework automatically. But looks like it is not Can anybody help me?

I finally found the solution by myself
Even if I am testing plugin for JIRA 3.11 I should usine JIRA 3.12 test-lib version. You can set it up using property jira.test-lib.version as defined above.

<jira.test-lib.version>3.12</jira.test-lib.version>

The problem is in JIRA 3.11 test-lib which really uses old licence.

Hello,

I followed the instructions listed at How to build an Atlassian Plugin and was able to produce a skeleton plugin jar for a plugin named 'first'.

Next, I proceeded to run mvn clean integration-test, which fails with a timeout at the cargo start-container task. The log file (target\output.log) reveals:

Jul 8, 2008 5:18:19 PM org.apache.tomcat.util.digester.Digester fatalError
SEVERE: Parse Fatal Error at line 33 column 35: An invalid XML character (Unicode: 0xc) was found in the value of attribute "url" and element is "Resource".
org.xml.sax.SAXParseException: An invalid XML character (Unicode: 0xc) was found in the value of attribute "url" and element is "Resource".

I looked at that line in conf/server.xml , and it shows like this :

url='jdbc:hsqldb :jirapluginsirst arget/jira-home/database'

Obviously the variable part of the constructed url is mangled and contains 0x0c and 0x09 characters.

Has anybody seen this before? Does anybody have a solution?

Thanks in advance, Gert-Jan Bartelds

I found a workaround to the mangled url problem:

in file MAVEN_REPO\com\atlassian\jira\plugins\jira-plugin-base\8\jira-plugin-base-8.pom , line 227, it says:

cargo.datasource.url=jdbc:hsqldb:${atlassian.product.config.directory}/jira-home/database|

Running mvn --debug showed that ${atlassian.product.config.directory} is correctly expanded, but uses backward slashes instead of forward (I'm on Windows...). Replacing the line with

cargo.datasource.url=jdbc:hsqldb:d:\jira\plugins\first\target/jira-home/database|

made no difference. Changing to forward slashes

cargo.datasource.url=jdbc:hsqldb:d:/jira/plugins/first/target/jira-home/database|

finally did the trick

For now I can live with this workaround, but I would welcome a more permanent solution.

Gert-Jan

Hi, I'm new to developing JIRA plug-ins.It looks like com.atlassian.jira.webtests.JIRAWebTest is a good resource for writing unit tests. Is there documentation, like the javadoc API, on this class somewhere?

Thanks,

Jeff