The CI4KE-Plugin (which stands for (Continuous Integration for Knowledge Engineering) tries to transfer the continuous integration (ci) methodology from the software- to the knowledge-engineering process. (For more information on ci in software engineering, see [1], [2]). Within the scope of this plugin, we mainly focus on the the regular execution of tests (which in fact can be any kind of knowledge-engineering-test or abstract test) and their easy formalisation and creation within the wiki (at runtime!).
The headline of the dashboard consists of the name of the article, which contains the knowledge (its the "monitored article" of this dashboard), the status of the most current "build" and the forecast. In the left column, the ten newest "builds" are listed. In terms of knowledge based CI, a "build" consists of several actions: Forming the knowledgebase to be tested, execute all registered tests against this kb, gather all the testresults and compute the "overall" result of these tests.
When a build in the left column gets clicked, its details are shown in the middle and right column. The middle column shows the changes in the knowledge-article between the selected build and its predecessor (exactly as the JSPWiki diff between these two pageversions would do). The right column holds the testresults of the selected build. As known from the xUnit-Testing-Frameworks, a test can either be Successful, Failed or Erroneous.
To add a dashboard to a wiki-article, use the following markup:
%%CIDashboard @monitoredArticle = BLA @tests = TestArticleContainsTODO @trigger = onDemand %
This for example is the markup which renders to the dashboard shown above. It consists of a DefaultMarkup block with "no" content, but (at least) three mandatory annotations. See the following table for a reference on all allowed annotations:
Annotation | Mandatory | Allowed Values | Description | Example |
---|---|---|---|---|
@monitoredArticle | yes | String | The title of the article which contains the knowledge this ci-dashboard is testing | Car-Diagnosis |
@tests | yes | String | A colon-separated list of the names of the tests which have to be executed for every build. For a testcase written in Java, the name of this test is simply its class-name. A testcase written in Groovy gets called by its explicit @name-annotation (see the howto-section for CITests for further reference on testcases). | SimpleTest:RuleRedundancyCheck: RuleInconsistencyCheck |
@trigger | yes | One of the following values: "onDemand" "onSave" "onNight" | Specifies when a new build gets executed. onDemand: No automatic build execution. Instead of that, an "Execute a new build"-button is rendered in the build-list. onSave: A new build gets executed every time the "monitored article" will be saved. onNight: (not yet implemented) Nightly build execution. | onDemand |
@id | no | String | Every dashboard has an ID to uniquely identify this dashboard in the whole wiki. In the easiest case, this ID is automatically created, taking the monitored article title AND the title of the article on which this dashboard is placed into account. Only if the same article is monitored more than once from the same "dashboard article", the @id annotation is mandatory. Example: Dashboard 1 is placed on the article A monitoring the article B. Its id is automatically created ("A-B"). When placing a second dashboard on the article A monitoring the article B as well, you have to give both dashboards an ID. | ID.of.dashboard.Car-Diagnosis |
CI is all about testing! Therefore, the ci-plugin enables you to write self-executable tests, following the unit-testing metaphore.
In the very essence, every testclass has to implement the CITest interface:
public interface CITest extends Callable<CITestResult> { public void init(CIConfig config); }
The init() method initialises the test (like the setUp() method in JUnit). The CIConfig object holds all the parameters from the dashboard which is calling the test. Moreover, you habe to implement the following call() method, which have to result a CITestResult instance.
Note: Instead of implementing the CITest interface, you can also extend the AbstractCITest class, which initialises the test by copying the CIConfig parameter instance to a private member variable config (from where it is accessible for all subclasses of AbstractCITest). See the following trivial example:
package de.d3web.we.ci4ke.testmodules; import de.d3web.we.ci4ke.handling.AbstractCITest; import de.d3web.we.ci4ke.handling.CITestResult; import de.d3web.we.ci4ke.handling.CITestResult.TestResultType; public class TrivialCITest extends AbstractCITest { @Override public CITestResult call() throws Exception { if (config.getMonitoredArticleTitle().length() < 20) { return new CITestResult(TestResultType.SUCCESSFUL); } else { return new CITestResult(TestResultType.FAILED, "Title longer than 20 Characters!"); } } }
Currently, every CITest-class has to be saved in the de.d3web.we.ci4ke.testmodules package. Like it was said before, the name of a CITest written in java is its classname.
Tests can also be written directly in the wiki, using the dynamic language Groovy. You just have to implement the call() method as you would with java, wrap around the source code in and specify the @name annotation:
%%CITest public CITestResult call() { ..... } @name: TestName %
Example:
%%CITest public CITestResult call() { if (config.getMonitoredArticleTitle().length() < 20) new CITestResult(SUCCESSFUL) else new CITestResult(FAILED, "Title longer than 20 Characters!") } @name: TrivialCITestGroovy %
As you can see, Groovy supports a much more simpler and easier syntax, but you loose a lot of static typing and compile time checking safety due to the runtime execution and compilation of groovy. Be sure to test your test-code before productive usage :-)
[#1] http://en.wikipedia.org/wiki/Continuous_integration
[#2] http://martinfowler.com/articles/continuousIntegration.html