Module molly.tests
Module with test generators and checkers.
List-Append
list-append operations are either appends or reads
Detects cycles in histories where operations are transactions over named lists lists, and operations are either appends or reads.
The append test models the database as a collection of named lists, and performs transactions comprised of read and append operations. A read returns the value of a particular list, and an append adds a single unique element to the end of a particular list. We derive ordering dependencies between these transactions, and search for cycles in that dependency graph to identify consistency anomalies.
In terms of Molly, values in operation are lists of integers. Each operation performs a transaction, comprised of micro-operations which are either reads of some value (returning the entire list) or appends (adding a single number to whatever the present value of the given list is). We detect cycles in these transactions using Elle's cycle-detection system.
Generator molly.tests.list_append_gen produces an operations compatible with Molly:
{ index = 2, type = "invoke", value = {{ "append", 255, 8 } { "r", 253, null }}}
{ index = 3, type = "ok", value = {{ "append", 255, 8 } { "r", 253, { 1, 3, 4 }}}}
{ index = 4, type = "invoke", value = {{ "append", 256, 4 } { "r", 255, null } { "r", 256, nil } { "r", 253, null }}}
{ index = 5, type = "ok", value = {{ "append", 256, 4 } { "r", 255, { 2, 3, 4, 5, 8 }} { "r", 256, { 1, 2, 4 }} {{ "r", 253, { 1, 3, 4 }}}}
{ index = 6, type = "invoke", value = {{ "append", 250, 10 } { "r", 253, null }{ "r", 255, null } { "append", 256, 3 }}}
A partial test, including a generator and checker. You'll need to provide a client which can understand operations of the form:
{ type = "invoke", f = "txn", value = {{ "r", 3, null } { "append", 3, 2 } { "r", 3, null }}}
and return completions like:
{ type = "invoke", f = "txn", value = {{ "r", 3, { 1 }} { "append", 3, 2 } { "r", 3, { 1, 2 }}}}
where the key 3
identifies some list, whose value is initially [1]
, and
becomes [1 2]
.
Lists are encoded as rows in a table; key names are table names, and the set of all rows determines the list contents.
This test requires a way to order table contents.
RW Register
Generator produces concurrent atomic updates to a shared register. Writes are assumed to be unique, but this is the only constraint.
Operations are of two forms:
{ "r", "x", 1 } denotes a read of <code>x</code> observing the value 1.
{ "w", "x", 2 } denotes a write of <code>x</code>, settings its value to 2.
Example of history:
{ type = "invoke", f = "txn", value = {{ "w", "x", 1 }}, process = 0, index = 1}
{ type = "ok", f = "txn", value = {{ "w", "x", 1 }}, process = 0, index = 2}
{ type = "invoke", f = "txn", value = {{ "r", "x", null }}, process = 0, index = 3}
{ type = "ok", f = "txn", value = {{ "r", "x", 2 }}, process = 0, index = 4}
Note that in Lua associative array is an array that can be indexed not only
with numbers, but also with strings or any other value of the language,
except nil. Null values in Lua tables are represented as JSON null
(json.NULL
, a Lua lightuserdata
NULL pointer). is provided for
comparison.
Functions
rw_register_gen () | Write/Read operations generator. |
list_append_gen ([opts]) | List-Append operations generator. |
Functions
- rw_register_gen ()
-
Write/Read operations generator.
Returns:
-
an iterator
Usage:
> log = require('log') > tests = require('molly.tests') > for _it, v in tests.rw_register_gen() do log.info(v()) end {"f":"txn","value":[["r","x",null]]} {"f":"txn","value":[["w","x",58]]} {"f":"txn","value":[["r","x",null]]} {"f":"txn","value":[["w","x",80]]} {"f":"txn","value":[["r","x",null]]} {"f":"txn","value":[["w","x",46]]} {"f":"txn","value":[["r","x",null]]} {"f":"txn","value":[["w","x",19]]} {"f":"txn","value":[["r","x",null]]} {"f":"txn","value":[["w","x",66]]} --- ...
- list_append_gen ([opts])
-
List-Append operations generator.
A generator for operations where values are transactions made up of reads and appends to various integer keys.
Parameters:
- opts Table with options.
- key_count number Number of distinct keys at any point. Default is 3.
- min_txn_len number Minimum number of operations per txn. Default is 1.
- max_txn_len number Maximum number of operations per txn. Default is 2.
- max_writes_per_key number Maximum number of operations per key. Default is 32.
Returns:
-
an iterator
Usage:
> log = require('log') > tests = require('molly.tests') > for _it, v in tests.list_append_gen() do log.info(v()) end {"f":"txn","value":[["r",3,null]]} {"f":"txn","value":[["append",3,1]]} {"f":"txn","value":[["r",2,null]]} {"f":"txn","value":[["append",3,2]]} {"f":"txn","value":[["r",1,null]]} {"f":"txn","value":[["append",2,3]]} {"f":"txn","value":[["r",2,null]]} {"f":"txn","value":[["append",3,4]]} {"f":"txn","value":[["r",2,null]]} {"f":"txn","value":[["append",2,5]]} --- ...
- opts Table with options.