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

SaaS connector test refactoring #1795

Merged
merged 16 commits into from
Mar 6, 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ The types of changes are:
* Improve "Upload a new dataset YAML" [#1531](https://github.com/ethyca/fides/pull/2258)
* Access and erasure support for Yotpo [#2708](https://github.com/ethyca/fides/pull/2708)
* Allow SendGrid template usage [#2728](https://github.com/ethyca/fides/pull/2728)
* Added ConnectorRunner to simplify SaaS connector testing [#1795](https://github.com/ethyca/fides/pull/1795)

### Changed

Expand Down
23 changes: 8 additions & 15 deletions data/saas/config/zendesk_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@ saas_config:
fides_key: <instance_fides_key>
name: Zendesk SaaS Config
type: zendesk
description: A sample schema representing the Zendesk connector for Fidesops
description: A sample schema representing the Zendesk connector for Fides
version: 0.0.1

connector_params:
- name: domain
- name: username
- name: api_key
- name: page_size

client_config:
protocol: https
Expand All @@ -28,7 +27,7 @@ saas_config:
value: test@ethyca

endpoints:
- name: users
- name: user
requests:
read:
method: GET
Expand All @@ -47,7 +46,7 @@ saas_config:
- name: user_id
references:
- dataset: <instance_fides_key>
field: users.id
field: user.id
direction: from
- name: user_identities
requests:
Expand All @@ -56,15 +55,13 @@ saas_config:
path: /api/v2/users/<user_id>/identities.json
query_params:
- name: page[size]
value: <page_size>
value: 100
param_values:
- name: user_id
references:
- dataset: <instance_fides_key>
field: users.id
field: user.id
direction: from
- name: page_size
connector_param: page_size
data_path: identities
pagination:
strategy: link
Expand All @@ -78,15 +75,13 @@ saas_config:
path: /api/v2/users/<user_id>/tickets/requested.json
query_params:
- name: page[size]
value: <page_size>
value: 100
param_values:
- name: user_id
references:
- dataset: <instance_fides_key>
field: users.id
field: user.id
direction: from
- name: page_size
connector_param: page_size
data_path: tickets
pagination:
strategy: link
Expand All @@ -109,15 +104,13 @@ saas_config:
path: /api/v2/tickets/<ticket_id>/comments.json
query_params:
- name: page[size]
value: <page_size>
value: 100
param_values:
- name: ticket_id
references:
- dataset: <instance_fides_key>
field: tickets.id
direction: from
- name: page_size
connector_param: page_size
data_path: comments
pagination:
strategy: link
Expand Down
4 changes: 2 additions & 2 deletions data/saas/dataset/zendesk_dataset.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
dataset:
- fides_key: <instance_fides_key>
name: Zendesk Dataset
description: A sample dataset representing the Zendesk connector for Fidesops
description: A sample dataset representing the Zendesk connector for Fides
collections:
- name: users
- name: user
fields:
- name: id
data_categories: [system.operations]
Expand Down
69 changes: 69 additions & 0 deletions data/saas/saas_connector_scaffolding/new_fixtures.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from typing import Any, Dict, Generator

import pydash
import pytest

from tests.ops.integration_tests.saas.connector_runner import (
ConnectorRunner,
generate_random_email,
)
from tests.ops.test_helpers.vault_client import get_secrets

secrets = get_secrets("{{ connector_id }}")


@pytest.fixture(scope="session")
def {{ connector_id }}_secrets(saas_config) -> Dict[str, Any]:
return {
"domain": pydash.get(saas_config, "{{ connector_id }}.domain")
or secrets["domain"]
# add the rest of your secrets here
}


@pytest.fixture(scope="session")
def {{ connector_id }}_identity_email(saas_config) -> str:
return (
pydash.get(saas_config, "{{ connector_id }}.identity_email") or secrets["identity_email"]
)


@pytest.fixture
def {{ connector_id }}_erasure_identity_email() -> str:
return generate_random_email()


@pytest.fixture
def {{ connector_id }}_external_references() -> Dict[str, Any]:
return {}


@pytest.fixture
def {{ connector_id }}_erasure_external_references() -> Dict[str, Any]:
return {}


@pytest.fixture
def {{ connector_id }}_erasure_data(
{{ connector_id }}_erasure_identity_email: str,
) -> Generator:
# create the data needed for erasure tests here
yield {}


@pytest.fixture
def {{ connector_id }}_runner(
db,
cache,
{{ connector_id }}_secrets,
{{ connector_id }}_external_references,
{{ connector_id }}_erasure_external_references,
) -> ConnectorRunner:
return ConnectorRunner(
db,
cache,
"{{ connector_id }}",
{{ connector_id }}_secrets,
external_references={{ connector_id }}_external_references,
erasure_external_references={{ connector_id }}_erasure_external_references,
)
51 changes: 51 additions & 0 deletions data/saas/saas_connector_scaffolding/test_new_task.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import pytest

from fides.api.ops.models.policy import Policy
from tests.ops.integration_tests.saas.connector_runner import ConnectorRunner


@pytest.mark.integration_saas
class Test{{ connector_name }}Connector:
def test_connection(self, {{ connector_id }}_runner: ConnectorRunner):
{{ connector_id }}_runner.test_connection()

async def test_access_request(
self, {{ connector_id }}_runner: ConnectorRunner, policy, {{ connector_id }}_identity_email: str
):
access_results = await {{ connector_id }}_runner.access_request(
access_policy=policy, identities={"email": {{ connector_id }}_identity_email}
)

async def test_strict_erasure_request(
self,
{{ connector_id }}_runner: ConnectorRunner,
policy: Policy,
erasure_policy_string_rewrite: Policy,
{{ connector_id }}_erasure_identity_email: str,
{{ connector_id }}_erasure_data,
):
(
access_results,
erasure_results,
) = await {{ connector_id }}_runner.strict_erasure_request(
access_policy=policy,
erasure_policy=erasure_policy_string_rewrite,
identities={"email": {{ connector_id }}_erasure_identity_email},
)

async def test_non_strict_erasure_request(
self,
{{ connector_id }}_runner: ConnectorRunner,
policy: Policy,
erasure_policy_string_rewrite: Policy,
{{ connector_id }}_erasure_identity_email: str,
{{ connector_id }}_erasure_data,
):
(
access_results,
erasure_results,
) = await {{ connector_id }}_runner.non_strict_erasure_request(
access_policy=policy,
erasure_policy=erasure_policy_string_rewrite,
identities={"email": {{ connector_id }}_erasure_identity_email},
)
57 changes: 57 additions & 0 deletions noxfiles/utils_nox.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""Contains various utility-related nox sessions."""
from pathlib import Path

import nox

from constants_nox import COMPOSE_FILE, INTEGRATION_COMPOSE_FILE, TEST_ENV_COMPOSE_FILE
Expand Down Expand Up @@ -60,3 +62,58 @@ def teardown(session: nox.Session) -> None:
def install_requirements(session: nox.Session) -> None:
session.install("-r", "requirements.txt")
session.install("-r", "dev-requirements.txt")


@nox.session()
def init_saas_connector(session: nox.Session) -> None:
connector_name = session.posargs[0].replace(" ", "")
connector_id = "_".join(session.posargs[0].lower().split(" "))
variable_map = {"connector_name": connector_name, "connector_id": connector_id}

# create empty config and dataset files
try:
Path(f"data/saas/config/{variable_map['connector_id']}_config.yml").touch(
exist_ok=False
)
Path(f"data/saas/dataset/{variable_map['connector_id']}_dataset.yml").touch(
exist_ok=False
)
except Exception:
session.error(
f"Files for {session.posargs[0]} already exist, skipping initialization"
)

# location of Jinja templates
from jinja2 import Environment, FileSystemLoader

environment = Environment(
loader=FileSystemLoader("data/saas/saas_connector_scaffolding/")
)

# render fixtures file
fixtures_template = environment.get_template("new_fixtures.jinja")
filename = f"tests/fixtures/saas/{variable_map['connector_id']}_fixtures.py"
contents = fixtures_template.render(variable_map)
try:
with open(filename, mode="x", encoding="utf-8") as fixtures:
fixtures.write(contents)
fixtures.close()
except FileExistsError:
session.error(
f"Files for {session.posargs[0]} already exist, skipping initialization"
)

# render tests file
test_template = environment.get_template("test_new_task.jinja")
filename = (
f"tests/ops/integration_tests/saas/test_{variable_map['connector_id']}_task.py"
)
contents = test_template.render(variable_map)
try:
with open(filename, mode="x", encoding="utf-8") as tests:
tests.write(contents)
tests.close()
except FileExistsError:
session.error(
f"Files for {session.posargs[0]} already exist, skipping initialization"
)
Loading