Rugg Language guide
Overview
Rugg is a simple, concise language to describe fielsystem test scenarios, that was designed with the following objectives in mind :
- Rugg scripts should be short one-liners
- Allow to express parallel and sequencial processing with ease
- Easy repetition on range of values (ex: from 10 to 100, etc)
- Maximize expressivity, minimize syntactic complexity
We will present in this document, which is a complement to the Rugg main page, the various aspects of the Rugg language, and conclude by giving a list of useful examples.
Concepts
- Scenarios are scripts that execise some specific aspects of the filesystem. Scripts can be combined in many different ways to create comple tests. A scenario must comply to some constraints listed below.
- Zones are regular files that can be
created using the
rugg
API. Zones can be divided into subzones, which can be manipulated as regular files. This allows to make tests on the low-level filesystem blocks covered by the zone file.
Syntax
Rugg scripts are one-liners: they must be short and expressive. As such, the Rugg syntax is simply a sequence of operations and values, that can be “piped” together using compositions.
ATOM := VALUE | OPERATION | '(' EXPRESSION ')' OPERATION := NAME VALUE* EXPRESSION := ATOM ( COMPOSITION ATOM )*
In practive, the syntax is really similar to the Unix shells, where you do something like:
command | command ; another command && yet another command
excepted that Rugg offers you different compositions that the "piping" composition. For the impatient, here is an example of Rugg code:
zone 5Mb, subdivide 10 | blank | ensure blank : fill same text, ensure same
Rugg scripts can also be multi-line (spaces and new lines are
considered as separators), and comments can be specified by
prefixing a line by #
.
# Here is a comment for my script # and I can make it multi-line zone 50Mb, blank, fill
Operations
To create test scenarios, you can use a number of basic operations that allow you to manipulate zones, generate data, and ensure that the data is as expected. Here is the list of the currently implemented operations:
zone SIZE
: Creates a new zone of the givenSIZE
blank ZONE(S)
Blanks the given zone or set of zones. Data is erased, and the write offset is set to 0.fill METHOD? DATA? VARIANT? ZONE
fills the given zone with the given kind of data, starting at the beginning of the file. The METHOD can besame
to indicate the same data should be filled among the successivefill same
operations. The DATA can be eithertext
,blank
orbinary
, depending on the type of data to be generated. The VARIANT can befast
, when you want to favor speed in place of randomness of data.ensure WHAT
ensures that the given files have the same, different or blank data, depending on the WHAT parameter. Reading will start where the read offset points in each given file, and will be left where the ensure test has stopped reading. TheWHAT
argument can be eithersame
,different
,blank
orblank
, with optional prefixing bynot
for getting the opposite result.subdivide NUMBER ZONE
Subdivides the given zone in the given number of subzones. You should not create more than a thousand sub-zones per running Rugg interepreter, as you may reach the maximum limit of opened file descriptors.join ZONE
: Joins the given zone, after it has been subdivided.sig ZONE(S)
: Prints out the SHA-1 signatures for the given zones. This is to be used mainly for debugging purposes.time
: Prints the time elapsed since the program start, or since the lasttime
operation. This is very useful for benchmarkingunlink ZONE(S)
: Cleans up the given zone. This physically removes the given zone(s) from the filesystem.
These operations are sufficient for writing useful test cases.
Values
Operations can be parametered by giving them values. Rugg recognizes three different kind of values :
- WORDS, which are simply sequence of
characters (think “unquoted
strings”). Words are for instance what you give to the
ensure
operation to describe what you want to check. - NUMBERS, are integer or floating numbers. The separator is a dot.
- QUANTITIES, are numbers suffixed by a
unit (supported units are
b
,kb
,mb
andgb
, as well as freespace-relative unit%
), which indicate a quantity of data. - RANGES, are a way to specify sets of
numbers or quantities, with a given number of element. A range is
described by a start and end range (which will be included in the
resulting set), and by a total number of values. The range
1..10
will return 10 values, while1..10/5
will only return 5 values.
From the above value, the most powerful (and useful) are the ranges.
Combinators
Last but not least, you will need to combine your operations to create scenarios. Combination is simply the operation that “joins” or “pipes” your operations together, that is pass the result of an operation A to an operation B.
There are different ways to make an operation B use the result of an operation A:
- Composition, where the result of A is
directly applied to B. Think of the mathematic expression
g(f(x))
. - Iteration, which is a special kind of composition where A is expected to return a set (instead of a single value), and that B is sequentially applied to each element of the result of A. This is like “for each x of A, do B(x)”. An iteration returns a set which contains each element of the result of A applied to B.
- Application, which is an alternative version of the Iteration, where the application of B on the elements of the result of A is made “at once”, using multiple threads (one per element of the result of A).
The iteration and the application allow you to easily express sequential and parallel execution, and then allows you to make tests involving concurrency.
Quick reference
|
A NUMBER |
|
A QUANTITY of data |
|
A QUANTITY of data relative to free space |
|
Ranges with inclusive bounds and the total number of elements |
|
Creates a new zone |
|
Fills with the (same) text or binary data |
|
blanks the zone |
|
Checks the given zones |
|
creates a set of NUMBER subzones |
|
physically removes the current zone |
|
prints out the SHA-1 signature for the zone content |
|
prints the time since the program start or last time call |
Sequence |
|
The result of A is passed as argument to B |
Iteration |
|
B is sequentially invoked with each element of the result of A as argument. |
Application |
|
B is invoked in a new thread for each element of the result of A |
Grouping |
|
Creates a new operation that is the given combination of A and B. |
Tips
- When writing scenarios, log the different steps of your tests, and try to output progress information, and maybe also put the processing time for each scenario. This will be very useful when you will run long tests.
- Install some 'dev' packages, or install the source of the Linux
kernel somewhere and update your locate database
(
updatedb
). This will enable give Rugg some data from where to pick data.