Migrate API tests in test_jobs.py to use test_history context.

More configurable, better error reporting, cleans up jobs, etc..
This commit is contained in:
John Chilton
2018-08-10 19:43:24 -04:00
parent 0b1d804cf6
commit c6b593b1ca
+111 -93
View File
@@ -11,6 +11,8 @@ from base.api_asserts import assert_status_code_is_ok # noqa: I100
from base.populators import ( # noqa: I100
DatasetCollectionPopulator,
DatasetPopulator,
skip_without_tool,
uses_test_history,
wait_on,
wait_on_state,
)
@@ -23,14 +25,16 @@ class JobsApiTestCase(api.ApiTestCase):
self.dataset_populator = DatasetPopulator(self.galaxy_interactor)
self.dataset_collection_populator = DatasetCollectionPopulator(self.galaxy_interactor)
def test_index(self):
@uses_test_history(require_new=True)
def test_index(self, history_id):
# Create HDA to ensure at least one job exists...
self.__history_with_new_dataset()
self.__history_with_new_dataset(history_id)
jobs = self.__jobs_index()
assert "upload1" in map(itemgetter("tool_id"), jobs)
def test_system_details_admin_only(self):
self.__history_with_new_dataset()
@uses_test_history(require_new=True)
def test_system_details_admin_only(self, history_id):
self.__history_with_new_dataset(history_id)
jobs = self.__jobs_index(admin=False)
job = jobs[0]
self._assert_not_has_keys(job, "command_line", "external_id")
@@ -39,12 +43,13 @@ class JobsApiTestCase(api.ApiTestCase):
job = jobs[0]
self._assert_has_keys(job, "command_line", "external_id")
def test_index_state_filter(self):
@uses_test_history(require_new=True)
def test_index_state_filter(self, history_id):
# Initial number of ok jobs
original_count = len(self.__uploads_with_state("ok"))
# Run through dataset upload to ensure num uplaods at least greater
# by 1.
self.__history_with_ok_dataset()
self.__history_with_ok_dataset(history_id)
# Verify number of ok jobs is actually greater.
count_increased = False
@@ -60,8 +65,9 @@ class JobsApiTestCase(api.ApiTestCase):
message = template % (original_count, new_count)
raise AssertionError(message)
def test_index_date_filter(self):
self.__history_with_new_dataset()
@uses_test_history(require_new=True)
def test_index_date_filter(self, history_id):
self.__history_with_new_dataset(history_id)
two_weeks_ago = (datetime.datetime.utcnow() - datetime.timedelta(7)).isoformat()
last_week = (datetime.datetime.utcnow() - datetime.timedelta(7)).isoformat()
next_week = (datetime.datetime.utcnow() + datetime.timedelta(7)).isoformat()
@@ -78,30 +84,33 @@ class JobsApiTestCase(api.ApiTestCase):
jobs = self.__jobs_index(data={"date_range_min": last_week, "date_range_max": next_week})
assert today_job_id in map(itemgetter("id"), jobs)
def test_index_history(self):
history_id, _ = self.__history_with_new_dataset()
@uses_test_history(require_new=True)
def test_index_history(self, history_id):
self.__history_with_new_dataset(history_id)
jobs = self.__jobs_index(data={"history_id": history_id})
assert len(jobs) > 0
history_id = self.dataset_populator.new_history()
jobs = self.__jobs_index(data={"history_id": history_id})
assert len(jobs) == 0
with self.dataset_populator.test_history() as other_history_id:
jobs = self.__jobs_index(data={"history_id": other_history_id})
assert len(jobs) == 0
def test_index_multiple_states_filter(self):
@uses_test_history(require_new=True)
def test_index_multiple_states_filter(self, history_id):
# Initial number of ok jobs
original_count = len(self.__uploads_with_state("ok", "new"))
# Run through dataset upload to ensure num uplaods at least greater
# by 1.
self.__history_with_ok_dataset()
self.__history_with_ok_dataset(history_id)
# Verify number of ok jobs is actually greater.
new_count = len(self.__uploads_with_state("new", "ok"))
assert original_count < new_count, new_count
def test_show(self):
@uses_test_history(require_new=True)
def test_show(self, history_id):
# Create HDA to ensure at least one job exists...
self.__history_with_new_dataset()
self.__history_with_new_dataset(history_id)
jobs_response = self._get("jobs")
first_job = jobs_response.json()[0]
@@ -114,8 +123,9 @@ class JobsApiTestCase(api.ApiTestCase):
job_details = show_jobs_response.json()
self._assert_has_key(job_details, 'id', 'state', 'exit_code', 'update_time', 'create_time')
def test_show_security(self):
history_id, _ = self.__history_with_new_dataset()
@uses_test_history(require_new=True)
def test_show_security(self, history_id):
self.__history_with_new_dataset(history_id)
jobs_response = self._get("jobs", data={"history_id": history_id})
job = jobs_response.json()[0]
job_id = job["id"]
@@ -131,8 +141,9 @@ class JobsApiTestCase(api.ApiTestCase):
show_jobs_response = self._get("jobs/%s" % job_id, admin=True)
self._assert_has_keys(show_jobs_response.json(), "command_line", "external_id")
def test_deleting_output_keep_running_until_all_deleted(self):
history_id, job_state, outputs = self._setup_running_two_output_job(120)
@uses_test_history(require_new=True)
def test_deleting_output_keep_running_until_all_deleted(self, history_id):
job_state, outputs = self._setup_running_two_output_job(history_id, 120)
self._hack_to_skip_test_if_state_ok(job_state)
@@ -153,8 +164,9 @@ class JobsApiTestCase(api.ApiTestCase):
final_state = wait_on_state(job_state, assert_ok=False, timeout=15)
assert final_state in ["deleted_new", "deleted"], final_state
def test_purging_output_keep_running_until_all_purged(self):
history_id, job_state, outputs = self._setup_running_two_output_job(120)
@uses_test_history(require_new=True)
def test_purging_output_keep_running_until_all_purged(self, history_id):
job_state, outputs = self._setup_running_two_output_job(history_id, 120)
# Pretty much right away after the job is running, these paths should be populated -
# if they are grab them and make sure they are deleted at the end of the job.
@@ -194,8 +206,9 @@ class JobsApiTestCase(api.ApiTestCase):
if output_dataset_paths_exist:
wait_on(paths_deleted, "path deletion")
def test_purging_output_cleaned_after_ok_run(self):
history_id, job_state, outputs = self._setup_running_two_output_job(10)
@uses_test_history(require_new=True)
def test_purging_output_cleaned_after_ok_run(self, history_id):
job_state, outputs = self._setup_running_two_output_job(history_id, 10)
# Pretty much right away after the job is running, these paths should be populated -
# if they are grab them and make sure they are deleted at the end of the job.
@@ -230,8 +243,7 @@ class JobsApiTestCase(api.ApiTestCase):
message = "Job state switch from running to ok too quickly - the rest of the test requires the job to be in a running state. Skipping test."
raise SkipTest(message)
def _setup_running_two_output_job(self, sleep_time):
history_id = self.dataset_populator.new_history()
def _setup_running_two_output_job(self, history_id, sleep_time):
payload = self.dataset_populator.run_tool_payload(
tool_id='create_2',
inputs=dict(
@@ -259,7 +271,7 @@ class JobsApiTestCase(api.ApiTestCase):
jobs_response = self._get("jobs/%s" % jobs[0]["id"])
return jobs_response
return history_id, job_state, outputs
return job_state, outputs
def _raw_update_history_item(self, history_id, item_id, data):
update_url = self._api_url("histories/%s/contents/%s" % (history_id, item_id), use_key=True)
@@ -267,57 +279,59 @@ class JobsApiTestCase(api.ApiTestCase):
assert_status_code_is_ok(update_response)
return update_response
def test_resume_job(self):
with self.dataset_populator.test_history() as history_id:
hda1 = self.dataset_populator.new_dataset(history_id, content="samp1\t10.0\nsamp2\t20.0\n")
hda2 = self.dataset_populator.new_dataset(history_id, content="samp1\t30.0\nsamp2\t40.0\n")
# Submit first job
payload = self.dataset_populator.run_tool_payload(
tool_id='cat_data_and_sleep',
inputs={
'sleep_time': 15,
'input1': {'src': 'hda', 'id': hda2['id']},
'queries_0|input2': {'src': 'hda', 'id': hda2['id']}
},
history_id=history_id,
)
run_response = self._post("tools", data=payload).json()
output = run_response["outputs"][0]
# Submit second job that waits on job1
payload = self.dataset_populator.run_tool_payload(
tool_id='cat1',
inputs={
'input1': {'src': 'hda', 'id': hda1['id']},
'queries_0|input2': {'src': 'hda', 'id': output['id']}
},
history_id=history_id,
)
run_response = self._post("tools", data=payload).json()
job_id = run_response['jobs'][0]['id']
output = run_response["outputs"][0]
# Delete second jobs input while second job is waiting for first job
delete_response = self._delete("histories/%s/contents/%s" % (history_id, hda1['id']))
self._assert_status_code_is(delete_response, 200)
self.dataset_populator.wait_for_history_jobs(history_id, assert_ok=False)
dataset_details = self._get("histories/%s/contents/%s" % (history_id, output['id'])).json()
assert dataset_details['state'] == 'paused'
# Undelete input dataset
undelete_response = self._put("histories/%s/contents/%s" % (history_id, hda1['id']),
data=json.dumps({'deleted': False}))
self._assert_status_code_is(undelete_response, 200)
resume_response = self._put("jobs/%s/resume" % job_id)
self._assert_status_code_is(resume_response, 200)
self.dataset_populator.wait_for_history_jobs(history_id, assert_ok=True)
dataset_details = self._get("histories/%s/contents/%s" % (history_id, output['id'])).json()
assert dataset_details['state'] == 'ok'
@skip_without_tool("cat_data_and_sleep")
@uses_test_history(require_new=True)
def test_resume_job(self, history_id):
hda1 = self.dataset_populator.new_dataset(history_id, content="samp1\t10.0\nsamp2\t20.0\n")
hda2 = self.dataset_populator.new_dataset(history_id, content="samp1\t30.0\nsamp2\t40.0\n")
# Submit first job
payload = self.dataset_populator.run_tool_payload(
tool_id='cat_data_and_sleep',
inputs={
'sleep_time': 15,
'input1': {'src': 'hda', 'id': hda2['id']},
'queries_0|input2': {'src': 'hda', 'id': hda2['id']}
},
history_id=history_id,
)
run_response = self._post("tools", data=payload).json()
output = run_response["outputs"][0]
# Submit second job that waits on job1
payload = self.dataset_populator.run_tool_payload(
tool_id='cat1',
inputs={
'input1': {'src': 'hda', 'id': hda1['id']},
'queries_0|input2': {'src': 'hda', 'id': output['id']}
},
history_id=history_id,
)
run_response = self._post("tools", data=payload).json()
job_id = run_response['jobs'][0]['id']
output = run_response["outputs"][0]
# Delete second jobs input while second job is waiting for first job
delete_response = self._delete("histories/%s/contents/%s" % (history_id, hda1['id']))
self._assert_status_code_is(delete_response, 200)
self.dataset_populator.wait_for_history_jobs(history_id, assert_ok=False)
dataset_details = self._get("histories/%s/contents/%s" % (history_id, output['id'])).json()
assert dataset_details['state'] == 'paused'
# Undelete input dataset
undelete_response = self._put("histories/%s/contents/%s" % (history_id, hda1['id']),
data=json.dumps({'deleted': False}))
self._assert_status_code_is(undelete_response, 200)
resume_response = self._put("jobs/%s/resume" % job_id)
self._assert_status_code_is(resume_response, 200)
self.dataset_populator.wait_for_history_jobs(history_id, assert_ok=True)
dataset_details = self._get("histories/%s/contents/%s" % (history_id, output['id'])).json()
assert dataset_details['state'] == 'ok'
def _get_history_item_as_admin(self, history_id, item_id):
response = self._get("histories/%s/contents/%s?view=detailed" % (history_id, item_id), admin=True)
assert_status_code_is_ok(response)
return response.json()
def test_search(self):
history_id, dataset_id = self.__history_with_ok_dataset()
@uses_test_history(require_new=True)
def test_search(self, history_id):
dataset_id = self.__history_with_ok_dataset(history_id)
# We first copy the datasets, so that the update time is lower than the job creation time
new_history_id = self.dataset_populator.new_history()
copy_payload = {"content": dataset_id, "source": "hda", "type": "dataset"}
@@ -343,9 +357,10 @@ class JobsApiTestCase(api.ApiTestCase):
self._assert_status_code_is(delete_respone, 200)
self._search(search_payload, expected_search_count=0)
def test_search_handle_identifiers(self):
@uses_test_history(require_new=True)
def test_search_handle_identifiers(self, history_id):
# Test that input name and element identifier of a jobs' output must match for a job to be returned.
history_id, dataset_id = self.__history_with_ok_dataset()
dataset_id = self.__history_with_ok_dataset(history_id)
inputs = json.dumps({
'input1': {'src': 'hda', 'id': dataset_id}
})
@@ -358,8 +373,9 @@ class JobsApiTestCase(api.ApiTestCase):
search_payload = self._search_payload(history_id=history_id, tool_id='identifier_single', inputs=inputs)
self._search(search_payload, expected_search_count=0)
def test_search_delete_outputs(self):
history_id, dataset_id = self.__history_with_ok_dataset()
@uses_test_history(require_new=True)
def test_search_delete_outputs(self, history_id):
dataset_id = self.__history_with_ok_dataset(history_id)
inputs = json.dumps({
'input1': {'src': 'hda', 'id': dataset_id}
})
@@ -370,9 +386,10 @@ class JobsApiTestCase(api.ApiTestCase):
search_payload = self._search_payload(history_id=history_id, tool_id='cat1', inputs=inputs)
self._search(search_payload, expected_search_count=0)
def test_search_with_hdca_list_input(self):
history_id, list_id_a = self.__history_with_ok_collection(collection_type='list')
history_id, list_id_b = self.__history_with_ok_collection(collection_type='list', history_id=history_id)
@uses_test_history(require_new=True)
def test_search_with_hdca_list_input(self, history_id):
list_id_a = self.__history_with_ok_collection(collection_type='list', history_id=history_id)
list_id_b = self.__history_with_ok_collection(collection_type='list', history_id=history_id)
inputs = json.dumps({
'f1': {'src': 'hdca', 'id': list_id_a},
'f2': {'src': 'hdca', 'id': list_id_b},
@@ -393,8 +410,9 @@ class JobsApiTestCase(api.ApiTestCase):
search_payload = self._search_payload(history_id=history_id, tool_id='multi_data_param', inputs=inputs)
self._search(search_payload, expected_search_count=0)
def test_search_delete_hdca_output(self):
history_id, list_id_a = self.__history_with_ok_collection(collection_type='list')
@uses_test_history(require_new=True)
def test_search_delete_hdca_output(self, history_id):
list_id_a = self.__history_with_ok_collection(collection_type='list', history_id=history_id)
inputs = json.dumps({
'input1': {'src': 'hdca', 'id': list_id_a},
})
@@ -413,8 +431,9 @@ class JobsApiTestCase(api.ApiTestCase):
search_payload = self._search_payload(history_id=history_id, tool_id='collection_creates_list', inputs=inputs)
self._search(search_payload, expected_search_count=0)
def test_search_with_hdca_pair_input(self):
history_id, list_id_a = self.__history_with_ok_collection(collection_type='pair')
@uses_test_history(require_new=True)
def test_search_with_hdca_pair_input(self, history_id):
list_id_a = self.__history_with_ok_collection(collection_type='pair', history_id=history_id)
inputs = json.dumps({
'f1': {'src': 'hdca', 'id': list_id_a},
'f2': {'src': 'hdca', 'id': list_id_a},
@@ -441,8 +460,9 @@ class JobsApiTestCase(api.ApiTestCase):
self._assert_status_code_is(delete_respone, 200)
self._search(search_payload, expected_search_count=0)
def test_search_with_hdca_list_pair_input(self):
history_id, list_id_a = self.__history_with_ok_collection(collection_type='list:pair')
@uses_test_history(require_new=True)
def test_search_with_hdca_list_pair_input(self, history_id):
list_id_a = self.__history_with_ok_collection(collection_type='list:pair', history_id=history_id)
inputs = json.dumps({
'f1': {'src': 'hdca', 'id': list_id_a},
'f2': {'src': 'hdca', 'id': list_id_a},
@@ -493,15 +513,13 @@ class JobsApiTestCase(api.ApiTestCase):
return [j for j in jobs if j['tool_id'] == 'upload1']
return filter(lambda j: j["tool_id"] == "upload1", jobs)
def __history_with_new_dataset(self):
history_id = self.dataset_populator.new_history()
def __history_with_new_dataset(self, history_id):
dataset_id = self.dataset_populator.new_dataset(history_id)["id"]
return history_id, dataset_id
return dataset_id
def __history_with_ok_dataset(self):
history_id = self.dataset_populator.new_history()
def __history_with_ok_dataset(self, history_id):
dataset_id = self.dataset_populator.new_dataset(history_id, wait=True)["id"]
return history_id, dataset_id
return dataset_id
def __history_with_ok_collection(self, collection_type='list', history_id=None):
if not history_id:
@@ -513,7 +531,7 @@ class JobsApiTestCase(api.ApiTestCase):
elif collection_type == 'list:pair':
fetch_response = self.dataset_collection_populator.create_list_of_pairs_in_history(history_id).json()
self.dataset_collection_populator.wait_for_fetched_collection(fetch_response)
return history_id, fetch_response["outputs"][0]['id']
return fetch_response["outputs"][0]['id']
def __jobs_index(self, **kwds):
jobs_response = self._get("jobs", **kwds)