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))) => values [1],[6]
check extract(slider(diota(0,1,10))) => values [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.
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 popuiolating 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(Charstring msg,Charstring fn,Vector
args,Integer times)->Real can be used to compare the performance of
different implementations of an OSQL function fn. It runs fn(arg)
times times. Notice that external factors influence the execution
time, so it must be interpreted with care.
Example: Let's define a slow slow_primes function where the
argument is declared Number.
create function slow_primes(Number n) -> Bag of Number
as select p
from Number p
where not exists divisors(n)=p
Let's test the performance of primes:
set :tm =
running time_function
on the prime function a couple of times. The time_function prints
the total time for all calls to the console but returns the average
time per call.
set :tm = time_function("Running prime(9856323)","prime",[9856323],100000);
