small format update, support new testing format in generator base pkg

This commit is contained in:
protolambda 2019-04-07 17:26:24 +10:00
parent 9eb640dd3b
commit c350aaecf7
No known key found for this signature in database
GPG Key ID: EC89FDBB2B4C7623
4 changed files with 68 additions and 43 deletions

View File

@ -0,0 +1,6 @@
# Testing fork timeline
# Equal to GENESIS_EPOCH
phase0: 536870912
# No other forks considered in testing yet (to be implemented)

View File

@ -89,14 +89,14 @@ The aim is to provide clients with a well-defined scope of work to run a particu
## Test Suite ## Test Suite
``` ```
title: <required, string, short, one line> -- Display name for the test suite title: <string, short, one line> -- Display name for the test suite
summary: <required, string, average, 1-3 lines> -- Summarizes the test suite summary: <string, average, 1-3 lines> -- Summarizes the test suite
forks_timeline: <required, string, reference to a fork definition file, without extension> -- Used to determine the forking timeline forks_timeline: <string, reference to a fork definition file, without extension> -- Used to determine the forking timeline
forks: <required, list of strings> -- Runner decides what to do: run for each fork, or run for all at once, each fork transition, etc. forks: <list of strings> -- Runner decides what to do: run for each fork, or run for all at once, each fork transition, etc.
- ... <required, string, first the fork name, then the spec version> - ... <string, first the fork name, then the spec version>
config: <required, string, reference to a config file, without extension> -- Used to determine which set of constants to run (possibly compile time) with config: <string, reference to a config file, without extension> -- Used to determine which set of constants to run (possibly compile time) with
runner: <required, string, no spaces, python-like naming format> *MUST be consistent with folder structure* runner: <string, no spaces, python-like naming format> *MUST be consistent with folder structure*
handler: <optional, string, no spaces, python-like naming format> *MUST be consistent with folder structure* handler: <string, no spaces, python-like naming format> *MUST be consistent with folder structure*
test_cases: <list, values being maps defining a test case each> test_cases: <list, values being maps defining a test case each>
... ...
@ -163,7 +163,7 @@ To prevent parsing of hundreds of different YAML files to test a specific test t
``` ```
. <--- root of eth2.0 tests repository . <--- root of eth2.0 tests repository
├── bls <--- collection of handler for a specific test-runner, example runner: "bls" ├── bls <--- collection of handler for a specific test-runner, example runner: "bls"
│   ├── signing <--- collection of test suites for a specific handler, example handler: "signing". If no handler, use a dummy folder "main" │   ├── signing <--- collection of test suites for a specific handler, example handler: "signing". If no multiple handlers, use a dummy folder (e.g. "main"), and specify that in the yaml.
│   │   ├── sign_msg.yml <--- an entry list of test suites │   │   ├── sign_msg.yml <--- an entry list of test suites
│   │   ... <--- more suite files (optional) │   │   ... <--- more suite files (optional)
│   ... <--- more handlers │   ... <--- more handlers

View File

@ -59,11 +59,12 @@ Create a `requirements.txt` in the root of your generator directory:
``` ```
eth-utils==1.4.1 eth-utils==1.4.1
../../test_libs/gen_helpers ../../test_libs/gen_helpers
``` ../../test_libs/config_helpers
And optionally, to include pyspec, add:
```
../../test_libs/pyspec ../../test_libs/pyspec
``` ```
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.
Note: make sure to run `make pyspec` from the root of the specs repository, to build the pyspec requirement. Note: make sure to run `make pyspec` from the root of the specs repository, to build the pyspec requirement.
Install all the necessary requirements (re-run when you add more): Install all the necessary requirements (re-run when you add more):
@ -82,45 +83,60 @@ from eth_utils import (
to_dict, to_tuple to_dict, to_tuple
) )
from preset_loader import loader
from eth2spec.phase0 import spec
@to_dict @to_dict
def bar_test_case(v: int): def example_test_case(v: int):
yield "bar_v", v yield "spec_SHARD_COUNT", spec.SHARD_COUNT
yield "bar_v_plus_1", v + 1 yield "example", v
yield "bar_list", list(range(v))
@to_tuple @to_tuple
def generate_bar_test_cases(): def generate_example_test_cases():
for i in range(10): for i in range(10):
yield bar_test_case(i) yield example_test_case(i)
def bar_test_suite() -> gen_typing.TestSuite: def example_minimal_suite(configs_path: str) -> gen_typing.TestSuite:
presets = loader.load_presets(configs_path, 'minimal')
spec.apply_constants_preset(presets)
return gen_suite.render_suite( return gen_suite.render_suite(
title="bar_minimal", title="example_minimal",
summary="Minimal example suite, testing bar.", summary="Minimal example suite, testing bar.",
fork="v0.5.1", forks_timeline="testing",
forks=["phase0"],
config="minimal", config="minimal",
test_cases=generate_bar_test_cases()) handler="main",
test_cases=generate_example_test_cases())
def example_mainnet_suite(configs_path: str) -> gen_typing.TestSuite:
presets = loader.load_presets(configs_path, 'mainnet')
spec.apply_constants_preset(presets)
return gen_suite.render_suite(
title="example_main_net",
summary="Main net based example suite.",
forks_timeline= "mainnet",
forks=["phase0"],
config="testing",
handler="main",
test_cases=generate_example_test_cases())
if __name__ == "__main__": if __name__ == "__main__":
gen_runner.run_generator("foo", [bar_test_suite]) gen_runner.run_generator("example", [example_minimal_suite, example_mainnet_suite])
```
And to use the pyspec:
```
from eth2spec.phase0 import spec
``` ```
Recommendations: Recommendations:
- you can have more than just 1 generator, e.g. ` gen_runner.run_generator("foo", [bar_test_suite, abc_test_suite, example_test_suite])` - 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])`
- you can concatenate lists of test cases, if you don't want to split it up in suites. - you can concatenate lists of test cases, if you don't want to split it up in suites.
- you can split your suite generators into different python files/packages, good for code organization. - 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 - 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).
- the test-generator accepts `--output` and `--force` (overwrite output) - the test-generator accepts `--output` and `--force` (overwrite output)
## How to add a new test generator ## How to add a new test generator
@ -133,13 +149,13 @@ In order to add a new test generator that builds `New Tests`:
with any dependencies it may need. Leave it empty if your generator has none. 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. 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. By adding the base generator to your requirements, you can make a generator really easily. See docs below.
4. Your generator is called with `-o some/file/path/for_testing/can/be_anything`. 4. Your generator is called with `-o some/file/path/for_testing/can/be_anything -c some/other/path/to_configs/`.
The base generator helps you handle this; you only have to define suite headers, The base generator helps you handle this; you only have to define suite headers,
and a list of tests for each suite you generate. and a list of tests for each suite you generate.
5. Finally, add any linting or testing commands to the 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) [circleci config file](https://github.com/ethereum/eth2.0-test-generators/blob/master/.circleci/config.yml)
if desired to increase code quality. if desired to increase code quality.
Note: you do not have to change the makefile. 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. 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. Do note that generators should be easy to maintain, lean, and based on the spec.

View File

@ -1,17 +1,20 @@
from typing import Iterable from typing import Iterable
from eth_utils import ( from eth_utils import to_dict
to_dict,
)
from gen_base.gen_typing import TestCase from gen_base.gen_typing import TestCase
@to_dict @to_dict
def render_suite(*, title: str, summary: str, fork: str, config: str, test_cases: Iterable[TestCase]): def render_suite(*,
title: str, summary: str,
forks_timeline: str, forks: Iterable[str],
config: str,
handler: str,
test_cases: Iterable[TestCase]):
yield "title", title yield "title", title
if summary is not None: yield "summary", summary
yield "summary", summary yield "forks_timeline", forks_timeline,
yield "fork", fork yield "forks", forks
yield "config", config yield "config", config
yield "handler", handler
yield "test_cases", test_cases yield "test_cases", test_cases