From f276c028dd4869a97129140cea28f02f3889ac47 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sat, 16 May 2020 10:04:53 +0300 Subject: feat(subplot.md): add acceptance criteria for cleanup functionality Add acceptance checks for the cleanup functionality, for Python and Bash templates. --- subplot.md | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ subplot.py | 30 ++++++++-- subplot.yaml | 16 +++++- 3 files changed, 225 insertions(+), 6 deletions(-) diff --git a/subplot.md b/subplot.md index 05b9341..f0dfa9b 100644 --- a/subplot.md +++ b/subplot.md @@ -691,6 +691,191 @@ then bar was done ~~~~ +## Automatic cleanup in scenarios + +A binding can define a cleanup function, which gets called at the end +of the scenario in reverse order for the successful steps. If a step +fails, all the cleanups for the successful steps are still called. We +test this for every language templat we support. + +~~~{#cleanup.yaml .file .yaml .numberLines} +- given: foo + function: foo + cleanup: foo_cleanup +- given: bar + function: bar + cleanup: bar_cleanup +- given: failure + function: failure + cleanup: failure_cleanup +~~~ + +~~~{#cleanup.py .file .python .numberLines} +def foo(ctx): + pass +def foo_cleanup(ctx): + pass +def bar(ctx): + pass +def bar_cleanup(ctx): + pass +def failure(ctx): + assert 0 +def failure_cleanup(ctx): + pass +~~~ + +~~~{#cleanup.sh .file .bash .numberLines} +foo() { + true +} +foo_cleanup() { + true +} +bar() { + true +} +bar_cleanup() { + true +} +failure() { + return 1 +} +failure_cleanup() { + true +} +~~~ + + +### Cleanup functions gets called on success (Python) + +~~~scenario +given file cleanup-success-python.md +and file cleanup.yaml +and file cleanup.py +when I run sp-codegen --run cleanup-success-python.md -o test.py +then scenario "Cleanup" was run +and step "given foo" was run, and then step "given bar" +and cleanup for "given bar" was run, and then for "given foo" +and program finished successfully +~~~ + + +~~~~~{#cleanup-success-python.md .file .markdown .numberLines} +--- +title: Cleanup +bindings: cleanup.yaml +functions: cleanup.py +template: python +... + +# Cleanup + +~~~scenario +given foo +given bar +~~~ +~~~~~ + + +### Cleanup functions get called on failure (Python) + +~~~scenario +given file cleanup-fail-python.md +and file cleanup.yaml +and file cleanup.py +when I try to run sp-codegen --run cleanup-fail-python.md -o test.py +then scenario "Cleanup" was run +and step "given foo" was run, and then step "given bar" +and cleanup for "given bar" was run, and then for "given foo" +and cleanup for "given failure" was not run +and exit code is non-zero +~~~ + +~~~~~{#cleanup-fail-python.md .file .markdown .numberLines} +--- +title: Cleanup +bindings: cleanup.yaml +functions: cleanup.py +template: python +... + +# Cleanup + +~~~scenario +given foo +given bar +given failure +~~~ +~~~~~ + + +### Cleanup functions gets called on success (Bash) + +~~~scenario +given file cleanup-success-bash.md +and file cleanup.yaml +and file cleanup.sh +when I run sp-codegen --run cleanup-success-bash.md -o test.sh +then scenario "Cleanup" was run +and step "given foo" was run, and then step "given bar" +and cleanup for "given bar" was run, and then for "given foo" +and program finished successfully +~~~ + +~~~~~{#cleanup-success-bash.md .file .markdown .numberLines} +--- +title: Cleanup +bindings: cleanup.yaml +functions: cleanup.sh +template: bash +... + +# Cleanup + +~~~scenario +given foo +given bar +~~~ +~~~~~ + + +### Cleanup functions get called on failure (Bash) + +If a step fails, all the cleanups for the preceding steps are still +called, in reverse order. + +~~~scenario +given file cleanup-fail-bash.md +and file cleanup.yaml +and file cleanup.sh +when I try to run sp-codegen --run cleanup-fail-bash.md -o test.sh +then scenario "Cleanup" was run +and step "given foo" was run, and then step "given bar" +and cleanup for "given bar" was run, and then for "given foo" +and cleanup for "given failure" was not run +and exit code is non-zero +~~~ + +~~~~~{#cleanup-fail-bash.md .file .markdown .numberLines} +--- +title: Cleanup +bindings: cleanup.yaml +functions: cleanup.sh +template: bash +... + +# Cleanup + +~~~scenario +given foo +given bar +given failure +~~~ +~~~~~ + + + ## Capturing parts of steps for functions A scenario step binding can capture parts of a scenario step, to be diff --git a/subplot.py b/subplot.py index 1495553..e586b53 100644 --- a/subplot.py +++ b/subplot.py @@ -35,14 +35,14 @@ def run_docgen_with_date(ctx, md=None, output=None, date=None): exit_code_zero(ctx) -def try_codegen_and_program(ctx, filename=None): +def try_codegen_and_program(ctx, filename=None, testprog=None): codegen = binary("sp-codegen") tmpldir = os.path.join(srcdir, "templates") - runcmd(ctx, [codegen, filename, "-o", "test.py", "--run", "--templates", tmpldir]) + runcmd(ctx, [codegen, filename, "-o", testprog, "--run", "--templates", tmpldir]) -def run_codegen_and_program(ctx, filename=None): - try_codegen_and_program(ctx, filename=filename) +def run_codegen_and_program(ctx, filename=None, testprog=None): + try_codegen_and_program(ctx, filename=filename, testprog=testprog) exit_code_zero(ctx) @@ -111,6 +111,28 @@ def step_was_run(ctx, keyword=None, name=None): stdout_matches(ctx, pattern="\n step: {} {}\n".format(keyword, name)) +def step_was_run_and_then(ctx, keyword1=None, name1=None, keyword2=None, name2=None): + stdout_matches( + ctx, + pattern="\n step: {} {}\n step: {} {}".format( + keyword1, name1, keyword2, name2 + ), + ) + + +def cleanup_was_run(ctx, keyword1=None, name1=None, keyword2=None, name2=None): + stdout_matches( + ctx, + pattern="\n cleanup: {} {}\n cleanup: {} {}\n".format( + keyword1, name1, keyword2, name2 + ), + ) + + +def cleanup_was_not_run(ctx, keyword=None, name=None): + stdout_does_not_match(ctx, pattern="\n cleanup: {} {}\n".format(keyword, name)) + + def exit_code_zero(ctx): if ctx.get("exit") != 0: print("context:", ctx.as_dict()) diff --git a/subplot.yaml b/subplot.yaml index 607e361..8d4187f 100644 --- a/subplot.yaml +++ b/subplot.yaml @@ -17,13 +17,13 @@ - when: I try to run sp-docgen {md} -o {output} function: try_docgen -- when: I run sp-codegen --run {filename} -o test.py +- when: I run sp-codegen --run {filename} -o {testprog} function: run_codegen_and_program - when: I run sp-codegen {filename} -o {testprog} function: run_codegen -- when: I try to run sp-codegen --run {filename} -o test.py +- when: I try to run sp-codegen --run {filename} -o {testprog} function: try_codegen_and_program - when: I run python3 {testprog} {pattern} @@ -84,6 +84,18 @@ function: step_was_run regex: true +- then: step "(?Pgiven|when|then) (?P.+)" was run, and then step "(?Pgiven|when|then) (?P.+)" + function: step_was_run_and_then + regex: true + +- then: cleanup for "(?Pgiven|when|then) (?P.+)" was run, and then for "(?Pgiven|when|then) (?P.+)" + function: cleanup_was_run + regex: true + +- then: cleanup for "(?Pgiven|when|then) (?P.+)" was not run + function: cleanup_was_not_run + regex: true + - then: program finished successfully function: exit_code_zero -- cgit v1.2.1