Skip to content

Commit

Permalink
Issue #108 - Added some behave tests for the CLI.
Browse files Browse the repository at this point in the history
  • Loading branch information
Rob Barry committed Aug 27, 2021
1 parent 1554590 commit 794bbbd
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 2 deletions.
41 changes: 41 additions & 0 deletions csvqb/csvqb/tests/behaviour/cli.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
Feature: Test the csvqb Command Line Interface.

Scenario: The csvqb build command should take an info.json and CSV and output CSV-Ws into the default './out' directory.
Given the existing test-case file "configloaders/data.csv"
And the existing test-case file "configloaders/info.json"
When the csvqb CLI is run with "build --config configloaders/info.json configloaders/data.csv"
Then the csvqb CLI should succeed
And the csvqb CLI should print "Creating output directory"
And the file at "out/ons-international-trade-in-services-by-subnational-areas-of-the-uk.csv" should exist
And the file at "out/ons-international-trade-in-services-by-subnational-areas-of-the-uk.csv-metadata.json" should exist
And the file at "out/validation-errors.json" should not exist

Scenario: The csvqb build command should not output CSV-Ws when validation errors occur
Given the existing test-case file "configloaders/validation-error/data.csv"
And the existing test-case file "configloaders/validation-error/info.json"
When the csvqb CLI is run with "build --config configloaders/validation-error/info.json configloaders/validation-error/data.csv"
Then the csvqb CLI should fail with status code 1
And the csvqb CLI should print "Validation Error"
And the csvqb CLI should print "Column 'Measure Type' not found in data provided"
And the file at "out/validation-error-output.csv" should not exist
And the file at "out/validation-error-output.csv-metadata.json" should not exist
And the file at "out/validation-errors.json" should not exist

Scenario: The csvqb build command should output validation errors to file
Given the existing test-case file "configloaders/validation-error/data.csv"
And the existing test-case file "configloaders/validation-error/info.json"
When the csvqb CLI is run with "build --validation-errors-to-file --config configloaders/validation-error/info.json configloaders/validation-error/data.csv"
Then the csvqb CLI should fail with status code 1
And the file at "out/validation-errors.json" should exist
And the validation-errors.json file in the "out" directory should contain
"""
Column 'Measure Type' not found in data provided
"""

Scenario: The csvqb build command should still output CSV-Ws if the user overrides validation errors
Given the existing test-case file "configloaders/validation-error/data.csv"
And the existing test-case file "configloaders/validation-error/info.json"
When the csvqb CLI is run with "build --ignore-validation-errors --config configloaders/validation-error/info.json configloaders/validation-error/data.csv"
Then the csvqb CLI should succeed
And the file at "out/validation-error-output.csv" should exist
And the file at "out/validation-error-output.csv-metadata.json" should exist
59 changes: 59 additions & 0 deletions csvqb/csvqb/tests/behaviour/steps/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from behave import when, then
import subprocess
from typing import Tuple
from devtools.behave.temporarydirectory import get_context_temp_dir_path


@when('the csvqb CLI is run with "{arguments}"')
def step_impl(context, arguments: str):
command: str = f"csvqb {arguments.strip()}"
(status_code, response) = run_command_in_temp_dir(context, command)
context.csvqb_cli_result = (status_code, response)


@then("the csvqb CLI should succeed")
def step_impl(context):
(status_code, response) = context.csvqb_cli_result
assert status_code == 0, status_code
assert "Build Complete" in response, response


@then("the csvqb CLI should fail with status code {status_code}")
def step_impl(context, status_code: str):
(status_code, response) = context.csvqb_cli_result
assert status_code == int(status_code), status_code


@then('the csvqb CLI should print "{printed_text}"')
def step_impl(context, printed_text: str):
(status_code, response) = context.csvqb_cli_result
assert printed_text in response, response


@then('the validation-errors.json file in the "{out_dir}" directory should contain')
def step_impl(context, out_dir: str):
tmp_dir_path = get_context_temp_dir_path(context)
expected_text_contents: str = context.text.strip()
validation_errors_file = tmp_dir_path / out_dir / "validation-errors.json"
assert validation_errors_file.exists()

with open(validation_errors_file, "r") as f:
file_contents = f.read()

assert expected_text_contents in file_contents, file_contents


def run_command_in_temp_dir(context, command: str) -> Tuple[int, str]:
tmp_dir_path = get_context_temp_dir_path(context)
process = subprocess.Popen(
command,
shell=True,
cwd=tmp_dir_path,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
status_code = process.wait()
response = process.stdout.read().decode("utf-8") + process.stderr.read().decode(
"utf-8"
)
return status_code, response
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Period,Location,Flow,Industry Grouping,Marker,Value,Undefined Column
2020-01,West Midlands,Imports,Barbed Wire,,20,Undefined Column Value
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"id": "validation-error-output",
"title": "Validation Error Output",
"publisher": "HM Revenue & Customs",
"description": "All bulletins provide details on percentage of one litre or less & more than one litre bottles. This information is provided on a yearly basis.",
"landingPage": "https://www.gov.uk/government/statistics/bottles-bulletin",
"datasetNotes": [
"\"UK bottles-bulletin Tables\" Excel file, latest version on page"
],
"published": "2019-02-28",
"families": [
"Trade"
],
"extract": {
"source": "XLS",
"stage": "Done"
},
"transform": {
"airtable": "recys4OhEtE0gE14P",
"columns": {
"Period": {
"parent": "http://purl.org/linked-data/sdmx/2009/dimension#refPeriod",
"value": "http://reference.data.gov.uk/id/{+period}"
},
"Measure Type": {
"dimension": "http://purl.org/linked-data/cube#measureType",
"value": "http://gss-data.org.uk/def/x/{+measure_type}",
"types": ["one-litre-and-less", "more-than-one-litre", "number-of-bottles"]
},
"Unit": {
"attribute": "http://purl.org/linked-data/sdmx/2009/attribute#unitMeasure",
"value": "http://gss-data.org.uk/def/concept/measurement-units/{+unit}"
},
"Value": {
"datatype": "integer"
}
},
"main_issue": 67
},
"sizingNotes": "",
"notes": ""
}
26 changes: 24 additions & 2 deletions devtools/devtools/behave/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,31 @@
from .temporarydirectory import get_context_temp_dir_path


@Given('the existing test-case files "{file}"')
@Given('the existing test-case file "{file}"')
def step_impl(context, file):
test_cases_dir = _get_test_cases_dir()
test_case_file = test_cases_dir / file

if not test_case_file.exists():
raise Exception(f"Could not find test-case file {file}")

temp_dir = get_context_temp_dir_path(context)
output_file_path = temp_dir.joinpath(test_case_file.relative_to(test_cases_dir))

_ensure_directory_hierarchy_exists(output_file_path.parent)

shutil.copy(test_case_file, output_file_path)


def _ensure_directory_hierarchy_exists(directory: Path):
if not directory.exists():
_ensure_directory_hierarchy_exists(directory.parent)
directory.mkdir()


@Given('the existing test-case files "{files_glob}"')
def step_impl(context, files_glob: str):
test_cases_dir = _get_test_cases_dir()

matching_files = list(test_cases_dir.rglob(f"**/{file}"))
if len(matching_files) == 0:
Expand All @@ -32,7 +54,7 @@ def step_impl(context, file):
@then('the file at "{file}" should exist')
def step_impl(context, file):
temp_dir = get_context_temp_dir_path(context)
assert (temp_dir / file).exists()
assert (temp_dir / file).exists(), file


def _get_test_cases_dir(start_dir: Path = Path(".")):
Expand Down

0 comments on commit 794bbbd

Please sign in to comment.