Litmus:DevelopersNotes
Here's some notes, thoughts, and rambling of interest to those looking to become involved with Litmus development. Feel free to add to this page and post questions or clarifications.
Architecture
Litmus is more or less organized as a classic MVC (Model View Controller) application. Two perl modules are used to facilitate this, Class::DBI and the Template Toolkit, and it's a good idea to have some familiarity with these modules when working on Litmus.
The Model - Class::DBI
Since writing SQL by hand is a pain, Litmus uses Class::DBI to talk to the database. The schema is contained in a set of perl modules found in litmus/Litmus/DB, and the cgi scripts and templates interact with the database using these modules. When it is nessecery to write more complex database queries (or where queries have been tuned manually and inlined for performance reasons), Class::DBI provides several methods to allow for manual SQL queries. Additional subroutines in the Litmus::DB::* modules handle these needs. It's worth taking a quick look through the Class::DBI documentation, or looking at some of the Litmus code that uses it, for a quick overview.
The View - Template Toolkit
Litmus uses the Template Toolkit to generate its output. Templates are conveniently stored in the templates/ directory (please use caution when opening the directory, as contents may have shifted during the flight). Currently, all templates are the default templates and are written in English, but since Litmus may one day want to support localizations and customizations, the template files themselves can be found in templates/en/default. The overall configuration for the template system is located in litmus/Litmus/Template.pm.
Once a CGI script has done whatever retrieval or processing it needs to do, it prepares a collection of one or more variables to be sent to the template. Each template defines an interface (described in a comment at the top of the template file), indicating what variables it requires and what variables are optional (there is currently no error checking here, so things may blow up if you don't pass all required variables to a template. The script then calls Template->process(), passing it the name of the template file and the variable list. The template can then access and manipulate these variables.
The template language itself is fairly straightforward. Everything that's not a template tag is just straight HTML and gets sent to the browser. Template tags are indicated with the markers [% and %]. Commands are fairly normal (IF, FOREACH, etc...), but see the Template Toolkit documentation or the existing templates for more details. To use a variable, just give its name. Methods can be invoked with the dot (.) operator. For example, if the variable named "test" contains a Litmus::DB::Test object and you want to print its testid, you can just say [% test.testid %].
One important note: to prevent cross-site scripting attacks, it's important that any information coming from the database be "filtered," such that any HTML tags are properly escaped. To do this, just use the FILTER command when mentioning a template variable. In other words, the example above should really be written as [% test.testid FILTER html %]. Other filters exist for more specialized situations, such as "js" and "testdata" (which allows only a specific list of html tags that are allowed to appear in testcases). When in doubt, filter it.
Formats
Testcases are rather difficult documents to store in databases; the sorts of fields that apply to a manual functional test (e.g. steps and expected results) don't really apply to an automated XUL test where fields like XUL and JavaScript would be more appropriate. Furthermore, the display of tests can depend on the format; a manual testcase should provide a listing of steps, while a topsite testcase should provide only a hyperlink, and a fully automated test should just provide a link to run the test. As such, Litmus provides the format mechanism, which allows for arbitrary storage and formatting of test data.
If you've peaked at the schema for the "tests" table, you've noticed a bunch of funny looking fields with names like t1 (long text), s1 (short text), and i1 (integers). If a particular format requires more fields, that can easily be taken care of by adding more columns to the schema.
The "formats" table provides a list of format names. Each format has an equilivant directory in litmus/formats where format-specific data is stored. Inside that directory, another file named format-name.pl must exist. That file contains the hash %column_mappings, which describes the mappings between human-readable column names, like "steps" and "expectedresults," and database columns, such as "t1" and "t2." Behind the scenes, we do some dark magic to allow you to just say $test->exepctedresults(), rather than having to say $test->t2() (though you still can say this if you would like).
The template system is also a part of the format mechanism. When a template file wants to display test data, it calls [% test.format.display(test, 0, "template.html.tmpl") %], where "test" is the test object to display data for, "0" is a flag to indicate whether UI to edit the testcase should be included, and "template.html.tmpl" is the format template to display. The template processor is automatically directed to include the template for the correct format. Format templates are found in formats/format-name/.
Note that the format API is still under development as Litmus evolves.
Where to find stuff
Most of the files in the Litmus codebase are fairly self-explanatory. Here's a short guide to where things are kept.
- createdb.sql - the database schema. Used at install-time to create the litmus table.
- populatedb.pl - creates the initial configuration of products, groups, etc... Currently the only way to manipulate these features.
- localconfig - installation-specific configuration, including database name and authentication details.
- data/litmusconfig.js - a JavaScript cache (regenerated whenever poopulatedb.pl is run) containing the full heirachy of products, groups, subgroups, platforms, and operating systems. Used by the select-box code to dynamically populate these fields.
- formats/ - test formats. See above for details.
- Litmus/ - libraries and modules.
- Litmus/DB - Class::DBI modules for each database table. The M in MVC.
- skins/ - css files, images, etc...
- templates/ - template files. See above for details.