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

Tests/db backend tests #370 #385

Merged
merged 23 commits into from
Nov 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
dd18e18
feat: Add new entity endpoints for icat5
Reillyhewitson Oct 5, 2022
4dd4895
docs: Updated postman collection with new entities
Reillyhewitson Oct 5, 2022
49f31b3
Fix linting
Reillyhewitson Oct 5, 2022
0ce5727
change nulls and backrefs
Reillyhewitson Oct 26, 2022
99fb986
Change dates backref as causing KeyErrors
Reillyhewitson Oct 26, 2022
92f8682
generate openapi and fix model references
Reillyhewitson Oct 31, 2022
df446d6
Test all models and fix issues
Reillyhewitson Nov 1, 2022
c434218
address linter issues
Reillyhewitson Nov 1, 2022
5dc78c3
Add test for updating data
Reillyhewitson Oct 12, 2022
451e618
Add tests for multiple updates
Reillyhewitson Oct 12, 2022
9cc8757
Implement more tests
Reillyhewitson Oct 13, 2022
b31d037
test_create_data encountering datetime error
Reillyhewitson Oct 13, 2022
0e7fc3d
test_update_vallid encounters a datetime faillure
Reillyhewitson Oct 13, 2022
6972dcc
Fix sessions and linting
Reillyhewitson Oct 13, 2022
3a5a4a3
Add tests for where filter
Reillyhewitson Nov 1, 2022
55574cb
Fix tests for icat5
Reillyhewitson Nov 2, 2022
b311637
Revert changes to invalid update with id
Reillyhewitson Nov 3, 2022
652d1db
figure out strange behaviour, make tests more useful
Reillyhewitson Nov 3, 2022
e3e2005
Add login test
Reillyhewitson Nov 14, 2022
2eb6e11
Add explanation for why test might fail
Reillyhewitson Nov 16, 2022
6549b3e
linting and safety
Reillyhewitson Nov 16, 2022
9cfa727
Requested changes from review
Reillyhewitson Nov 22, 2022
b9831bd
Merge branch 'main' into tests/db-backend-tests-#370
Reillyhewitson Nov 23, 2022
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
2 changes: 1 addition & 1 deletion datagateway_api/src/datagateway_api/database/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def commit_changes(self):
except Exception as e:
log.error("Error whilst committing changes to %s, rolling back", self.table)
self.session.rollback()
raise e
raise BadRequestError(f"Bad request: {e}")


class CountQuery(Query):
Expand Down
6 changes: 5 additions & 1 deletion datagateway_api/src/datagateway_api/database/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@
from sqlalchemy.orm.collections import InstrumentedList

from datagateway_api.src.common.date_handler import DateHandler
from datagateway_api.src.common.exceptions import DatabaseError, FilterError
from datagateway_api.src.common.exceptions import (
DatabaseError,
FilterError,
)

Base = declarative_base()

Expand Down Expand Up @@ -179,6 +182,7 @@ def update_from_dict(self, dictionary):
"""
for key in dictionary:
setattr(self, key, dictionary[key])

return self.to_dict()


Expand Down
36 changes: 34 additions & 2 deletions test/datagateway_api/db/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from datagateway_api.src.common.config import Config
from datagateway_api.src.common.constants import Constants
from datagateway_api.src.common.exceptions import MissingRecordError
from datagateway_api.src.datagateway_api.database.helpers import (
delete_row_by_id,
insert_row_into_table,
Expand All @@ -15,6 +16,7 @@
INVESTIGATION,
INVESTIGATIONINSTRUMENT,
)
from test.datagateway_api.db.endpoints.test_create_db import TestDBCreateData


def set_meta_attributes(entity):
Expand Down Expand Up @@ -65,8 +67,11 @@ def single_investigation_test_data_db():
investigation = create_investigation_db_data()

yield investigation

delete_row_by_id(INVESTIGATION, investigation.id)
try:
delete_row_by_id(INVESTIGATION, investigation.id)
except MissingRecordError as e:
# This should occur on DELETE endpoints, normal behaviour for those tests
print(e)


@pytest.fixture()
Expand Down Expand Up @@ -134,3 +139,30 @@ def final_facilitycycle_id(flask_test_app_db, valid_db_credentials_header):
headers=valid_db_credentials_header,
)
return final_facilitycycle_result.json["id"]


@pytest.fixture()
def remove_test_created_investigation_data(
flask_test_app_db, valid_db_credentials_header,
):
yield

created_test_data = flask_test_app_db.get(
f"{Config.config.datagateway_api.extension}/investigations?where="
'{"name":{"like":'
f'"{TestDBCreateData.investigation_name_prefix}"'
"}}",
headers=valid_db_credentials_header,
)

investigation_ids = []

for investigation in created_test_data.json:
investigation_ids.append(investigation["id"])

for investigation_id in investigation_ids:
flask_test_app_db.delete(
f"{Config.config.datagateway_api.extension}/investigations"
f"/{investigation_id}",
headers=valid_db_credentials_header,
)
114 changes: 114 additions & 0 deletions test/datagateway_api/db/endpoints/test_create_db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import pytest

from datagateway_api.src.common.config import Config


def prepare_db_data_for_assertion(response_json):
response_json.pop("createId")
response_json.pop("createTime")
response_json.pop("id")
response_json.pop("modId")
response_json.pop("modTime")
response_json.pop("visitId")

if response_json["releaseDate"] is None:
return response_json

response_json["endDate"] = response_json["endDate"][:-6]
response_json["startDate"] = response_json["startDate"][:-6]

if response_json["releaseDate"] is None:
return response_json
else:
response_json["releaseDate"] = response_json["releaseDate"][:-6]

return response_json


class TestDBCreateData:
investigation_name_prefix = "DB Test Data for API Testing, Data Creation"

@pytest.mark.usefixtures("remove_test_created_investigation_data")
def test_valid_create_data(self, flask_test_app_db, valid_db_credentials_header):
create_investigations_json = [
{
"name": f"{self.investigation_name_prefix} {i}",
"title": "Test data for the DB Backend on DataGateway API",
"summary": "DB Test data for DataGateway API testing",
"releaseDate": "2020-03-03 08:00:08",
"startDate": "2020-02-02 09:00:09",
"endDate": "2020-02-03 10:00:10",
"visitId": "Data Creation Visit DB",
"doi": "DataGateway API DB Test DOI",
"facilityID": 1,
"typeID": 1,
"fileCount": 1,
"fileSize": 6,
}
for i in range(2)
]

test_response = flask_test_app_db.post(
f"{Config.config.datagateway_api.extension}/investigations",
headers=valid_db_credentials_header,
json=create_investigations_json,
)

response_json = test_response.json

for investigation_request in response_json:
prepare_db_data_for_assertion(investigation_request)

for investigation in create_investigations_json:
investigation.pop("visitId")
assert create_investigations_json == response_json

@pytest.mark.usefixtures("remove_test_created_investigation_data")
def test_valid_boundary_create_data(
self, flask_test_app_db, valid_db_credentials_header,
):
"""Create a single investigation, as opposed to multiple"""

create_investigation_json = {
"name": f"{self.investigation_name_prefix} 0",
"title": "Test data for the DB Backend on the API",
"summary": "Test data for DataGateway API testing",
"releaseDate": "2020-03-03 08:00:08",
"startDate": "2020-02-02 09:00:09",
"endDate": "2020-02-03 10:00:10",
"visitId": "Data Creation Visit",
"doi": "DataGateway API Test DOI",
"facilityID": 1,
"typeID": 1,
"fileCount": 3,
"fileSize": 2,
}

test_response = flask_test_app_db.post(
f"{Config.config.datagateway_api.extension}/investigations",
headers=valid_db_credentials_header,
json=create_investigation_json,
)

response_json = prepare_db_data_for_assertion(test_response.json)

create_investigation_json.pop("visitId")

assert create_investigation_json == response_json

def test_invalid_create_data(
self, flask_test_app_db, valid_db_credentials_header,
):
"""An investigation requires a minimum of: name, visitId, facility, type"""

invalid_request_body = {
"title": "Test Title for DataGateway API Backend testing",
}

test_response = flask_test_app_db.post(
f"{Config.config.datagateway_api.extension}/investigations",
headers=valid_db_credentials_header,
json=invalid_request_body,
)

assert test_response.status_code == 400
40 changes: 40 additions & 0 deletions test/datagateway_api/db/endpoints/test_delete_by_id_db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from datagateway_api.src.common.config import Config


class TestDeleteById:
def test_valid_delete_with_id(
self,
flask_test_app_db,
valid_db_credentials_header,
single_investigation_test_data_db,
):
single_investigation_test_data = single_investigation_test_data_db.to_dict()

test_response = flask_test_app_db.delete(
f"{Config.config.datagateway_api.extension}/investigations"
f'/{single_investigation_test_data["id"]}',
headers=valid_db_credentials_header,
)

assert test_response.status_code == 204

def test_invalid_delete_with_id(
self, flask_test_app_db, valid_db_credentials_header,
):
"""Request with a non-existent ID"""

final_investigation_result = flask_test_app_db.get(
f"{Config.config.datagateway_api.extension}/investigations"
'/findone?order="id DESC"',
headers=valid_db_credentials_header,
)
test_data_id = final_investigation_result.json["id"]

# Adding 100 onto the ID to the most recent result should ensure a 404
test_response = flask_test_app_db.delete(
f"{Config.config.datagateway_api.extension}/investigations"
f"/{test_data_id + 100}",
headers=valid_db_credentials_header,
)

assert test_response.status_code == 404
66 changes: 66 additions & 0 deletions test/datagateway_api/db/endpoints/test_update_by_id_db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
from datagateway_api.src.common.config import Config


class TestUpdateByID:
def test_valid_update_with_id(
self,
flask_test_app_db,
valid_db_credentials_header,
single_investigation_test_data_db,
):
update_data_json = {
"doi": "DB Test Data Identifier",
"summary": "DB Test Summary",
"startDate": "2019-01-04 01:01:01",
}

single_investigation_test_data = single_investigation_test_data_db.to_dict()

single_investigation_test_data.update(update_data_json)
test_response = flask_test_app_db.patch(
f"{Config.config.datagateway_api.extension}/investigations"
f"/{single_investigation_test_data['id']}",
headers=valid_db_credentials_header,
json=update_data_json,
)

response_json = test_response.json

# The DB returns times with timezone indicators,
# but does not accept them being created.
# This strips the timezone indicators out so that the results can be compared.
Reillyhewitson marked this conversation as resolved.
Show resolved Hide resolved
response_json["startDate"] = response_json["startDate"][:-6]

assert response_json == single_investigation_test_data

def test_invalid_update_with_id(
self,
flask_test_app_db,
valid_db_credentials_header,
single_investigation_test_data_db,
):
"""This test will attempt to put the DB in an invalid state"""

invalid_update_json = {
"doi": "_" * 300,
}

single_investigation_test_data = single_investigation_test_data_db.to_dict()

test_response = flask_test_app_db.patch(
f"{Config.config.datagateway_api.extension}/investigations"
f"/{single_investigation_test_data['id']}",
headers=valid_db_credentials_header,
json=invalid_update_json,
)

print(
"If this test is failing "
"you may need to set sql_mode to "
"STRICT_ALL_TABLES",
)
Reillyhewitson marked this conversation as resolved.
Show resolved Hide resolved

# If this test is failing
# you may need to set sql_mode to
# STRICT_ALL_TABLES
assert test_response.status_code == 400
85 changes: 85 additions & 0 deletions test/datagateway_api/db/endpoints/test_update_multiple_db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
from datagateway_api.src.common.config import Config


class TestUpdateMultipleEntities:
def test_valid_multiple_update_data(
self,
flask_test_app_db,
valid_db_credentials_header,
multiple_investigation_test_data_db,
):
expected_doi = "DB Test Data Identifier"
expected_summary = "DB Test summary"

update_data_list = []
test_data_list = []

for investigation_object in multiple_investigation_test_data_db:
investigation = investigation_object.to_dict()
investigation["doi"] = expected_doi
investigation["summary"] = expected_summary

update_entity = {
"id": investigation["id"],
"doi": expected_doi,
"summary": expected_summary,
}
update_data_list.append(update_entity)
test_data_list.append(investigation)

test_response = flask_test_app_db.patch(
f"{Config.config.datagateway_api.extension}/investigations",
headers=valid_db_credentials_header,
json=update_data_list,
)

assert test_response.json == test_data_list

def test_valid_boundary_update_data(
self,
flask_test_app_db,
valid_db_credentials_header,
single_investigation_test_data_db,
):
""" Request body is a dictionary, not a list of dictionaries"""

expected_doi = "Test Data Identifier"
expected_summary = "Test Summary"
single_investigation_test_data = single_investigation_test_data_db.to_dict()

update_data_json = {
"id": single_investigation_test_data["id"],
"doi": expected_doi,
"summary": expected_summary,
}
single_investigation_test_data["doi"] = expected_doi
single_investigation_test_data["summary"] = expected_summary

test_response = flask_test_app_db.patch(
f"{Config.config.datagateway_api.extension}/investigations",
headers=valid_db_credentials_header,
json=update_data_json,
)

assert test_response.json == [single_investigation_test_data]

def test_invalid_missing_update_data(
self,
flask_test_app_db,
valid_db_credentials_header,
single_investigation_test_data_db,
):
"""There should be an ID in the request body to know which entity to update"""

update_data_json = {
"doi": "Test Data Identifier",
"summary": "Test Summary",
}

test_response = flask_test_app_db.patch(
f"{Config.config.datagateway_api.extension}/investigations",
headers=valid_db_credentials_header,
json=update_data_json,
)

assert test_response.status_code == 400
Loading