Skip to content

Commit

Permalink
Check airlock review logic in e2e tests (#2900)
Browse files Browse the repository at this point in the history
  • Loading branch information
tanya-borisova committed Dec 8, 2022
1 parent ca4abf6 commit 9193390
Show file tree
Hide file tree
Showing 8 changed files with 221 additions and 38 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ test-e2e-shared-services:

test-e2e-custom:
$(call target_title, "Running E2E tests with custom selector ${SELECTOR}") \
&& . ${MAKEFILE_DIR}/devops/scripts/check_dependencies.sh env,auth \
&& . ${MAKEFILE_DIR}/devops/scripts/load_env.sh ${MAKEFILE_DIR}/e2e_tests/.env \
&& cd e2e_tests \
&& \
Expand Down
3 changes: 3 additions & 0 deletions e2e_tests/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,7 @@

# Set workspace id of an existing workspace to skip creation of a workspace during E2E tests
TEST_WORKSPACE_ID: str = config("TEST_WORKSPACE_ID", default="")
TEST_WORKSPACE_SERVICE_ID: str = config("TEST_WORKSPACE_SERVICE_ID", default="")
TEST_AAD_WORKSPACE_ID: str = config("TEST_AAD_WORKSPACE_ID", default="")
TEST_AIRLOCK_IMPORT_REVIEW_WORKSPACE_ID: str = config("TEST_AIRLOCK_IMPORT_REVIEW_WORKSPACE_ID", default="")
TEST_AIRLOCK_IMPORT_REVIEW_WORKSPACE_SERVICE_ID: str = config("TEST_AIRLOCK_IMPORT_REVIEW_WORKSPACE_SERVICE_ID", default="")
108 changes: 97 additions & 11 deletions e2e_tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,40 +31,82 @@ def verify(pytestconfig):
return False


async def create_or_get_test_workspace(auth_type: str, verify: bool, pre_created_workspace_id: str = "", client_id: str = "", client_secret: str = "") -> Tuple[str, str]:
async def create_or_get_test_workspace(
auth_type: str,
verify: bool,
template_name: str = resource_strings.BASE_WORKSPACE,
pre_created_workspace_id: str = "",
client_id: str = "",
client_secret: str = "") -> Tuple[str, str]:
if pre_created_workspace_id != "":
return f"/workspaces/{pre_created_workspace_id}", pre_created_workspace_id

LOGGER.info("Creating workspace")
LOGGER.info(f"Creating workspace {template_name}")

description = " ".join([x.capitalize() for x in template_name.split("-")[2:]])
payload = {
"templateName": resource_strings.BASE_WORKSPACE,
"templateName": template_name,
"properties": {
"display_name": "E2E test workspace",
"description": "Test workspace for E2E tests",
"address_space_size": "small",
"auth_type": auth_type
"display_name": f"E2E {description} workspace ({auth_type} AAD)",
"description": f"{template_name} test workspace for E2E tests",
"auth_type": auth_type,
"address_space_size": "small"
}
}
if config.TEST_WORKSPACE_APP_PLAN != "":
payload["properties"]["app_service_plan_sku"] = config.TEST_WORKSPACE_APP_PLAN

if auth_type == "Manual":
payload["properties"]["client_id"] = client_id
payload["properties"]["client_secret"] = client_secret

if config.TEST_WORKSPACE_APP_PLAN != "":
payload["properties"]["app_service_plan_sku"] = config.TEST_WORKSPACE_APP_PLAN

admin_token = await get_admin_token(verify=verify)
workspace_path, workspace_id = await post_resource(payload, resource_strings.API_WORKSPACES, access_token=admin_token, verify=verify)

LOGGER.info(f"Workspace {workspace_id} {template_name} created")
return workspace_path, workspace_id


async def create_or_get_test_workpace_service(workspace_path, workspace_owner_token, pre_created_workspace_service_id, verify):
if pre_created_workspace_service_id != "":
workspace_service_id = pre_created_workspace_service_id
workspace_service_path = f"{workspace_path}/{resource_strings.API_WORKSPACE_SERVICES}/{workspace_service_id}"
return workspace_service_path, workspace_service_id

# create a guac service
service_payload = {
"templateName": resource_strings.GUACAMOLE_SERVICE,
"properties": {
"display_name": "Workspace service test",
"description": ""
}
}

workspace_service_path, workspace_service_id = await post_resource(
payload=service_payload,
endpoint=f'/api{workspace_path}/{resource_strings.API_WORKSPACE_SERVICES}',
access_token=workspace_owner_token,
verify=verify)

return workspace_service_path, workspace_service_id


async def clean_up_test_workspace(pre_created_workspace_id: str, workspace_path: str, verify: bool):
# Only delete the workspace if it wasn't pre-created
if pre_created_workspace_id == "":
LOGGER.info("Deleting workspace")
LOGGER.info(f"Deleting workspace {pre_created_workspace_id}")
admin_token = await get_admin_token(verify=verify)
await disable_and_delete_resource(f'/api{workspace_path}', admin_token, verify)


async def clean_up_test_workspace_service(pre_created_workspace_service_id: str, workspace_service_path: str, verify: bool):
if pre_created_workspace_service_id == "":
LOGGER.info(f"Deleting workspace service {pre_created_workspace_service_id}")
admin_token = await get_admin_token(verify=verify)
await disable_and_delete_resource(f'/api{workspace_service_path}', admin_token, verify)


# Session scope isn't in effect with python-xdist: https://github.com/microsoft/AzureTRE/issues/2868
@pytest.fixture(scope="session")
async def setup_test_workspace(verify) -> Tuple[str, str, str]:
pre_created_workspace_id = config.TEST_WORKSPACE_ID
Expand All @@ -80,6 +122,25 @@ async def setup_test_workspace(verify) -> Tuple[str, str, str]:
clean_up_test_workspace(pre_created_workspace_id=pre_created_workspace_id, workspace_path=workspace_path, verify=verify)


# Session scope isn't in effect with python-xdist: https://github.com/microsoft/AzureTRE/issues/2868
@pytest.fixture(scope="session")
async def setup_test_workspace_and_workspace_service(verify, setup_test_workspace):
# Set up
workspace_path, workspace_id, workspace_owner_token = setup_test_workspace

pre_created_workspace_service_id = config.TEST_WORKSPACE_SERVICE_ID
workspace_service_path, workspace_service_id = await create_or_get_test_workpace_service(
workspace_path,
workspace_owner_token=workspace_owner_token,
pre_created_workspace_service_id=pre_created_workspace_service_id,
verify=verify)

yield workspace_path, workspace_id, workspace_service_path, workspace_service_id, workspace_owner_token

clean_up_test_workspace_service(pre_created_workspace_service_id=pre_created_workspace_service_id, workspace_service_path=workspace_service_path, verify=verify)


# Session scope isn't in effect with python-xdist: https://github.com/microsoft/AzureTRE/issues/2868
@pytest.fixture(scope="session")
async def setup_test_aad_workspace(verify) -> Tuple[str, str, str]:
pre_created_workspace_id = config.TEST_AAD_WORKSPACE_ID
Expand All @@ -92,3 +153,28 @@ async def setup_test_aad_workspace(verify) -> Tuple[str, str, str]:

# Tear-down
clean_up_test_workspace(pre_created_workspace_id=pre_created_workspace_id, workspace_path=workspace_path, verify=verify)


# Session scope isn't in effect with python-xdist: https://github.com/microsoft/AzureTRE/issues/2868
@pytest.fixture(scope="session")
async def setup_test_airlock_import_review_workspace_and_workspace_service(verify) -> Tuple[str, str, str, str, str]:
pre_created_workspace_id = config.TEST_AIRLOCK_IMPORT_REVIEW_WORKSPACE_ID
# Set up
workspace_path, workspace_id = await create_or_get_test_workspace(auth_type="Automatic", verify=verify, template_name=resource_strings.AIRLOCK_IMPORT_REVIEW_WORKSPACE, pre_created_workspace_id=pre_created_workspace_id)

admin_token = await get_admin_token(verify=verify)
workspace_owner_token, _ = await get_workspace_auth_details(admin_token=admin_token, workspace_id=workspace_id, verify=verify)
pre_created_workspace_service_id = config.TEST_AIRLOCK_IMPORT_REVIEW_WORKSPACE_SERVICE_ID

workspace_service_path, workspace_service_id = await create_or_get_test_workpace_service(
workspace_path,
workspace_owner_token=workspace_owner_token,
pre_created_workspace_service_id=pre_created_workspace_service_id,
verify=verify)

workspace_owner_token, _ = await get_workspace_auth_details(admin_token=admin_token, workspace_id=workspace_id, verify=verify)
yield workspace_path, workspace_id, workspace_service_path, workspace_service_id, workspace_owner_token

# Tear-down
clean_up_test_workspace_service(pre_created_workspace_service_id=pre_created_workspace_service_id, workspace_service_path=workspace_service_path, verify=verify)
clean_up_test_workspace(pre_created_workspace_id=pre_created_workspace_id, workspace_path=workspace_path, verify=verify)
4 changes: 2 additions & 2 deletions e2e_tests/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ async def get_template(template_name, endpoint, token, verify):
yield response


async def get_shared_service_id_by_name(template_name: str, verify, token) -> Optional[dict]:
async def get_shared_service_by_name(template_name: str, verify, token) -> Optional[dict]:
async with AsyncClient(verify=verify, timeout=TIMEOUT) as client:
full_endpoint = get_full_endpoint('/api/shared-services')
auth_headers = get_auth_header(token)
Expand Down Expand Up @@ -123,7 +123,7 @@ async def get_admin_token(verify) -> str:
try:
responseJson = response.json()
except JSONDecodeError:
assert False, "Failed to parse response as JSON: {}".format(response.content)
assert False, "Failed to parse response as JSON: {} {}".format(response.status_code, response.content)

assert "access_token" in responseJson, "Failed to get access_token: {}".format(response.content)
token = responseJson["access_token"]
Expand Down
15 changes: 8 additions & 7 deletions e2e_tests/resources/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ async def get_resource(endpoint, access_token, verify):

response = await client.get(full_endpoint, headers=auth_headers, timeout=TIMEOUT)

LOGGER.info(f'RESPONSE Status code: {response.status_code} Content: {response.content}')
LOGGER.info(f'RESPONSE Status code: {response.status_code}')
assert (response.status_code == status.HTTP_200_OK), f"Get for endpoint {full_endpoint} failed"

return response.json()


async def post_resource(payload, endpoint, access_token, verify, method="POST", wait=True, etag="*"):
async def post_resource(payload, endpoint, access_token, verify, method="POST", wait=True, etag="*", access_token_for_wait=None):
async with AsyncClient(verify=verify, timeout=30.0) as client:

full_endpoint = get_full_endpoint(endpoint)
Expand All @@ -38,15 +38,16 @@ async def post_resource(payload, endpoint, access_token, verify, method="POST",
check_method = patch_done
response = await client.patch(full_endpoint, headers=auth_headers, json=payload, timeout=TIMEOUT)

LOGGER.info(f'RESPONSE Status code: {response.status_code} Content: {response.content}')
assert (response.status_code == status.HTTP_202_ACCEPTED), f"Request for resource {payload['templateName']} creation failed"
LOGGER.info(f'RESPONSE Status code: {response.status_code}')
assert (response.status_code == status.HTTP_202_ACCEPTED), f"Request failed with response {response.status_code} and content {response.content}"

resource_path = response.json()["operation"]["resourcePath"]
resource_id = response.json()["operation"]["resourceId"]
operation_endpoint = response.headers["Location"]

if wait:
await wait_for(check_method, client, operation_endpoint, auth_headers, [strings.RESOURCE_STATUS_DEPLOYMENT_FAILED, strings.RESOURCE_STATUS_UPDATING_FAILED])
wait_auth_headers = get_auth_header(access_token_for_wait) if access_token_for_wait else auth_headers
await wait_for(check_method, client, operation_endpoint, wait_auth_headers, [strings.RESOURCE_STATUS_DEPLOYMENT_FAILED, strings.RESOURCE_STATUS_UPDATING_FAILED])

return resource_path, resource_id

Expand All @@ -61,14 +62,14 @@ async def disable_and_delete_resource(endpoint, access_token, verify):
# disable
payload = {"isEnabled": False}
response = await client.patch(full_endpoint, headers=auth_headers, json=payload, timeout=TIMEOUT)
LOGGER.info(f'RESPONSE Status code: {response.status_code} Content: {response.content}')
LOGGER.info(f'RESPONSE Status code: {response.status_code}')
assert (response.status_code == status.HTTP_202_ACCEPTED), "Disable resource failed"
operation_endpoint = response.headers["Location"]
await wait_for(patch_done, client, operation_endpoint, auth_headers, [strings.RESOURCE_STATUS_UPDATING_FAILED])

# delete
response = await client.delete(full_endpoint, headers=auth_headers, timeout=TIMEOUT)
LOGGER.info(f'RESPONSE Status code: {response.status_code} Content: {response.content}')
LOGGER.info(f'RESPONSE Status code: {response.status_code}')
assert (response.status_code == status.HTTP_200_OK), "The resource couldn't be deleted"

resource_id = response.json()["operation"]["resourceId"]
Expand Down
1 change: 1 addition & 0 deletions e2e_tests/resources/strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
API_USER_RESOURCES = "user-resources"

BASE_WORKSPACE = "tre-workspace-base"
AIRLOCK_IMPORT_REVIEW_WORKSPACE = "tre-workspace-airlock-import-review"

AZUREML_SERVICE = "tre-service-azureml"
INNEREYE_SERVICE = "tre-service-innereye"
Expand Down
Loading

0 comments on commit 9193390

Please sign in to comment.