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

Updates for Fedora 6.5 #20

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
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
Next Next commit
Re-add in camel-toolbox test
  • Loading branch information
whikloj committed Mar 3, 2023
commit 36f8564dfe8ff8f23c16290cd4eab4f3d373a5df
42 changes: 32 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -68,6 +68,8 @@ second_site:
password1: password1
user2: user2
password2: password2
solrurl: http://someserver:8080/solr
triplestoreurl: http://someserver:8080/fuseki/test/sparql
```

To use the `second_site` configuration, simply start the testrunner with
@@ -82,11 +84,13 @@ You can also choose to run only a subset of all tests using the `-t|--tests` arg
of the following values which indicate which tests to run.
* `authz` - Authorization tests
* `basic` - Basic interaction tests
* `sparql` - Sparql operation tests
* `camel` - Camel toolbox tests (see [note](#camel-tests))
* `fixity` - Binary fixity tests
* `indirect` - Indirect container tests
* `rdf` - RDF serialization tests
* `version` - Versioning tests
* `sparql` - Sparql operation tests
* `transaction` - Transcation tests
* `fixity` - Binary fixity tests
* `version` - Versioning tests

Without this parameter all the above tests will be run.

@@ -95,6 +99,14 @@ To run only the `authz` and `sparql` tests you would execute:
./testrunner.py -c config.yml -t authz,sparql
```

##### Camel Tests
`camel` tests are **NOT** executed by default, due to timing issues they should be run separately.

They also require the configuration to have a `solrurl` parameter pointing to a Solr endpoint and a
`triplestoreurl` parameter pointing to the SPARQL endpoint of a triplestore fed.

Both of these systems must be fed by the fcrepo-camel-toolbox for this testing.

## Tests implemented

### authz
@@ -121,11 +133,27 @@ To run only the `authz` and `sparql` tests you would execute:
1. Create a LDP Indirect container
1. Validate the correct Link header type

### camel - not run by default
1. Create a container
1. Check the container is indexed to Solr
1. Check the container is indexed to the triplestore

### fixity
1. Create a binary resource
1. Get a fixity result for that resource
1. Compare that the SHA-1 hash matches the expected value

### indirect
1. Create a pcdm:Object
2. Create a pcdm:Collection
3. Create an indirect container "members" inside the pcdm:Collection
4. Create a proxy object for the pcdm:Object inside the **members** indirectContainer
5. Verify that the pcdm:Collection has the memberRelation property added pointing to the pcdm:Object

### rdf
1. Create a RDFSource object.
1. Retrieve that object in all possible RDF serializations.

### sparql
1. Create a container
1. Set the dc:title of the container with a Patch request
@@ -137,7 +165,7 @@ To run only the `authz` and `sparql` tests you would execute:
1. Verify the title
1. Create a container
1. Update the title to text with Unicode characters
1. Verify the title
1. Verify the title

### transaction
1. Create a transaction
@@ -170,9 +198,3 @@ To run only the `authz` and `sparql` tests you would execute:
1. Create Memento at deleted memento's datetime
1. Verify Memento exists

### indirect
1. Create a pcdm:Object
2. Create a pcdm:Collection
3. Create an indirect container "members" inside the pcdm:Collection
4. Create a proxy object for the pcdm:Object inside the **members** indirectContainer
5. Verify that the pcdm:Collection has the memberRelation property added pointing to the pcdm:Object
12 changes: 12 additions & 0 deletions TestConstants.py
Original file line number Diff line number Diff line change
@@ -10,6 +10,8 @@
USER2_PASS_PARAM = "password2"
LOG_FILE_PARAM = "logfile"
SELECTED_TESTS_PARAM = "selected_tests"
SOLR_URL_PARAM = "solrurl"
TRIPLESTORE_URL_PARAM = "triplestoreurl"
# Via RFC 7231 3.3
PAYLOAD_HEADERS = ['Content-Length', 'Content-Range', 'Trailer', 'Transfer-Encoding']

@@ -31,6 +33,9 @@
# General Mime and LDP constants
JSONLD_MIMETYPE = "application/ld+json"
SPARQL_UPDATE_MIMETYPE = "application/sparql-update"
TURTLE_MIMETYPE = "text/turtle"
SPARQL_QUERY_MIMETYPE = "application/sparql-query"
SPARQL_RESULT_JSON_MIMETYPE = "application/sparql-results+json"

LDP_NS = "http://www.w3.org/ns/ldp#"
LDP_CONTAINER = LDP_NS + "Container"
@@ -50,3 +55,10 @@
"@prefix pcdm: <http://pcdm.org/models#> ." \
"<> a pcdm:Object ;" \
"dc:title \"An Object\" ."

PCDM_CONTAINER_TITLE = "PCDM Container"

PCDM_CONTAINER_TTL = "@prefix dc: <http://purl.org/dc/elements/1.1/> ." \
"@prefix pcdm: <http://pcdm.org/models#> ." \
"<> a pcdm:Object ;" \
"dc:title \"{0}\" .".format(PCDM_CONTAINER_TITLE)
136 changes: 136 additions & 0 deletions camel_tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#!/bin/env python

import TestConstants
from abstract_fedora_tests import FedoraTests, register_tests, Test
import uuid
import datetime
import requests
import json
import pyjq


@register_tests
class FedoraCamelTests(FedoraTests):

# Create test objects all inside here for easy of review.
CONTAINER = "/test_camel"

# How many seconds to wait for indexing to Solr and/or triplestore.
CONTAINER_WAIT = 30

def run_tests(self):
if not (self.hasSolrUrl() and self.hasTriplestoreUrl()):
print("**** Cannot run camel tests without a Solr and/or Triplestore base url ****")
else:
super().run_tests()

@Test
def createObject(self):
self.log("Create an object")
internal_id = str(uuid.uuid4())
expected_url = self.getBaseUri() + "/" + internal_id
headers = {
'Slug': internal_id,
'Content-type': TestConstants.TURTLE_MIMETYPE
}
r = self.do_post(headers=headers, body=TestConstants.PCDM_CONTAINER_TTL)
self.assertEqual(201, r.status_code, "Did not get expected response code")

if self.hasSolrUrl():
self.log("Checking for item in Solr")
solr_response = self.timedQuery('querySolr', 'solrNumFound', expected_url)
if solr_response is not None:
self.assertEqual(expected_url, self.getIdFromSolr(solr_response), "Did not find ID in Solr.")
else:
self.fail("Timed out waiting to find record in Solr.")

if self.hasTriplestoreUrl():
self.log("Checking for item in Triplestore")
triplestore_response = self.timedQuery('queryTriplestore', 'triplestoreNumFound', expected_url)
if triplestore_response is not None:
self.assertEqual(TestConstants.PCDM_CONTAINER_TITLE, self.getIdFromTriplestore(triplestore_response),
"Did not find ID in Triplestore")
else:
self.fail("Timed out waiting to find record in Triplestore")

# Utility functions.
def timedQuery(self, query_method, check_method, query_value):
query_func = getattr(self, query_method, None)
check_func = getattr(self, check_method, None)
if query_func is None or check_func is None:
Exception("Can't find expected methods {0}, {1}".format(query_method, check_method))
current_time = datetime.datetime.now()
end_time = current_time + datetime.timedelta(seconds=self.CONTAINER_WAIT)
last_query = None
while current_time <= end_time:
# If a multiple of 5 seconds has passed since the last query, do the query
if last_query is None or (current_time - last_query).seconds >= 5:
last_query = datetime.datetime.now()
response = query_func(query_value)
if check_func(response) is not None:
return response
current_time = datetime.datetime.now()
return None

def hasSolrUrl(self):
try:
return self.config[TestConstants.SOLR_URL_PARAM] is not None and \
len(self.config[TestConstants.SOLR_URL_PARAM].strip()) > 0
except KeyError:
return False

def hasTriplestoreUrl(self):
try:
return self.config[TestConstants.TRIPLESTORE_URL_PARAM] is not None and \
len(self.config[TestConstants.TRIPLESTORE_URL_PARAM].strip()) > 0
except KeyError:
return False

def solrNumFound(self, response):
body = response.content.decode('UTF-8')
json_body = json.loads(body)
num_found = pyjq.first('.response.numFound', json_body)
if num_found is not None and int(num_found) > 0:
return num_found
return None

def querySolr(self, expected_id):
solr_select = self.config[TestConstants.SOLR_URL_PARAM].rstrip('/') + "/select"
params = {
'q': 'id:"' + expected_id + '"',
'wt': 'json'
}
r = requests.get(solr_select, params=params)
self.assertEqual(200, r.status_code, "Did not query Solr successfully.")
return r

def getIdFromSolr(self, response):
body = response.content.decode('UTF-8')
json_body = json.loads(body)
found_title = pyjq.first('.response.docs[].id', json_body)
return found_title

def queryTriplestore(self, expected_id):
query = "PREFIX dc: <http://purl.org/dc/elements/1.1/> SELECT ?o WHERE { <" + expected_id + "> dc:title ?o}"
headers = {
'Content-type': TestConstants.SPARQL_QUERY_MIMETYPE,
'Accept': TestConstants.SPARQL_RESULT_JSON_MIMETYPE
}
r = requests.post(self.config[TestConstants.TRIPLESTORE_URL_PARAM], headers=headers, data=query)
self.assertEqual(200, r.status_code, 'Did not query Triplestore successfully.')
return r

def triplestoreNumFound(self, response):
body = response.content.decode('UTF-8')
json_body = json.loads(body)
# This results a list of matching bindings, so it can be an empty list.
num_found = pyjq.all('.results.bindings[].o', json_body)
if num_found is not None and len(num_found) > 0:
return num_found
return None

def getIdFromTriplestore(self, response):
body = response.content.decode('UTF-8')
json_body = json.loads(body)
found_id = pyjq.first('.results.bindings[].o.value', json_body)
return found_id
10 changes: 10 additions & 0 deletions config.yml.example
Original file line number Diff line number Diff line change
@@ -7,3 +7,13 @@ default:
password1: testpass
user2: testuser2
password2: testpass
tomcat:
baseurl: http://localhost:8080/fcrepo/rest
admin_user: fedoraAdmin
admin_password: secret3
user1: adminuser
password1: password2
user2: testuser
password2: password1
solrurl: http://localhost:8080/solr
triplestoreurl: http://localhost:8080/fuseki/test/query
2 changes: 1 addition & 1 deletion rdf_tests.py
Original file line number Diff line number Diff line change
@@ -64,4 +64,4 @@ def testRdfSerialization(self):
r = self.do_get(location)
self.assertEqual(410, r.status_code, "Object's tombstone not found.")

self.log("Passed")
self.log("Passed")
12 changes: 9 additions & 3 deletions testrunner.py
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@
from transaction_tests import FedoraTransactionTests
from authz_tests import FedoraAuthzTests
from indirect_tests import FedoraIndirectTests
from camel_tests import FedoraCamelTests


class FedoraTestRunner:
@@ -31,7 +32,9 @@ class FedoraTestRunner:
(TestConstants.USER2_NAME_PARAM, True),
(TestConstants.USER2_PASS_PARAM, True),
(TestConstants.LOG_FILE_PARAM, False),
(TestConstants.SELECTED_TESTS_PARAM, False)
(TestConstants.SELECTED_TESTS_PARAM, False),
(TestConstants.SOLR_URL_PARAM, False),
(TestConstants.TRIPLESTORE_URL_PARAM, False)
]
config = {}
logger = None
@@ -99,6 +102,9 @@ def run_tests(self):
if test == 'all' or test == 'indirect':
indirect = FedoraIndirectTests(self.config)
indirect.run_tests()
if test == 'camel':
camel = FedoraCamelTests(self.config)
camel.run_tests()

def main(self, args):
self.set_up(args)
@@ -116,7 +122,7 @@ def csv_list(string):


class CSVAction(argparse.Action):
valid_options = ["authz", "basic", "sparql", "rdf", "version", "transaction", "fixity", "indirect"]
valid_options = ["authz", "basic", "sparql", "rdf", "version", "transaction", "fixity", "indirect", "camel"]

def __call__(self, parser, args, values, option_string=None):
if isinstance(values, list):
@@ -158,7 +164,7 @@ def __call__(self, parser, args, values, option_string=None):
parser.add_argument('-k', '--' + TestConstants.USER2_PASS_PARAM, dest=TestConstants.USER2_PASS_PARAM,
help="Second regular user password")
parser.add_argument('-t', '--tests', dest="selected_tests", help='Comma separated list of which tests to run from '
'{0}. Defaults to running all tests'.format(",".join(CSVAction.valid_options)),
'{0}. Defaults to running all tests'.format(", ".join(CSVAction.valid_options)),
default=['all'], type=csv_list, action=CSVAction)

args = parser.parse_args()