Make examples in READMEs runnable and testable
This commit is contained in:
@@ -55,6 +55,26 @@ def plan_runner():
|
||||
return run_plan
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def example_plan_runner():
|
||||
"Returns a function to run Terraform plan on an example."
|
||||
|
||||
def run_plan(fixture_path, is_module=True, targets=None, **tf_vars):
|
||||
"Runs Terraform plan and returns parsed output"
|
||||
tf = tftest.TerraformTest(fixture_path, BASEDIR,
|
||||
os.environ.get('TERRAFORM', 'terraform'))
|
||||
tf.setup()
|
||||
plan = tf.plan(output=True, tf_vars=tf_vars, targets=targets)
|
||||
modules = plan.modules
|
||||
resources = []
|
||||
for name, module in modules.items():
|
||||
for _, resource in module.resources.items():
|
||||
resources.append(resource)
|
||||
return plan, modules, resources
|
||||
|
||||
return run_plan
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def apply_runner():
|
||||
"Returns a function to run Terraform apply on a fixture."
|
||||
|
||||
32
tests/modules/examples/conftest.py
Normal file
32
tests/modules/examples/conftest.py
Normal file
@@ -0,0 +1,32 @@
|
||||
from pathlib import Path
|
||||
|
||||
import marko
|
||||
|
||||
|
||||
MODULES_PATH = Path(__file__).parents[3] / 'modules/'
|
||||
|
||||
|
||||
def pytest_generate_tests(metafunc):
|
||||
if 'example' in metafunc.fixturenames:
|
||||
modules = [
|
||||
x for x in MODULES_PATH.iterdir()
|
||||
if x.is_dir()
|
||||
]
|
||||
modules.sort()
|
||||
examples = []
|
||||
ids = []
|
||||
for module in modules:
|
||||
readme = module / 'README.md'
|
||||
if not readme.exists(): continue
|
||||
doc = marko.parse(readme.read_text())
|
||||
index = 0
|
||||
for child in doc.children:
|
||||
if isinstance(child, marko.block.FencedCode) and child.lang == 'hcl':
|
||||
index += 1
|
||||
code = child.children[0].children
|
||||
if 'tftest:skip' in code:
|
||||
continue
|
||||
examples.append(code)
|
||||
ids.append(f'{module.stem}:example{index}')
|
||||
|
||||
metafunc.parametrize('example', examples, ids=ids)
|
||||
24
tests/modules/examples/test_plan.py
Normal file
24
tests/modules/examples/test_plan.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import tftest
|
||||
import re
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
import marko
|
||||
|
||||
MODULES_PATH = Path(__file__, '../../../../modules/').resolve()
|
||||
VARIABLES_PATH = Path(__file__, '../variables.tf').resolve()
|
||||
EXPECTED_RESOURCES_RE = re.compile(r'# tftest:modules=(\d+):resources=(\d+)')
|
||||
|
||||
|
||||
def test_example(example_plan_runner, tmp_path, example):
|
||||
(tmp_path / 'modules').symlink_to(MODULES_PATH)
|
||||
(tmp_path / 'variables.tf').symlink_to(VARIABLES_PATH)
|
||||
(tmp_path / 'main.tf').write_text(example)
|
||||
|
||||
match = EXPECTED_RESOURCES_RE.search(example)
|
||||
expected_modules = int(match.group(1)) if match is not None else 1
|
||||
expected_resources = int(match.group(2)) if match is not None else 1
|
||||
|
||||
plan, modules, resources = example_plan_runner(str(tmp_path))
|
||||
assert expected_modules == len(modules)
|
||||
assert expected_resources == len(resources)
|
||||
54
tests/modules/examples/variables.tf
Normal file
54
tests/modules/examples/variables.tf
Normal file
@@ -0,0 +1,54 @@
|
||||
# common variables used for examples
|
||||
variable "organization_id" {
|
||||
default = "organization/organization"
|
||||
}
|
||||
|
||||
variable "project_id" {
|
||||
default = "projects/project-id"
|
||||
}
|
||||
|
||||
variable "billing_account_id" {
|
||||
default = "billing_account_id"
|
||||
}
|
||||
|
||||
variable "bucket" {
|
||||
default = "bucket"
|
||||
}
|
||||
|
||||
variable "region" {
|
||||
default = "region"
|
||||
}
|
||||
|
||||
variable "zone" {
|
||||
default = "zone"
|
||||
}
|
||||
|
||||
variable "vpc" {
|
||||
default = {
|
||||
name = "vpc_name"
|
||||
self_link = "vpc_self_link"
|
||||
}
|
||||
}
|
||||
|
||||
variable "subnet" {
|
||||
default = {
|
||||
name = "subnet_name"
|
||||
region = "subnet_region"
|
||||
cidr = "subnet_cidr"
|
||||
self_link = "subnet_self_link"
|
||||
}
|
||||
}
|
||||
|
||||
variable "kms_key" {
|
||||
default = {
|
||||
self_link = "kms_key_self_link"
|
||||
}
|
||||
}
|
||||
|
||||
variable "service_account" {
|
||||
default = {
|
||||
id = "service_account_id"
|
||||
email = "service_account_email"
|
||||
iam_email = "service_account_iam_email"
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
pytest>=4.6.0
|
||||
PyYAML>=5.3
|
||||
tftest>=1.5.2
|
||||
marko>=0.9.1
|
||||
|
||||
Reference in New Issue
Block a user