def should_return_error_when_trying_to_delete_dataset_with_versions() -> None: storage_bucket_name = get_param(ParameterName.STORAGE_BUCKET_NAME) with Dataset() as dataset, S3Object( file_object=BytesIO(), bucket_name=storage_bucket_name, key= f"{dataset.dataset_id}/{any_dataset_version_id()}/{any_safe_filename()}", ): response = entrypoint.lambda_handler( { "httpMethod": "DELETE", "body": { "id": dataset.dataset_id } }, any_lambda_context()) expected_message = ( f"Conflict: Can’t delete dataset “{dataset.dataset_id}”: dataset versions still exist" ) assert response == { "statusCode": HTTPStatus.CONFLICT, "body": { "message": expected_message }, }
def should_return_error_when_trying_to_delete_dataset_with_versions() -> None: with Dataset() as dataset, S3Object( file_object=BytesIO(), bucket_name=ResourceName.STORAGE_BUCKET_NAME.value, key= f"{dataset.dataset_id}/{any_dataset_version_id()}/{any_safe_filename()}", ): response = lambda_handler( { HTTP_METHOD_KEY: "DELETE", BODY_KEY: { DATASET_ID_SHORT_KEY: dataset.dataset_id } }, any_lambda_context(), ) expected_message = ( f"Conflict: Can’t delete dataset “{dataset.dataset_id}”: dataset versions still exist" ) assert response == { STATUS_CODE_KEY: HTTPStatus.CONFLICT, BODY_KEY: { MESSAGE_KEY: expected_message }, }
def should_delete_dataset_with_no_versions() -> None: with Dataset() as dataset: response = lambda_handler( { HTTP_METHOD_KEY: "DELETE", BODY_KEY: { DATASET_ID_SHORT_KEY: dataset.dataset_id } }, any_lambda_context(), ) assert response == {STATUS_CODE_KEY: HTTPStatus.NO_CONTENT, BODY_KEY: {}}
def should_return_error_when_trying_to_delete_dataset_with_missing_id( ) -> None: response = lambda_handler({ HTTP_METHOD_KEY: "DELETE", BODY_KEY: {} }, any_lambda_context()) assert response == { STATUS_CODE_KEY: HTTPStatus.BAD_REQUEST, BODY_KEY: { MESSAGE_KEY: f"Bad Request: '{DATASET_ID_SHORT_KEY}' is a required property" }, }
def should_fail_if_updating_not_existing_dataset() -> None: dataset_id = any_dataset_id() body = {"id": dataset_id, "title": any_dataset_title()} response = entrypoint.lambda_handler({ "httpMethod": "PATCH", "body": body }, any_lambda_context()) assert response == { "statusCode": HTTPStatus.NOT_FOUND, "body": { "message": f"Not Found: dataset '{dataset_id}' does not exist" }, }
def should_fail_if_updating_not_existing_dataset() -> None: dataset_id = any_dataset_id() body = {DATASET_ID_SHORT_KEY: dataset_id, TITLE_KEY: any_dataset_title()} response = lambda_handler({ HTTP_METHOD_KEY: "PATCH", BODY_KEY: body }, any_lambda_context()) assert response == { STATUS_CODE_KEY: HTTPStatus.NOT_FOUND, BODY_KEY: { MESSAGE_KEY: f"Not Found: dataset '{dataset_id}' does not exist" }, }
def should_fail_if_updating_with_already_existing_dataset_title() -> None: dataset_title = any_dataset_title() body = {DATASET_ID_SHORT_KEY: any_dataset_id(), TITLE_KEY: dataset_title} with Dataset(title=dataset_title): response = lambda_handler({ HTTP_METHOD_KEY: "PATCH", BODY_KEY: body }, any_lambda_context()) assert response == { STATUS_CODE_KEY: HTTPStatus.CONFLICT, BODY_KEY: { MESSAGE_KEY: f"Conflict: dataset '{dataset_title}' already exists" }, }
def should_fail_if_post_request_containing_duplicate_dataset_title() -> None: dataset_title = any_dataset_title() body = {"title": dataset_title} with Dataset(title=dataset_title): response = entrypoint.lambda_handler( { "httpMethod": "POST", "body": body }, any_lambda_context()) assert response == { "statusCode": HTTPStatus.CONFLICT, "body": { "message": f"Conflict: dataset '{dataset_title}' already exists" }, }
def should_fail_if_updating_with_already_existing_dataset_title() -> None: dataset_title = any_dataset_title() body = {"id": any_dataset_id(), "title": dataset_title} with Dataset(title=dataset_title): response = entrypoint.lambda_handler( { "httpMethod": "PATCH", "body": body }, any_lambda_context()) assert response == { "statusCode": HTTPStatus.CONFLICT, "body": { "message": f"Conflict: dataset '{dataset_title}' already exists" }, }
def should_return_single_dataset(subtests: SubTests) -> None: # Given a dataset instance with Dataset() as dataset: body = {DATASET_ID_SHORT_KEY: dataset.dataset_id} # When requesting the dataset by ID and type response = lambda_handler({ HTTP_METHOD_KEY: "GET", BODY_KEY: body }, any_lambda_context()) logger.info("Response: %s", response) # Then we should get the dataset in return with subtests.test(msg="status code"): assert response[STATUS_CODE_KEY] == HTTPStatus.OK with subtests.test(msg="ID"): assert response[BODY_KEY][DATASET_ID_SHORT_KEY] == dataset.dataset_id
def should_fail_if_post_request_containing_duplicate_dataset_title() -> None: dataset_title = any_dataset_title() body = { TITLE_KEY: dataset_title, DESCRIPTION_KEY: any_dataset_description() } with Dataset(title=dataset_title): response = lambda_handler({ HTTP_METHOD_KEY: "POST", BODY_KEY: body }, any_lambda_context()) assert response == { STATUS_CODE_KEY: HTTPStatus.CONFLICT, BODY_KEY: { MESSAGE_KEY: f"Conflict: dataset '{dataset_title}' already exists" }, }
def should_return_client_error_when_title_contains_unsupported_characters( subtests: SubTests, ) -> None: for character in "!@#$%^&*(){}?+| /=": with subtests.test(msg=character): response = entrypoint.lambda_handler( { "httpMethod": "POST", "body": { "title": character } }, any_lambda_context()) assert response == { "statusCode": HTTPStatus.BAD_REQUEST, "body": { "message": f"Bad Request: '{character}' does not match '{TITLE_PATTERN}'" }, }
def should_create_dataset(subtests: SubTests) -> None: dataset_title = any_dataset_title() body = {"title": dataset_title} response = entrypoint.lambda_handler({ "httpMethod": "POST", "body": body }, any_lambda_context()) logger.info("Response: %s", response) with subtests.test(msg="status code"): assert response["statusCode"] == HTTPStatus.CREATED with subtests.test(msg="ID length"): assert len(response["body"]["id"]) == 41 with subtests.test(msg="title"): assert response["body"]["title"] == dataset_title
def should_update_dataset(subtests: SubTests) -> None: new_dataset_title = any_dataset_title() with Dataset() as dataset: body = {"id": dataset.dataset_id, "title": new_dataset_title} response = entrypoint.lambda_handler( { "httpMethod": "PATCH", "body": body, }, any_lambda_context(), ) logger.info("Response: %s", response) with subtests.test(msg="status code"): assert response["statusCode"] == HTTPStatus.OK with subtests.test(msg="title"): assert response["body"]["title"] == new_dataset_title
def should_update_dataset(subtests: SubTests) -> None: new_dataset_title = any_dataset_title() with Dataset() as dataset: body = { DATASET_ID_SHORT_KEY: dataset.dataset_id, TITLE_KEY: new_dataset_title } response = lambda_handler({ HTTP_METHOD_KEY: "PATCH", BODY_KEY: body }, any_lambda_context()) logger.info("Response: %s", response) with subtests.test(msg="status code"): assert response[STATUS_CODE_KEY] == HTTPStatus.OK with subtests.test(msg="title"): assert response[BODY_KEY][TITLE_KEY] == new_dataset_title
def should_return_single_dataset(subtests: SubTests) -> None: # Given a dataset instance with Dataset() as dataset: body = {"id": dataset.dataset_id} # When requesting the dataset by ID and type response = entrypoint.lambda_handler( { "httpMethod": "GET", "body": body }, any_lambda_context()) logger.info("Response: %s", response) # Then we should get the dataset in return with subtests.test(msg="status code"): assert response["statusCode"] == HTTPStatus.OK with subtests.test(msg="ID"): assert response["body"]["id"] == dataset.dataset_id
def should_return_all_datasets(subtests: SubTests) -> None: # Given two datasets with Dataset() as first_dataset, Dataset() as second_dataset: # When requesting all datasets response = entrypoint.lambda_handler({ "httpMethod": "GET", "body": {} }, any_lambda_context()) logger.info("Response: %s", response) # Then we should get both datasets in return with subtests.test(msg="status code"): assert response["statusCode"] == HTTPStatus.OK actual_dataset_ids = [entry["id"] for entry in response["body"]] for dataset_id in (first_dataset.dataset_id, second_dataset.dataset_id): with subtests.test(msg=f"ID {dataset_id}"): assert dataset_id in actual_dataset_ids
def should_return_all_datasets(subtests: SubTests) -> None: # Given two datasets with Dataset() as first_dataset, Dataset() as second_dataset: # When requesting all datasets response = lambda_handler({ HTTP_METHOD_KEY: "GET", BODY_KEY: {} }, any_lambda_context()) logger.info("Response: %s", response) # Then we should get both datasets in return with subtests.test(msg="status code"): assert response[STATUS_CODE_KEY] == HTTPStatus.OK actual_dataset_ids = [ entry[DATASET_ID_SHORT_KEY] for entry in response[BODY_KEY] ] for dataset_id in (first_dataset.dataset_id, second_dataset.dataset_id): with subtests.test(msg=f"ID {dataset_id}"): assert dataset_id in actual_dataset_ids
def should_return_client_error_when_title_contains_unsupported_characters( subtests: SubTests, ) -> None: for character in "!@#$%^&*(){}?+| /=": with subtests.test(msg=character): response = lambda_handler( { HTTP_METHOD_KEY: "POST", BODY_KEY: { TITLE_KEY: character, DESCRIPTION_KEY: any_dataset_description() }, }, any_lambda_context(), ) assert response == { STATUS_CODE_KEY: HTTPStatus.BAD_REQUEST, BODY_KEY: { MESSAGE_KEY: f"Bad Request: '{character}' does not match '{TITLE_PATTERN}'" }, }
def should_return_single_dataset_filtered_by_title(subtests: SubTests) -> None: # Given matching and non-matching dataset instances dataset_title = any_dataset_title() body = {"title": dataset_title} with Dataset(title=dataset_title) as matching_dataset, Dataset(): # When requesting a specific type and title response = entrypoint.lambda_handler( { "httpMethod": "GET", "body": body }, any_lambda_context()) logger.info("Response: %s", response) with subtests.test(msg="ID"): # Then only the matching dataset should be returned assert response["body"][0]["id"] == matching_dataset.dataset_id with subtests.test(msg="status code"): assert response["statusCode"] == HTTPStatus.OK with subtests.test(msg="body length"): assert len(response["body"]) == 1
def should_return_single_dataset_filtered_by_title(subtests: SubTests) -> None: # Given matching and non-matching dataset instances dataset_title = any_dataset_title() body = {TITLE_KEY: dataset_title} with Dataset(title=dataset_title) as matching_dataset, Dataset(): # When requesting a specific type and title response = lambda_handler({ HTTP_METHOD_KEY: "GET", BODY_KEY: body }, any_lambda_context()) logger.info("Response: %s", response) with subtests.test(msg="ID"): # Then only the matching dataset should be returned assert response[BODY_KEY][0][ DATASET_ID_SHORT_KEY] == matching_dataset.dataset_id with subtests.test(msg="status code"): assert response[STATUS_CODE_KEY] == HTTPStatus.OK with subtests.test(msg="body length"): assert len(response[BODY_KEY]) == 1
def should_create_dataset(subtests: SubTests, s3_client: S3Client) -> None: dataset_title = any_dataset_title() dataset_description = any_dataset_description() body = {TITLE_KEY: dataset_title, DESCRIPTION_KEY: dataset_description} try: with patch("backend.datasets.create.SQS_RESOURCE") as sqs_mock: response = lambda_handler({ HTTP_METHOD_KEY: "POST", BODY_KEY: body }, any_lambda_context()) logger.info("Response: %s", response) with subtests.test(msg="status code"): assert response[STATUS_CODE_KEY] == HTTPStatus.CREATED with subtests.test(msg="ID length"): assert len(response[BODY_KEY][DATASET_ID_SHORT_KEY]) == 26 with subtests.test(msg="title"): assert response[BODY_KEY][TITLE_KEY] == dataset_title catalog = get_s3_prefix_versions( ResourceName.STORAGE_BUCKET_NAME.value, dataset_title, s3_client)[0] dataset_prefix = ( f"{dataset_title}{DATASET_KEY_SEPARATOR}{response[BODY_KEY][DATASET_ID_SHORT_KEY]}" ) expected_sqs_call = { "MessageBody": dataset_prefix, "MessageAttributes": { MESSAGE_ATTRIBUTE_TYPE_KEY: { STRING_VALUE_KEY: MESSAGE_ATTRIBUTE_TYPE_ROOT, DATA_TYPE_KEY: DATA_TYPE_STRING, } }, } with smart_open( f"{S3_URL_PREFIX}{ResourceName.STORAGE_BUCKET_NAME.value}/{catalog['Key']}" ) as new_catalog_metadata_file: catalog_json = load(new_catalog_metadata_file) with subtests.test(msg="catalog title"): assert catalog_json[STAC_TITLE_KEY] == dataset_title with subtests.test(msg="catalog description"): assert catalog_json[ STAC_DESCRIPTION_KEY] == dataset_description with subtests.test(msg="root catalog"): assert sqs_mock.get_queue_by_name.return_value.send_message.called with subtests.test(msg="correct url passed to sqs"): assert (sqs_mock.get_queue_by_name.return_value.send_message. call_args[1] == expected_sqs_call) finally: delete_s3_prefix(ResourceName.STORAGE_BUCKET_NAME.value, dataset_title, s3_client)