Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nebari validate unit tests #1938

Merged
merged 3 commits into from
Aug 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
project_name: test
amazon_web_services:
kubernetes_version: '1.0'
27 changes: 27 additions & 0 deletions tests/tests_unit/cli_validate/aws.happy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
provider: aws
namespace: dev
nebari_version: 2023.7.2.dev23+g53d17964.d20230824
project_name: test
domain: test.example.com
ci_cd:
type: none
terraform_state:
type: local
security:
keycloak:
initial_root_password: i8mawmz1ek6s9n9ms6ifgwborgryve8q
authentication:
type: password
theme:
jupyterhub:
hub_title: Nebari - test
welcome: Welcome! Learn about Nebari's features and configurations in <a href="https://www.nebari.dev/docs">the
documentation</a>. If you have any questions or feedback, reach the team on
<a href="https://www.nebari.dev/docs/community#getting-support">Nebari's support
forums</a>.
hub_subtitle: Your open source data science platform, hosted on Amazon Web Services
certificate:
type: lets-encrypt
acme_email: test@example.com
amazon_web_services:
kubernetes_version: '1.20'
27 changes: 27 additions & 0 deletions tests/tests_unit/cli_validate/azure.happy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
provider: azure
namespace: dev
nebari_version: 2023.7.2.dev23+g53d17964.d20230824
project_name: test
domain: test.example.com
ci_cd:
type: none
terraform_state:
type: local
security:
keycloak:
initial_root_password: m1s25vc4k43dxbk5jaxubxcq39n4vmjq
authentication:
type: password
theme:
jupyterhub:
hub_title: Nebari - test
welcome: Welcome! Learn about Nebari's features and configurations in <a href="https://www.nebari.dev/docs">the
documentation</a>. If you have any questions or feedback, reach the team on
<a href="https://www.nebari.dev/docs/community#getting-support">Nebari's support
forums</a>.
hub_subtitle: Your open source data science platform, hosted on Azure
certificate:
type: lets-encrypt
acme_email: test@example.com
azure:
kubernetes_version: '1.20'
27 changes: 27 additions & 0 deletions tests/tests_unit/cli_validate/do.happy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
provider: do
namespace: dev
nebari_version: 2023.7.2.dev23+g53d17964.d20230824
project_name: test
domain: test.example.com
ci_cd:
type: none
terraform_state:
type: local
security:
keycloak:
initial_root_password: m1s25vc4k43dxbk5jaxubxcq39n4vmjq
authentication:
type: password
theme:
jupyterhub:
hub_title: Nebari - test
welcome: Welcome! Learn about Nebari's features and configurations in <a href="https://www.nebari.dev/docs">the
documentation</a>. If you have any questions or feedback, reach the team on
<a href="https://www.nebari.dev/docs/community#getting-support">Nebari's support
forums</a>.
hub_subtitle: Your open source data science platform, hosted on Azure
certificate:
type: lets-encrypt
acme_email: test@example.com
digital_ocean:
kubernetes_version: '1.20.2-do.0'
27 changes: 27 additions & 0 deletions tests/tests_unit/cli_validate/gcp.happy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
provider: gcp
namespace: dev
nebari_version: 2023.7.2.dev23+g53d17964.d20230824
project_name: test
domain: test.example.com
ci_cd:
type: none
terraform_state:
type: local
security:
keycloak:
initial_root_password: m1s25vc4k43dxbk5jaxubxcq39n4vmjq
authentication:
type: password
theme:
jupyterhub:
hub_title: Nebari - test
welcome: Welcome! Learn about Nebari's features and configurations in <a href="https://www.nebari.dev/docs">the
documentation</a>. If you have any questions or feedback, reach the team on
<a href="https://www.nebari.dev/docs/community#getting-support">Nebari's support
forums</a>.
hub_subtitle: Your open source data science platform, hosted on Azure
certificate:
type: lets-encrypt
acme_email: test@example.com
google_cloud_platform:
kubernetes_version: '1.20'
2 changes: 2 additions & 0 deletions tests/tests_unit/cli_validate/local.error.extra-fields.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
project_name: test
this_is_an_error: true
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
project_name: 123invalidproject
25 changes: 25 additions & 0 deletions tests/tests_unit/cli_validate/local.happy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
provider: local
namespace: dev
nebari_version: 2023.7.2.dev23+g53d17964.d20230824
project_name: test
domain: test.example.com
ci_cd:
type: none
terraform_state:
type: local
security:
keycloak:
initial_root_password: muwti3n4d7m81c1svcgaahwhfi869yhg
authentication:
type: password
theme:
jupyterhub:
hub_title: Nebari - test
welcome: Welcome! Learn about Nebari's features and configurations in <a href="https://www.nebari.dev/docs">the
documentation</a>. If you have any questions or feedback, reach the team on
<a href="https://www.nebari.dev/docs/community#getting-support">Nebari's support
forums</a>.
hub_subtitle: Your open source data science platform, hosted
certificate:
type: lets-encrypt
acme_email: test@example.com
1 change: 1 addition & 0 deletions tests/tests_unit/cli_validate/min.happy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
project_name: test
32 changes: 7 additions & 25 deletions tests/tests_unit/test_cli_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,11 @@
from typer.testing import CliRunner

from _nebari.cli import create_cli
from _nebari.provider.cloud import (
amazon_web_services,
azure_cloud,
digital_ocean,
google_cloud,
)

runner = CliRunner()

MOCK_KUBERNETES_VERSIONS = ["1.24"]
TEST_KUBERNETES_VERSION = {"default": "1.20", "do": "1.20.2-do.0"}

MOCK_ENV = {
k: "test"
for k in [
Expand Down Expand Up @@ -95,9 +90,11 @@ def generate_test_data_test_all_init_happy_path():
for ci_provider in ["none", "github-actions", "gitlab-ci"]:
for terraform_state in ["local", "remote", "existing"]:
for email in ["noreply@example.com"]:
for (
kubernetes_version
) in MOCK_KUBERNETES_VERSIONS + ["latest"]:
for kubernetes_version in [
TEST_KUBERNETES_VERSION[provider]
if provider in TEST_KUBERNETES_VERSION
else TEST_KUBERNETES_VERSION["default"]
] + ["latest"]:
test_data.append(
(
provider,
Expand Down Expand Up @@ -129,7 +126,6 @@ def generate_test_data_test_all_init_happy_path():


def test_all_init_happy_path(
monkeypatch,
provider: str,
project_name: str,
domain_name: str,
Expand All @@ -141,20 +137,6 @@ def test_all_init_happy_path(
email: str,
kubernetes_version: str,
):
# the kubernetes-version parameter can trigger calls out to AWS, Azure, etc... to validate, mocking
monkeypatch.setattr(
amazon_web_services, "kubernetes_versions", lambda: MOCK_KUBERNETES_VERSIONS
)
monkeypatch.setattr(
azure_cloud, "kubernetes_versions", lambda: MOCK_KUBERNETES_VERSIONS
)
monkeypatch.setattr(
digital_ocean, "kubernetes_versions", lambda _: MOCK_KUBERNETES_VERSIONS
)
monkeypatch.setattr(
google_cloud, "kubernetes_versions", lambda _: MOCK_KUBERNETES_VERSIONS
)

app = create_cli()
args = [
"init",
Expand Down
140 changes: 140 additions & 0 deletions tests/tests_unit/test_cli_validate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import re
from pathlib import Path
from typing import List

import pytest
from typer.testing import CliRunner

from _nebari.cli import create_cli

TEST_DATA_DIR = Path(__file__).resolve().parent / "cli_validate"

MOCK_ENV = {
k: "test"
for k in [
"AWS_ACCESS_KEY_ID",
"AWS_SECRET_ACCESS_KEY", # aws
"GOOGLE_CREDENTIALS",
"PROJECT_ID", # gcp
"ARM_SUBSCRIPTION_ID",
"ARM_TENANT_ID",
"ARM_CLIENT_ID",
"ARM_CLIENT_SECRET", # azure
"DIGITALOCEAN_TOKEN",
"SPACES_ACCESS_KEY_ID",
"SPACES_SECRET_ACCESS_KEY", # digital ocean
]
}

runner = CliRunner()


@pytest.mark.parametrize(
"args, exit_code, content",
[
# --help
(["--help"], 0, ["Usage:"]),
(["-h"], 0, ["Usage:"]),
# error, missing args
([], 2, ["Missing option"]),
(["--config"], 2, ["requires an argument"]),
(["-c"], 2, ["requires an argument"]),
(
["--enable-commenting"],
2,
["Missing option"],
), # /~https://github.com/nebari-dev/nebari/issues/1937
],
)
def test_validate_stdout(args: List[str], exit_code: int, content: List[str]):
app = create_cli()
result = runner.invoke(app, ["validate"] + args)
assert result.exit_code == exit_code
for c in content:
assert c in result.stdout


def generate_test_data_test_validate_local_happy_path():
"""
Search the cli_validate folder for happy path test cases
and add them to the parameterized list of inputs for
test_validate_local_happy_path
"""

test_data = []
for f in TEST_DATA_DIR.iterdir():
if f.is_file() and re.match(r"^\w*\.happy\.yaml$", f.name): # sample.happy.yaml
test_data.append((f.name))
keys = [
"config_yaml",
]
return {"keys": keys, "test_data": test_data}


def test_validate_local_happy_path(config_yaml: str):
test_file = TEST_DATA_DIR / config_yaml
assert test_file.exists() is True

app = create_cli()
result = runner.invoke(app, ["validate", "--config", test_file], env=MOCK_ENV)
assert not result.exception
assert 0 == result.exit_code
assert "Successfully validated configuration" in result.stdout


def generate_test_data_test_validate_error():
"""
Search the cli_validate folder for unhappy path test cases
and add them to the parameterized list of inputs for
test_validate_error. Optionally parse an expected
error message from the file name to assert is present
in the validate output
"""

test_data = []
for f in TEST_DATA_DIR.iterdir():
if f.is_file():
m = re.match(
r"^\w*\.error\.([\w-]*)\.yaml$", f.name
) # sample.error.message.yaml
if m:
test_data.append((f.name, m.groups()[0]))
elif re.match(r"^\w*\.error\.yaml$", f.name): # sample.error.yaml
test_data.append((f.name, None))
keys = [
"config_yaml",
"expected_message",
]
return {"keys": keys, "test_data": test_data}


def test_validate_error(config_yaml: str, expected_message: str):
test_file = TEST_DATA_DIR / config_yaml
assert test_file.exists() is True

app = create_cli()
result = runner.invoke(app, ["validate", "--config", test_file], env=MOCK_ENV)
print(result.stdout)
assert result.exception
assert 1 == result.exit_code
assert "ERROR validating configuration" in result.stdout
if expected_message:
# since this will usually come from a parsed filename, assume spacing/hyphenation/case is optional
assert (expected_message in result.stdout.lower()) or (
expected_message.replace("-", " ").replace("_", " ")
in result.stdout.lower()
)


def pytest_generate_tests(metafunc):
"""
Dynamically generate test data parameters for test functions by looking for
and executing an associated generate_test_data_{function_name} if one exists.
"""

try:
td = eval(f"generate_test_data_{metafunc.function.__name__}")()
metafunc.parametrize(",".join(td["keys"]), td["test_data"])
except Exception:
# expected when a generate_test_data_ function doesn't exist
pass