OSQL Testing
OSQL support unit testing through the validate
statement. It
contains a description and one or more check
clauses.
For example, let's define a function prime
that takes a number as
input and return true if it is a prime:
create function prime(Integer n) -> boolean
as not exists(select d
from Integer d
where d in range(2,floor(sqrt(n)))
and 0 = mod(n,d));
Now we can test that we get the expected return for various parameters with a validate statement:
validate "my prime"
check prime(0) => true
check prime(13) => true
check prime(4) => null
check prime(20) => null
check prime(31) => true;
Try changing the statement so that it fails.
Validating streams
When working with streams, the functions vectorof(Stream b)->Vector
v
and extract(Stream s)->Bag
are useful for converting the finite
stream elements into vectors or bags, respectively. For example,
consider a function that returns a stream of sliding windows over
stream s
:
create function slider(Stream s) -> stream of Vector
as winagg(s,1,5);
The following statement validates the output from slider
on finite
streams of integers converted to vectors:
validate "slider with vectorof"
check vectorof(slider(diota(0,1,10))) =>
[[1],[6]];
The following converts the streams to bags instead of vectors:
validate "slider with extract"
check extract(slider(diota(0,1,10))) => bag([1],[6])
check extract(slider(diota(0,1,10))) => bag([6],[1]);
A vector is an ordered sequence of objects while a bag is an unordered
collection. This makes vectorof
the preferred choice for testing
stream output where the order is known. If the order is
undeterministic, as may be the case with pivot streams, use extract
.
The inverse of extract
is streamof(Bag b)->Stream
. The inverse of
vectorof
if vstream(Stream s)->Vector
For infinite real-time streams, a useful function is timeout
that
runs a stream a specified number of seconds.
timeout(heartbeat(1),2.5);
This allows to convert an infinite stream to a finite stream for real-time validation:
validate "heartbeat"
check count(extract(timeout(heartbeat(1),2.5))) =>
3;
For more complex tests where the output is large, it can be useful to store the testdata in a CSV or JSON file.
Setting up or running a test may also involve populating database
tables. Tables can be cleared by SQL's delete from mytable
that
deletes all rows in mytable
.
Testing performance
The system function time_function
can be used to compare the
performance of different implementations. Notice that external factors
influence execution times, so it must be interpreted with care. Try
running time_function on the prime function a couple of times. Note
that time_function
prints the total time to the console but returns
the average time. It is the average time that is shown below.
time_function("Running prime(9856323)","prime",[9856323],100000);