Thursday, August 23, 2012

Mondrian - Writing test cases

Debugging mondrian isn't always easy (ok - that's a nice way to put it, it's by far the hardest project I worked with)


Now that mondrian is on github, things are much simpler than when a cryptic perforce was used.


There are 2 options to debug mondrian code:
  1. Attach debugger to biserver
  2. Setup a unit test case
Number one is quick and dirty, works most of the cases. If you need to do some heavy lifting development, you definitely need to go for option 2.  Also, if you want to commit your changes back to mondrian, Julian Hyde and the rest of the team will force you to submit a unit test for it. And it's a good thing

Attaching a debugger to biserver


In order to do this you need to configure your bi server to use the JVM debugging flags. Add this to your start script (exactly where, depends on the method you use to start pentaho, usually start-pentaho.sh):

-Xrunjdwp:transport=dt_socket,address=8765,server=y,suspend=n

Now, configure your IDE to attach to that port. I use netbeans, and looks something like this:


 From this point on, just place breakpoints (I won't teach you where in mondrian you should put them - that's a different story) and should work.

Setup a unit test case

The above method works ok, but you'll have the entire pentaho stack, and having to permanently stop / start it is very cumbersome.

The best way is to setup a unit test and just work with mondrian source code. Since sometimes it's hard to replicate a specific issue in foodmart (the cube mondrian uses for it's unit tests) here's an example for using your own cube in a test case:

package webdetails;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import mondrian.olap.MondrianProperties;
import mondrian.olap.Util;
import mondrian.test.FoodMartTestCase;
import mondrian.test.TestContext;

public class NullParentTestCase extends FoodMartTestCase {

    @Override
    public TestContext getTestContext() {

        Util.PropertyList connectProperties = new Util.PropertyList();
        connectProperties.put("Provider", "mondrian");
        String jdbcURL = MondrianProperties.instance().getProperty("mondrian.marketshare.jdbcURL");
        if (jdbcURL != null) {
            connectProperties.put("Jdbc", jdbcURL);
        }


        URL catalogURL = null;

        try {
            catalogURL = Util.toURL(new File(MondrianProperties.instance().getProperty("mondrian.marketshare.file")));
        } catch (MalformedURLException e) {
            throw new Error(e.getMessage());
        }

        connectProperties.put("catalog", catalogURL.toString());

        return TestContext.instance().withProperties(connectProperties).withCube("Market Share");

    }

    public void testQueryLocationsByBrowser() {

        assertQueryReturns(
                "SELECT NON EMPTY [Browsers].[Major].Members ON COLUMNS, "
                + "[Locations].[Location].Members ON ROWS "
                + "FROM [Market Share]",
                null);
    }
}
Here's the important part from mondrian.properties:

mondrian.marketshare.jdbcURL=jdbc:mysql://127.0.0.1:3306/metrics?autoReconnect=true&user=x&password=pto
mondrian.marketshare.file = /home/pedro/marketshare.mondrian.xml

Have fun!

1 comment:

  1. You should take a look at TestContext.create(). It allows you to extend FoodMart with any arbitrary schema elements. There are a lot of examples in the test suite. It is much simpler than loading schema files directly (which we don't ever do).

    ReplyDelete