def delete(cls, record, account, public_id=None): """ Record a "delete" request, with the associated (minimal) record data, requested by the given account Delete requests need only come with enough record data to identify the public record :param record: The mimimal record data for identifying the record :param account: the account to carry out the request on behalf of :param public_id: the public id of a public record for which this is a delete request :return: the Request object that was created """ if record is None: raise RequestAPIException("You can't call 'delete' with a NoneType record argument") if account is None: raise RequestAPIException("You can't call 'delete' with a NoneType account argument") req = Request() req.record = record req.owner = account.id req.action = "delete" if public_id is not None: req.public_id = public_id req.save() return req
def test_05_request_dao(self): # Check the DAO methods on the Request object dao = Request() source = RequestFixtureFactory.example() req = Request(source) req.owner = "test1" req.action = "update" req.public_id = "abcdefg" req.save(blocking=True) req2 = dao.pull(req.id) assert req2 is not None # check successful queries for identifiers res = dao.find_by_identifier("doi", "10.1234/me", "test1") assert len(res) == 1 res = dao.find_by_identifier("pmcid", "PMC1234", "test1") assert len(res) == 1 res = dao.find_by_identifier("pmid", "87654321", "test1") assert len(res) == 1 res = dao.find_by_identifier("url", "http://example.com/whatever", "test1") assert len(res) == 1 # check unsuccessful ones res = dao.find_by_identifier("doi", "10.1234/you", "test1") assert len(res) == 0 res = dao.find_by_identifier("pmcid", "PMC5678", "test1") assert len(res) == 0 res = dao.find_by_identifier("pmid", "123456789", "test1") assert len(res) == 0 res = dao.find_by_identifier("url", "http://example.com/this", "test1") assert len(res) == 0 # and check using the wrong owner res = dao.find_by_identifier("doi", "10.1234/me", "test2") assert len(res) == 0 res = dao.find_by_identifier("pmcid", "PMC1234", "test2") assert len(res) == 0 res = dao.find_by_identifier("pmid", "87654321", "test2") assert len(res) == 0 res = dao.find_by_identifier("url", "http://example.com/whatever", "test2") assert len(res) == 0
def test_03_pull_request(self): # Pull a Request through the ApiRequest object acc = MonitorUKAccount() acc.id = "abcdefghij" acc.save(blocking=True) # first make a request which contains that doi req_source = RequestFixtureFactory.example() req = Request(req_source) req.save(blocking=True) # you can't pull a request object, so just show that that's true... # pull by doi should fail result = ApiRequest.pull("10.1234/me", account=acc) assert result is None # pull by request id should fail result = ApiRequest.pull(req.id, account=acc) assert result is None
def test_10_find_request(self): # Find a Request through a number of routes source = RequestFixtureFactory.example() req = Request(source) req.save(blocking=True) time.sleep(2) source = RequestFixtureFactory.example() req1 = Request(source) req1.save(blocking=True) # document to form the basis of the queries source2 = RequestFixtureFactory.example() # create sources with one of each kind of identifier, then look them up using the # find_request_by_identifier method result = RequestApi.find_request_by_identifier("doi", "10.1234/me", "abcdefghij") assert result is not None assert result.created_date == req1.created_date result = RequestApi.find_request_by_identifier("pmid", "87654321", "abcdefghij") assert result is not None assert result.created_date == req1.created_date result = RequestApi.find_request_by_identifier("pmcid", "PMC1234", "abcdefghij") assert result is not None assert result.created_date == req1.created_date result = RequestApi.find_request_by_identifier("url", "http://example.com/whatever", "abcdefghij") assert result is not None assert result.created_date == req1.created_date # finally, ensure that you don't get a match when you shouldn't result = RequestApi.find_request_by_identifier("doi", "10.1234/another", "abcdefghij") assert result is None result = RequestApi.find_request_by_identifier("doi", "10.1234/me", "test") assert result is None
def update(cls, record, account, public_id=None): """ Record an "update" request, with the associated record data, requested by the given account :param record: The raw dict data (e.g. coming from the web API) which makes up the body of the request :param account: the account to carry out the request on behalf of :param public_id: The public id of a public record for which this is an update :return: the Request object that was created """ if record is None: raise RequestAPIException("You can't call 'update' with a NoneType record argument") if account is None: raise RequestAPIException("You can't call 'update' with a NoneType account argument") req = Request() req.record = record req.owner = account.id req.action = "update" if public_id is not None: req.public_id = public_id req.save() return req
def test_13_request_iterator(self): # Check we can iterate successfully over lists of Requests sources = RequestFixtureFactory.request_per_day("2001-01", 10) for s in sources: req = Request(s) req.save() time.sleep(2) dao = Request() gen = dao.list_all_since("2001-01-01T00:00:00Z", page_size=5) # set the page size small, to ensure the iterator has to work results = [x for x in gen] assert len(results) == 10 dates = [r.created_date for r in results] comp = deepcopy(dates) comp.sort() # this puts the dates in ascending order (i.e. oldest first) # the point of this comparison is to show that the results came out in the right order. # that is, oldest first assert dates == comp
def test_11_process_requests_exception(self): # What happens when the process_reuests method fails for a variety of reasons sources = RequestFixtureFactory.request_per_day("2001-01", 9) dois = ["10.1234/first", "10.1234/second", "10.1234/third"] # we're going to construct a series of requests for each doi # starting with a create, then an update, followed by a delete # (not that it matters, as we're going to pump them through a mock) for i in range(len(sources)): s = sources[i] doi_idx = i % 3 # iterate over the dois 3 times doi = dois[doi_idx] s["record"]["dc:identifier"] = [{"type": "doi", "id": doi}] if i < 3: s["record"]["dc:title"] = "Create" req = Request(s) req.action = "update" req.save() elif i < 6: s["record"]["dc:title"] = "Update" req = Request(s) req.action = "update" req.save() else: s["record"]["dc:title"] = "Delete" req = Request(s) req.action = "delete" req.save() time.sleep(2) # set up the mocks PublicApi.publish = publish_mock PublicApi.remove = delete_mock # now run the process job back to the first day with self.assertRaises(TestException): WorkflowApi.process_requests() # we know this died during the 6th update request being processed, # so just check that the workflow state reflects that wfs_dao = WorkflowState() wfs = wfs_dao.pull("requests") assert wfs.last_request == "2001-01-05T00:00:00Z" assert len(wfs.already_processed) == 1
def test_11_process_requests_cycle(self): # Run through the process of processing a Request into a PublicAPC source = RequestFixtureFactory.example() if "id" in source: del source["id"] pub_dao = PublicAPC() wfs_dao = WorkflowState() # first make a record for the first time first = deepcopy(source) del first["record"]["dc:title"] req = Request(first) req.owner = "test" req.action = "update" req.save(blocking=True) # run the job WorkflowApi.process_requests() time.sleep(2) # first check that a public record was made pubs = pub_dao.find_by_doi("10.1234/me") assert len(pubs) == 1 assert pubs[0].record.get("dc:title") is None # check that the workflow state was created wfs = wfs_dao.pull("requests") assert wfs is not None assert wfs.last_request == req.created_date assert wfs.already_processed == [req.id] # now run an update with a different date second = deepcopy(source) second["record"]["dc:title"] = "Update" second["created_date"] = "2002-01-01T00:00:00Z" req2 = Request(second) req2.owner = "test" req2.action = "update" req2.save(blocking=True) # run the job again WorkflowApi.process_requests() time.sleep(2) # check the public record was updated pubs = pub_dao.find_by_doi("10.1234/me") assert len(pubs) == 1 assert pubs[0].record.get("dc:title") == "Update" # check that the workflow state was updated wfs = wfs_dao.pull("requests") assert wfs is not None assert wfs.last_request == req2.created_date assert wfs.already_processed == [req2.id] # now run an update with the same date, to observe the difference in the workflow state third = deepcopy(source) third["record"]["dc:title"] = "Update 2" third["created_date"] = "2002-01-01T00:00:00Z" req3 = Request(third) req3.owner = "test" req3.action = "update" req3.save(blocking=True) # run the job again WorkflowApi.process_requests() time.sleep(2) # check the public record was updated pubs = pub_dao.find_by_doi("10.1234/me") assert len(pubs) == 1 assert ( pubs[0].record.get("dc:title") == "Update 2" ) # should have been updated, as there are only apc contributions from one source # check that the workflow state was updated wfs = wfs_dao.pull("requests") assert wfs is not None assert wfs.last_request == req3.created_date assert wfs.already_processed == [req2.id, req3.id] # processed records should have been appended # finally issue a delete request fourth = deepcopy(source) fourth["created_date"] = "2003-01-01T00:00:00Z" req4 = Request(fourth) req4.owner = "test" req4.action = "delete" req4.save(blocking=True) # run the job again WorkflowApi.process_requests() time.sleep(2) # check the public record was updated pubs = pub_dao.find_by_doi("10.1234/me") assert len(pubs) == 0 # check that the workflow state was updated wfs = wfs_dao.pull("requests") assert wfs is not None assert wfs.last_request == req4.created_date assert wfs.already_processed == [req4.id] # processed records should have been appended