Skip to content

Commit

Permalink
Merge pull request #86 from RockefellerArchiveCenter/issue-82
Browse files Browse the repository at this point in the history
Validates accession and bag data against local schema
  • Loading branch information
helrond authored Jan 27, 2020
2 parents ea42030 + d52bee8 commit a080c00
Show file tree
Hide file tree
Showing 33 changed files with 575 additions and 691 deletions.
29 changes: 10 additions & 19 deletions bagdiscovery/library.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import json
import jsonschema
import os
import requests
import shutil
import tarfile

from bravado_core.spec import Spec
from bravado_core.validate import validate_object

from .models import Bag
from ursa_major import settings

Expand All @@ -15,6 +13,12 @@ class BagDiscoveryException(Exception): pass
class CleanupException(Exception): pass


def validate_data(data):
with open(os.path.join(settings.BASE_DIR, settings.SCHEMA_PATH), "r") as jf:
schema = json.load(jf)
jsonschema.validate(instance=data, schema=schema)


class BagDiscovery:
"""Discovers and stores bags, and delivers data to another service."""
def __init__(self, url, dirs=None):
Expand Down Expand Up @@ -59,8 +63,11 @@ def save_bag_data(self, bag):
try:
with open(os.path.join(self.tmp_dir, bag.bag_identifier, "{}.json".format(bag.bag_identifier))) as json_file:
bag_data = json.load(json_file)
validate_data(bag_data)
bag.data = bag_data
bag.save()
except jsonschema.exceptions.ValidationError as e:
raise BagDiscoveryException("Invalid bag data: {}: {}".format(list(e.path), e.message))
except Exception as e:
raise BagDiscoveryException("Error saving bag data: {}".format(e), bag.bag_identifier)

Expand Down Expand Up @@ -104,19 +111,3 @@ def run(self):
return ("Transfer was not found.", self.identifier)
except Exception as e:
raise CleanupException(e, self.identifier)


class DataValidator:
def __init__(self, schema_url):
bravado_config = {
'validate_swagger_spec': False,
'validate_requests': False,
'validate_responses': False,
'use_models': True,
}
spec_dict = requests.get(schema_url).json()
self.spec = Spec.from_dict(spec_dict, config=bravado_config)
self.Accession = spec_dict['definitions']['Accession']

def validate(self, data):
validate_object(self.spec, self.Accession, data)
35 changes: 17 additions & 18 deletions bagdiscovery/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,19 @@ def setUp(self):
makedirs(dir)

def createobjects(self):
with process_vcr.use_cassette('store_bags.json'):
print('*** Creating objects ***')
accession_count = 0
transfer_count = 0
for f in listdir(data_fixture_dir):
with open(join(data_fixture_dir, f), 'r') as json_file:
accession_data = json.load(json_file)
request = self.factory.post(reverse('accession-list'), accession_data, format='json')
response = AccessionViewSet.as_view(actions={"post": "create"})(request)
self.assertEqual(response.status_code, 201, "Wrong HTTP code")
accession_count += 1
transfer_count += len(accession_data['transfers'])
self.assertEqual(len(Accession.objects.all()), accession_count, "Wrong number of accessions created")
self.assertEqual(len(Bag.objects.all()), transfer_count, "Wrong number of transfers created")
print('*** Creating objects ***')
accession_count = 0
transfer_count = 0
for f in listdir(data_fixture_dir):
with open(join(data_fixture_dir, f), 'r') as json_file:
accession_data = json.load(json_file)
request = self.factory.post(reverse('accession-list'), accession_data, format='json')
response = AccessionViewSet.as_view(actions={"post": "create"})(request)
self.assertEqual(response.status_code, 201, "Response error: {}".format(response.data))
accession_count += 1
transfer_count += len(accession_data['transfers'])
self.assertEqual(len(Accession.objects.all()), accession_count, "Wrong number of accessions created")
self.assertEqual(len(Bag.objects.all()), transfer_count, "Wrong number of transfers created")

def process_bags(self):
with process_vcr.use_cassette('process_bags.json'):
Expand All @@ -73,24 +72,24 @@ def run_view(self):
print('*** Test run view ***')
request = self.factory.post(reverse('bagdiscovery'), {"test": True})
response = BagDiscoveryView.as_view()(request)
self.assertEqual(response.status_code, 200, "Wrong HTTP code")
self.assertEqual(response.status_code, 200, "Response error: {}".format(response.data))

def cleanup_view(self):
print('*** Test cleanup view ***')
for bag in Bag.objects.all():
request = self.factory.post(reverse('cleanup'), {"test": True, "identifier": bag.bag_identifier})
response = CleanupRoutineView.as_view()(request)
self.assertEqual(response.status_code, 200, "Wrong HTTP code")
self.assertEqual(response.status_code, 200, "Response error: {}".format(response.data))

def schema(self):
print('*** Getting schema view ***')
schema = self.client.get(reverse('schema'))
self.assertEqual(schema.status_code, 200, "Wrong HTTP code")
self.assertEqual(schema.status_code, 200, "Response error: {}".format(schema))

def health_check(self):
print('*** Getting status view ***')
status = self.client.get(reverse('api_health_ping'))
self.assertEqual(status.status_code, 200, "Wrong HTTP code")
self.assertEqual(status.status_code, 200, "Response error: {}".format(status))

def tearDown(self):
for d in [self.src_dir, self.dest_dir]:
Expand Down
15 changes: 3 additions & 12 deletions bagdiscovery/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from rest_framework.viewsets import ModelViewSet
from rest_framework.response import Response

from .library import BagDiscovery, CleanupRoutine, DataValidator
from .library import BagDiscovery, CleanupRoutine, validate_data
from .models import Accession, Bag
from .serializers import AccessionSerializer, AccessionListSerializer, BagSerializer, BagListSerializer
from ursa_major import settings
Expand Down Expand Up @@ -35,18 +35,9 @@ def get_serializer_class(self):
return AccessionListSerializer
return AccessionSerializer

def format_field_path(self, absolute_path):
path = []
for part in absolute_path:
if type(part) is str:
path.append(part)
elif type(part) is int:
path[-1] = path[-1] + "[{}]".format(part)
return '.'.join(path)

def create(self, request):
try:
DataValidator(settings.SCHEMA_URL).validate(request.data)
validate_data(request.data)
accession = Accession.objects.create(
data=request.data
)
Expand All @@ -59,7 +50,7 @@ def create(self, request):
transfer_ids.append(t['identifier'])
return Response(prepare_response(("Accession stored and transfer objects created", transfer_ids)), status=201)
except ValidationError as e:
return Response(prepare_response("Invalid accession data: {}: {}".format(self.format_field_path(e.absolute_path), e.message)), status=400)
return Response(prepare_response("Invalid accession data: {}: {}".format(list(e.path), e.message)), status=400)
except IntegrityError as e:
return Response(prepare_response(e), status=409)
except Exception as e:
Expand Down
Binary file modified fixtures/bags/108f7857-6c40-4838-99cb-e19437d93d85.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/10fd15d0-6b65-43e6-a8ec-132d1d46f024.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/1f4ba5d4-ea2d-4bc3-9dfc-a61f8e2224c4.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/1f77ea3a-7911-491f-84a8-898622be74aa.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/2677047c-ad05-4201-8649-8fcabaf2ad47.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/286e977d-ff33-4345-a532-4d6d85c25b3a.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/2913657b-df1f-4997-8240-e69277b00847.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/2db47a0b-d469-4ab6-a9e2-606d5c620c3c.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/39d63509-9a6e-4047-a504-dcfcf0d5af15.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/67447d09-932e-4315-a719-7c9c3d03de66.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/6dfe74ae-5e80-4e42-90fb-aa4ecec752f2.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/77f47741-2339-4f72-9d45-42fe26d46f9f.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/7e941c05-dc2f-499d-af96-128440737d5d.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/83c3c5df-6319-485d-87bf-6b2d2e6fbbd8.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/9de98d3b-709f-418e-941f-b9bdb19dd48a.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/abcbcf60-d197-4c54-bf67-42f80b10f190.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/b388b08e-aa38-43cf-8870-7eb4fac0447b.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/c0ba9e67-baa4-434f-8891-bab25e8655c6.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/c886ab20-0641-4a21-b2d0-8a0a3f1db3b2.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/c96cf4ac-ea26-42ba-82f5-c640bc93dfce.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/cb73cc38-b829-48ad-a90f-2dbd93da6721.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/ea245504-ea90-404e-b515-86cc53c4957c.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/f38e502f-395e-414e-ab77-44c35f4a401a.tar.gz
Binary file not shown.
Binary file modified fixtures/bags/fb03ad48-c851-4bac-9b1e-6b7b8c454665.tar.gz
Binary file not shown.
Loading

0 comments on commit a080c00

Please sign in to comment.