From e7da799137b760386adb6da3805a6ab7743c3776 Mon Sep 17 00:00:00 2001 From: Adam Shire Date: Fri, 17 Feb 2023 16:34:45 -0500 Subject: [PATCH] Set up initial CLI command and configuration Why these changes are being introduced: CLI command structure and config need to be updated from the template repo defaults. How this addresses that need: * Adds expected command options and updates configuration as needed. * Updates tests to reflect all changes. * Updates README with descriptions for all required environemnt variables Relevant ticket(s): * https://mitlibraries.atlassian.net/browse/IN-732 --- Makefile | 5 ++- Pipfile | 4 +- Pipfile.lock | 82 ++++++++++++++++++++++------------ README.md | 15 ++++--- sapinvoices/cli.py | 86 ++++++++++++++++++++++++++++++------ sapinvoices/config.py | 35 +++++++++++++-- setup.cfg | 7 +-- tests/conftest.py | 14 +++++- tests/test_cli.py | 39 +++++++++++----- tests/test_config.py | 100 +++++++++++++++++++++++++++++++++++++++--- 10 files changed, 312 insertions(+), 75 deletions(-) diff --git a/Makefile b/Makefile index 125e3db..03b5033 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ coveralls: test ### Code quality and safety commands ### -lint: bandit black mypy pylama safety ## Run linting, code quality, and safety checks +lint: bandit black mypy pylama pydocstyle safety ## Run linting, code quality, and safety checks bandit: pipenv run bandit -r sapinvoices @@ -43,6 +43,9 @@ mypy: pylama: pipenv run pylama --options setup.cfg +pydocstyle: + pipenv run pydocstyle sapinvoices + safety: pipenv check pipenv verify diff --git a/Pipfile b/Pipfile index 50f011f..212739c 100644 --- a/Pipfile +++ b/Pipfile @@ -6,6 +6,7 @@ name = "pypi" [packages] click = "*" sentry-sdk = "*" +freezegun = "*" [dev-packages] bandit = "*" @@ -15,9 +16,10 @@ coveralls = "*" mypy = "*" pylama = {extras = ["all"], version = "*"} pytest = "*" +pydocstyle = "*" [requires] python_version = "3.11" [scripts] -sapinvoices = "python -c \"from sapinvoices.cli import main; main()\"" +sap = "python -c \"from sapinvoices.cli import sap; sap()\"" diff --git a/Pipfile.lock b/Pipfile.lock index 5baa775..665294f 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "c5be4279f566454e470fe5cf0e0e829b5611f52dd48f7be7e94d5b0eb4f5a6fc" + "sha256": "0fbe9aa925009753accdc51262129c544c932af2b66938d1b3e36282703ac373" }, "pipfile-spec": 6, "requires": { @@ -32,6 +32,22 @@ "index": "pypi", "version": "==8.1.3" }, + "freezegun": { + "hashes": [ + "sha256:cd22d1ba06941384410cd967d8a99d5ae2442f57dfafeff2fda5de8dc5c05446", + "sha256:ea1b963b993cb9ea195adbd893a48d573fda951b0da64f60883d7e988b606c9f" + ], + "index": "pypi", + "version": "==1.2.2" + }, + "python-dateutil": { + "hashes": [ + "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", + "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.8.2" + }, "sentry-sdk": { "hashes": [ "sha256:69ecbb2e1ff4db02a06c4f20f6f69cb5dfe3ebfbc06d023e40d77cf78e9c37e7", @@ -40,6 +56,14 @@ "index": "pypi", "version": "==1.15.0" }, + "six": { + "hashes": [ + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.16.0" + }, "urllib3": { "hashes": [ "sha256:076907bf8fd355cde77728471316625a4d2f7e713c125f51953bb5b3eecf4f72", @@ -413,35 +437,35 @@ }, "mypy": { "hashes": [ - "sha256:01b1b9e1ed40544ef486fa8ac022232ccc57109f379611633ede8e71630d07d2", - "sha256:0ab090d9240d6b4e99e1fa998c2d0aa5b29fc0fb06bd30e7ad6183c95fa07593", - "sha256:14d776869a3e6c89c17eb943100f7868f677703c8a4e00b3803918f86aafbc52", - "sha256:1ace23f6bb4aec4604b86c4843276e8fa548d667dbbd0cb83a3ae14b18b2db6c", - "sha256:2efa963bdddb27cb4a0d42545cd137a8d2b883bd181bbc4525b568ef6eca258f", - "sha256:2f6ac8c87e046dc18c7d1d7f6653a66787a4555085b056fe2d599f1f1a2a2d21", - "sha256:3ae4c7a99e5153496243146a3baf33b9beff714464ca386b5f62daad601d87af", - "sha256:3cfad08f16a9c6611e6143485a93de0e1e13f48cfb90bcad7d5fde1c0cec3d36", - "sha256:4e5175026618c178dfba6188228b845b64131034ab3ba52acaffa8f6c361f805", - "sha256:50979d5efff8d4135d9db293c6cb2c42260e70fb010cbc697b1311a4d7a39ddb", - "sha256:5cd187d92b6939617f1168a4fe68f68add749902c010e66fe574c165c742ed88", - "sha256:5cfca124f0ac6707747544c127880893ad72a656e136adc935c8600740b21ff5", - "sha256:5e398652d005a198a7f3c132426b33c6b85d98aa7dc852137a2a3be8890c4072", - "sha256:67cced7f15654710386e5c10b96608f1ee3d5c94ca1da5a2aad5889793a824c1", - "sha256:7306edca1c6f1b5fa0bc9aa645e6ac8393014fa82d0fa180d0ebc990ebe15964", - "sha256:7cc2c01dfc5a3cbddfa6c13f530ef3b95292f926329929001d45e124342cd6b7", - "sha256:87edfaf344c9401942883fad030909116aa77b0fa7e6e8e1c5407e14549afe9a", - "sha256:8845125d0b7c57838a10fd8925b0f5f709d0e08568ce587cc862aacce453e3dd", - "sha256:92024447a339400ea00ac228369cd242e988dd775640755fa4ac0c126e49bb74", - "sha256:a86b794e8a56ada65c573183756eac8ac5b8d3d59daf9d5ebd72ecdbb7867a43", - "sha256:bb2782a036d9eb6b5a6efcdda0986774bf798beef86a62da86cb73e2a10b423d", - "sha256:be78077064d016bc1b639c2cbcc5be945b47b4261a4f4b7d8923f6c69c5c9457", - "sha256:c7cf862aef988b5fbaa17764ad1d21b4831436701c7d2b653156a9497d92c83c", - "sha256:e0626db16705ab9f7fa6c249c017c887baf20738ce7f9129da162bb3075fc1af", - "sha256:f34495079c8d9da05b183f9f7daec2878280c2ad7cc81da686ef0b484cea2ecf", - "sha256:fe523fcbd52c05040c7bee370d66fee8373c5972171e4fbc323153433198592d" + "sha256:0af4f0e20706aadf4e6f8f8dc5ab739089146b83fd53cb4a7e0e850ef3de0bb6", + "sha256:15b5a824b58c7c822c51bc66308e759243c32631896743f030daf449fe3677f3", + "sha256:17455cda53eeee0a4adb6371a21dd3dbf465897de82843751cf822605d152c8c", + "sha256:2013226d17f20468f34feddd6aae4635a55f79626549099354ce641bc7d40262", + "sha256:24189f23dc66f83b839bd1cce2dfc356020dfc9a8bae03978477b15be61b062e", + "sha256:27a0f74a298769d9fdc8498fcb4f2beb86f0564bcdb1a37b58cbbe78e55cf8c0", + "sha256:28cea5a6392bb43d266782983b5a4216c25544cd7d80be681a155ddcdafd152d", + "sha256:448de661536d270ce04f2d7dddaa49b2fdba6e3bd8a83212164d4174ff43aa65", + "sha256:48525aec92b47baed9b3380371ab8ab6e63a5aab317347dfe9e55e02aaad22e8", + "sha256:5bc8d6bd3b274dd3846597855d96d38d947aedba18776aa998a8d46fabdaed76", + "sha256:5deb252fd42a77add936b463033a59b8e48eb2eaec2976d76b6878d031933fe4", + "sha256:5f546ac34093c6ce33f6278f7c88f0f147a4849386d3bf3ae193702f4fe31407", + "sha256:5fdd63e4f50e3538617887e9aee91855368d9fc1dea30da743837b0df7373bc4", + "sha256:65b122a993d9c81ea0bfde7689b3365318a88bde952e4dfa1b3a8b4ac05d168b", + "sha256:71a808334d3f41ef011faa5a5cd8153606df5fc0b56de5b2e89566c8093a0c9a", + "sha256:920169f0184215eef19294fa86ea49ffd4635dedfdea2b57e45cb4ee85d5ccaf", + "sha256:93a85495fb13dc484251b4c1fd7a5ac370cd0d812bbfc3b39c1bafefe95275d5", + "sha256:a2948c40a7dd46c1c33765718936669dc1f628f134013b02ff5ac6c7ef6942bf", + "sha256:c6c2ccb7af7154673c591189c3687b013122c5a891bb5651eca3db8e6c6c55bd", + "sha256:c96b8a0c019fe29040d520d9257d8c8f122a7343a8307bf8d6d4a43f5c5bfcc8", + "sha256:d42a98e76070a365a1d1c220fcac8aa4ada12ae0db679cb4d910fabefc88b994", + "sha256:dbeb24514c4acbc78d205f85dd0e800f34062efcc1f4a4857c57e4b4b8712bff", + "sha256:e60d0b09f62ae97a94605c3f73fd952395286cf3e3b9e7b97f60b01ddfbbda88", + "sha256:e64f48c6176e243ad015e995de05af7f22bbe370dbb5b32bd6988438ec873919", + "sha256:e831662208055b006eef68392a768ff83596035ffd6d846786578ba1714ba8f6", + "sha256:eda5c8b9949ed411ff752b9a01adda31afe7eae1e53e946dbdf9db23865e66c4" ], "index": "pypi", - "version": "==1.0.0" + "version": "==1.0.1" }, "mypy-extensions": { "hashes": [ @@ -504,7 +528,7 @@ "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019", "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1" ], - "markers": "python_version >= '3.6'", + "index": "pypi", "version": "==6.3.0" }, "pyflakes": { diff --git a/README.md b/README.md index dd52135..2726737 100644 --- a/README.md +++ b/README.md @@ -12,15 +12,16 @@ sets trasmitted invoice to paid in Alma - To run the app: `pipenv run sapinvoices --help` ## Required ENV - -- `SENTRY_DSN` = If set to a valid Sentry DSN, enables Sentry exception monitoring. This is not needed for local development. -- `WORKSPACE` = Set to `dev` for local development, this will be set to `stage` and `prod` in those environments by Terraform. - `ALMA_API_URL` = Base URL for making Alma API calls - `ALMA_API_READ_WRITE_KEY` = API key for making Alma API calls - `SAP_DROPBOX_CONNECTION` = JSON formatted connection information for accessing SAP dropbox -- `SAP_REPLY_TO_EMAIL` +- `SAP_REPLY_TO_EMAIL` = reply-to email on emails to SAP recipient email lists - `SAP_FINAL_RECIPIENT_EMAIL` = moira list to recieves final run emails - `SAP_REVIEW_RECIPIENT_EMAIL` = moira list to recieve review run emails -- `SES_SEND_FROM_EMAIL` -- `SSM_PATH` -- `LOG_LEVEL` +- `SES_SEND_FROM_EMAIL` = email address that SES sends from +- `SSM_PATH` = the path to ssm variables +- `WORKSPACE` = Set to `dev` for local development, this will be set to `stage` and `prod` in those environments by Terraform. + +## Optional ENV +- `LOG_LEVEL` = Optional, set to a valid Python logging level (e.g. DEBUG, case-insensitive) if desired. Can also be passed as an option directly to the ccslips command. Defaults to INFO if not set or passed to the command. +- `SENTRY_DSN` = If set to a valid Sentry DSN, enables Sentry exception monitoring. This is not needed for local development. \ No newline at end of file diff --git a/sapinvoices/cli.py b/sapinvoices/cli.py index 228d5d0..cb6f55e 100644 --- a/sapinvoices/cli.py +++ b/sapinvoices/cli.py @@ -1,28 +1,88 @@ +import datetime import logging -from datetime import timedelta -from time import perf_counter +from typing import Optional import click -from sapinvoices.config import configure_logger, configure_sentry +from sapinvoices.config import configure_logger, configure_sentry, load_config_values logger = logging.getLogger(__name__) -@click.command() +@click.group() +@click.pass_context +def sap(ctx: click.Context) -> None: + ctx.ensure_object(dict) + ctx.obj["today"] = datetime.datetime.today() + + +@sap.command() +@click.pass_context +def create_sandbox_data(ctx: click.Context) -> None: + """Create sample data in the Alma sandbox instance. + + In order to run successfully, the sandbox Acquisitions read/write API key must be + set in config (in .env if running locally, or in SSM if on stage). This command + will not run in the production environment, and should never be run with production + config values. + """ + logger.info("Creating sample data in Alma sandbox for today: %s", ctx.obj["today"]) + click.echo("sap data gets created in the sandbox...") + + +@sap.command() +@click.option( + "--final-run", + is_flag=True, + help="Flag to indicate this is a final run and should include all steps of the " + "process. Default if this flag is not passed is to do a review run, which only " + "creates and sends summary and report files for review by stakeholders. Note: some " + "steps of a final run will not be completed unless the '--real-run' flag is also " + "passed, however that will write data to external systems and should thus be used " + "with caution. See '--real-run' option documentation for details.", +) +@click.option( + "--real-run", + is_flag=True, + help="USE WITH CAUTION. If '--real-run' flag is passed, files will be emailed " + "to stakeholders and, if the '--final-run' flag is also passed, invoices will be " + "sent to SAP and marked as paid in Alma. If this flag is not passed, this command " + "defaults to a dry run, in which files will not be emailed or sent to SAP, instead " + "their contents will be logged for review, and invoices will also not be marked as " + "paid in Alma.", +) @click.option( - "-v", "--verbose", is_flag=True, help="Pass to log at debug level instead of info" + "-l", + "--log-level", + envvar="LOG_LEVEL", + help="Case-insensitive Python log level to use, e.g. debug or warning. Defaults to " + "INFO if not provided or found in ENV.", ) -def main(verbose: bool) -> None: - start_time = perf_counter() +@click.pass_context +def process_invoices( + ctx: click.Context, final_run: bool, real_run: bool, log_level: Optional[str] +) -> None: + """Process invoices for payment via SAP. + + Retrieves "Waiting to be sent" invoices from Alma, extracts and formats data + needed for submission to SAP for payment. If not a final run, creates and sends + formatted review reports to Acquisitions staff. If a final run, creates and sends + formatted cover sheets and summary reports to Acquisitions staff, submits data and + control files to SAP, and marks invoices as paid in Alma after submission to SAP. + """ + config_values = load_config_values() + log_level = log_level or "INFO" root_logger = logging.getLogger() - logger.info(configure_logger(root_logger, verbose)) + logger.info(configure_logger(root_logger, log_level)) logger.info(configure_sentry()) - logger.info("Running process") - - # Do things here! - elapsed_time = perf_counter() - start_time logger.info( - "Total time to complete process: %s", str(timedelta(seconds=elapsed_time)) + "alma-sapinvoices config settings loaded for environment: %s", + config_values["WORKSPACE"], ) + + logger.info("Starting SAP invoices process with options: \n") + logger.info("Date: %s \n", ctx.obj["today"]) + logger.info("Final run: %s \n", final_run) + logger.info("Real run: %s", real_run) + click.echo("invoice processing happens...") diff --git a/sapinvoices/config.py b/sapinvoices/config.py index a8d65c0..1a25f39 100644 --- a/sapinvoices/config.py +++ b/sapinvoices/config.py @@ -3,21 +3,36 @@ import sentry_sdk +EXPECTED_ENVIRONMENT_VARIABLES = [ + "ALMA_API_URL", + "ALMA_API_READ_WRITE_KEY", + "SAP_DROPBOX_CONNECTION", + "SAP_REPLY_TO_EMAIL", + "SAP_FINAL_RECIPIENT_EMAIL", + "SAP_REVIEW_RECIPIENT_EMAIL", + "SES_SEND_FROM_EMAIL", + "SSM_PATH", + "WORKSPACE", +] -def configure_logger(logger: logging.Logger, verbose: bool) -> str: - if verbose: + +def configure_logger(logger: logging.Logger, log_level_string: str) -> str: + if log_level_string.upper() not in logging.getLevelNamesMapping(): + raise ValueError(f"'{log_level_string}' is not a valid Python logging level") + log_level = logging.getLevelName(log_level_string.upper()) + if log_level < 20: logging.basicConfig( format="%(asctime)s %(levelname)s %(name)s.%(funcName)s() line %(lineno)d: " "%(message)s" ) - logger.setLevel(logging.DEBUG) + logger.setLevel(log_level) for handler in logging.root.handlers: handler.addFilter(logging.Filter("sapinvoices")) else: logging.basicConfig( format="%(asctime)s %(levelname)s %(name)s.%(funcName)s(): %(message)s" ) - logger.setLevel(logging.INFO) + logger.setLevel(log_level) return ( f"Logger '{logger.name}' configured with level=" f"{logging.getLevelName(logger.getEffectiveLevel())}" @@ -31,3 +46,15 @@ def configure_sentry() -> str: sentry_sdk.init(sentry_dsn, environment=env) return f"Sentry DSN found, exceptions will be sent to Sentry with env={env}" return "No Sentry DSN found, exceptions will not be sent to Sentry" + + +def load_config_values() -> dict: + settings = { + variable: os.environ[variable] for variable in EXPECTED_ENVIRONMENT_VARIABLES + } + if "prod" in settings["SSM_PATH"] and settings["WORKSPACE"] != "prod": + raise RuntimeError( + "Production SSM_PATH may ONLY be used in the production " + "environment. Check your env variables and try again." + ) + return settings diff --git a/setup.cfg b/setup.cfg index cc8b645..51d1e32 100644 --- a/setup.cfg +++ b/setup.cfg @@ -8,14 +8,15 @@ ignore_missing_imports = True [pylama] ignore = C0114,C0116,D100,D103,W0012 -linters = eradicate,isort,mccabe,pycodestyle,pydocstyle,pyflakes,pylint +linters = eradicate,isort,mccabe,pycodestyle,pyflakes,pylint max_line_length = 90 [pylama:isort] profile = black -[pylama:pydocstyle] -convention = pep257 +[pydocstyle] +ignore = D100,D103,D213 + [tool:pytest] log_level = DEBUG diff --git a/tests/conftest.py b/tests/conftest.py index 5072cf1..176af28 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -6,7 +6,19 @@ @pytest.fixture(autouse=True) def test_env(): - os.environ = {"SENTRY_DSN": None, "WORKSPACE": "test"} + os.environ = { + "ALMA_API_URL": "test", + "ALMA_API_READ_WRITE_KEY": "test", + "LOG_LEVEL": "DEBUG", + "SAP_DROPBOX_CONNECTION": "test", + "SAP_REPLY_TO_EMAIL": "test", + "SAP_FINAL_RECIPIENT_EMAIL": "test", + "SAP_REVIEW_RECIPIENT_EMAIL": "test", + "SENTRY_DSN": None, + "SES_SEND_FROM_EMAIL": "test", + "SSM_PATH": "test", + "WORKSPACE": "test", + } yield diff --git a/tests/test_cli.py b/tests/test_cli.py index 8b37cea..f62f673 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,17 +1,34 @@ -from sapinvoices.cli import main +import pytest +from sapinvoices.cli import sap -def test_cli_no_options(caplog, runner): - result = runner.invoke(main) + +def test_create_sandbox_sap_data_(runner): + result = runner.invoke(sap, ["create-sandbox-data"]) + assert result.exit_code == 0 + + +def test_sap_invoices_review_run(runner): + result = runner.invoke(sap, ["process-invoices"]) + assert result.exit_code == 0 + + +@pytest.mark.xfail +def test_sap_invoices_review_run_no_invoices(runner): + result = runner.invoke(sap, ["process-invoices"]) + assert result.exit_code == 1 + + +def test_sap_invoices_review_run_real_run(runner): + result = runner.invoke(sap, ["process-invoices", "--real-run"]) + assert result.exit_code == 0 + + +def test_sap_invoices_final_run(runner): + result = runner.invoke(sap, ["process-invoices", "--final-run"]) assert result.exit_code == 0 - assert "Logger 'root' configured with level=INFO" in caplog.text - assert "Running process" in caplog.text - assert "Total time to complete process" in caplog.text -def test_cli_all_options(caplog, runner): - result = runner.invoke(main, ["--verbose"]) +def test_sap_invoices_final_run_real_run(runner): + result = runner.invoke(sap, ["process-invoices", "--final-run", "--real-run"]) assert result.exit_code == 0 - assert "Logger 'root' configured with level=DEBUG" in caplog.text - assert "Running process" in caplog.text - assert "Total time to complete process" in caplog.text diff --git a/tests/test_config.py b/tests/test_config.py index 9195f28..ecba938 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,22 +1,45 @@ import logging -from sapinvoices.config import configure_logger, configure_sentry +import pytest +from sapinvoices.config import configure_logger, configure_sentry, load_config_values -def test_configure_logger_not_verbose(): + +def test_configure_logger_with_invalid_level_raises_error(): logger = logging.getLogger(__name__) - result = configure_logger(logger, verbose=False) + with pytest.raises(ValueError) as error: + configure_logger(logger, log_level_string="oops") + assert "'oops' is not a valid Python logging level" in str(error) + + +def test_configure_logger_info_level_or_higher(): + logger = logging.getLogger(__name__) + result = configure_logger(logger, log_level_string="info") assert logger.getEffectiveLevel() == 20 assert result == "Logger 'tests.test_config' configured with level=INFO" -def test_configure_logger_verbose(): +def test_configure_logger_debug_level_or_lower(): logger = logging.getLogger(__name__) - result = configure_logger(logger, verbose=True) + result = configure_logger(logger, log_level_string="DEBUG") assert logger.getEffectiveLevel() == 10 assert result == "Logger 'tests.test_config' configured with level=DEBUG" +def test_configure_sap_invoices_settings_from_env(): + assert load_config_values() == { + "ALMA_API_URL": "test", + "ALMA_API_READ_WRITE_KEY": "test", + "SAP_DROPBOX_CONNECTION": "test", + "SAP_REPLY_TO_EMAIL": "test", + "SAP_FINAL_RECIPIENT_EMAIL": "test", + "SAP_REVIEW_RECIPIENT_EMAIL": "test", + "SES_SEND_FROM_EMAIL": "test", + "SSM_PATH": "test", + "WORKSPACE": "test", + } + + def test_configure_sentry_no_env_variable(monkeypatch): monkeypatch.delenv("SENTRY_DSN", raising=False) result = configure_sentry() @@ -33,3 +56,70 @@ def test_configure_sentry_env_variable_is_dsn(monkeypatch): monkeypatch.setenv("SENTRY_DSN", "https://1234567890@00000.ingest.sentry.io/123456") result = configure_sentry() assert result == "Sentry DSN found, exceptions will be sent to Sentry with env=test" + + +def test_load_config_values_missing_config_raises_error(monkeypatch): + with pytest.raises(KeyError): + monkeypatch.delenv("ALMA_API_URL", raising=False) + load_config_values() + + +def test_load_config_values_success(): + assert load_config_values() == { + "ALMA_API_URL": "test", + "ALMA_API_READ_WRITE_KEY": "test", + "SAP_DROPBOX_CONNECTION": "test", + "SAP_REPLY_TO_EMAIL": "test", + "SAP_FINAL_RECIPIENT_EMAIL": "test", + "SAP_REVIEW_RECIPIENT_EMAIL": "test", + "SES_SEND_FROM_EMAIL": "test", + "SSM_PATH": "test", + "WORKSPACE": "test", + } + + +def test_load_config_ssm_safety_check_raises_error(monkeypatch): + monkeypatch.setenv("WORKSPACE", "whatever") + monkeypatch.setenv("SSM_PATH", "/test/example/prod") + with pytest.raises(RuntimeError) as error: + load_config_values() + assert str(error.value) == ( + "Production SSM_PATH may ONLY be used in the production environment. " + "Check your env variables and try again." + ) + + +def test_load_config_ssm_safety_check_does_not_raise_error_in_prod(monkeypatch): + monkeypatch.setenv("WORKSPACE", "prod") + monkeypatch.setenv("SSM_PATH", "/test/example/prod") + + assert load_config_values() == { + "ALMA_API_URL": "test", + "ALMA_API_READ_WRITE_KEY": "test", + "SAP_DROPBOX_CONNECTION": "test", + "SAP_REPLY_TO_EMAIL": "test", + "SAP_FINAL_RECIPIENT_EMAIL": "test", + "SAP_REVIEW_RECIPIENT_EMAIL": "test", + "SES_SEND_FROM_EMAIL": "test", + "SSM_PATH": "/test/example/prod", + "WORKSPACE": "prod", + } + + +def test_load_config_ssm_safety_check_does_not_raise_error_with_not_prod_path( + monkeypatch, +): + monkeypatch.setenv("WORKSPACE", "prod") + monkeypatch.setenv("SSM_PATH", "/test/example/dev") + + assert load_config_values() == { + "ALMA_API_URL": "test", + "ALMA_API_READ_WRITE_KEY": "test", + "SAP_DROPBOX_CONNECTION": "test", + "SAP_REPLY_TO_EMAIL": "test", + "SAP_FINAL_RECIPIENT_EMAIL": "test", + "SAP_REVIEW_RECIPIENT_EMAIL": "test", + "SES_SEND_FROM_EMAIL": "test", + "SSM_PATH": "/test/example/dev", + "WORKSPACE": "prod", + }