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

Add Tests for ICAT Backend #191

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
119 commits
Select commit Hold shift + click to select a range
db43d3d
#150: Work out how the existing tests will work with the new test st…
MRichards99 Sep 28, 2020
2dee8f0
#150: Allow backends to be created for testing purposes
MRichards99 Sep 29, 2020
79e6e88
Merge branch 'feature/remove-sql-dependency-from-backends-#154' into …
MRichards99 Oct 26, 2020
04f25f1
Merge branch 'feature/configure-log-file-location-#182' into feature/…
MRichards99 Nov 9, 2020
96b3728
#150: Add pytest to dev dependencies
MRichards99 Nov 9, 2020
29f8111
#150: Add nox 'tests' session
MRichards99 Nov 9, 2020
b655de1
Merge branch 'feature/fix-code-linting-#184' into feature/test-multip…
MRichards99 Nov 9, 2020
343f8d4
#150: Add tests for DateHandler
MRichards99 Nov 9, 2020
230eaca
#150: Make config file path configurable
MRichards99 Nov 10, 2020
d1b045f
#150: Add tests for config
MRichards99 Nov 10, 2020
257082e
#150: Add pytest-cov to the repo
MRichards99 Nov 10, 2020
57fcd68
#150: Add configuration options required for repo's tests
MRichards99 Nov 10, 2020
7455c48
#150: Add tests for test configuration options
MRichards99 Nov 10, 2020
572e89c
#150: Combine config test username and password
MRichards99 Nov 10, 2020
71720d0
#150: Add pytest fixtures for filter testing
MRichards99 Nov 11, 2020
d5b189b
#150: Add tests for ICAT where filters
MRichards99 Nov 11, 2020
3c350ee
#150: Add tests for ICAT order filters
MRichards99 Nov 11, 2020
90f3b4b
#150: Add tests for ICAT distinct filters
MRichards99 Nov 11, 2020
7fe62ff
#150: Add tests for ICAT include filters
MRichards99 Nov 11, 2020
34d46ba
#150: Add tests for ICAT skip filters
MRichards99 Nov 11, 2020
f4ef19f
#150: Add tests for ICAT limit filters
MRichards99 Nov 11, 2020
55397e5
#150: Add test for backend creation
MRichards99 Nov 11, 2020
9625cc1
Merge branch 'master' into feature/test-multiple-backends-#150
MRichards99 Nov 13, 2020
e621f42
#150: Add tests for filter handler
MRichards99 Nov 16, 2020
7bf1141
#150: Ensure list flatten always returns the list in the same order
MRichards99 Nov 19, 2020
5444bd5
#150: Add way of injecting data into ICAT for testing endpoint and I…
MRichards99 Nov 19, 2020
d7b88dd
#150: Add beginning of tests for ICATQuery
MRichards99 Nov 19, 2020
07e42ec
#150: Add skeleton classes for remaining ICAT backend tests
MRichards99 Nov 20, 2020
ebf8b2e
#150: Fix failing filter tests
MRichards99 Nov 23, 2020
a3c16e1
#150: Rename pytest fixture for ICAT data injection
MRichards99 Nov 23, 2020
df48005
#150: Correct argument case
MRichards99 Nov 23, 2020
367eebb
#150: Add function to remove ICAT meta attributes and new test
MRichards99 Nov 23, 2020
6de60c7
#150: Add test to break a query
MRichards99 Nov 23, 2020
08b8fb6
#150: Add fixture to return auth header
MRichards99 Nov 23, 2020
00923bd
#150: Add fixture for flask test app
MRichards99 Nov 23, 2020
833f8e9
#150: Add tests for valid GET requests
MRichards99 Nov 23, 2020
9e0c56b
#150: Add update test
MRichards99 Nov 24, 2020
9c3ece5
#150: Add fixture to inject multiple investigation results
MRichards99 Nov 24, 2020
fdafb7a
#150: Add test for skip & limit filter merge
MRichards99 Nov 24, 2020
fc7f3a1
#150: Add tests for PATCH endpoints
MRichards99 Nov 24, 2020
510943e
#150: Add invalid test for data updates
MRichards99 Nov 24, 2020
6477491
#150: Modify existing test to actually point to an update by ID endp…
MRichards99 Nov 24, 2020
451e4d7
#150: Add invalid update by ID test
MRichards99 Nov 24, 2020
ba62e44
#150: Change ICATValidationError to raise a BadRequestError
MRichards99 Nov 24, 2020
bead8cf
#150: Add more invalid tests for update endpoint
MRichards99 Nov 25, 2020
a2fd644
#150: Add tests for no result requests
MRichards99 Nov 25, 2020
03c7c8f
#150: Add tests for DELETE endpoints
MRichards99 Nov 25, 2020
9edd0e9
#150: Add pytest plugin to improve assertion diffs
MRichards99 Nov 25, 2020
ce048da
#150: Fix data creation
MRichards99 Nov 25, 2020
e358ec7
#150: Add valid test for data creation
MRichards99 Nov 25, 2020
e1f07b7
#150: Add invalid tests for data creation
MRichards99 Nov 25, 2020
b16098e
#150: Add test to create single investigation
MRichards99 Nov 25, 2020
ba59926
#150: Move endpoint tests to their own files/classes
MRichards99 Nov 25, 2020
79bdbbe
#150: Add tests to check all endpoints exist and have correct HTTP m…
MRichards99 Nov 26, 2020
861b4f8
#150: Add session handling tests for ICAT backend
MRichards99 Nov 27, 2020
1470b22
#150: Add invalid tests for ISIS specific endpoints
MRichards99 Nov 27, 2020
25f2282
#150: Simplify icat_query fixture
MRichards99 Nov 30, 2020
275cb43
#150: Use one-off session ID for logout test
MRichards99 Nov 30, 2020
7aae8c8
#150: Refactor creation of investigation test data
MRichards99 Nov 30, 2020
9ed2694
#150: Fix test failures due to refactor
MRichards99 Nov 30, 2020
5910404
#150: Add valid tests for table endpoints
MRichards99 Nov 30, 2020
49ef7f8
#150: Increase coverage of PythonICATIncludeFilter
MRichards99 Nov 30, 2020
90f14a1
#150: Fix order filter test failures
MRichards99 Nov 30, 2020
e85f378
#150: Solve linting issues
MRichards99 Nov 30, 2020
2c37baa
#150: Remove planning comments made at start of branch
MRichards99 Nov 30, 2020
64f9981
#150: Move Flask/API setup into functions
MRichards99 Nov 30, 2020
9532d91
#150: Checkpoint in making backend configurable for testing
MRichards99 Dec 2, 2020
6902921
#150: Expand flask test app so the backend can be configured
MRichards99 Dec 2, 2020
7a6a8ef
#150: Move QueryFilterFactory to its own file
MRichards99 Dec 3, 2020
70dc393
#150: Allow backend type to be set when a flask test fixture runs
MRichards99 Dec 3, 2020
3890c55
#150: Add separate flask app fixtures for each backend
MRichards99 Dec 3, 2020
db97d8a
#150: Fix failing endpoint rule tests
MRichards99 Dec 3, 2020
adc48d1
#150: Fix imports on database helpers
MRichards99 Dec 3, 2020
dd9a92a
#150: Correct import for QueryFilterFactory
MRichards99 Dec 3, 2020
c676f46
#150: Fix imports on test helpers
MRichards99 Dec 3, 2020
c29f68e
#150: Fix logging issues when dealing with session IDs which are str…
MRichards99 Dec 3, 2020
dce47c1
#150: Remove unneeded import
MRichards99 Dec 3, 2020
bcea7ec
#150: Fix FlaskAppTest based on changes to main.py
MRichards99 Dec 3, 2020
c866be3
#150: General cleanup of recent work
MRichards99 Dec 3, 2020
b8324db
#150: Restructure test files
MRichards99 Dec 3, 2020
cff2ce4
#150: Rewrite DB entity helper tests in pytest
MRichards99 Dec 3, 2020
cf89d7e
#150: Rewrite database helper tests
MRichards99 Dec 3, 2020
b97b19b
#150: Rewrite JSON validity tests
MRichards99 Dec 3, 2020
a07f0db
#150: Rewrite DB session decorator tests
MRichards99 Dec 3, 2020
89d58d6
#150: Rename valid ICAT creds header
MRichards99 Dec 3, 2020
e8f1139
#150: Rewrite session ID from header tests
MRichards99 Dec 3, 2020
74215cd
#150: Complete TODOs from 'backend can be set for tests' work
MRichards99 Dec 3, 2020
d6f6ab8
#150: Rewrite get_filter_from_query_string tests
MRichards99 Dec 4, 2020
97bf1a4
#150: Rewrite queries_records tests
MRichards99 Dec 4, 2020
f5c4558
#150: Add test to ensure all required abstract methods are present f…
MRichards99 Dec 4, 2020
b6c7c66
#150: Add get by ID tests for DB backend
MRichards99 Dec 4, 2020
bbca31c
#150: Add tests for /count for DB backend
MRichards99 Dec 4, 2020
6baf55d
#150: Move endpoint rules tests
MRichards99 Dec 4, 2020
578f897
#150: Ensure filenames are unique across test suite
MRichards99 Dec 4, 2020
42359fc
#150: Create localised conftest files
MRichards99 Dec 4, 2020
b2af27d
#150: Add remaining data creation fixtures for DB backend tests
MRichards99 Dec 4, 2020
1b91217
#150: Add get with filter tests for DB backend
MRichards99 Dec 4, 2020
8c1941d
#150: Fix openapi YAML creation
MRichards99 Dec 7, 2020
3eec346
#150: Add findone tests for DB backend
MRichards99 Dec 7, 2020
c5a867c
#150: Actually fix openapi YAML creation
MRichards99 Dec 7, 2020
0c59b58
#150: Add ISIS endpoint testing for DB backend
MRichards99 Dec 7, 2020
4039233
#150: Add documentation for running the tests
MRichards99 Dec 8, 2020
3b6251c
Merge branch 'feature/fix-code-linting-#184' into feature/test-multip…
MRichards99 Dec 8, 2020
5f10ecc
Merge branch 'feature/fix-code-linting-#184' into feature/test-multip…
MRichards99 Dec 8, 2020
96f5aec
#190: Make small changes to existing docs
MRichards99 Dec 8, 2020
8b24725
#190: Update README.md for ICAT backend
MRichards99 Dec 9, 2020
f2f7f55
#165: Add a note to remind users to have user's Python added to PATH
MRichards99 Dec 9, 2020
60c56f6
#190: Rename query_filter_factory.py
MRichards99 Dec 9, 2020
93d0980
#190: Make change to project tree based on previous commit
MRichards99 Dec 18, 2020
91f90a1
Merge branch 'feature/fix-code-linting-#184' into feature/test-multip…
MRichards99 Dec 18, 2020
135965c
#165: Remove details regarding tmpdir cmd option
MRichards99 Jan 4, 2021
01449cc
Merge branch 'feature/fix-code-linting-#184' into feature/test-multip…
MRichards99 Jan 4, 2021
baff80d
Update datagateway_api/common/backends.py
MRichards99 Jan 4, 2021
e826e20
#150: Make requested changes on PR review
MRichards99 Jan 4, 2021
6dea07e
Merge branch 'feature/test-multiple-backends-#150' of github.com:ral-…
MRichards99 Jan 4, 2021
f320600
#190: Make requested changes from PR linked to this issue
MRichards99 Jan 4, 2021
73bb72d
#190: Add link to icat.manual repo for tutorials on setting up an IC…
MRichards99 Jan 5, 2021
fb3900b
#190: Add --without-hashes options to poetry export cmd
MRichards99 Jan 5, 2021
5301cfd
Merge pull request #192 from ral-facilities/feature/add-icat-backend-…
MRichards99 Jan 5, 2021
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ config.json
.vscode/
.nox/
.python-version
.coverage
546 changes: 428 additions & 118 deletions README.md

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion config.json.example
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@
"debug_mode": false,
"generate_swagger": false,
"host": "127.0.0.1",
"port": "5000"
"port": "5000",
"test_user_credentials": {"username": "root", "password": "pw"},
"test_mechanism": "simple"
}
4 changes: 2 additions & 2 deletions datagateway_api/common/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def get_facility_cycles_for_instrument_count_with_filters(
pass

@abstractmethod
def get_investigations_for_instrument_in_facility_cycle_with_filters(
def get_investigations_for_instrument_facility_cycle_with_filters(
self, session_id, instrument_id, facilitycycle_id, filters,
):
"""
Expand All @@ -188,7 +188,7 @@ def get_investigations_for_instrument_in_facility_cycle_with_filters(
pass

@abstractmethod
def get_investigation_count_for_instrument_facility_cycle_with_filters(
def get_investigation_count_instrument_facility_cycle_with_filters(
self, session_id, instrument_id, facilitycycle_id, filters,
):
"""
Expand Down
33 changes: 23 additions & 10 deletions datagateway_api/common/backends.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
import sys

from datagateway_api.common.backend import Backend
from datagateway_api.common.config import config
from datagateway_api.common.database.backend import DatabaseBackend
from datagateway_api.common.icat.backend import PythonICATBackend


backend_type = config.get_backend_type()
def create_backend(backend_type):
"""
Create an instance of a backend dependent on the value parsed into the function. The
value will typically be from the contents of `config.json`, however when creating a
backend during automated tests the value will be from the Flask app's config (which
will be set in the API's config at `common.config`

if backend_type == "db":
backend = DatabaseBackend()
elif backend_type == "python_icat":
backend = PythonICATBackend()
else:
sys.exit(f"Invalid config value '{backend_type}' for config option backend")
backend = Backend()
The API will exit if a valid value isn't given.

:param backend_type: The type of backend that should be created and used for the API
:type backend_type: :class:`str`
:return: Either an instance of `common.database.backend.DatabaseBackend` or
`common.icat.backend.PythonICATBackend`
"""

if backend_type == "db":
backend = DatabaseBackend()
elif backend_type == "python_icat":
backend = PythonICATBackend()
else:
# Might turn to a warning so the abstract class can be tested?
sys.exit(f"Invalid config value '{backend_type}' for config option backend")

return backend
32 changes: 28 additions & 4 deletions datagateway_api/common/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,30 @@


class Config(object):
def __init__(self):
config_path = Path(__file__).parent.parent.parent / "config.json"
with open(config_path) as target:
def __init__(self, path=Path(__file__).parent.parent.parent / "config.json"):
self.path = path
with open(self.path) as target:
self.config = json.load(target)
target.close()

def get_backend_type(self):
try:
return self.config["backend"]
except KeyError:
sys.exit("Missing config value, backend")

def set_backend_type(self, backend_type):
"""
This setter is used as a way for automated tests to set the backend type. The
API can detect if the Flask app setup is from an automated test by checking the
app's config for a `TEST_BACKEND`. If this value exists (a KeyError will be
raised when the API is run normally, which will then grab the backend type from
`config.json`), it needs to be set using this function. This is required because
creating filters in the `QueryFilterFactory` is backend-specific so the backend
type must be fetched. This must be done using this module (rather than directly
importing and checking the Flask app's config) to avoid circular import issues.
"""
self.config["backend"] = backend_type

def get_db_url(self):
try:
return self.config["DB_URL"]
Expand Down Expand Up @@ -76,6 +88,18 @@ def get_port(self):
except KeyError:
sys.exit("Missing config value, port")

def get_test_user_credentials(self):
try:
return self.config["test_user_credentials"]
except KeyError:
sys.exit("Missing config value, test_user_credentials")

def get_test_mechanism(self):
try:
return self.config["test_mechanism"]
except KeyError:
sys.exit("Missing config value, test_mechanism")

def get_icat_properties(self):
"""
ICAT properties can be retrieved using Python ICAT's client object, however this
Expand Down
3 changes: 3 additions & 0 deletions datagateway_api/common/constants.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from datetime import datetime

from datagateway_api.common.config import config


Expand All @@ -6,3 +8,4 @@ class Constants:
ACCEPTED_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
PYTHON_ICAT_DISTNCT_CONDITION = "!= null"
ICAT_PROPERTIES = config.get_icat_properties()
TEST_MOD_CREATE_DATETIME = datetime(2000, 1, 1)
4 changes: 2 additions & 2 deletions datagateway_api/common/database/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def get_facility_cycles_for_instrument_count_with_filters(

@requires_session_id
@queries_records
def get_investigations_for_instrument_in_facility_cycle_with_filters(
def get_investigations_for_instrument_facility_cycle_with_filters(
self, session_id, instrument_id, facilitycycle_id, filters,
):
return get_investigations_for_instrument_in_facility_cycle(
Expand All @@ -133,7 +133,7 @@ def get_investigations_for_instrument_in_facility_cycle_with_filters(

@requires_session_id
@queries_records
def get_investigation_count_for_instrument_facility_cycle_with_filters(
def get_investigation_count_instrument_facility_cycle_with_filters(
self, session_id, instrument_id, facilitycycle_id, filters,
):
return get_investigations_for_instrument_in_facility_cycle_count(
Expand Down
78 changes: 11 additions & 67 deletions datagateway_api/common/database/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@

from sqlalchemy.orm import aliased

from datagateway_api.common.config import config
from datagateway_api.common.database.filters import (
DatabaseIncludeFilter as IncludeFilter,
DatabaseWhereFilter as WhereFilter,
)
from datagateway_api.common.database.models import (
FACILITY,
FACILITYCYCLE,
Expand All @@ -16,40 +19,13 @@
)
from datagateway_api.common.database.session_manager import session_manager
from datagateway_api.common.exceptions import (
ApiError,
AuthenticationError,
BadRequestError,
FilterError,
MissingRecordError,
)
from datagateway_api.common.filter_order_handler import FilterOrderHandler


backend_type = config.get_backend_type()
if backend_type == "db":
from datagateway_api.common.database.filters import (
DatabaseDistinctFieldFilter as DistinctFieldFilter,
DatabaseIncludeFilter as IncludeFilter,
DatabaseLimitFilter as LimitFilter,
DatabaseOrderFilter as OrderFilter,
DatabaseSkipFilter as SkipFilter,
DatabaseWhereFilter as WhereFilter,
)
elif backend_type == "python_icat":
from datagateway_api.common.icat.filters import (
PythonICATDistinctFieldFilter as DistinctFieldFilter,
PythonICATIncludeFilter as IncludeFilter,
PythonICATLimitFilter as LimitFilter,
PythonICATOrderFilter as OrderFilter,
PythonICATSkipFilter as SkipFilter,
PythonICATWhereFilter as WhereFilter,
)
else:
raise ApiError(
"Cannot select which implementation of filters to import, check the config file"
" has a valid backend type",
)

log = logging.getLogger()


Expand Down Expand Up @@ -202,42 +178,6 @@ def execute_query(self):
self.commit_changes()


class QueryFilterFactory(object):
@staticmethod
def get_query_filter(request_filter):
"""
Given a filter return a matching Query filter object

This factory is not in common.filters so the created filter can be for the
correct backend. Moving the factory into that file would mean the filters would
be based off the abstract classes (because they're in the same file) which won't
enable filters to be unique to the backend

:param request_filter: dict - The filter to create the QueryFilter for
:return: The QueryFilter object created
"""
filter_name = list(request_filter)[0].lower()
if filter_name == "where":
field = list(request_filter[filter_name].keys())[0]
operation = list(request_filter[filter_name][field].keys())[0]
value = request_filter[filter_name][field][operation]
return WhereFilter(field, value, operation)
elif filter_name == "order":
field = request_filter["order"].split(" ")[0]
direction = request_filter["order"].split(" ")[1]
return OrderFilter(field, direction)
elif filter_name == "skip":
return SkipFilter(request_filter["skip"])
elif filter_name == "limit":
return LimitFilter(request_filter["limit"])
elif filter_name == "include":
return IncludeFilter(request_filter["include"])
elif filter_name == "distinct":
return DistinctFieldFilter(request_filter["distinct"])
else:
raise FilterError(f" Bad filter: {request_filter}")


def insert_row_into_table(table, row):
"""
Insert the given row into its table
Expand Down Expand Up @@ -285,7 +225,7 @@ def get_row_by_id(table, id_):
:return: the record retrieved
"""
with ReadQuery(table) as read_query:
log.info(" Querying %s for record with ID: %d", table.__tablename__, id_)
log.info(" Querying %s for record with ID: %s", table.__tablename__, id_)
where_filter = WhereFilter("ID", id_, "eq")
where_filter.apply_filter(read_query)
return read_query.get_single_result()
Expand All @@ -299,7 +239,7 @@ def delete_row_by_id(table, id_):
:param table: the table to be searched
:param id_: the id of the record to delete
"""
log.info(" Deleting row from %s with ID: %d", table.__tablename__, id_)
log.info(" Deleting row from %s with ID: %s", table.__tablename__, id_)
row = get_row_by_id(table, id_)
with DeleteQuery(table, row) as delete_query:
delete_query.execute_query()
Expand Down Expand Up @@ -389,7 +329,11 @@ def get_first_filtered_row(table, filters):
:return: the first row matching the filter
"""
log.info(" Getting first filtered row for %s", table.__tablename__)
return get_rows_by_filter(table, filters)[0]
try:
result = get_rows_by_filter(table, filters)[0]
except IndexError:
raise MissingRecordError()
return result


def get_filtered_row_count(table, filters):
Expand Down
12 changes: 9 additions & 3 deletions datagateway_api/common/filters.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from abc import ABC, abstractmethod
import logging

from datagateway_api.common.exceptions import BadRequestError
from datagateway_api.common.exceptions import BadRequestError, FilterError

log = logging.getLogger()

Expand Down Expand Up @@ -55,14 +55,20 @@ class SkipFilter(QueryFilter):
precedence = 3

def __init__(self, skip_value):
self.skip_value = skip_value
if skip_value >= 0:
self.skip_value = skip_value
else:
raise FilterError("The value of the skip filter must be positive")


class LimitFilter(QueryFilter):
precedence = 4

def __init__(self, limit_value):
self.limit_value = limit_value
if limit_value >= 0:
self.limit_value = limit_value
else:
raise FilterError("The value of the limit filter must be positive")


class IncludeFilter(QueryFilter):
Expand Down
2 changes: 1 addition & 1 deletion datagateway_api/common/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
from flask_restful import reqparse
from sqlalchemy.exc import IntegrityError

from datagateway_api.common.database.helpers import QueryFilterFactory
from datagateway_api.common.exceptions import (
ApiError,
AuthenticationError,
BadRequestError,
FilterError,
MissingCredentialsError,
)
from datagateway_api.common.query_filter_factory import QueryFilterFactory

log = logging.getLogger()

Expand Down
4 changes: 2 additions & 2 deletions datagateway_api/common/icat/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def get_facility_cycles_for_instrument_count_with_filters(

@requires_session_id
@queries_records
def get_investigations_for_instrument_in_facility_cycle_with_filters(
def get_investigations_for_instrument_facility_cycle_with_filters(
self, session_id, instrument_id, facilitycycle_id, filters, **kwargs,
):
client = kwargs["client"] if kwargs["client"] else create_client()
Expand All @@ -147,7 +147,7 @@ def get_investigations_for_instrument_in_facility_cycle_with_filters(

@requires_session_id
@queries_records
def get_investigation_count_for_instrument_facility_cycle_with_filters(
def get_investigation_count_instrument_facility_cycle_with_filters(
self, session_id, instrument_id, facilitycycle_id, filters, **kwargs,
):
client = kwargs["client"] if kwargs["client"] else create_client()
Expand Down
9 changes: 6 additions & 3 deletions datagateway_api/common/icat/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ def update_attributes(old_entity, new_entity):
- typically if Python ICAT doesn't allow an attribute to be edited (e.g. modId &
modTime)
"""
log.debug("Updating entity attributes: %s", list(new_entity.keys()))
for key in new_entity:
try:
original_data_attribute = getattr(old_entity, key)
Expand All @@ -194,8 +195,10 @@ def update_attributes(old_entity, new_entity):
def push_data_updates_to_icat(entity):
try:
entity.update()
except (ICATValidationError, ICATInternalError) as e:
except ICATInternalError as e:
raise PythonICATError(e)
except ICATValidationError as e:
raise BadRequestError(e)


def get_entity_by_id(
Expand Down Expand Up @@ -517,13 +520,13 @@ def create_entities(client, entity_type, data):
for entity in created_icat_data:
try:
entity.create()
except (ICATValidationError, ICATInternalError) as e:
except ICATInternalError as e:
for entity_json in created_data:
# Delete any data that has been pushed to ICAT before the exception
delete_entity_by_id(client, entity_type, entity_json["id"])

raise PythonICATError(e)
except (ICATObjectExistsError, ICATParameterError) as e:
except (ICATObjectExistsError, ICATParameterError, ICATValidationError) as e:
for entity_json in created_data:
delete_entity_by_id(client, entity_type, entity_json["id"])

Expand Down
2 changes: 1 addition & 1 deletion datagateway_api/common/icat/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,4 +325,4 @@ def flatten_query_included_fields(self, includes):
ICAT query
"""

return [m for n in (field.split(".") for field in includes) for m in n]
return [m for n in (field.split(".") for field in sorted(includes)) for m in n]
Loading