-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Eng 1345 create api endpoint to get tables associated for workflow_id (…
…#216) * Add route url * first draft * Draft 2 -- custom sql * SQL return all operators * distinct load list * lint * Custom response struct * package-lock update * lint * table_artifact merge conflict * lint * black * Right version of black * ENG-1358 Set up backend integration tests & include in Github Actions (#214)
- Loading branch information
1 parent
ef15abb
commit df986f3
Showing
19 changed files
with
449 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Backend Integration Tests | ||
|
||
These tests are run against the Aqueduct backend to check the endpoints' reads and outputs are as expected. | ||
|
||
The `setup_class` sets up all the workflows which are read by each test. When all the tests in the suite are done, the workflows set up in `setup_class` are deleted in the `teardown_class`. | ||
|
||
## Creating Tests | ||
The workflows ran in setup tests are all the Python files in the `setup/` folder. Each Python file is called in the format `{python_file} {api_key} {server_address}`. At the top, you can parse those arguments like so: | ||
``` | ||
import sys | ||
api_key, server_address = sys.argv[1], sys.argv[2] | ||
``` | ||
After that, you can write a workflow as you would do as a typical user. | ||
At the very end, the tests **require** you to print the flow id (e.g. `print(flow.id())`). This is parsed by the suite setup function and saved to a list of flow ids. At the end of testing, the teardown function will iterate through the flow ids and delete the associated workflows. | ||
|
||
## Usage | ||
|
||
Running all the tests in this repo: | ||
`API_KEY=<your api key> SERVER_ADDRESS=<your server's address> pytest . -rP` | ||
|
||
Running all the tests in a single file: | ||
- `<your env variables> pytest <path to test file> -rP` | ||
|
||
Running a specific test: | ||
- `<your env variables> pytest . -rP -k '<specific test name>'` | ||
|
||
Running tests in parallel, with concurrency 5: | ||
- Install pytest-xdist | ||
- `<your env variables> pytest . -rP -n 5` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import os | ||
|
||
import pytest | ||
|
||
import aqueduct | ||
|
||
API_KEY_ENV_NAME = "API_KEY" | ||
SERVER_ADDR_ENV_NAME = "SERVER_ADDRESS" | ||
|
||
|
||
def pytest_configure(config): | ||
pytest.api_key = os.getenv(API_KEY_ENV_NAME) | ||
pytest.server_address = os.getenv(SERVER_ADDR_ENV_NAME) | ||
|
||
if pytest.api_key is None or pytest.server_address is None: | ||
raise Exception( | ||
"Test Setup Error: api_key and server_address must be set as environmental variables." | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import sys | ||
|
||
api_key, server_address = sys.argv[1], sys.argv[2] | ||
|
||
### | ||
# Workflow that loads a table from the `aqueduct_demo` then saves it to `table_1` in append mode. | ||
# This save operator is then replaced by one that saves to `table_1` in replace mode. | ||
# In the next deployment of this run, it saves to `table_1` in append mode. | ||
# In the last deployment, it saves to `table_2` in append mode. | ||
### | ||
|
||
import aqueduct | ||
|
||
name = "Test: Changing Saves" | ||
client = aqueduct.Client(api_key, server_address) | ||
integration = client.integration(name="aqueduct_demo") | ||
|
||
### | ||
|
||
table = integration.sql(query="SELECT * FROM wine;") | ||
|
||
table.save(integration.config(table="table_1", update_mode="append")) | ||
|
||
flow = client.publish_flow( | ||
name=name, | ||
artifacts=[table], | ||
) | ||
|
||
### | ||
|
||
table = integration.sql(query="SELECT * FROM wine;") | ||
|
||
table.save(integration.config(table="table_1", update_mode="replace")) | ||
|
||
flow = client.publish_flow( | ||
name=name, | ||
artifacts=[table], | ||
) | ||
|
||
### | ||
|
||
table = integration.sql(query="SELECT * FROM wine;") | ||
|
||
table.save(integration.config(table="table_1", update_mode="append")) | ||
|
||
flow = client.publish_flow( | ||
name=name, | ||
artifacts=[table], | ||
) | ||
|
||
### | ||
|
||
table = integration.sql(query="SELECT * FROM wine;") | ||
|
||
table.save(integration.config(table="table_2", update_mode="append")) | ||
|
||
flow = client.publish_flow( | ||
name=name, | ||
artifacts=[table], | ||
) | ||
|
||
### | ||
|
||
print(flow.id()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import os | ||
import subprocess | ||
import sys | ||
from pathlib import Path | ||
|
||
import pytest | ||
import requests | ||
|
||
import aqueduct | ||
|
||
|
||
class TestBackend: | ||
GET_WORKFLOW_TABLES_TEMPLATE = "/api/workflow/%s/tables" | ||
WORKFLOW_PATH = Path(__file__).parent / "setup" | ||
|
||
@classmethod | ||
def setup_class(cls): | ||
cls.client = aqueduct.Client(pytest.api_key, pytest.server_address) | ||
cls.flows = {} | ||
|
||
workflow_files = [ | ||
f | ||
for f in os.listdir(cls.WORKFLOW_PATH) | ||
if os.path.isfile(os.path.join(cls.WORKFLOW_PATH, f)) | ||
] | ||
for workflow in workflow_files: | ||
proc = subprocess.Popen( | ||
[ | ||
"python3", | ||
os.path.join(cls.WORKFLOW_PATH, workflow), | ||
pytest.api_key, | ||
pytest.server_address, | ||
], | ||
stdout=subprocess.PIPE, | ||
stderr=subprocess.PIPE, | ||
) | ||
out, err = proc.communicate() | ||
out = out.decode("utf-8") | ||
err = err.decode("utf-8") | ||
if err: | ||
raise Exception(f"Could not run workflow {workflow}.\n\n{err}") | ||
else: | ||
cls.flows[workflow] = out.strip().split()[-1] | ||
|
||
@classmethod | ||
def teardown_class(cls): | ||
for flow in cls.flows: | ||
cls.client.delete_flow(cls.flows[flow]) | ||
|
||
@classmethod | ||
def get_response_class(cls, endpoint, additional_headers={}): | ||
headers = {"api-key": pytest.api_key} | ||
headers.update(additional_headers) | ||
url = cls.client._api_client.construct_full_url(endpoint) | ||
r = requests.get(url, headers=headers) | ||
return r | ||
|
||
def test_endpoint_getworkflowtables(self): | ||
endpoint = self.GET_WORKFLOW_TABLES_TEMPLATE % self.flows["changing_saves.py"] | ||
data = self.get_response_class(endpoint).json()["table_details"] | ||
|
||
assert len(data) == 3 | ||
|
||
# table_name, update_mode | ||
data_set = set( | ||
[ | ||
("table_1", "append"), | ||
("table_1", "replace"), | ||
("table_2", "append"), | ||
] | ||
) | ||
assert set([(item["table_name"], item["update_mode"]) for item in data]) == data_set | ||
|
||
# Check all in same integration | ||
assert len(set([item["integration_id"] for item in data])) == 1 | ||
assert len(set([item["service"] for item in data])) == 1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.