2019-03-27 16:32:13 +00:00
# Eth2.0 Test Generators
This directory of contains all the generators for YAML tests, consumed by Eth 2.0 client implementations.
Any issues with the generators and/or generated tests should be filed
in the repository that hosts the generator outputs, here: [ethereum/eth2.0-tests ](https://github.com/ethereum/eth2.0-tests/ ).
Whenever a release is made, the new tests are automatically built and
[eth2TestGenBot ](https://github.com/eth2TestGenBot ) commits the changes to the test repository.
## How to run generators
pre-requisites:
- Python 3 installed
- PIP 3
- GNU make
### Cleaning
2019-03-28 16:24:18 +00:00
This removes the existing virtual environments (`/test_generators/< generator > /venv`), and generated tests (`/yaml_tests/`).
2019-03-27 16:32:13 +00:00
```bash
make clean
```
### Running all test generators
This runs all the generators.
```bash
2019-03-28 16:24:18 +00:00
make gen_yaml_tests
2019-03-27 16:32:13 +00:00
```
### Running a single generator
The make file auto-detects generators in the `test_generators/` directory,
and provides a tests-gen target for each generator, see example.
```bash
2019-03-28 16:24:18 +00:00
make ./yaml_tests/shuffling/
2019-03-27 16:32:13 +00:00
```
## Developing a generator
Simply open up the generator (not all at once) of choice in your favorite IDE/editor, and run:
```bash
2019-03-28 16:24:18 +00:00
# From the root of the generator directory:
2019-03-27 16:32:13 +00:00
# Create a virtual environment (any venv/.venv/.venvs is git-ignored)
2019-03-28 15:10:16 +00:00
python3 -m venv venv
2019-03-27 16:32:13 +00:00
# Activate the venv, this is where dependencies are installed for the generator
2019-03-28 15:10:16 +00:00
. venv/bin/activate
2019-03-27 16:32:13 +00:00
```
Now that you have a virtual environment, write your generator.
It's recommended to extend the base-generator.
Create a `requirements.txt` in the root of your generator directory:
```
eth-utils==1.4.1
2019-03-28 15:10:16 +00:00
../../test_libs/gen_helpers
2019-04-07 07:26:24 +00:00
../../test_libs/config_helpers
2019-03-28 15:10:16 +00:00
../../test_libs/pyspec
```
2019-04-07 07:26:24 +00:00
The config helper and pyspec is optional, but preferred. We encourage generators to derive tests from the spec itself, to prevent code duplication and outdated tests.
Applying configurations to the spec is easy, and enables you to create test suites with different contexts.
2019-03-28 15:10:16 +00:00
Note: make sure to run `make pyspec` from the root of the specs repository, to build the pyspec requirement.
2019-03-27 16:32:13 +00:00
Install all the necessary requirements (re-run when you add more):
```bash
2019-03-27 18:30:47 +00:00
pip3 install -r requirements.txt
2019-03-27 16:32:13 +00:00
```
And write your initial test generator, extending the base generator:
Write a `main.py` file, here's an example:
```python
from gen_base import gen_runner, gen_suite, gen_typing
from eth_utils import (
to_dict, to_tuple
)
2019-04-07 07:26:24 +00:00
from preset_loader import loader
from eth2spec.phase0 import spec
2019-03-27 16:32:13 +00:00
@to_dict
2019-04-07 07:26:24 +00:00
def example_test_case(v: int):
yield "spec_SHARD_COUNT", spec.SHARD_COUNT
yield "example", v
2019-03-27 16:32:13 +00:00
@to_tuple
2019-04-07 07:26:24 +00:00
def generate_example_test_cases():
2019-03-27 16:32:13 +00:00
for i in range(10):
2019-04-07 07:26:24 +00:00
yield example_test_case(i)
2019-03-27 16:32:13 +00:00
2019-04-07 08:28:32 +00:00
def example_minimal_suite(configs_path: str) -> gen_typing.TestSuiteOutput:
2019-04-07 07:26:24 +00:00
presets = loader.load_presets(configs_path, 'minimal')
spec.apply_constants_preset(presets)
2019-03-27 16:32:13 +00:00
2019-04-07 08:28:32 +00:00
return ("mini", "core", gen_suite.render_suite(
2019-04-07 07:26:24 +00:00
title="example_minimal",
2019-03-27 16:32:13 +00:00
summary="Minimal example suite, testing bar.",
2019-04-07 07:26:24 +00:00
forks_timeline="testing",
forks=["phase0"],
2019-03-27 16:32:13 +00:00
config="minimal",
2019-04-07 07:26:24 +00:00
handler="main",
2019-04-07 08:28:32 +00:00
test_cases=generate_example_test_cases()))
2019-03-27 16:32:13 +00:00
2019-04-07 08:28:32 +00:00
def example_mainnet_suite(configs_path: str) -> gen_typing.TestSuiteOutput:
2019-04-07 07:26:24 +00:00
presets = loader.load_presets(configs_path, 'mainnet')
spec.apply_constants_preset(presets)
2019-03-27 16:32:13 +00:00
2019-04-07 08:28:32 +00:00
return ("full", "core", gen_suite.render_suite(
2019-04-07 07:26:24 +00:00
title="example_main_net",
summary="Main net based example suite.",
forks_timeline= "mainnet",
forks=["phase0"],
config="testing",
handler="main",
2019-04-07 08:28:32 +00:00
test_cases=generate_example_test_cases()))
2019-03-27 16:32:13 +00:00
2019-03-28 15:27:28 +00:00
2019-04-07 07:26:24 +00:00
if __name__ == "__main__":
gen_runner.run_generator("example", [example_minimal_suite, example_mainnet_suite])
2019-03-28 15:27:28 +00:00
```
2019-03-27 16:32:13 +00:00
Recommendations:
2019-04-07 07:26:24 +00:00
- you can have more than just 1 suite creator, e.g. ` gen_runner.run_generator("foo", [bar_test_suite, abc_test_suite, example_test_suite])`
2019-03-27 16:32:13 +00:00
- you can concatenate lists of test cases, if you don't want to split it up in suites.
2019-04-07 07:26:24 +00:00
- you can split your suite creators into different python files/packages, good for code organization.
- use config "minimal" for performance. But also implement a suite with the default config where necessary.
- you may be able to write your test suite creator in a way where it does not make assumptions on constants.
If so, you can generate test suites with different configurations for the same scenario (see example).
2019-03-27 16:32:13 +00:00
- the test-generator accepts `--output` and `--force` (overwrite output)
## How to add a new test generator
In order to add a new test generator that builds `New Tests` :
1. Create a new directory `new_tests` , within the `test_generators` directory.
Note that `new_tests` is also the name of the directory in which the tests will appear in the tests repository later.
2. Your generator is assumed to have a `requirements.txt` file,
with any dependencies it may need. Leave it empty if your generator has none.
3. Your generator is assumed to have a `main.py` file in its root.
By adding the base generator to your requirements, you can make a generator really easily. See docs below.
2019-04-07 07:26:24 +00:00
4. Your generator is called with `-o some/file/path/for_testing/can/be_anything -c some/other/path/to_configs/` .
2019-03-27 16:32:13 +00:00
The base generator helps you handle this; you only have to define suite headers,
and a list of tests for each suite you generate.
5. Finally, add any linting or testing commands to the
[circleci config file ](https://github.com/ethereum/eth2.0-test-generators/blob/master/.circleci/config.yml )
if desired to increase code quality.
2019-04-07 07:26:24 +00:00
2019-03-27 16:32:13 +00:00
Note: you do not have to change the makefile.
However, if necessary (e.g. not using python, or mixing in other languages), submit an issue, and it can be a special case.
Do note that generators should be easy to maintain, lean, and based on the spec.
## How to remove a test generator
If a test generator is not needed anymore, undo the steps described above and make a new release:
2019-03-28 16:24:18 +00:00
1. remove the generator directory
2019-03-27 16:32:13 +00:00
2. remove the generated tests in the `eth2.0-tests` repository by opening a PR there.
3. make a new release