Skip to content

Commit

Permalink
SaaS connector test refactoring (#1795)
Browse files Browse the repository at this point in the history
  • Loading branch information
galvana authored Mar 6, 2023
1 parent e5edd4f commit 1c39399
Show file tree
Hide file tree
Showing 18 changed files with 808 additions and 1,065 deletions.
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

0 comments on commit 1c39399

Please sign in to comment.