Skip to content

Commit

Permalink
feat: add unit tests for json syntax validation
Browse files Browse the repository at this point in the history
  • Loading branch information
Yifan Zhang committed Aug 1, 2023
1 parent 2aefed9 commit 1348011
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 9 deletions.
3 changes: 3 additions & 0 deletions gdk/common/exceptions/error_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
"Recipe file not found. "
"Please ensure that the component's recipe file is initialized as either recipe.json or recipe.yaml."
)
MULTIPLE_INPUT_RECIPES_EXIST = (
"Both JSON and YAML recipe files found. Only one recipe file (JSON or YAML) should exist."
)

# CLI MODEL
INVALID_CLI_MODEL = "CLI model is invalid. Please provide a valid model to create the CLI parser."
Expand Down
19 changes: 10 additions & 9 deletions gdk/common/validate_user_input_recipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ def get_recipe():
# validate the json recipe syntax
recipe_data = validate_recipe_syntax(user_recipe_file)

# TODO: validate the user-input recipe file

return recipe_data


Expand All @@ -36,7 +34,7 @@ def get_user_input_recipe_file():
Looks for user input-recipe file in the current work directory of the command.
Raises an exception if the recipe file is not present.
Raises an exception if both JSON and YAML recipe files are present or if no recipe file is found.
Parameters
----------
Expand All @@ -47,12 +45,15 @@ def get_user_input_recipe_file():
recipe_file(pathlib.Path): Path of the recipe file.
"""
recipe_file_json = Path(utils.get_current_directory()).joinpath(consts.user_input_recipe_json).resolve()
if not utils.file_exists(recipe_file_json):
recipe_file_yaml = Path(utils.get_current_directory()).joinpath(consts.user_input_recipe_yaml).resolve()
if not utils.file_exists(recipe_file_yaml):
raise Exception(error_messages.USER_INPUT_RECIPE_NOT_EXISTS)
return recipe_file_yaml
return recipe_file_json
recipe_file_yaml = Path(utils.get_current_directory()).joinpath(consts.user_input_recipe_yaml).resolve()

if utils.file_exists(recipe_file_json) and utils.file_exists(recipe_file_yaml):
raise Exception(error_messages.MULTIPLE_INPUT_RECIPES_EXIST)

if not utils.file_exists(recipe_file_json) and not utils.file_exists(recipe_file_yaml):
raise Exception(error_messages.USER_INPUT_RECIPE_NOT_EXISTS)

return recipe_file_json if utils.file_exists(recipe_file_json) else recipe_file_yaml

Check warning on line 56 in gdk/common/validate_user_input_recipe.py

View check run for this annotation

Codecov / codecov/patch

gdk/common/validate_user_input_recipe.py#L56

Added line #L56 was not covered by tests


def validate_recipe_syntax(recipe_file):
Expand Down
135 changes: 135 additions & 0 deletions tests/gdk/common/test_validate_user_input_recipe.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import json
from pathlib import Path

import pytest

import gdk.common.validate_user_input_recipe as recipe
from gdk.common.exceptions import error_messages


def test_get_recipe_valid_recipe_found(mocker):
expected_recipe = {
"RecipeFormatVersion": "2020-01-25",
"ComponentName": "com.example.HelloWorld",
"ComponentVersion": "1.0.0",
"ComponentDescription": "My first Greengrass component.",
"ComponentPublisher": "Amazon",
"ComponentConfiguration": {
"DefaultConfiguration": {
"Message": "world",
"SampleList": [
"1",
"2",
"3"
],
"SampleNestedList": [
[
"1"
],
[
"2"
],
[
"3"
]
],
"SampleMap": {
"key1": "value1",
"key2": {
"key3": [
"value2",
"value3"
],
"key4": {
"key41": "value4"
}
}
}
}
},
"Manifests": [
{
"Platform": {
"os": "linux"
},
"Lifecycle": {
"Run": "python3 -u {artifacts:path}/hello_world.py '{configuration:/Message}'"
},
"Artifacts": [
{
"URI": "s3://DOC-EXAMPLE-BUCKET/artifacts/com.example.HelloWorld/1.0.0/hello_world.py"
}
]
}
]
}

mock_get_recipe_file = mocker.patch(
"gdk.common.validate_user_input_recipe.get_user_input_recipe_file",
return_value=Path(".").joinpath("tests/gdk/static/project_utils").joinpath("valid_component_recipe.json"),
)

assert recipe.get_recipe() == expected_recipe
assert mock_get_recipe_file.called


def test_get_recipe_invalid_recipe_file(mocker):
mock_get_recipe_file = mocker.patch(
"gdk.common.validate_user_input_recipe.get_user_input_recipe_file",
return_value=Path(".").joinpath("tests/gdk/static/project_utils").joinpath("invalid_component_recipe.json"),
)

with pytest.raises(SystemExit) as exit_info:
recipe.get_recipe()

assert mock_get_recipe_file.called
# Assert that the exit code is 1
assert exit_info.type == SystemExit
assert exit_info.value.code == 1


def test_no_recipe_file_exists(mocker):
mock_file_exists = mocker.patch("gdk.common.utils.file_exists", return_value=False)

with pytest.raises(Exception) as err:
recipe.get_user_input_recipe_file()
assert err.value.args[0] == error_messages.USER_INPUT_RECIPE_NOT_EXISTS
assert mock_file_exists.called


def test_both_recipe_file_exists(mocker):
mock_file_exists = mocker.patch("gdk.common.utils.file_exists", return_value=True)

with pytest.raises(Exception) as err:
recipe.get_user_input_recipe_file()
assert err.value.args[0] == error_messages.MULTIPLE_INPUT_RECIPES_EXIST
assert mock_file_exists.called


# Mock the open function and its return value
@pytest.fixture
def mock_open(mocker):
m = mocker.mock_open()
m.return_value.__iter__ = lambda self: self
m.return_value.__next__ = lambda self: self.readline()
return m


def test_validate_recipe_syntax_invalid_json(mocker, mock_open):
invalid_json_content = '{"key": "value"'
mock_open(invalid_json_content)
mocker.patch("builtins.open", mock_open)

with pytest.raises(SystemExit) as e:
recipe.validate_recipe_syntax("invalid_recipe.json")

assert e.type == SystemExit
assert e.value.code == 1


def test_parse_json_error(caplog):
error_message = "Expecting property name enclosed in double quotes: line 1 column 3 (char 2)"
recipe.parse_json_error(json.JSONDecodeError(error_message, "", 1))
assert "Expecting property name enclosed in double quotes" in caplog.text
assert "line 1" in caplog.text
assert "If none of the above is the cause, please review the overall JSON syntax and resolve any issues." in caplog.text

0 comments on commit 1348011

Please sign in to comment.