## Light Client model-based testing guide In this directory you will find the model-based tests for the light client. They are "model-based" because they are based on the formal `TLA+` model of the Light Client: see [Lightclient.tla](Lightclient_003_draft.tla). The tests themselves are simple `TLA+` assertions, that describe the desired shape of the Light Client execution; see [LightTests.tla](LightTests.tla) for some examples. To be able to specify test assertions we have extended the Light Client model with `history` variable, which records the whole execution history. So, by way of referring to `history` you simply specify declaratively what execution history you want to see. After you have specified your `TLA+` test, list it among the tests of a _test batch_, such as [MC4_4_faulty.json](MC4_4_faulty.json). Such test batches are then executed automatically when you run `cargo test`. When you run `cargo test` some machinery will run under the hood, namely: * [Apalache model checker](https://github.com/informalsystems/apalache) will execute your `TLA+` test, and will try to find an execution you've described. * The model execution (or _counterexample_ in model checking terms) will be translated into the format that is understood by the Light Client implementation. For that translation two other components are necessary: * [Jsonatr (JSON Arrifact Translator)](https://github.com/informalsystems/jsonatr) performs the translation by executing this [transformation spec](_jsonatr-lib/apalache_to_lite_test.json); * [Tendermint Testgen](https://github.com/informalsystems/tendermint-rs/tree/main/testgen) takes care of translating abstract values from the model into the concrete implementation values. * `timeout` command is used to limit the test execution time. So, for the model-based test to run, the programs `apalache-mc`, `jsonatr`, `tendermint-testgen` and `timeout` should be present in your `PATH`. If any of the programs is not found, execution of a model-based test will be skipped. #### Installing Apalache First, download the latest Apalache's release from [here](https://github.com/informalsystems/apalache/releases). Then, unpack it, find the `apalache-pkg-X.Y.Z-full.jar` file, and create an executable bash script named `apalache-mc` with the following content: ```bash #!/bin/bash java -jar apalache-pkg-X.Y.Z-full.jar $@ ``` Please check [Apalache's installation instructions](https://apalache.informal.systems/docs/apalache/installation/index.html) for more details and alternative ways of running Apalache. Note that having an `apalache-mc` executable, as shown above, is required. Having a Bash `alias`, as recommended [here](https://apalache.informal.systems/docs/apalache/installation/docker.html#setting-an-alias), won't be enough. #### Installing `jsonatr` ```bash $ git clone https://github.com/informalsystems/jsonatr $ cd jsonatr/ $ cargo install --path . ``` #### Installing `tendermint-testgen` ```bash $ cargo install tendermint-testgen ``` #### Installing `timeout` `timeout` should be present by default on all Linux distributions, but may be absent on Macs. In that case it can be installed using `brew install coreutils`. ### Running model-based tests To run your model-based tests, use this command: ```bash $ cargo test -p tendermint-light-client --test model_based -- --nocapture ``` The results will be printed to the screen, and also saved to the disk in the [_test_run](_test_run) directory. Results include: * [Report](_test_run/report) on which tests were run, and what is the outcome * For each test, it's relevant files are also saved in the subdirectory of [_test_run](_test_run). E.g. For the test `TestSuccess`, which is referenced in [MC4_4_faulty.json](MC4_4_faulty.json), the results of it's execution will be saved into [_test_run/MC4_4_faulty.json/TestSuccess](_test_run/MC4_4_faulty.json/TestSuccess). These results include, for a successful test: * [log file](_test_run/MC4_4_faulty.json/TestSuccess/log), where test logs are stored * [TLA+ counterexample](_test_run/MC4_4_faulty.json/TestSuccess/MC4_4_faulty_TestSuccess.tla), the counterexample produced by Apalache in `TLA+` format * [JSON test fixture](_test_run/MC4_4_faulty.json/TestSuccess/MC4_4_faulty_TestSuccess.json), the actual static Light Client test, generated by Jsonatr from the counterexample. One important feature of the model-based testing is that each time you run a model-based test, a different static test could be produced. This happens due to the fact that the test you describe is very abstract, and it's requirements can be fulfilled by a multitude of concrete tests. To see what peculiarities a particular test has, please inspect the test report or logs. We suggest the following workflow for running model-based tests: 1. Experiment with your model-based test, by trying different scenarios. For that you might want to run your test in isolation, as counterexample generation by Apalache may take a significant time. In order to run only your test, just create a new test batch with your test, and temporarily remove/rename other test batches (files or directories starting with `_` are ignored). 2. After running your model-based test, inspect its report/logs. 3. If you find the test details interesting, simply copy the auto-generated `.json` and `.tla` files into the [single_step](single_step) directory. 4. Next time you run `cargo test` these static tests will be picked up and executed automatically.