Add more unit tests for ligo.gracedb.rest.GraceDb

parent 99651820
......@@ -287,3 +287,74 @@ def test_force_noauth_and_fail_if_noauth():
'constructor: fail_if_noauth=True and force_noauth=True.')
with pytest.raises(ValueError, match=err_str):
GraceDb(force_noauth=True, fail_if_noauth=True)
@pytest.mark.parametrize(
"resource,key",
[
('api_versions', 'api-versions'),
('server_version', 'server-version'),
('links', 'links'),
('templates', 'templates'),
('groups', 'groups'),
('pipelines', 'pipelines'),
('searches', 'searches'),
('allowed_labels', 'labels'),
('superevent_categories', 'superevent-categories'),
('em_groups', 'em-groups'),
('voevent_types', 'voevent-types'),
('signoff_types', 'signoff-types'),
('signoff_statuses', 'signoff-statuses'),
('instruments', 'instruments'),
]
)
def test_properties_from_api_root(safe_client, resource, key):
si_prop = 'ligo.gracedb.rest.GraceDb.service_info'
with mock.patch(si_prop, new_callable=mock.PropertyMock()) as mock_si:
getattr(safe_client, resource)
call_args, call_kwargs = mock_si.get.call_args
assert mock_si.get.call_count == 1
assert len(call_args) == 1
assert call_kwargs == {}
assert call_args[0] == key
@pytest.mark.parametrize("api_version", [1, 1.2, [], (), {}])
def test_bad_api_version(api_version):
err_msg = 'api_version should be a string'
with pytest.raises(TypeError, match=err_msg):
GraceDb(api_version=api_version)
@pytest.mark.parametrize(
"service_url,api_version",
[
('test', None),
('test/', None),
('test', 'v1'),
('test/', 'v2'),
('test/', 'default'),
],
)
def test_set_service_url(safe_client, service_url, api_version):
safe_client._set_service_url(service_url, api_version)
# Construct expected service urls
expected_service_url = service_url.rstrip('/') + '/'
expected_versioned_service_url = expected_service_url
if api_version and api_version != 'default':
expected_versioned_service_url += api_version + '/'
assert safe_client._service_url == expected_service_url
assert safe_client._versioned_service_url == expected_versioned_service_url
def test_legacy_service_url(safe_client, capsys):
service_url = 'fake-service-url'
safe_client._service_url = service_url
assert safe_client.service_url == service_url
stdout = capsys.readouterr().out
assert stdout.strip() == \
"DEPRECATED: this attribute has been moved to '_service_url'"
try:
from unittest import mock
except ImportError: # python < 3
import mock
import pytest
@pytest.mark.parametrize("emo_number", [None, 12])
def test_superevent_emobservations(safe_client, emo_number):
superevent_id = 'TS190302abc'
# Set up templates mock
mock_template = mock.MagicMock()
if emo_number:
template_key = 'superevent-emobservation-detail-template'
else:
template_key = 'superevent-emobservation-list-template'
mock_template_dict = {template_key: mock_template}
template_prop = 'ligo.gracedb.rest.GraceDb.templates'
with mock.patch('ligo.gracedb.rest.GraceDb.get') as mock_get, \
mock.patch(template_prop, mock_template_dict): # noqa: E127
safe_client.emobservations(superevent_id,
emobservation_num=emo_number)
get_call_args, get_call_kwargs = mock_get.call_args
assert len(get_call_args) == 1
assert get_call_kwargs == {}
# Test template call kwargs
num_kwargs = 1
if emo_number:
num_kwargs += 1
template_call_args, template_call_kwargs = mock_template.format.call_args
assert template_call_args == ()
assert len(template_call_kwargs) == num_kwargs
assert template_call_kwargs['superevent_id'] == superevent_id
if emo_number:
assert template_call_kwargs['N'] == emo_number
@pytest.mark.parametrize("emo_number", [None, 12])
def test_event_logs(safe_client, emo_number):
graceid = 'T123456'
# Set up templates mock
mock_template = mock.MagicMock()
if emo_number:
template_key = 'emobservation-detail-template'
else:
template_key = 'emobservation-list-template'
mock_template_dict = {template_key: mock_template}
template_prop = 'ligo.gracedb.rest.GraceDb.templates'
with mock.patch('ligo.gracedb.rest.GraceDb.get') as mock_get, \
mock.patch(template_prop, mock_template_dict): # noqa: E127
safe_client.emobservations(graceid, emobservation_num=emo_number)
get_call_args, get_call_kwargs = mock_get.call_args
assert len(get_call_args) == 1
assert get_call_kwargs == {}
# Test template call kwargs
num_kwargs = 1
if emo_number:
num_kwargs += 1
template_call_args, template_call_kwargs = mock_template.format.call_args
assert template_call_args == ()
assert len(template_call_kwargs) == num_kwargs
assert template_call_kwargs['graceid'] == graceid
if emo_number:
assert template_call_kwargs['N'] == emo_number
@pytest.mark.parametrize(
"is_event,obj_id",
[
(True, "T123456"),
(False, "TS121212abc"),
]
)
def test_write_emobservations(safe_client, is_event, obj_id):
# Generate data
emgroup = 'FAKE_EMGROUP'
ra_list = [1] * 4
ra_width_list = [2] * 4
dec_list = [3] * 4
dec_width_list = [4] * 4
start_time_list = [5] * 4
duration_list = [6] * 4
comment = 'test'
# Set up templates mock
mock_template = mock.MagicMock()
if is_event:
template_key = 'emobservation-list-template'
else:
template_key = 'superevent-emobservation-list-template'
mock_template_dict = {template_key: mock_template}
template_prop = 'ligo.gracedb.rest.GraceDb.templates'
# Set up emgroup mock
si_prop = 'ligo.gracedb.rest.GraceDb.service_info'
mock_si_dict = {'em-groups': [emgroup]}
with mock.patch('ligo.gracedb.rest.GraceDb.post') as mock_post, \
mock.patch(si_prop, mock_si_dict), \
mock.patch(template_prop, mock_template_dict): # noqa: E127
safe_client.writeEMObservation(
obj_id, emgroup, ra_list, ra_width_list, dec_list, dec_width_list,
start_time_list, duration_list, comment=comment
)
# Test call to self.post
post_call_args, post_call_kwargs = mock_post.call_args
assert len(post_call_args) == 1
assert len(post_call_kwargs) == 1
assert 'body' in post_call_kwargs
request_body = post_call_kwargs['body']
assert request_body['group'] == emgroup
assert request_body['ra_list'] == ra_list
assert request_body['ra_width_list'] == ra_width_list
assert request_body['dec_list'] == dec_list
assert request_body['dec_width_list'] == dec_width_list
assert request_body['start_time_list'] == start_time_list
assert request_body['duration_list'] == duration_list
assert request_body['comment'] == comment
# Test template call kwargs
template_call_args, template_call_kwargs = mock_template.format.call_args
assert template_call_args == ()
assert len(template_call_kwargs) == 1
if is_event:
call_key = 'graceid'
else:
call_key = 'superevent_id'
assert template_call_kwargs[call_key] == obj_id
@pytest.mark.parametrize(
"ras,ra_widths,decs,dec_widths,start_times,durations",
[
([1] * 4, [1] * 4, [1] * 4, [1] * 4, [1] * 4, [1] * 5),
([1] * 4, [1] * 4, [1] * 4, [1] * 4, [1] * 5, [1] * 4),
([1] * 4, [1] * 4, [1] * 4, [1] * 5, [1] * 4, [1] * 4),
([1] * 4, [1] * 4, [1] * 5, [1] * 4, [1] * 4, [1] * 4),
([1] * 4, [1] * 5, [1] * 4, [1] * 4, [1] * 4, [1] * 4),
([1] * 5, [1] * 4, [1] * 4, [1] * 4, [1] * 4, [1] * 4),
([1] * 1, [1] * 2, [1] * 3, [1] * 4, [1] * 5, [1] * 6),
]
)
def test_write_emobservation_different_list_lengths(
safe_client, ras, ra_widths, decs, dec_widths, start_times, durations
):
# Set up emgroup mock
si_prop = 'ligo.gracedb.rest.GraceDb.service_info'
mock_si_dict = {'em-groups': ['emgroup1']}
err_msg = ("raList, decList, startTimeList, raWidthList, decWidthList, "
"and durationList should be the same length")
with mock.patch(si_prop, mock_si_dict):
with pytest.raises(ValueError, match=err_msg):
safe_client.writeEMObservation(
'TS121212a', 'emgroup1', ras, ra_widths, decs, dec_widths,
start_times, durations, comment="test"
)
def test_write_emobservation_bad_emgroup(safe_client):
# Set up emgroup mock
si_prop = 'ligo.gracedb.rest.GraceDb.service_info'
mock_si_dict = {'em-groups': ['emgroup1']}
err_msg = "group must be one of {groups}".format(
groups=", ".join(mock_si_dict['em-groups']))
with mock.patch(si_prop, mock_si_dict):
with pytest.raises(ValueError, match=err_msg):
safe_client.writeEMObservation(
'TS121212a', 'emgroup20', 1, 1, 1, 1, 1, 1, comment="test"
)
try:
from unittest import mock
except ImportError: # python < 3
import mock
import six
import pytest
@pytest.mark.parametrize(
"group,pipeline,search,offline,labels",
[
('g1', 'p1', None, True, None),
('g1', 'p2', 's2', False, None),
('g2', 'p2', None, False, 'l1'),
('g1', 'p1', None, False, ['l1']),
('g1', 'p1', None, False, ['l2', 'l1']),
]
)
def test_create_event(safe_client, group, pipeline, search, offline, labels):
filename = 'file.xml'
# Mock service info dict
si_property = 'ligo.gracedb.rest.GraceDb.service_info'
mock_si_dict = {
'groups': ['g1', 'g2'],
'pipelines': ['p1', 'p2'],
'searches': ['s1', 's2'],
'labels': ['l1', 'l2'],
}
# Set up mock open
open_func = 'ligo.gracedb.rest.open'
mock_data = 'fake data'
open_mocker = mock.mock_open(read_data=mock_data)
# Call function
links_prop = 'ligo.gracedb.rest.GraceDb.links'
post_func = 'ligo.gracedb.rest.GraceDb.post'
with mock.patch(links_prop, new_callable=mock.PropertyMock), \
mock.patch(open_func, open_mocker), \
mock.patch(si_property, mock_si_dict), \
mock.patch(post_func) as mock_post: # noqa: E127
safe_client.createEvent(group, pipeline, filename, search=search,
labels=labels, offline=offline)
# Get args used to call post
call_args, call_kwargs = mock_post.call_args
assert len(call_args) == 2
assert len(call_kwargs) == 1
assert 'files' in call_kwargs
assert call_kwargs['files'] == [('eventFile', filename, mock_data,)]
# Check body (convert to dict)
body = dict(call_args[1])
assert body['group'] == group
assert body['pipeline'] == pipeline
assert body['offline'] == offline
if search:
assert body['search'] == search
else:
assert 'search' not in body
if labels:
if isinstance(labels, six.string_types):
labels = [labels]
req_labels = []
for t in call_args[1]:
if t[0] == 'labels':
req_labels.append(t[1])
assert sorted(labels) == sorted(req_labels)
def test_create_event_from_stdin(safe_client):
# Mock service info dict
si_property = 'ligo.gracedb.rest.GraceDb.service_info'
mock_si_dict = {
'groups': ['g1', 'g2'],
'pipelines': ['p1', 'p2'],
'searches': ['s1', 's2'],
'labels': ['l1', 'l2'],
}
# Set up mock sys.stdin.read
stdin_obj = 'ligo.gracedb.rest.sys.stdin'
mock_stdin_data = 'fake stdin data'
# Call function
links_prop = 'ligo.gracedb.rest.GraceDb.links'
post_func = 'ligo.gracedb.rest.GraceDb.post'
with mock.patch(links_prop, new_callable=mock.PropertyMock), \
mock.patch(si_property, mock_si_dict), \
mock.patch(stdin_obj) as mock_stdin, \
mock.patch(post_func) as mock_post: # noqa: E127
mock_stdin.read.return_value = mock_stdin_data
safe_client.createEvent('g1', 'p1', '-')
# Get args used to call post
call_args, call_kwargs = mock_post.call_args
assert len(call_args) == 2
assert len(call_kwargs) == 1
assert 'files' in call_kwargs
assert call_kwargs['files'] == [('eventFile', 'initial.data',
mock_stdin_data,)]
def test_create_event_with_filecontents(safe_client):
# Mock service info dict
si_property = 'ligo.gracedb.rest.GraceDb.service_info'
mock_si_dict = {
'groups': ['g1', 'g2'],
'pipelines': ['p1', 'p2'],
'searches': ['s1', 's2'],
'labels': ['l1', 'l2'],
}
# File data
filename = 'file.xml'
filecontents = 'event file contents'
# Call function
links_prop = 'ligo.gracedb.rest.GraceDb.links'
post_func = 'ligo.gracedb.rest.GraceDb.post'
with mock.patch(links_prop, new_callable=mock.PropertyMock), \
mock.patch(si_property, mock_si_dict), \
mock.patch(post_func) as mock_post: # noqa: E127
safe_client.createEvent('g1', 'p1', filename,
filecontents=filecontents)
# Get args used to call post
call_args, call_kwargs = mock_post.call_args
assert len(call_args) == 2
assert len(call_kwargs) == 1
assert 'files' in call_kwargs
assert call_kwargs['files'] == [('eventFile', filename, filecontents,)]
def test_create_event_with_bad_group(safe_client):
# Mock service info dict
si_property = 'ligo.gracedb.rest.GraceDb.service_info'
mock_si_dict = {'groups': ['g1']}
# Call
with mock.patch(si_property, mock_si_dict):
with pytest.raises(ValueError, match='bad group'):
safe_client.createEvent('g2', '', '')
def test_create_event_with_bad_pipeline(safe_client):
# Mock service info dict
si_property = 'ligo.gracedb.rest.GraceDb.service_info'
mock_si_dict = {'groups': ['g1'], 'pipelines': ['p1']}
# Call
with mock.patch(si_property, mock_si_dict):
with pytest.raises(ValueError, match='bad pipeline'):
safe_client.createEvent('g1', 'p2', '')
def test_create_event_with_bad_search(safe_client):
# Mock service info dict
si_property = 'ligo.gracedb.rest.GraceDb.service_info'
mock_si_dict = {'groups': ['g1'], 'pipelines': ['p1'], 'searches': ['s1']}
# Call
with mock.patch(si_property, mock_si_dict):
with pytest.raises(ValueError, match='bad search'):
safe_client.createEvent('g1', 'p1', '', search='s2')
@pytest.mark.parametrize("offline", [1, 1.3, {}, [], (True,), None])
def test_create_event_with_bad_offline(safe_client, offline):
# Mock service info dict
si_property = 'ligo.gracedb.rest.GraceDb.service_info'
mock_si_dict = {'groups': ['g1'], 'pipelines': ['p1'], 'searches': ['s1']}
# Call
err_msg = "offline parameter should be a bool"
with mock.patch(si_property, mock_si_dict):
with pytest.raises(TypeError, match=err_msg):
safe_client.createEvent('g1', 'p1', '', search='s1',
offline=offline)
@pytest.mark.parametrize("labels", [1, 1.3, {}])
def test_create_event_with_bad_label_type(safe_client, labels):
# Mock service info dict
si_property = 'ligo.gracedb.rest.GraceDb.service_info'
mock_si_dict = {'groups': ['g1'], 'pipelines': ['p1'], 'searches': ['s1']}
# Call
err_msg = "labels arg is {tl}, should be str or list".format(
tl=type(labels))
with mock.patch(si_property, mock_si_dict):
with pytest.raises(TypeError, match=err_msg):
safe_client.createEvent('g1', 'p1', '', search='s1',
labels=labels)
def test_create_event_with_bad_label_value(safe_client):
label = 'l3'
# Mock service info dict
si_property = 'ligo.gracedb.rest.GraceDb.service_info'
mock_si_dict = {
'groups': ['g1'],
'pipelines': ['p1'],
'searches': ['s1'],
'labels': ['l1', 'l2'],
}
# Call
err_msg = "Label '{label}' does not exist in the database".format(
label=label)
with mock.patch(si_property, mock_si_dict):
with pytest.raises(ValueError, match=err_msg):
safe_client.createEvent('g1', 'p1', '', search='s1',
labels=label)
@pytest.mark.parametrize(
"labels",
[["BAD"], 'BAD', ["GOOD_LABEL", "BAD"], ('BAD', 'GOOD_LABEL')]
)
def test_creation_with_bad_labels(safe_client, labels):
with mock.patch('ligo.gracedb.rest.GraceDb.allowed_labels',
new_callable=mock.PropertyMock) as mock_labels:
mock_labels.return_value = ['GOOD_LABEL']
with pytest.raises(ValueError):
safe_client.createSuperevent(1, 2, 3, preferred_event='T0001',
category='T', labels=labels)
@pytest.mark.parametrize("labels", [1, 2.34, {'test': 'bad'}, (1, 'GOOD')])
def test_creation_with_bad_label_type(safe_client, labels):
with pytest.raises(TypeError):
safe_client.createSuperevent(1, 2, 3, preferred_event='T0001',
category='T', labels=labels)
@pytest.mark.parametrize("category", ['other', 'new', 'etc'])
def test_creation_with_bad_category(safe_client, category):
with mock.patch('ligo.gracedb.rest.GraceDb.superevent_categories',
new_callable=mock.PropertyMock) as mock_sc:
mock_sc.return_value = {
'P': 'Production',
'T': 'Test',
'M': 'MDC',
}
with pytest.raises(ValueError):
safe_client.createSuperevent(1, 2, 3, preferred_event='T0001',
category=category)
@pytest.mark.parametrize("category", [1, 2.34, {'test': 'bad'}, None])
def test_creation_with_bad_category_type(safe_client, category):
with mock.patch('ligo.gracedb.rest.GraceDb.superevent_categories',
new_callable=mock.PropertyMock) as mock_sc:
mock_sc.return_value = {
'P': 'Production',
'T': 'Test',
'M': 'MDC',
}
with pytest.raises(TypeError):
safe_client.createSuperevent(1, 2, 3, preferred_event='T0001',
category=category)
pass
@pytest.mark.parametrize(
"events",
[1, ['G0001', 3], [()], [1, 2, 3.44]]
)
def test_creation_with_bad_event_graceids(safe_client, events):
with pytest.raises(TypeError):
safe_client.createSuperevent(1, 2, 3, preferred_event='T0001',
category='T', events=events)
@pytest.mark.parametrize(
"t_start,t_0,t_end,preferred_event,category,events,labels",
[
(1, 2, 3, 'T0001', 'T', None, None),
(1, 2, 3, 'T0001', 'T', 'T0002', None),
(1, 2, 3, 'T0001', 'T', None, 'INJ'),
(1, 2, 3, 'T0001', 'T', ['T0002', 'T0003'], ['INJ', 'DQV']),
]
)
def test_creation_args(
safe_client, t_start, t_0, t_end, preferred_event, category, events, labels
):
with mock.patch('ligo.gracedb.rest.GraceDb.superevent_categories',
new_callable=mock.PropertyMock) as mock_sc, \
mock.patch('ligo.gracedb.rest.GraceDb.allowed_labels', # noqa: E127
new_callable=mock.PropertyMock) as mock_labels, \
mock.patch('ligo.gracedb.rest.GraceDb.links',
new_callable=mock.PropertyMock), \
mock.patch('ligo.gracedb.rest.GraceDb.post') as mock_post:
mock_sc.return_value = {
'P': 'Production',
'T': 'Test',
'M': 'MDC',
}
mock_labels.return_value = ['DQV', 'INJ']
safe_client.createSuperevent(
t_start, t_0, t_end, preferred_event, category=category,
labels=labels, events=events
)
# Check args
call_args, call_kwargs = mock_post.call_args
body = call_kwargs['body']
assert body['t_start'] == t_start
assert body['t_0'] == t_0
assert body['t_end'] == t_end
assert body['preferred_event'] == preferred_event
assert body['category'] == category
if events:
if isinstance(events, six.string_types):
events = [events]
assert body['events'] == events
if labels:
if isinstance(labels, six.string_types):
labels = [labels]
assert body['labels'] == labels
def test_update_no_args(safe_client):
err_msg = 'Provide at least one of t_start, t_0, t_end, or preferred_event'
with pytest.raises(ValueError, match=err_msg):
safe_client.updateSuperevent('S181224a')