def test_client_request_params(self): httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json.dumps({"result": ""}), status=200, content_type="application/json", ) client = Client( instance=self.mock_connection["instance"], user=self.mock_connection["user"], password=self.mock_connection["pass"], raise_on_empty=self.mock_connection["raise_on_empty"], use_ssl=False, ) client.request_params = {"foo1": "bar1", "foo2": "bar2"} r = client.query(table="incident", query={}) r.get_one() # Parse QS and make sure `request_params` actually ended up in the request qs_str = r.last_response.url.split("?")[1] qs = dict( (x[0], x[1]) for x in [x.split("=") for x in qs_str.split("&")]) self.assertEqual(qs["foo1"], "bar1") self.assertEqual(qs["foo2"], "bar2")
def test_client_request_params(self): httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json.dumps({'result': ''}), status=200, content_type="application/json") client = Client(instance=self.mock_connection['instance'], user=self.mock_connection['user'], password=self.mock_connection['pass'], raise_on_empty=self.mock_connection['raise_on_empty'], use_ssl=False) client.request_params = {'foo1': 'bar1', 'foo2': 'bar2'} r = client.query(table='incident', query={}) r.get_one() # Parse QS and make sure `request_params` actually ended up in the request qs_str = r.last_response.url.split("?")[1] qs = dict( (x[0], x[1]) for x in [x.split("=") for x in qs_str.split("&")]) self.assertEqual(qs['foo1'], 'bar1') self.assertEqual(qs['foo2'], 'bar2')
def test_client_request_params(self): httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json.dumps({'result': ''}), status=200, content_type="application/json") client = Client(instance=self.mock_connection['instance'], user=self.mock_connection['user'], password=self.mock_connection['pass'], raise_on_empty=self.mock_connection['raise_on_empty'], use_ssl=False) client.request_params = {'foo1': 'bar1', 'foo2': 'bar2'} r = client.query(table='incident', query={}) r.get_one() # Parse QS and make sure `request_params` actually ended up in the request qs_str = r.last_response.url.split("?")[1] qs = dict((x[0], x[1]) for x in [x.split("=") for x in qs_str.split("&")]) self.assertEqual(qs['foo1'], 'bar1') self.assertEqual(qs['foo2'], 'bar2')
def test_valid_resource_paths_unicode(self): """:meth:`resource` should return a :class:`pysnow.Response` object with paths set to the expected value""" api_path = u"/api/path" base_path = u"/base/path" c = Client(user="******", password="******", instance="instance") r = c.resource(api_path=api_path, base_path=base_path) self.assertEquals(r._api_path, api_path) self.assertEquals(r._base_path, base_path)
def test_valid_resource_paths_unicode(self): """:meth:`resource` should return a :class:`pysnow.Response` object with paths set to the expected value""" api_path = u'/api/path' base_path = u'/base/path' c = Client(user="******", password="******", instance="instance") r = c.resource(api_path=api_path, base_path=base_path) self.assertEquals(r._api_path, api_path) self.assertEquals(r._base_path, base_path)
def test_client_valid_request_params(self): """Client `request_params` property should match what was passed as an argument""" params = {'foo': 'bar'} c = Client(instance="test", user="******", password="******", request_params=params) self.assertEqual(c.request_params, params) # Remove tests below when `default_payload` has been removed from `Client` c = Client(instance="test", user="******", password="******", default_payload=params) self.assertEqual(c.default_payload, params)
def setUp(self): # Mock client configuration self.mock_connection = { 'instance': 'mock_instance', 'user': '******', 'pass': '******', 'raise_on_empty': False } self.mock_connection['host'] = "%s.service-now.com" % self.mock_connection['instance'] # Mock incident attributes self.mock_incident = { 'stats': 'api/now/stats/incident', 'path': 'api/now/table/incident', 'number': 'INC01234', 'sys_id': '98ace1a537ea2a00cf5c9c9953990e19', 'link_arg': '?page=2' } # Mock attachment attributes self.mock_attachment = { 'path': 'api/now/attachment/upload', 'sys_id': 'b39fb9c1db0032000062f34ebf96198b', 'file_name': 'attachment.txt', } self.client = Client(instance=self.mock_connection['instance'], user=self.mock_connection['user'], password=self.mock_connection['pass'], use_ssl=False, raise_on_empty=self.mock_connection['raise_on_empty']) # Use `nosetests -l debug` to enable this logger logging.basicConfig(level=logging.DEBUG) self.log = logging.getLogger('debug')
def test_client_valid_request_params(self): """Client `request_params` property should match what was passed as an argument""" params = {"foo": "bar"} c = Client(instance="test", user="******", password="******", request_params=params) self.assertEqual(c.request_params, params)
def test_client_use_ssl(self): """ Client should construct base URL with correct scheme depending on use_ssl """ instance = "foo" host = "foo.bar.com" # Test with instance c = Client(user="******", password="******", instance=instance, use_ssl=False) self.assertEqual(c.base_url, "http://foo.service-now.com") c = Client(user="******", password="******", instance=instance, use_ssl=True) self.assertEqual(c.base_url, "https://foo.service-now.com") # Test with host c = Client(user="******", password="******", host=host, use_ssl=False) self.assertEqual(c.base_url, "http://foo.bar.com") c = Client(user="******", password="******", host=host, use_ssl=True) self.assertEqual(c.base_url, "https://foo.bar.com")
def test_invalid_resource_paths(self): """:meth:`resource` should raise an InvalidUsage exception if an invalid api_path was provided""" c = Client(user="******", password="******", instance="instance") self.assertRaises(InvalidUsage, c.resource) self.assertRaises(InvalidUsage, c.resource, api_path="not_valid") self.assertRaises(InvalidUsage, c.resource, api_path="not/valid") self.assertRaises(InvalidUsage, c.resource, api_path="not/valid/") self.assertRaises(InvalidUsage, c.resource, api_path="/") self.assertRaises(InvalidUsage, c.resource, base_path="not_valid") self.assertRaises(InvalidUsage, c.resource, base_path="not/valid") self.assertRaises(InvalidUsage, c.resource, base_path="not/valid/") self.assertRaises(InvalidUsage, c.resource, base_path="/")
def setUp(self): # Mock client configuration self.mock_connection = { "instance": "mock_instance", "user": "******", "pass": "******", "raise_on_empty": False, } self.mock_connection["host"] = ("%s.service-now.com" % self.mock_connection["instance"]) # Mock incident attributes self.mock_incident = { "stats": "api/now/stats/incident", "path": "api/now/table/incident", "number": "INC01234", "sys_id": "98ace1a537ea2a00cf5c9c9953990e19", "link_arg": "?page=2", } # Mock attachment attributes self.mock_attachment = { "path": "api/now/attachment/upload", "sys_id": "b39fb9c1db0032000062f34ebf96198b", "file_name": "attachment.txt", } self.client = Client( instance=self.mock_connection["instance"], user=self.mock_connection["user"], password=self.mock_connection["pass"], use_ssl=False, raise_on_empty=self.mock_connection["raise_on_empty"], ) # Use `nosetests -l debug` to enable this logger logging.basicConfig(level=logging.DEBUG) self.log = logging.getLogger("debug")
def setUp(self): # Mock client configuration self.mock_connection = { 'instance': 'mock_instance', 'user': '******', 'pass': '******', 'raise_on_empty': False } self.mock_connection[ 'host'] = "%s.service-now.com" % self.mock_connection['instance'] # Mock incident attributes self.mock_incident = { 'stats': 'api/now/stats/incident', 'path': 'api/now/table/incident', 'number': 'INC01234', 'sys_id': '98ace1a537ea2a00cf5c9c9953990e19', 'link_arg': '?page=2' } # Mock attachment attributes self.mock_attachment = { 'path': 'api/now/attachment/upload', 'sys_id': 'b39fb9c1db0032000062f34ebf96198b', 'file_name': 'attachment.txt', } self.client = Client( instance=self.mock_connection['instance'], user=self.mock_connection['user'], password=self.mock_connection['pass'], use_ssl=False, raise_on_empty=self.mock_connection['raise_on_empty']) # Use `nosetests -l debug` to enable this logger logging.basicConfig(level=logging.DEBUG) self.log = logging.getLogger('debug')
def test_client_user_password(self): """Should be able to create a client given user name and password.""" Client("snow.example.com", user="******", password="******")
def setUp(self): self.error_message_body = { 'message': 'test_message', 'detail': 'test_details' } self.record_response_get_dict = { 'sys_id': '98ace1a537ea2a00cf5c9c9953990e19', 'attr1': 'foo', 'attr2': 'bar' } self.record_response_get_one = [{ 'sys_id': '98ace1a537ea2a00cf5c9c9953990e19', 'attr1': 'foo', 'attr2': 'bar' }] self.record_response_get_three = [ { 'sys_id': '37ea2a00cf5c9c995399098ace1a5e19', 'attr1': 'foo1', 'attr2': 'bar1' }, { 'sys_id': '98ace1a537ea2a00cf5c9c9953990e19', 'attr1': 'foo2', 'attr2': 'bar2' }, { 'sys_id': 'a00cf5c9c9953990e1998ace1a537ea2', 'attr1': 'foo3', 'attr2': 'bar3' } ] self.record_response_create = { 'sys_id': '90e11a537ea2a00cf598ace9c99539c9', 'attr1': 'foo_create', 'attr2': 'bar_create' } self.record_response_update = { 'sys_id': '2a00cf5c9c99539998ace1a537ea0e19', 'attr1': 'foo_updated', 'attr2': 'bar_updated' } self.record_response_delete = { 'status': 'record deleted' } self.client_kwargs = { 'user': '******', 'password': '******', 'instance': 'mock_instance' } self.attachment = { 'sys_id': 'attachment_sys_id', 'size_bytes': '512', 'file_name': 'test1.txt' } self.attachment_path = 'tests/data/attachment.txt' self.base_path = '/api/now' self.api_path = '/table/incident' self.client = Client(**self.client_kwargs) self.resource = self.client.resource(base_path=self.base_path, api_path=self.api_path) self.mock_url_builder = self.resource._url_builder self.attachment_upload_url = self.resource._base_url + self.resource._base_path + '/attachment/file' self.mock_url_builder_base = self.resource._url_builder.get_url() self.mock_url_builder_sys_id = (self.mock_url_builder .get_appended_custom('/{0}'.format(self.record_response_get_one[0]['sys_id']))) self.dict_query = {'sys_id': self.record_response_get_one[0]['sys_id']} self.get_fields = ['foo', 'bar']
class TestResourceRequest(unittest.TestCase): """Performs resource-request tests""" def setUp(self): self.error_message_body = { 'message': 'test_message', 'detail': 'test_details' } self.record_response_get_dict = { 'sys_id': '98ace1a537ea2a00cf5c9c9953990e19', 'attr1': 'foo', 'attr2': 'bar' } self.record_response_get_one = [{ 'sys_id': '98ace1a537ea2a00cf5c9c9953990e19', 'attr1': 'foo', 'attr2': 'bar' }] self.record_response_get_three = [{ 'sys_id': '37ea2a00cf5c9c995399098ace1a5e19', 'attr1': 'foo1', 'attr2': 'bar1' }, { 'sys_id': '98ace1a537ea2a00cf5c9c9953990e19', 'attr1': 'foo2', 'attr2': 'bar2' }, { 'sys_id': 'a00cf5c9c9953990e1998ace1a537ea2', 'attr1': 'foo3', 'attr2': 'bar3' }] self.record_response_create = { 'sys_id': '90e11a537ea2a00cf598ace9c99539c9', 'attr1': 'foo_create', 'attr2': 'bar_create' } self.record_response_update = { 'sys_id': '2a00cf5c9c99539998ace1a537ea0e19', 'attr1': 'foo_updated', 'attr2': 'bar_updated' } self.record_response_delete = {'status': 'record deleted'} self.client_kwargs = { 'user': '******', 'password': '******', 'instance': 'mock_instance' } self.attachment = { 'sys_id': 'attachment_sys_id', 'size_bytes': '512', 'file_name': 'test1.txt' } self.attachment_path = 'tests/data/attachment.txt' self.base_path = '/api/now' self.api_path = '/table/incident' self.client = Client(**self.client_kwargs) self.resource = self.client.resource(base_path=self.base_path, api_path=self.api_path) self.mock_url_builder = self.resource._url_builder self.attachment_upload_url = self.resource._base_url + self.resource._base_path + '/attachment/file' self.mock_url_builder_base = self.resource._url_builder.get_url() self.mock_url_builder_sys_id = ( self.mock_url_builder.get_appended_custom('/{0}'.format( self.record_response_get_one[0]['sys_id']))) self.dict_query = {'sys_id': self.record_response_get_one[0]['sys_id']} self.get_fields = ['foo', 'bar'] def test_create_resource(self): """:class:`Resource` object repr type should be string, and its path should be set to api_path + base_path """ r = self.client.resource(base_path=self.base_path, api_path=self.api_path) resource_repr = type(repr(r)) self.assertEquals(resource_repr, str) self.assertEquals(r._base_path, self.base_path) self.assertEquals(r._api_path, self.api_path) self.assertEquals(r.path, self.base_path + self.api_path) @httpretty.activate def test_response_count(self): """:prop:`count` of :class:`pysnow.Response` should raise an exception if count is set to non-integer""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, status=200, content_type="application/json") response = self.resource.get(self.dict_query) self.assertRaises(TypeError, setattr, response, 'count', 'foo') self.assertRaises(TypeError, setattr, response, 'count', True) self.assertRaises(TypeError, setattr, response, 'count', {'foo': 'bar'}) @httpretty.activate def test_response_error(self): """:class:`pysnow.Response` should raise an exception if an error is encountered in the response body""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_error( self.error_message_body), status=200, content_type="application/json") response = self.resource.get(self.dict_query, stream=True) expected_str = "Error in response. Message: %s, Details: %s" % ( self.error_message_body['message'], self.error_message_body['detail']) try: response.first() except ResponseError as e: self.assertEquals(str(e), expected_str) @httpretty.activate def test_get_request_fields(self): """:meth:`get_request` should return a :class:`pysnow.Response` object""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, status=200, content_type="application/json") response = self.resource.get(self.dict_query, fields=self.get_fields) qs = qs_as_dict(response._response.request.url) str_fields = ','.join(self.get_fields) # List of fields should end up as comma-separated string self.assertEquals(type(response), Response) self.assertEquals(qs['sysparm_fields'], str_fields) @httpretty.activate def test_get_offset(self): """offset passed to :meth:`get` should set sysparm_offset in query""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result( self.record_response_get_one), status=200, content_type="application/json") offset = 5 response = self.resource.get(self.dict_query, offset=offset) qs = qs_as_dict(response._response.request.url) self.assertEquals(int(qs['sysparm_offset']), offset) @httpretty.activate def test_get_limit(self): """limit passed to :meth:`get` should set sysparm_limit in QS""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result( self.record_response_get_one), status=200, content_type="application/json") limit = 2 response = self.resource.get(self.dict_query, limit=limit) qs = qs_as_dict(response._response.request.url) self.assertEquals(int(qs['sysparm_limit']), limit) @httpretty.activate def test_get_one(self): """:meth:`one` of :class:`pysnow.Response` should raise an exception if more than one match was found""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result( self.record_response_get_one), status=200, content_type="application/json") response = self.resource.get(self.dict_query) result = response.one() self.assertEquals(result['sys_id'], self.record_response_get_one[0]['sys_id']) @httpretty.activate def test_get_all_empty(self): """:meth:`all` generator of :class:`pysnow.Response` should return an empty list if there are no matches""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result([]), status=200, content_type="application/json") response = self.resource.get(self.dict_query, stream=True) result = list(response.all()) self.assertEquals(result, []) @httpretty.activate def test_get_all_single(self): """Single items with all() using the stream parser should return a list containing the item""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result( self.record_response_get_dict), status=200, content_type="application/json") response = self.resource.get(self.dict_query, stream=True) result = list(response.all())[0] self.assertEquals(result, self.record_response_get_dict) @httpretty.activate def test_get_buffer_missing_result_keys(self): """:meth:`one` of :class:`pysnow.Response` should raise an exception if none of the expected keys was found in the result""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=json.dumps({}), status=200, content_type="application/json") response = self.resource.get(self.dict_query) self.assertRaises(MissingResult, response.one) @httpretty.activate def test_get_stream_missing_result_keys(self): """:meth:`one` of :class:`pysnow.Response` should raise an exception if none of the expected keys was found in the result""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=json.dumps({}), status=200, content_type="application/json") response = self.resource.get(self.dict_query, stream=True) self.assertRaises(MissingResult, response.first) @httpretty.activate def test_http_error_get_one(self): """:meth:`one` of :class:`pysnow.Response` should raise an HTTPError exception if a non-200 response code was encountered""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, status=500, content_type="application/json") response = self.resource.get(self.dict_query) self.assertRaises(HTTPError, response.one) @httpretty.activate def test_get_one_many(self): """:meth:`one` of :class:`pysnow.Response` should raise an exception if more than one match was found""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result( self.record_response_get_three), status=200, content_type="application/json") response = self.resource.get(self.dict_query) self.assertRaises(MultipleResults, response.one) @httpretty.activate def test_get_one_empty(self): """:meth:`one` of :class:`pysnow.Response` should raise an exception if no matches were found""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result([]), status=200, content_type="application/json") response = self.resource.get(self.dict_query) self.assertRaises(NoResults, response.one) @httpretty.activate def test_get_one_or_none_empty(self): """:meth:`one_or_none` of :class:`pysnow.Response` should return `None` if no matches were found """ httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result([]), status=200, content_type="application/json") response = self.resource.get(self.dict_query) result = response.one_or_none() self.assertEquals(result, None) @httpretty.activate def test_get_first_or_none_empty(self): """:meth:`first_or_none` of :class:`pysnow.Response` should return None if no records were found""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result([]), status=200, content_type="application/json") response = self.resource.get(self.dict_query, stream=True) result = response.first_or_none() self.assertEquals(result, None) @httpretty.activate def test_get_first_or_none(self): """:meth:`first_or_none` of :class:`pysnow.Response` should return first match if multiple records were found""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result( self.record_response_get_three), status=200, content_type="application/json") response = self.resource.get(self.dict_query, stream=True) result = response.first_or_none() self.assertEquals(result, self.record_response_get_three[0]) @httpretty.activate def test_get_first(self): """:meth:`first` of :class:`pysnow.Response` should return first match if multiple records were found""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result( self.record_response_get_three), status=200, content_type="application/json") response = self.resource.get(self.dict_query, stream=True) result = response.first() self.assertEquals(result, self.record_response_get_three[0]) @httpretty.activate def test_get_first_empty(self): """:meth:`first` of :class:`pysnow.Response` should raise an exception if matches were found""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result([]), status=200, content_type="application/json") response = self.resource.get(self.dict_query, stream=True) self.assertRaises(NoResults, response.first) @httpretty.activate def test_create(self): """:meth:`create` should return a dictionary of the new record""" httpretty.register_uri(httpretty.POST, self.mock_url_builder_base, body=get_serialized_result( self.record_response_create), status=200, content_type="application/json") response = self.resource.create(self.record_response_create) self.assertEquals(type(response.one()), dict) self.assertEquals(response.one(), self.record_response_create) @httpretty.activate def test_update(self): """:meth:`update` should return a dictionary of the updated record""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result( self.record_response_get_one), status=200, content_type="application/json") httpretty.register_uri(httpretty.PUT, self.mock_url_builder_sys_id, body=get_serialized_result( self.record_response_update), status=200, content_type="application/json") response = self.resource.update(self.dict_query, self.record_response_update) result = response.one() self.assertEquals(type(result), dict) self.assertEquals(self.record_response_update['attr1'], result['attr1']) @httpretty.activate def test_update_invalid_payload(self): """:meth:`update` should raise an exception if payload is of invalid type""" self.assertRaises(InvalidUsage, self.resource.update, self.dict_query, 'foo') self.assertRaises(InvalidUsage, self.resource.update, self.dict_query, False) self.assertRaises(InvalidUsage, self.resource.update, self.dict_query, 1) self.assertRaises(InvalidUsage, self.resource.update, self.dict_query, ('foo', 'bar')) self.assertRaises(InvalidUsage, self.resource.update, self.dict_query, ['foo', 'bar']) @httpretty.activate def test_delete(self): """:meth:`delete` should return a dictionary containing status""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result( self.record_response_get_one), status=200, content_type="application/json") httpretty.register_uri(httpretty.DELETE, self.mock_url_builder_sys_id, body=get_serialized_result( self.record_response_delete), status=204, content_type="application/json") result = self.resource.delete(self.dict_query) self.assertEquals(type(result), dict) self.assertEquals(result['status'], 'record deleted') @httpretty.activate def test_delete_chained(self): """:meth:`Response.delete` should return a dictionary containing status""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result( self.record_response_get_one), status=200, content_type="application/json") httpretty.register_uri(httpretty.DELETE, self.mock_url_builder_sys_id, body=get_serialized_result( self.record_response_delete), status=204, content_type="application/json") result = self.resource.get(query={}).delete() self.assertEquals(type(result), dict) self.assertEquals(result['status'], 'record deleted') @httpretty.activate def test_custom(self): """:meth:`custom` should return a :class:`pysnow.Response` object""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result( self.record_response_get_one), status=200, content_type="application/json") method = 'GET' response = self.resource.request(method) self.assertEquals(response._response.request.method, method) self.assertEquals(type(response), Response) @httpretty.activate def test_custom_with_headers(self): """Headers provided to :meth:`custom` should end up in the request""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result( self.record_response_get_one), status=200, content_type="application/json") headers = {'foo': 'bar'} response = self.resource.request('GET', headers=headers) self.assertEquals(response._response.request.headers['foo'], headers['foo']) @httpretty.activate def test_custom_with_path(self): """path_append passed to :meth:`custom` should get appended to the request path""" path_append = '/foo' httpretty.register_uri(httpretty.GET, self.mock_url_builder_base + path_append, body=get_serialized_result( self.record_response_get_one), status=200, content_type="application/json") response = self.resource.request('GET', path_append='/foo') self.assertEquals(response._response.status_code, 200) @httpretty.activate def test_custom_with_path_invalid(self): """:meth:`custom` should raise an exception if the provided path is invalid""" self.assertRaises(InvalidUsage, self.resource.request, 'GET', path_append='foo') self.assertRaises(InvalidUsage, self.resource.request, 'GET', path_append={'foo': 'bar'}) self.assertRaises(InvalidUsage, self.resource.request, 'GET', path_append='foo/') self.assertRaises(InvalidUsage, self.resource.request, 'GET', path_append=True) @httpretty.activate def test_response_repr(self): """:meth:`get` should result in response obj repr describing the response""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result( self.record_response_get_one), status=200, content_type="application/json") response = self.resource.get(query={}) response_repr = repr(response) self.assertEquals(response_repr, '<Response [200 - GET]>') def test_attachment_non_table(self): """Accessing `Resource.attachments` from a non-table API should fail""" resource = self.client.resource(base_path=self.base_path, api_path='/invalid') self.assertRaises(InvalidUsage, getattr, resource, 'attachments') def test_attachment_type(self): """`Resource.attachments` should be of type Attachment""" attachment_type = type(self.resource.attachments) self.assertEqual(attachment_type, Attachment) def test_get_record_link(self): """`Resource.get_record_link()` should return full URL to the record""" record_link = self.resource.get_record_link( '98ace1a537ea2a00cf5c9c9953990e19') self.assertEqual(record_link, self.mock_url_builder_sys_id) @httpretty.activate def test_get_response_item(self): """Accessing the response as a dict should work""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result( self.record_response_get_one), status=200, content_type="application/json") response = self.resource.get(query={}) self.assertEquals(response['sys_id'], self.record_response_get_one[0].get('sys_id')) @httpretty.activate def test_get_buffered_first(self): """Using Response.first() without stream=True should fail""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result( self.record_response_get_one), status=200, content_type="application/json") response = self.resource.get(query={}) self.assertRaises(InvalidUsage, response.first) @httpretty.activate def test_response_update(self): """Using Response.update should update the queried record""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result( self.record_response_get_one), status=200, content_type="application/json") httpretty.register_uri(httpretty.PUT, self.mock_url_builder_sys_id, body=get_serialized_result( self.record_response_update), status=200, content_type="application/json") response = self.resource.get(query={}).update( self.record_response_update) self.assertEqual(self.record_response_update['sys_id'], response['sys_id']) @httpretty.activate def test_response_upload(self): """Using Response.upload() should attach the file to the queried record and return metadata""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result( self.record_response_get_one), status=200, content_type="application/json") httpretty.register_uri(httpretty.POST, self.attachment_upload_url, body=get_serialized_result(self.attachment), status=201, content_type="application/json") response = self.resource.get(query={}).upload( file_path=self.attachment_path) self.assertEqual(self.attachment['file_name'], response['file_name'])
def test_client_context_manager(self): with Client("snow.example.com", user="******", password="******") as c: assert isinstance(c, Client) assert c.session
def test_client_with_session(self): """Should be able to create a client given a requests session object.""" session = requests.Session() Client("snow.example.com", session=session)
class TestIncident(unittest.TestCase): def setUp(self): # Mock client configuration self.mock_connection = { 'instance': 'mock_instance', 'user': '******', 'pass': '******', 'raise_on_empty': False } self.mock_connection['host'] = "%s.service-now.com" % self.mock_connection['instance'] # Mock incident attributes self.mock_incident = { 'stats': 'api/now/stats/incident', 'path': 'api/now/table/incident', 'number': 'INC01234', 'sys_id': '98ace1a537ea2a00cf5c9c9953990e19', 'link_arg': '?page=2' } # Mock attachment attributes self.mock_attachment = { 'path': 'api/now/attachment/upload', 'sys_id': 'b39fb9c1db0032000062f34ebf96198b', 'file_name': 'attachment.txt', } self.client = Client(instance=self.mock_connection['instance'], user=self.mock_connection['user'], password=self.mock_connection['pass'], use_ssl=False, raise_on_empty=self.mock_connection['raise_on_empty']) # Use `nosetests -l debug` to enable this logger logging.basicConfig(level=logging.DEBUG) self.log = logging.getLogger('debug') def test_connection(self): self.assertEqual(self.client.instance, self.mock_connection['instance']) self.assertEqual(self.client.raise_on_empty, self.mock_connection['raise_on_empty']) self.assertEqual(self.client.request_params, {}) @httpretty.activate def test_client_request_params(self): httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json.dumps({'result': ''}), status=200, content_type="application/json") client = Client(instance=self.mock_connection['instance'], user=self.mock_connection['user'], password=self.mock_connection['pass'], raise_on_empty=self.mock_connection['raise_on_empty'], use_ssl=False) client.request_params = {'foo1': 'bar1', 'foo2': 'bar2'} r = client.query(table='incident', query={}) r.get_one() # Parse QS and make sure `request_params` actually ended up in the request qs_str = r.last_response.url.split("?")[1] qs = dict((x[0], x[1]) for x in [x.split("=") for x in qs_str.split("&")]) self.assertEqual(qs['foo1'], 'bar1') self.assertEqual(qs['foo2'], 'bar2') @httpretty.activate def test_invalid_query_type(self): json_body = json.dumps({'result': [{'number': self.mock_incident['number']}]}) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query=1) self.assertRaises(InvalidUsage, r.get_one) @httpretty.activate def test_get_count(self): json_body = json.dumps({'result': {'stats': {'count': '30'}}}) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['stats']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query={}) self.assertEqual(r.count, 30) @httpretty.activate def test_last_response_not_executed(self): json_body = json.dumps({'result': [{'number': self.mock_incident['number']}]}) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") try: str(self.client.query(table='incident', query={}).last_response) self.assertFalse('Getting last_response should fail when no `Request` has been executed') except NoRequestExecuted: pass @httpretty.activate def test_last_response(self): json_body = json.dumps({'result': [{'number': self.mock_incident['number']}]}) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query={}) r.get_one() # Make sure we get the expected status code back self.assertEqual(r.status_code, 200) # Make sure last_response is not None self.assertNotEqual(r.last_response, None) @httpretty.activate def test_get_incident_by_qb(self): """ Make sure fetching by dict type query works """ json_body = json.dumps({'result': [{'number': self.mock_incident['number']}]}) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") q = QueryBuilder().field('number').equals(self.mock_incident['number']) r = self.client.query(table='incident', query=q) # Make sure we got an incident back with the expected number self.assertEqual(r.get_one()['number'], self.mock_incident['number']) @httpretty.activate def test_get_incident_by_dict_query(self): """ Make sure fetching by dict type query works """ json_body = json.dumps({'result': [{'number': self.mock_incident['number']}]}) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) # Make sure we got an incident back with the expected number self.assertEqual(r.get_one()['number'], self.mock_incident['number']) @httpretty.activate def test_get_content_without_result(self): """ Make sure content without `result` fails """ json_body = json.dumps({}) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query={}) self.assertRaises(MissingResult, r.get_one) @httpretty.activate def test_get_limited_result(self): """ Make sure fetching by dict type query works """ json_body = json.dumps({'result': [{'number': self.mock_incident['number']}]}) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query={}) # Trigger a request by fetching next element from the generator next(r.get_all(limit=2)) # Get last request QS qs = httpretty.last_request().querystring # Make sure sysparm_limit equals limit self.assertEqual(int(qs['sysparm_limit'][0]), 2) # Make sure sysparm_suppress_pagination_header is True self.assertTrue(qs['sysparm_suppress_pagination_header']) @httpretty.activate def test_get_incident_by_string_query(self): """ Make sure fetching by string type query works """ json_body = json.dumps({'result': [{'number': self.mock_incident['number']}]}) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query='nameINincident,task^elementLIKEstate') # Make sure we got an incident back with the expected number self.assertEqual(r.get_one()['number'], self.mock_incident['number']) @httpretty.activate def test_get_sorted(self): """ Make sure order_by generates the expected sysparm_query string """ json_body = json.dumps({'result': [{'number': self.mock_incident['number']}]}) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query={}) next(r.get_multiple(order_by=['-number', 'category'])) qs_str = r.last_response.url.split("?")[1] qs = dict((x[0], x[1]) for x in [x.split("=") for x in qs_str.split("&")]) self.assertEqual(str(qs['sysparm_query']), '%5EORDERBYDESCnumber%5EORDERBYcategory') @httpretty.activate def test_get_sorted_invalid(self): """ Make sure get_multiple fails if order_by is not of type `list` """ json_body = json.dumps({'result': [{'number': self.mock_incident['number']}]}) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query={}) self.assertRaises(InvalidUsage, next, r.get_multiple(order_by='number')) self.assertRaises(InvalidUsage, next, r.get_multiple(order_by={'number': 1})) self.assertRaises(InvalidUsage, next, r.get_multiple(order_by=1)) @httpretty.activate def test_get_incident_content_error(self): """ Make sure error in content is properly handled """ httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json.dumps({'error': {'message': 'test'}}), status=200, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(UnexpectedResponse, r.get_one) @httpretty.activate def test_get_incident_invalid_query(self): """ Make sure querying by non-dict and non-string doesn't work """ json_body = json.dumps({'result': [{'number': self.mock_incident['number']}]}) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") # Pass query as a `list` , which is invalid r = self.client.query(table='incident', query=list()) self.assertRaises(InvalidUsage, r.get_one) @httpretty.activate def test_get_linked_result(self): """ Fetch multiple incident records from a linked result """ link_header = "<http://%s/%s/%s>; rel='next'" % ( self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['link_arg'] ) json_body_first = json.dumps({'result': [{'number': self.mock_incident['number'], 'linked': False}]}) json_body_second = json.dumps({'result': [{'number': self.mock_incident['number'], 'linked': True}]}) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body_first, status=200, content_type="application/json", adding_headers={'Link': link_header}) httpretty.register_uri(httpretty.GET, "http://%s/%s/%s" % ( self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['link_arg'] ), body=json_body_second, status=200, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) result = r.get_multiple() # Return the first result from the container first = next(result) self.assertEqual(first['number'], self.mock_incident['number']) # Make sure it's the record we're after self.assertFalse(first['linked']) # Return the second result from the container (linked) second = next(result) self.assertEqual(second['number'], self.mock_incident['number']) # Make sure it's the record we're after self.assertTrue(second['linked']) @httpretty.activate def test_get_incident_invalid_field_format(self): """ Make sure passing fields as non-list fails """ client = copy(self.client) json_body = json.dumps({'result': []}) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=404, content_type="application/json") client.raise_on_empty = True # If `raise_on_empty` is True and status code is 404, or 200 and empty result, an exception should be thrown. r = client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(NoResults, r.get_one) client.raise_on_empty = False r = client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(InvalidUsage, r.get_one, fields='test') @httpretty.activate def test_get_incident_field_filter(self): """ Make sure passing fields works as intended """ client = copy(self.client) json_body = json.dumps( { 'result': [ { 'sys_id': self.mock_incident['sys_id'], 'number': self.mock_incident['number'] } ] } ) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") r = client.query(table='incident', query={'number': self.mock_incident['number']}) result = r.get_one(fields=['sys_id', 'number']) # Make sure we get the selected fields back self.assertEqual(result['sys_id'], self.mock_incident['sys_id']) self.assertEqual(result['number'], self.mock_incident['number']) @httpretty.activate def test_get_incident_no_results(self): """ Make sure empty result sets are properly handled """ client = copy(self.client) json_body = json.dumps({'result': []}) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=404, content_type="application/json") client.raise_on_empty = True # If `raise_on_empty` is True and status code is 404, or 200 and empty result, an exception should be thrown. r = client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(NoResults, r.get_one) client.raise_on_empty = False r = client.query(table='incident', query={'number': self.mock_incident['number']}) res = r.get_one() # Quietly continue if `raise_on_empty` if False self.assertEqual(res, {}) self.assertEqual(r.status_code, 404) @httpretty.activate def test_insert_incident(self): """ Create new incident, make sure we get a sys_id back """ json_body = json.dumps({'result': [{'sys_id': self.mock_incident['sys_id']}]}) httpretty.register_uri(httpretty.POST, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=201, content_type="application/json") result = self.client.insert(table='incident', payload={'field1': 'value1', 'field2': 'value2'}) # Make sure we got an incident back self.assertEqual(result[0]['sys_id'], self.mock_incident['sys_id']) @httpretty.activate def test_insert_incident_status(self): """ Create new incident, make sure status code is 201 """ json_body = json.dumps({'result': [{'sys_id': self.mock_incident['sys_id']}]}) httpretty.register_uri(httpretty.POST, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=201, content_type="application/json") r = self.client._legacy_request('POST', 'incident') r.insert(payload={'field1': 'value1', 'field2': 'value2'}) # Make sure we got code 201 back self.assertEqual(r.status_code, 201) @httpretty.activate def test_insert_incident_invalid_status(self): """ Update an incident and get an unexpected status code back, make sure it fails properly. """ json_body = { 'result': [ { 'sys_id': self.mock_incident['sys_id'] } ], 'error': { 'message': 'Error summary', 'detail': 'Error detail ' } } httpretty.register_uri(httpretty.POST, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json.dumps(json_body), status=403, content_type="application/json") r = self.client._legacy_request('POST', 'incident') try: r.insert(payload={'field1': 'value1', 'field2': 'value2'}) except UnexpectedResponse as e: # Make sure the exception object contains summary and details self.assertEqual(e.error_summary, json_body['error']['message']) self.assertEqual(e.error_details, json_body['error']['detail']) pass @httpretty.activate def test_update_incident(self): """ Updates an existing incident. Checks for sys_id and status code 200 """ json_body = json.dumps({'result': [{'sys_id': self.mock_incident['sys_id'], 'this': 'that'}]}) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") httpretty.register_uri(httpretty.PUT, "http://%s/%s/%s" % (self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['sys_id']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) result = r.update({'this': 'that'}) # Make sure we got an incident back with the expected sys_id self.assertEqual(result[0]['sys_id'], self.mock_incident['sys_id']) self.assertEqual(result[0]['this'], 'that') self.assertEqual(r.status_code, 200) @httpretty.activate def test_update_incident_non_existent(self): """ Attempt to update a non-existent incident """ json_body = json.dumps({'result': {}}) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") httpretty.register_uri(httpretty.PUT, "http://%s/%s/%s" % (self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['sys_id']), body={}, status=200, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(NoResults, r.update, {'foo': 'bar'}) @httpretty.activate def test_update_incident_invalid_update(self): """ Make sure updates which are non-dict and non-string type are properly handled """ json_body = json.dumps({'result': [{'sys_id': self.mock_incident['sys_id'], 'this': 'that'}]}) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") httpretty.register_uri(httpretty.PUT, "http://%s/%s/%s" % (self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['sys_id']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(InvalidUsage, r.update, 'invalid update') @httpretty.activate def test_update_incident_multiple(self): """ Make sure update queries yielding more than 1 record fails """ json_body = json.dumps({'result': [{'sys_id': self.mock_incident['sys_id'], 'this': 'that'}, {'sys_id': self.mock_incident['sys_id'], 'this': 'that'}]}) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") httpretty.register_uri(httpretty.PUT, "http://%s/%s/%s" % (self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['sys_id']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(MultipleResults, r.update, {'foo': 'bar'}) @httpretty.activate def test_get_multiple_with_offset(self): """ Make sure offset works properly """ json_body = json.dumps({'result': [{'sys_id': self.mock_incident['sys_id'], 'this': 'that'}, {'sys_id': self.mock_incident['sys_id'], 'this': 'that'}]}) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) list(r.get_multiple(limit=100, offset=50)) qs = httpretty.last_request().querystring # Make sure sysparm_offset is set to the expected value self.assertEqual(int(qs['sysparm_offset'][0]), 50) # Make sure sysparm_limit is set to the expected value self.assertEqual(int(qs['sysparm_limit'][0]), 100) @httpretty.activate def test_attach_incident(self): """ Attaches file to an existing incident. Checks for table_sys_id, file_name and status code 201 """ json_get_body = json.dumps({'result': [{'sys_id': self.mock_incident['sys_id']}]}) json_post_body = json.dumps( { 'result': { 'sys_id': self.mock_attachment['sys_id'], 'table_sys_id': self.mock_incident['sys_id'], 'file_name': self.mock_attachment['file_name'] } } ) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_get_body, status=200, content_type="application/json") httpretty.register_uri(httpretty.POST, "http://%s/%s" % (self.mock_connection['host'], self.mock_attachment['path']), body=json_post_body, status=201, content_type="multipart/form-data") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) result = r.attach('tests/legacy/attachment.txt') # Make sure we got an incident back with the expected sys_id self.assertEqual(result['table_sys_id'], self.mock_incident['sys_id']) self.assertEqual(result['file_name'], self.mock_attachment['file_name']) self.assertEqual(r.status_code, 201) @httpretty.activate def test_attach_incident_non_existent(self): """ Attempts to attach file to a non-existent incident """ json_post_body = json.dumps( { 'result': { 'sys_id': self.mock_attachment['sys_id'], 'table_sys_id': self.mock_incident['sys_id'], 'file_name': self.mock_attachment['file_name'] } } ) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json.dumps({'result': {}}), status=200, content_type="application/json") httpretty.register_uri(httpretty.POST, "http://%s/%s" % (self.mock_connection['host'], self.mock_attachment['path']), body=json_post_body, status=201, content_type="multipart/form-data") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(NoResults, r.attach, 'tests/legacy/attachment.txt') @httpretty.activate def test_attach_incident_non_file(self): """ Attempts to attach a non-file to an incident """ json_post_body = json.dumps( { 'result': [ { 'sys_id': self.mock_attachment['sys_id'], 'table_sys_id': self.mock_incident['sys_id'], 'file_name': self.mock_attachment['file_name'] } ] } ) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_post_body, status=200, content_type="application/json") httpretty.register_uri(httpretty.POST, "http://%s/%s" % (self.mock_connection['host'], self.mock_attachment['path']), body=json_post_body, status=201, content_type="multipart/form-data") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(InvalidUsage, r.attach, 'tests/non_existing_file.txt') @httpretty.activate def test_attach_incident_multiple(self): """ Make sure attach fails when getting multiple records back """ json_get_body = json.dumps({'result': [{'sys_id': self.mock_incident['sys_id']}, {'sys_id': self.mock_incident['sys_id']}]}) json_post_body = json.dumps( { 'result': { 'sys_id': self.mock_attachment['sys_id'], 'table_sys_id': self.mock_incident['sys_id'], 'file_name': self.mock_attachment['file_name'] } } ) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_get_body, status=200, content_type="application/json") httpretty.register_uri(httpretty.POST, "http://%s/%s" % (self.mock_connection['host'], self.mock_attachment['path']), body=json_post_body, status=201, content_type="multipart/form-data") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(MultipleResults, r.attach, 'tests/legacy/attachment.txt') @httpretty.activate def test_delete_incident(self): """ Delete an incident, make sure we get a 204 back along with expected body """ httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json.dumps({'result': [{'sys_id': self.mock_incident['sys_id']}]}), status=200, content_type="application/json") httpretty.register_uri(httpretty.DELETE, "http://%s/%s/%s" % (self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['sys_id']), body=json.dumps({'success': True}), status=204, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) result = r.delete() self.assertEqual(result['success'], True) self.assertEqual(r.status_code, 204) @httpretty.activate def test_delete_incident_multiple(self): """ Make sure delete queries yielding more than 1 record fails """ json_body_get = json.dumps({'result': [{'sys_id': self.mock_incident['sys_id']}, {'sys_id': self.mock_incident['sys_id']}]}) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body_get, status=200, content_type="application/json") json_body_delete = json.dumps({'success': True}) httpretty.register_uri(httpretty.DELETE, "http://%s/%s/%s" % (self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['sys_id']), body=json_body_delete, status=204, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(MultipleResults, r.delete) @httpretty.activate def test_delete_incident_invalid_response(self): """ Make sure non-204 responses are properly handled """ httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json.dumps({'result': [{'sys_id': self.mock_incident['sys_id']}]}), status=200, content_type="application/json") httpretty.register_uri(httpretty.DELETE, "http://%s/%s/%s" % (self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['sys_id']), body=json.dumps({'success': True}), status=200, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(UnexpectedResponse, r.delete) @httpretty.activate def test_delete_incident_non_existent(self): """ Attempt to delete a non-existing record """ client = copy(self.client) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json.dumps({'result': {}}), status=200, content_type="application/json") httpretty.register_uri(httpretty.DELETE, "http://%s/%s/%s" % (self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['sys_id']), body=json.dumps({'success': True}), status=204, content_type="application/json") client.raise_on_empty = False r = client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(NoResults, r.delete) @httpretty.activate def test_clone_incident_non_existent(self): """ Attempt to clone a non-existing record """ httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json.dumps({'result': {}}), status=200, content_type="application/json") httpretty.register_uri(httpretty.DELETE, "http://%s/%s/%s" % (self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['sys_id']), body=json.dumps({'success': True}), status=204, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(NoResults, r.clone) @httpretty.activate def test_clone_incident_invalid_reset_fields(self): """ Attempt to pass reset_fields as non-list to clone() """ httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json.dumps({'result': {}}), status=200, content_type="application/json") httpretty.register_uri(httpretty.DELETE, "http://%s/%s/%s" % (self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['sys_id']), body=json.dumps({'success': True}), status=204, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(InvalidUsage, r.clone, reset_fields='test') @httpretty.activate def test_clone_incident_multiple(self): """ Make sure clone queries yielding more than 1 record fails """ json_body_get = json.dumps({'result': [{'sys_id': self.mock_incident['sys_id']}, {'sys_id': self.mock_incident['sys_id']}]}) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body_get, status=200, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(MultipleResults, r.clone) @httpretty.activate def test_clone_incident_flatten(self): """ Make sure clone payload is properly flattened """ json_body = json.dumps( { 'result': [ { 'sys_id': self.mock_incident['sys_id'], 'test': { 'value': 'test_value' } } ] } ) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") httpretty.register_uri(httpretty.POST, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=201, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) r.clone(reset_fields=['sys_id']) request_body = json.loads(httpretty.last_request().body.decode('utf-8')) self.assertEqual(request_body['test'], 'test_value') @httpretty.activate def test_clone_incident_reset_fields(self): """ Make sure reset fields works """ json_body = json.dumps( { 'result': [ { 'sys_id': self.mock_incident['sys_id'], 'number': self.mock_incident['number'] } ] } ) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") httpretty.register_uri(httpretty.POST, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=201, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) r.clone(reset_fields=['sys_id']) request_body = json.loads(httpretty.last_request().body.decode('utf-8')) self.assertEqual(request_body['number'], self.mock_incident['number']) self.assertFalse('sys_id' in request_body) @httpretty.activate def test_clone_unexpected_response(self): """ Make sure status code 403 is properly handled when cloning """ json_body = json.dumps( { 'result': [ { 'sys_id': self.mock_incident['sys_id'], 'number': self.mock_incident['number'] } ] } ) httpretty.register_uri(httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") httpretty.register_uri(httpretty.POST, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=403, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(UnexpectedResponse, r.clone)
class TestIncident(unittest.TestCase): def setUp(self): # Mock client configuration self.mock_connection = { "instance": "mock_instance", "user": "******", "pass": "******", "raise_on_empty": False, } self.mock_connection["host"] = ("%s.service-now.com" % self.mock_connection["instance"]) # Mock incident attributes self.mock_incident = { "stats": "api/now/stats/incident", "path": "api/now/table/incident", "number": "INC01234", "sys_id": "98ace1a537ea2a00cf5c9c9953990e19", "link_arg": "?page=2", } # Mock attachment attributes self.mock_attachment = { "path": "api/now/attachment/upload", "sys_id": "b39fb9c1db0032000062f34ebf96198b", "file_name": "attachment.txt", } self.client = Client( instance=self.mock_connection["instance"], user=self.mock_connection["user"], password=self.mock_connection["pass"], use_ssl=False, raise_on_empty=self.mock_connection["raise_on_empty"], ) # Use `nosetests -l debug` to enable this logger logging.basicConfig(level=logging.DEBUG) self.log = logging.getLogger("debug") def test_connection(self): self.assertEqual(self.client.instance, self.mock_connection["instance"]) self.assertEqual(self.client.raise_on_empty, self.mock_connection["raise_on_empty"]) self.assertEqual(self.client.request_params, {}) @httpretty.activate def test_client_request_params(self): httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json.dumps({"result": ""}), status=200, content_type="application/json", ) client = Client( instance=self.mock_connection["instance"], user=self.mock_connection["user"], password=self.mock_connection["pass"], raise_on_empty=self.mock_connection["raise_on_empty"], use_ssl=False, ) client.request_params = {"foo1": "bar1", "foo2": "bar2"} r = client.query(table="incident", query={}) r.get_one() # Parse QS and make sure `request_params` actually ended up in the request qs_str = r.last_response.url.split("?")[1] qs = dict( (x[0], x[1]) for x in [x.split("=") for x in qs_str.split("&")]) self.assertEqual(qs["foo1"], "bar1") self.assertEqual(qs["foo2"], "bar2") @httpretty.activate def test_invalid_query_type(self): json_body = json.dumps( {"result": [{ "number": self.mock_incident["number"] }]}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=200, content_type="application/json", ) r = self.client.query(table="incident", query=1) self.assertRaises(InvalidUsage, r.get_one) @httpretty.activate def test_get_count(self): json_body = json.dumps({"result": {"stats": {"count": "30"}}}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["stats"]), body=json_body, status=200, content_type="application/json", ) r = self.client.query(table="incident", query={}) self.assertEqual(r.count, 30) @httpretty.activate def test_last_response_not_executed(self): json_body = json.dumps( {"result": [{ "number": self.mock_incident["number"] }]}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=200, content_type="application/json", ) try: str(self.client.query(table="incident", query={}).last_response) self.assertFalse( "Getting last_response should fail when no `Request` has been executed" ) except NoRequestExecuted: pass @httpretty.activate def test_last_response(self): json_body = json.dumps( {"result": [{ "number": self.mock_incident["number"] }]}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=200, content_type="application/json", ) r = self.client.query(table="incident", query={}) r.get_one() # Make sure we get the expected status code back self.assertEqual(r.status_code, 200) # Make sure last_response is not None self.assertNotEqual(r.last_response, None) @httpretty.activate def test_get_incident_by_qb(self): """ Make sure fetching by dict type query works """ json_body = json.dumps( {"result": [{ "number": self.mock_incident["number"] }]}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=200, content_type="application/json", ) q = QueryBuilder().field("number").equals(self.mock_incident["number"]) r = self.client.query(table="incident", query=q) # Make sure we got an incident back with the expected number self.assertEqual(r.get_one()["number"], self.mock_incident["number"]) @httpretty.activate def test_get_incident_by_dict_query(self): """ Make sure fetching by dict type query works """ json_body = json.dumps( {"result": [{ "number": self.mock_incident["number"] }]}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=200, content_type="application/json", ) r = self.client.query(table="incident", query={"number": self.mock_incident["number"]}) # Make sure we got an incident back with the expected number self.assertEqual(r.get_one()["number"], self.mock_incident["number"]) @httpretty.activate def test_get_content_without_result(self): """ Make sure content without `result` fails """ json_body = json.dumps({}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=200, content_type="application/json", ) r = self.client.query(table="incident", query={}) self.assertRaises(MissingResult, r.get_one) @httpretty.activate def test_get_limited_result(self): """ Make sure fetching by dict type query works """ json_body = json.dumps( {"result": [{ "number": self.mock_incident["number"] }]}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=200, content_type="application/json", ) r = self.client.query(table="incident", query={}) # Trigger a request by fetching next element from the generator next(r.get_all(limit=2)) # Get last request QS qs = httpretty.last_request().querystring # Make sure sysparm_limit equals limit self.assertEqual(int(qs["sysparm_limit"][0]), 2) # Make sure sysparm_suppress_pagination_header is True self.assertTrue(qs["sysparm_suppress_pagination_header"]) @httpretty.activate def test_get_incident_by_string_query(self): """ Make sure fetching by string type query works """ json_body = json.dumps( {"result": [{ "number": self.mock_incident["number"] }]}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=200, content_type="application/json", ) r = self.client.query(table="incident", query="nameINincident,task^elementLIKEstate") # Make sure we got an incident back with the expected number self.assertEqual(r.get_one()["number"], self.mock_incident["number"]) @httpretty.activate def test_get_sorted(self): """ Make sure order_by generates the expected sysparm_query string """ json_body = json.dumps( {"result": [{ "number": self.mock_incident["number"] }]}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=200, content_type="application/json", ) r = self.client.query(table="incident", query={}) next(r.get_multiple(order_by=["-number", "category"])) qs_str = r.last_response.url.split("?")[1] qs = dict( (x[0], x[1]) for x in [x.split("=") for x in qs_str.split("&")]) self.assertEqual(str(qs["sysparm_query"]), "%5EORDERBYDESCnumber%5EORDERBYcategory") @httpretty.activate def test_get_sorted_invalid(self): """ Make sure get_multiple fails if order_by is not of type `list` """ json_body = json.dumps( {"result": [{ "number": self.mock_incident["number"] }]}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=200, content_type="application/json", ) r = self.client.query(table="incident", query={}) self.assertRaises(InvalidUsage, next, r.get_multiple(order_by="number")) self.assertRaises(InvalidUsage, next, r.get_multiple(order_by={"number": 1})) self.assertRaises(InvalidUsage, next, r.get_multiple(order_by=1)) @httpretty.activate def test_get_incident_content_error(self): """ Make sure error in content is properly handled """ httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json.dumps({"error": { "message": "test" }}), status=200, content_type="application/json", ) r = self.client.query(table="incident", query={"number": self.mock_incident["number"]}) self.assertRaises(UnexpectedResponse, r.get_one) @httpretty.activate def test_get_incident_invalid_query(self): """ Make sure querying by non-dict and non-string doesn't work """ json_body = json.dumps( {"result": [{ "number": self.mock_incident["number"] }]}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=200, content_type="application/json", ) # Pass query as a `list` , which is invalid r = self.client.query(table="incident", query=list()) self.assertRaises(InvalidUsage, r.get_one) @httpretty.activate def test_get_linked_result(self): """ Fetch multiple incident records from a linked result """ link_header = "<http://%s/%s/%s>; rel='next'" % ( self.mock_connection["host"], self.mock_incident["path"], self.mock_incident["link_arg"], ) json_body_first = json.dumps({ "result": [{ "number": self.mock_incident["number"], "linked": False }] }) json_body_second = json.dumps({ "result": [{ "number": self.mock_incident["number"], "linked": True }] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body_first, status=200, content_type="application/json", adding_headers={"Link": link_header}, ) httpretty.register_uri( httpretty.GET, "http://%s/%s/%s" % ( self.mock_connection["host"], self.mock_incident["path"], self.mock_incident["link_arg"], ), body=json_body_second, status=200, content_type="application/json", ) r = self.client.query(table="incident", query={"number": self.mock_incident["number"]}) result = r.get_multiple() # Return the first result from the container first = next(result) self.assertEqual(first["number"], self.mock_incident["number"]) # Make sure it's the record we're after self.assertFalse(first["linked"]) # Return the second result from the container (linked) second = next(result) self.assertEqual(second["number"], self.mock_incident["number"]) # Make sure it's the record we're after self.assertTrue(second["linked"]) @httpretty.activate def test_get_incident_invalid_field_format(self): """ Make sure passing fields as non-list fails """ client = copy(self.client) json_body = json.dumps({"result": []}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=404, content_type="application/json", ) client.raise_on_empty = True # If `raise_on_empty` is True and status code is 404, or 200 and empty result, an exception should be thrown. r = client.query(table="incident", query={"number": self.mock_incident["number"]}) self.assertRaises(NoResults, r.get_one) client.raise_on_empty = False r = client.query(table="incident", query={"number": self.mock_incident["number"]}) self.assertRaises(InvalidUsage, r.get_one, fields="test") @httpretty.activate def test_get_incident_field_filter(self): """ Make sure passing fields works as intended """ client = copy(self.client) json_body = json.dumps({ "result": [{ "sys_id": self.mock_incident["sys_id"], "number": self.mock_incident["number"], }] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=200, content_type="application/json", ) r = client.query(table="incident", query={"number": self.mock_incident["number"]}) result = r.get_one(fields=["sys_id", "number"]) # Make sure we get the selected fields back self.assertEqual(result["sys_id"], self.mock_incident["sys_id"]) self.assertEqual(result["number"], self.mock_incident["number"]) @httpretty.activate def test_get_incident_no_results(self): """ Make sure empty result sets are properly handled """ client = copy(self.client) json_body = json.dumps({"result": []}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=404, content_type="application/json", ) client.raise_on_empty = True # If `raise_on_empty` is True and status code is 404, or 200 and empty result, an exception should be thrown. r = client.query(table="incident", query={"number": self.mock_incident["number"]}) self.assertRaises(NoResults, r.get_one) client.raise_on_empty = False r = client.query(table="incident", query={"number": self.mock_incident["number"]}) res = r.get_one() # Quietly continue if `raise_on_empty` if False self.assertEqual(res, {}) self.assertEqual(r.status_code, 404) @httpretty.activate def test_insert_incident(self): """ Create new incident, make sure we get a sys_id back """ json_body = json.dumps( {"result": [{ "sys_id": self.mock_incident["sys_id"] }]}) httpretty.register_uri( httpretty.POST, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=201, content_type="application/json", ) result = self.client.insert(table="incident", payload={ "field1": "value1", "field2": "value2" }) # Make sure we got an incident back self.assertEqual(result[0]["sys_id"], self.mock_incident["sys_id"]) @httpretty.activate def test_insert_incident_status(self): """ Create new incident, make sure status code is 201 """ json_body = json.dumps( {"result": [{ "sys_id": self.mock_incident["sys_id"] }]}) httpretty.register_uri( httpretty.POST, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=201, content_type="application/json", ) r = self.client._legacy_request("POST", "incident") r.insert(payload={"field1": "value1", "field2": "value2"}) # Make sure we got code 201 back self.assertEqual(r.status_code, 201) @httpretty.activate def test_insert_incident_invalid_status(self): """ Update an incident and get an unexpected status code back, make sure it fails properly. """ json_body = { "result": [{ "sys_id": self.mock_incident["sys_id"] }], "error": { "message": "Error summary", "detail": "Error detail " }, } httpretty.register_uri( httpretty.POST, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json.dumps(json_body), status=403, content_type="application/json", ) r = self.client._legacy_request("POST", "incident") try: r.insert(payload={"field1": "value1", "field2": "value2"}) except UnexpectedResponse as e: # Make sure the exception object contains summary and details self.assertEqual(e.error_summary, json_body["error"]["message"]) self.assertEqual(e.error_details, json_body["error"]["detail"]) pass @httpretty.activate def test_update_incident(self): """ Updates an existing incident. Checks for sys_id and status code 200 """ json_body = json.dumps({ "result": [{ "sys_id": self.mock_incident["sys_id"], "this": "that" }] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=200, content_type="application/json", ) httpretty.register_uri( httpretty.PUT, "http://%s/%s/%s" % ( self.mock_connection["host"], self.mock_incident["path"], self.mock_incident["sys_id"], ), body=json_body, status=200, content_type="application/json", ) r = self.client.query(table="incident", query={"number": self.mock_incident["number"]}) result = r.update({"this": "that"}) # Make sure we got an incident back with the expected sys_id self.assertEqual(result[0]["sys_id"], self.mock_incident["sys_id"]) self.assertEqual(result[0]["this"], "that") self.assertEqual(r.status_code, 200) @httpretty.activate def test_update_incident_non_existent(self): """ Attempt to update a non-existent incident """ json_body = json.dumps({"result": {}}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=200, content_type="application/json", ) httpretty.register_uri( httpretty.PUT, "http://%s/%s/%s" % ( self.mock_connection["host"], self.mock_incident["path"], self.mock_incident["sys_id"], ), body={}, status=200, content_type="application/json", ) r = self.client.query(table="incident", query={"number": self.mock_incident["number"]}) self.assertRaises(NoResults, r.update, {"foo": "bar"}) @httpretty.activate def test_update_incident_invalid_update(self): """ Make sure updates which are non-dict and non-string type are properly handled """ json_body = json.dumps({ "result": [{ "sys_id": self.mock_incident["sys_id"], "this": "that" }] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=200, content_type="application/json", ) httpretty.register_uri( httpretty.PUT, "http://%s/%s/%s" % ( self.mock_connection["host"], self.mock_incident["path"], self.mock_incident["sys_id"], ), body=json_body, status=200, content_type="application/json", ) r = self.client.query(table="incident", query={"number": self.mock_incident["number"]}) self.assertRaises(InvalidUsage, r.update, "invalid update") @httpretty.activate def test_update_incident_multiple(self): """ Make sure update queries yielding more than 1 record fails """ json_body = json.dumps({ "result": [ { "sys_id": self.mock_incident["sys_id"], "this": "that" }, { "sys_id": self.mock_incident["sys_id"], "this": "that" }, ] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=200, content_type="application/json", ) httpretty.register_uri( httpretty.PUT, "http://%s/%s/%s" % ( self.mock_connection["host"], self.mock_incident["path"], self.mock_incident["sys_id"], ), body=json_body, status=200, content_type="application/json", ) r = self.client.query(table="incident", query={"number": self.mock_incident["number"]}) self.assertRaises(MultipleResults, r.update, {"foo": "bar"}) @httpretty.activate def test_get_multiple_with_offset(self): """ Make sure offset works properly """ json_body = json.dumps({ "result": [ { "sys_id": self.mock_incident["sys_id"], "this": "that" }, { "sys_id": self.mock_incident["sys_id"], "this": "that" }, ] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=200, content_type="application/json", ) r = self.client.query(table="incident", query={"number": self.mock_incident["number"]}) list(r.get_multiple(limit=100, offset=50)) qs = httpretty.last_request().querystring # Make sure sysparm_offset is set to the expected value self.assertEqual(int(qs["sysparm_offset"][0]), 50) # Make sure sysparm_limit is set to the expected value self.assertEqual(int(qs["sysparm_limit"][0]), 100) @httpretty.activate def test_attach_incident(self): """ Attaches file to an existing incident. Checks for table_sys_id, file_name and status code 201 """ json_get_body = json.dumps( {"result": [{ "sys_id": self.mock_incident["sys_id"] }]}) json_post_body = json.dumps({ "result": { "sys_id": self.mock_attachment["sys_id"], "table_sys_id": self.mock_incident["sys_id"], "file_name": self.mock_attachment["file_name"], } }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_get_body, status=200, content_type="application/json", ) httpretty.register_uri( httpretty.POST, "http://%s/%s" % (self.mock_connection["host"], self.mock_attachment["path"]), body=json_post_body, status=201, content_type="multipart/form-data", ) r = self.client.query(table="incident", query={"number": self.mock_incident["number"]}) result = r.attach("tests/legacy/attachment.txt") # Make sure we got an incident back with the expected sys_id self.assertEqual(result["table_sys_id"], self.mock_incident["sys_id"]) self.assertEqual(result["file_name"], self.mock_attachment["file_name"]) self.assertEqual(r.status_code, 201) @httpretty.activate def test_attach_incident_non_existent(self): """ Attempts to attach file to a non-existent incident """ json_post_body = json.dumps({ "result": { "sys_id": self.mock_attachment["sys_id"], "table_sys_id": self.mock_incident["sys_id"], "file_name": self.mock_attachment["file_name"], } }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json.dumps({"result": {}}), status=200, content_type="application/json", ) httpretty.register_uri( httpretty.POST, "http://%s/%s" % (self.mock_connection["host"], self.mock_attachment["path"]), body=json_post_body, status=201, content_type="multipart/form-data", ) r = self.client.query(table="incident", query={"number": self.mock_incident["number"]}) self.assertRaises(NoResults, r.attach, "tests/legacy/attachment.txt") @httpretty.activate def test_attach_incident_non_file(self): """ Attempts to attach a non-file to an incident """ json_post_body = json.dumps({ "result": [{ "sys_id": self.mock_attachment["sys_id"], "table_sys_id": self.mock_incident["sys_id"], "file_name": self.mock_attachment["file_name"], }] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_post_body, status=200, content_type="application/json", ) httpretty.register_uri( httpretty.POST, "http://%s/%s" % (self.mock_connection["host"], self.mock_attachment["path"]), body=json_post_body, status=201, content_type="multipart/form-data", ) r = self.client.query(table="incident", query={"number": self.mock_incident["number"]}) self.assertRaises(InvalidUsage, r.attach, "tests/non_existing_file.txt") @httpretty.activate def test_attach_incident_multiple(self): """ Make sure attach fails when getting multiple records back """ json_get_body = json.dumps({ "result": [ { "sys_id": self.mock_incident["sys_id"] }, { "sys_id": self.mock_incident["sys_id"] }, ] }) json_post_body = json.dumps({ "result": { "sys_id": self.mock_attachment["sys_id"], "table_sys_id": self.mock_incident["sys_id"], "file_name": self.mock_attachment["file_name"], } }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_get_body, status=200, content_type="application/json", ) httpretty.register_uri( httpretty.POST, "http://%s/%s" % (self.mock_connection["host"], self.mock_attachment["path"]), body=json_post_body, status=201, content_type="multipart/form-data", ) r = self.client.query(table="incident", query={"number": self.mock_incident["number"]}) self.assertRaises(MultipleResults, r.attach, "tests/legacy/attachment.txt") @httpretty.activate def test_delete_incident(self): """ Delete an incident, make sure we get a 204 back along with expected body """ httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json.dumps( {"result": [{ "sys_id": self.mock_incident["sys_id"] }]}), status=200, content_type="application/json", ) httpretty.register_uri( httpretty.DELETE, "http://%s/%s/%s" % ( self.mock_connection["host"], self.mock_incident["path"], self.mock_incident["sys_id"], ), body=json.dumps({"success": True}), status=204, content_type="application/json", ) r = self.client.query(table="incident", query={"number": self.mock_incident["number"]}) result = r.delete() self.assertEqual(result["success"], True) self.assertEqual(r.status_code, 204) @httpretty.activate def test_delete_incident_multiple(self): """ Make sure delete queries yielding more than 1 record fails """ json_body_get = json.dumps({ "result": [ { "sys_id": self.mock_incident["sys_id"] }, { "sys_id": self.mock_incident["sys_id"] }, ] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body_get, status=200, content_type="application/json", ) json_body_delete = json.dumps({"success": True}) httpretty.register_uri( httpretty.DELETE, "http://%s/%s/%s" % ( self.mock_connection["host"], self.mock_incident["path"], self.mock_incident["sys_id"], ), body=json_body_delete, status=204, content_type="application/json", ) r = self.client.query(table="incident", query={"number": self.mock_incident["number"]}) self.assertRaises(MultipleResults, r.delete) @httpretty.activate def test_delete_incident_invalid_response(self): """ Make sure non-204 responses are properly handled """ httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json.dumps( {"result": [{ "sys_id": self.mock_incident["sys_id"] }]}), status=200, content_type="application/json", ) httpretty.register_uri( httpretty.DELETE, "http://%s/%s/%s" % ( self.mock_connection["host"], self.mock_incident["path"], self.mock_incident["sys_id"], ), body=json.dumps({"success": True}), status=200, content_type="application/json", ) r = self.client.query(table="incident", query={"number": self.mock_incident["number"]}) self.assertRaises(UnexpectedResponse, r.delete) @httpretty.activate def test_delete_incident_non_existent(self): """ Attempt to delete a non-existing record """ client = copy(self.client) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json.dumps({"result": {}}), status=200, content_type="application/json", ) httpretty.register_uri( httpretty.DELETE, "http://%s/%s/%s" % ( self.mock_connection["host"], self.mock_incident["path"], self.mock_incident["sys_id"], ), body=json.dumps({"success": True}), status=204, content_type="application/json", ) client.raise_on_empty = False r = client.query(table="incident", query={"number": self.mock_incident["number"]}) self.assertRaises(NoResults, r.delete) @httpretty.activate def test_clone_incident_non_existent(self): """ Attempt to clone a non-existing record """ httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json.dumps({"result": {}}), status=200, content_type="application/json", ) httpretty.register_uri( httpretty.DELETE, "http://%s/%s/%s" % ( self.mock_connection["host"], self.mock_incident["path"], self.mock_incident["sys_id"], ), body=json.dumps({"success": True}), status=204, content_type="application/json", ) r = self.client.query(table="incident", query={"number": self.mock_incident["number"]}) self.assertRaises(NoResults, r.clone) @httpretty.activate def test_clone_incident_invalid_reset_fields(self): """ Attempt to pass reset_fields as non-list to clone() """ httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json.dumps({"result": {}}), status=200, content_type="application/json", ) httpretty.register_uri( httpretty.DELETE, "http://%s/%s/%s" % ( self.mock_connection["host"], self.mock_incident["path"], self.mock_incident["sys_id"], ), body=json.dumps({"success": True}), status=204, content_type="application/json", ) r = self.client.query(table="incident", query={"number": self.mock_incident["number"]}) self.assertRaises(InvalidUsage, r.clone, reset_fields="test") @httpretty.activate def test_clone_incident_multiple(self): """ Make sure clone queries yielding more than 1 record fails """ json_body_get = json.dumps({ "result": [ { "sys_id": self.mock_incident["sys_id"] }, { "sys_id": self.mock_incident["sys_id"] }, ] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body_get, status=200, content_type="application/json", ) r = self.client.query(table="incident", query={"number": self.mock_incident["number"]}) self.assertRaises(MultipleResults, r.clone) @httpretty.activate def test_clone_incident_flatten(self): """ Make sure clone payload is properly flattened """ json_body = json.dumps({ "result": [{ "sys_id": self.mock_incident["sys_id"], "test": { "value": "test_value" }, }] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=200, content_type="application/json", ) httpretty.register_uri( httpretty.POST, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=201, content_type="application/json", ) r = self.client.query(table="incident", query={"number": self.mock_incident["number"]}) r.clone(reset_fields=["sys_id"]) request_body = json.loads( httpretty.last_request().body.decode("utf-8")) self.assertEqual(request_body["test"], "test_value") @httpretty.activate def test_clone_incident_reset_fields(self): """ Make sure reset fields works """ json_body = json.dumps({ "result": [{ "sys_id": self.mock_incident["sys_id"], "number": self.mock_incident["number"], }] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=200, content_type="application/json", ) httpretty.register_uri( httpretty.POST, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=201, content_type="application/json", ) r = self.client.query(table="incident", query={"number": self.mock_incident["number"]}) r.clone(reset_fields=["sys_id"]) request_body = json.loads( httpretty.last_request().body.decode("utf-8")) self.assertEqual(request_body["number"], self.mock_incident["number"]) self.assertFalse("sys_id" in request_body) @httpretty.activate def test_clone_unexpected_response(self): """ Make sure status code 403 is properly handled when cloning """ json_body = json.dumps({ "result": [{ "sys_id": self.mock_incident["sys_id"], "number": self.mock_incident["number"], }] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=200, content_type="application/json", ) httpretty.register_uri( httpretty.POST, "http://%s/%s" % (self.mock_connection["host"], self.mock_incident["path"]), body=json_body, status=403, content_type="application/json", ) r = self.client.query(table="incident", query={"number": self.mock_incident["number"]}) self.assertRaises(UnexpectedResponse, r.clone)
class TestIncident(unittest.TestCase): def setUp(self): # Mock client configuration self.mock_connection = { 'instance': 'mock_instance', 'user': '******', 'pass': '******', 'raise_on_empty': False } self.mock_connection[ 'host'] = "%s.service-now.com" % self.mock_connection['instance'] # Mock incident attributes self.mock_incident = { 'stats': 'api/now/stats/incident', 'path': 'api/now/table/incident', 'number': 'INC01234', 'sys_id': '98ace1a537ea2a00cf5c9c9953990e19', 'link_arg': '?page=2' } # Mock attachment attributes self.mock_attachment = { 'path': 'api/now/attachment/upload', 'sys_id': 'b39fb9c1db0032000062f34ebf96198b', 'file_name': 'attachment.txt', } self.client = Client( instance=self.mock_connection['instance'], user=self.mock_connection['user'], password=self.mock_connection['pass'], use_ssl=False, raise_on_empty=self.mock_connection['raise_on_empty']) # Use `nosetests -l debug` to enable this logger logging.basicConfig(level=logging.DEBUG) self.log = logging.getLogger('debug') def test_connection(self): self.assertEqual(self.client.instance, self.mock_connection['instance']) self.assertEqual(self.client.raise_on_empty, self.mock_connection['raise_on_empty']) self.assertEqual(self.client.request_params, {}) @httpretty.activate def test_client_request_params(self): httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json.dumps({'result': ''}), status=200, content_type="application/json") client = Client(instance=self.mock_connection['instance'], user=self.mock_connection['user'], password=self.mock_connection['pass'], raise_on_empty=self.mock_connection['raise_on_empty'], use_ssl=False) client.request_params = {'foo1': 'bar1', 'foo2': 'bar2'} r = client.query(table='incident', query={}) r.get_one() # Parse QS and make sure `request_params` actually ended up in the request qs_str = r.last_response.url.split("?")[1] qs = dict( (x[0], x[1]) for x in [x.split("=") for x in qs_str.split("&")]) self.assertEqual(qs['foo1'], 'bar1') self.assertEqual(qs['foo2'], 'bar2') @httpretty.activate def test_invalid_query_type(self): json_body = json.dumps( {'result': [{ 'number': self.mock_incident['number'] }]}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query=1) self.assertRaises(InvalidUsage, r.get_one) @httpretty.activate def test_get_count(self): json_body = json.dumps({'result': {'stats': {'count': '30'}}}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['stats']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query={}) self.assertEqual(r.count, 30) @httpretty.activate def test_last_response_not_executed(self): json_body = json.dumps( {'result': [{ 'number': self.mock_incident['number'] }]}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") try: str(self.client.query(table='incident', query={}).last_response) self.assertFalse( 'Getting last_response should fail when no `Request` has been executed' ) except NoRequestExecuted: pass @httpretty.activate def test_last_response(self): json_body = json.dumps( {'result': [{ 'number': self.mock_incident['number'] }]}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query={}) r.get_one() # Make sure we get the expected status code back self.assertEqual(r.status_code, 200) # Make sure last_response is not None self.assertNotEqual(r.last_response, None) @httpretty.activate def test_get_incident_by_qb(self): """ Make sure fetching by dict type query works """ json_body = json.dumps( {'result': [{ 'number': self.mock_incident['number'] }]}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") q = QueryBuilder().field('number').equals(self.mock_incident['number']) r = self.client.query(table='incident', query=q) # Make sure we got an incident back with the expected number self.assertEqual(r.get_one()['number'], self.mock_incident['number']) @httpretty.activate def test_get_incident_by_dict_query(self): """ Make sure fetching by dict type query works """ json_body = json.dumps( {'result': [{ 'number': self.mock_incident['number'] }]}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) # Make sure we got an incident back with the expected number self.assertEqual(r.get_one()['number'], self.mock_incident['number']) @httpretty.activate def test_get_content_without_result(self): """ Make sure content without `result` fails """ json_body = json.dumps({}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query={}) self.assertRaises(MissingResult, r.get_one) @httpretty.activate def test_get_limited_result(self): """ Make sure fetching by dict type query works """ json_body = json.dumps( {'result': [{ 'number': self.mock_incident['number'] }]}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query={}) # Trigger a request by fetching next element from the generator next(r.get_all(limit=2)) # Get last request QS qs = httpretty.last_request().querystring # Make sure sysparm_limit equals limit self.assertEqual(int(qs['sysparm_limit'][0]), 2) # Make sure sysparm_suppress_pagination_header is True self.assertTrue(qs['sysparm_suppress_pagination_header']) @httpretty.activate def test_get_incident_by_string_query(self): """ Make sure fetching by string type query works """ json_body = json.dumps( {'result': [{ 'number': self.mock_incident['number'] }]}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query='nameINincident,task^elementLIKEstate') # Make sure we got an incident back with the expected number self.assertEqual(r.get_one()['number'], self.mock_incident['number']) @httpretty.activate def test_get_sorted(self): """ Make sure order_by generates the expected sysparm_query string """ json_body = json.dumps( {'result': [{ 'number': self.mock_incident['number'] }]}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query={}) next(r.get_multiple(order_by=['-number', 'category'])) qs_str = r.last_response.url.split("?")[1] qs = dict( (x[0], x[1]) for x in [x.split("=") for x in qs_str.split("&")]) self.assertEqual(str(qs['sysparm_query']), '%5EORDERBYDESCnumber%5EORDERBYcategory') @httpretty.activate def test_get_sorted_invalid(self): """ Make sure get_multiple fails if order_by is not of type `list` """ json_body = json.dumps( {'result': [{ 'number': self.mock_incident['number'] }]}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query={}) self.assertRaises(InvalidUsage, next, r.get_multiple(order_by='number')) self.assertRaises(InvalidUsage, next, r.get_multiple(order_by={'number': 1})) self.assertRaises(InvalidUsage, next, r.get_multiple(order_by=1)) @httpretty.activate def test_get_incident_content_error(self): """ Make sure error in content is properly handled """ httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json.dumps({'error': { 'message': 'test' }}), status=200, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(UnexpectedResponse, r.get_one) @httpretty.activate def test_get_incident_invalid_query(self): """ Make sure querying by non-dict and non-string doesn't work """ json_body = json.dumps( {'result': [{ 'number': self.mock_incident['number'] }]}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") # Pass query as a `list` , which is invalid r = self.client.query(table='incident', query=list()) self.assertRaises(InvalidUsage, r.get_one) @httpretty.activate def test_get_linked_result(self): """ Fetch multiple incident records from a linked result """ link_header = "<http://%s/%s/%s>; rel='next'" % ( self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['link_arg']) json_body_first = json.dumps({ 'result': [{ 'number': self.mock_incident['number'], 'linked': False }] }) json_body_second = json.dumps({ 'result': [{ 'number': self.mock_incident['number'], 'linked': True }] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body_first, status=200, content_type="application/json", adding_headers={'Link': link_header}) httpretty.register_uri( httpretty.GET, "http://%s/%s/%s" % (self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['link_arg']), body=json_body_second, status=200, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) result = r.get_multiple() # Return the first result from the container first = next(result) self.assertEqual(first['number'], self.mock_incident['number']) # Make sure it's the record we're after self.assertFalse(first['linked']) # Return the second result from the container (linked) second = next(result) self.assertEqual(second['number'], self.mock_incident['number']) # Make sure it's the record we're after self.assertTrue(second['linked']) @httpretty.activate def test_get_incident_invalid_field_format(self): """ Make sure passing fields as non-list fails """ client = copy(self.client) json_body = json.dumps({'result': []}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=404, content_type="application/json") client.raise_on_empty = True # If `raise_on_empty` is True and status code is 404, or 200 and empty result, an exception should be thrown. r = client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(NoResults, r.get_one) client.raise_on_empty = False r = client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(InvalidUsage, r.get_one, fields='test') @httpretty.activate def test_get_incident_field_filter(self): """ Make sure passing fields works as intended """ client = copy(self.client) json_body = json.dumps({ 'result': [{ 'sys_id': self.mock_incident['sys_id'], 'number': self.mock_incident['number'] }] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") r = client.query(table='incident', query={'number': self.mock_incident['number']}) result = r.get_one(fields=['sys_id', 'number']) # Make sure we get the selected fields back self.assertEqual(result['sys_id'], self.mock_incident['sys_id']) self.assertEqual(result['number'], self.mock_incident['number']) @httpretty.activate def test_get_incident_no_results(self): """ Make sure empty result sets are properly handled """ client = copy(self.client) json_body = json.dumps({'result': []}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=404, content_type="application/json") client.raise_on_empty = True # If `raise_on_empty` is True and status code is 404, or 200 and empty result, an exception should be thrown. r = client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(NoResults, r.get_one) client.raise_on_empty = False r = client.query(table='incident', query={'number': self.mock_incident['number']}) res = r.get_one() # Quietly continue if `raise_on_empty` if False self.assertEqual(res, {}) self.assertEqual(r.status_code, 404) @httpretty.activate def test_insert_incident(self): """ Create new incident, make sure we get a sys_id back """ json_body = json.dumps( {'result': [{ 'sys_id': self.mock_incident['sys_id'] }]}) httpretty.register_uri( httpretty.POST, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=201, content_type="application/json") result = self.client.insert(table='incident', payload={ 'field1': 'value1', 'field2': 'value2' }) # Make sure we got an incident back self.assertEqual(result[0]['sys_id'], self.mock_incident['sys_id']) @httpretty.activate def test_insert_incident_status(self): """ Create new incident, make sure status code is 201 """ json_body = json.dumps( {'result': [{ 'sys_id': self.mock_incident['sys_id'] }]}) httpretty.register_uri( httpretty.POST, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=201, content_type="application/json") r = self.client._legacy_request('POST', 'incident') r.insert(payload={'field1': 'value1', 'field2': 'value2'}) # Make sure we got code 201 back self.assertEqual(r.status_code, 201) @httpretty.activate def test_insert_incident_invalid_status(self): """ Update an incident and get an unexpected status code back, make sure it fails properly. """ json_body = { 'result': [{ 'sys_id': self.mock_incident['sys_id'] }], 'error': { 'message': 'Error summary', 'detail': 'Error detail ' } } httpretty.register_uri( httpretty.POST, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json.dumps(json_body), status=403, content_type="application/json") r = self.client._legacy_request('POST', 'incident') try: r.insert(payload={'field1': 'value1', 'field2': 'value2'}) except UnexpectedResponse as e: # Make sure the exception object contains summary and details self.assertEqual(e.error_summary, json_body['error']['message']) self.assertEqual(e.error_details, json_body['error']['detail']) pass @httpretty.activate def test_update_incident(self): """ Updates an existing incident. Checks for sys_id and status code 200 """ json_body = json.dumps({ 'result': [{ 'sys_id': self.mock_incident['sys_id'], 'this': 'that' }] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") httpretty.register_uri( httpretty.PUT, "http://%s/%s/%s" % (self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['sys_id']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) result = r.update({'this': 'that'}) # Make sure we got an incident back with the expected sys_id self.assertEqual(result[0]['sys_id'], self.mock_incident['sys_id']) self.assertEqual(result[0]['this'], 'that') self.assertEqual(r.status_code, 200) @httpretty.activate def test_update_incident_non_existent(self): """ Attempt to update a non-existent incident """ json_body = json.dumps({'result': {}}) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") httpretty.register_uri( httpretty.PUT, "http://%s/%s/%s" % (self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['sys_id']), body={}, status=200, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(NoResults, r.update, {'foo': 'bar'}) @httpretty.activate def test_update_incident_invalid_update(self): """ Make sure updates which are non-dict and non-string type are properly handled """ json_body = json.dumps({ 'result': [{ 'sys_id': self.mock_incident['sys_id'], 'this': 'that' }] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") httpretty.register_uri( httpretty.PUT, "http://%s/%s/%s" % (self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['sys_id']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(InvalidUsage, r.update, 'invalid update') @httpretty.activate def test_update_incident_multiple(self): """ Make sure update queries yielding more than 1 record fails """ json_body = json.dumps({ 'result': [{ 'sys_id': self.mock_incident['sys_id'], 'this': 'that' }, { 'sys_id': self.mock_incident['sys_id'], 'this': 'that' }] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") httpretty.register_uri( httpretty.PUT, "http://%s/%s/%s" % (self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['sys_id']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(MultipleResults, r.update, {'foo': 'bar'}) @httpretty.activate def test_get_multiple_with_offset(self): """ Make sure offset works properly """ json_body = json.dumps({ 'result': [{ 'sys_id': self.mock_incident['sys_id'], 'this': 'that' }, { 'sys_id': self.mock_incident['sys_id'], 'this': 'that' }] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) list(r.get_multiple(limit=100, offset=50)) qs = httpretty.last_request().querystring # Make sure sysparm_offset is set to the expected value self.assertEqual(int(qs['sysparm_offset'][0]), 50) # Make sure sysparm_limit is set to the expected value self.assertEqual(int(qs['sysparm_limit'][0]), 100) @httpretty.activate def test_attach_incident(self): """ Attaches file to an existing incident. Checks for table_sys_id, file_name and status code 201 """ json_get_body = json.dumps( {'result': [{ 'sys_id': self.mock_incident['sys_id'] }]}) json_post_body = json.dumps({ 'result': { 'sys_id': self.mock_attachment['sys_id'], 'table_sys_id': self.mock_incident['sys_id'], 'file_name': self.mock_attachment['file_name'] } }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_get_body, status=200, content_type="application/json") httpretty.register_uri( httpretty.POST, "http://%s/%s" % (self.mock_connection['host'], self.mock_attachment['path']), body=json_post_body, status=201, content_type="multipart/form-data") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) result = r.attach('tests/legacy/attachment.txt') # Make sure we got an incident back with the expected sys_id self.assertEqual(result['table_sys_id'], self.mock_incident['sys_id']) self.assertEqual(result['file_name'], self.mock_attachment['file_name']) self.assertEqual(r.status_code, 201) @httpretty.activate def test_attach_incident_non_existent(self): """ Attempts to attach file to a non-existent incident """ json_post_body = json.dumps({ 'result': { 'sys_id': self.mock_attachment['sys_id'], 'table_sys_id': self.mock_incident['sys_id'], 'file_name': self.mock_attachment['file_name'] } }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json.dumps({'result': {}}), status=200, content_type="application/json") httpretty.register_uri( httpretty.POST, "http://%s/%s" % (self.mock_connection['host'], self.mock_attachment['path']), body=json_post_body, status=201, content_type="multipart/form-data") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(NoResults, r.attach, 'tests/legacy/attachment.txt') @httpretty.activate def test_attach_incident_non_file(self): """ Attempts to attach a non-file to an incident """ json_post_body = json.dumps({ 'result': [{ 'sys_id': self.mock_attachment['sys_id'], 'table_sys_id': self.mock_incident['sys_id'], 'file_name': self.mock_attachment['file_name'] }] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_post_body, status=200, content_type="application/json") httpretty.register_uri( httpretty.POST, "http://%s/%s" % (self.mock_connection['host'], self.mock_attachment['path']), body=json_post_body, status=201, content_type="multipart/form-data") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(InvalidUsage, r.attach, 'tests/non_existing_file.txt') @httpretty.activate def test_attach_incident_multiple(self): """ Make sure attach fails when getting multiple records back """ json_get_body = json.dumps({ 'result': [{ 'sys_id': self.mock_incident['sys_id'] }, { 'sys_id': self.mock_incident['sys_id'] }] }) json_post_body = json.dumps({ 'result': { 'sys_id': self.mock_attachment['sys_id'], 'table_sys_id': self.mock_incident['sys_id'], 'file_name': self.mock_attachment['file_name'] } }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_get_body, status=200, content_type="application/json") httpretty.register_uri( httpretty.POST, "http://%s/%s" % (self.mock_connection['host'], self.mock_attachment['path']), body=json_post_body, status=201, content_type="multipart/form-data") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(MultipleResults, r.attach, 'tests/legacy/attachment.txt') @httpretty.activate def test_delete_incident(self): """ Delete an incident, make sure we get a 204 back along with expected body """ httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json.dumps( {'result': [{ 'sys_id': self.mock_incident['sys_id'] }]}), status=200, content_type="application/json") httpretty.register_uri( httpretty.DELETE, "http://%s/%s/%s" % (self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['sys_id']), body=json.dumps({'success': True}), status=204, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) result = r.delete() self.assertEqual(result['success'], True) self.assertEqual(r.status_code, 204) @httpretty.activate def test_delete_incident_multiple(self): """ Make sure delete queries yielding more than 1 record fails """ json_body_get = json.dumps({ 'result': [{ 'sys_id': self.mock_incident['sys_id'] }, { 'sys_id': self.mock_incident['sys_id'] }] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body_get, status=200, content_type="application/json") json_body_delete = json.dumps({'success': True}) httpretty.register_uri( httpretty.DELETE, "http://%s/%s/%s" % (self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['sys_id']), body=json_body_delete, status=204, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(MultipleResults, r.delete) @httpretty.activate def test_delete_incident_invalid_response(self): """ Make sure non-204 responses are properly handled """ httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json.dumps( {'result': [{ 'sys_id': self.mock_incident['sys_id'] }]}), status=200, content_type="application/json") httpretty.register_uri( httpretty.DELETE, "http://%s/%s/%s" % (self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['sys_id']), body=json.dumps({'success': True}), status=200, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(UnexpectedResponse, r.delete) @httpretty.activate def test_delete_incident_non_existent(self): """ Attempt to delete a non-existing record """ client = copy(self.client) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json.dumps({'result': {}}), status=200, content_type="application/json") httpretty.register_uri( httpretty.DELETE, "http://%s/%s/%s" % (self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['sys_id']), body=json.dumps({'success': True}), status=204, content_type="application/json") client.raise_on_empty = False r = client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(NoResults, r.delete) @httpretty.activate def test_clone_incident_non_existent(self): """ Attempt to clone a non-existing record """ httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json.dumps({'result': {}}), status=200, content_type="application/json") httpretty.register_uri( httpretty.DELETE, "http://%s/%s/%s" % (self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['sys_id']), body=json.dumps({'success': True}), status=204, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(NoResults, r.clone) @httpretty.activate def test_clone_incident_invalid_reset_fields(self): """ Attempt to pass reset_fields as non-list to clone() """ httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json.dumps({'result': {}}), status=200, content_type="application/json") httpretty.register_uri( httpretty.DELETE, "http://%s/%s/%s" % (self.mock_connection['host'], self.mock_incident['path'], self.mock_incident['sys_id']), body=json.dumps({'success': True}), status=204, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(InvalidUsage, r.clone, reset_fields='test') @httpretty.activate def test_clone_incident_multiple(self): """ Make sure clone queries yielding more than 1 record fails """ json_body_get = json.dumps({ 'result': [{ 'sys_id': self.mock_incident['sys_id'] }, { 'sys_id': self.mock_incident['sys_id'] }] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body_get, status=200, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(MultipleResults, r.clone) @httpretty.activate def test_clone_incident_flatten(self): """ Make sure clone payload is properly flattened """ json_body = json.dumps({ 'result': [{ 'sys_id': self.mock_incident['sys_id'], 'test': { 'value': 'test_value' } }] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") httpretty.register_uri( httpretty.POST, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=201, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) r.clone(reset_fields=['sys_id']) request_body = json.loads( httpretty.last_request().body.decode('utf-8')) self.assertEqual(request_body['test'], 'test_value') @httpretty.activate def test_clone_incident_reset_fields(self): """ Make sure reset fields works """ json_body = json.dumps({ 'result': [{ 'sys_id': self.mock_incident['sys_id'], 'number': self.mock_incident['number'] }] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") httpretty.register_uri( httpretty.POST, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=201, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) r.clone(reset_fields=['sys_id']) request_body = json.loads( httpretty.last_request().body.decode('utf-8')) self.assertEqual(request_body['number'], self.mock_incident['number']) self.assertFalse('sys_id' in request_body) @httpretty.activate def test_clone_unexpected_response(self): """ Make sure status code 403 is properly handled when cloning """ json_body = json.dumps({ 'result': [{ 'sys_id': self.mock_incident['sys_id'], 'number': self.mock_incident['number'] }] }) httpretty.register_uri( httpretty.GET, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=200, content_type="application/json") httpretty.register_uri( httpretty.POST, "http://%s/%s" % (self.mock_connection['host'], self.mock_incident['path']), body=json_body, status=403, content_type="application/json") r = self.client.query(table='incident', query={'number': self.mock_incident['number']}) self.assertRaises(UnexpectedResponse, r.clone)
def test_client_host(self): """Client host property should match host passed to constructor""" host = "123.123.123.123" c = Client(user="******", password="******", host=host) self.assertEqual(c.host, host)
class TestResourceRequest(unittest.TestCase): """Performs resource-request tests""" def setUp(self): self.error_message_body = { "message": "test_message", "detail": "test_details" } self.record_response_get_dict = { "sys_id": "98ace1a537ea2a00cf5c9c9953990e19", "attr1": "foo", "attr2": "bar", } self.record_response_get_one = [{ "sys_id": "98ace1a537ea2a00cf5c9c9953990e19", "attr1": "foo", "attr2": "bar", }] self.record_response_get_three = [ { "sys_id": "37ea2a00cf5c9c995399098ace1a5e19", "attr1": "foo1", "attr2": "bar1", }, { "sys_id": "98ace1a537ea2a00cf5c9c9953990e19", "attr1": "foo2", "attr2": "bar2", }, { "sys_id": "a00cf5c9c9953990e1998ace1a537ea2", "attr1": "foo3", "attr2": "bar3", }, ] self.record_response_create = { "sys_id": "90e11a537ea2a00cf598ace9c99539c9", "attr1": "foo_create", "attr2": "bar_create", } self.record_response_update = { "sys_id": "2a00cf5c9c99539998ace1a537ea0e19", "attr1": "foo_updated", "attr2": "bar_updated", } self.record_response_delete = {"status": "record deleted"} self.client_kwargs = { "user": "******", "password": "******", "instance": "mock_instance", } self.attachment = { "sys_id": "attachment_sys_id", "size_bytes": "512", "file_name": "test1.txt", } self.attachment_path = "tests/data/attachment.txt" self.base_path = "/api/now" self.api_path = "/table/incident" self.client = Client(**self.client_kwargs) self.resource = self.client.resource(base_path=self.base_path, api_path=self.api_path) self.mock_url_builder = self.resource._url_builder self.attachment_upload_url = (self.resource._base_url + self.resource._base_path + "/attachment/file") self.mock_url_builder_base = self.resource._url_builder.get_url() self.mock_url_builder_sys_id = self.mock_url_builder.get_appended_custom( "/{0}".format(self.record_response_get_one[0]["sys_id"])) self.dict_query = {"sys_id": self.record_response_get_one[0]["sys_id"]} self.get_fields = ["foo", "bar"] def test_create_resource(self): """:class:`Resource` object repr type should be string, and its path should be set to api_path + base_path """ r = self.client.resource(base_path=self.base_path, api_path=self.api_path) resource_repr = type(repr(r)) self.assertEquals(resource_repr, str) self.assertEquals(r._base_path, self.base_path) self.assertEquals(r._api_path, self.api_path) self.assertEquals(r.path, self.base_path + self.api_path) @httpretty.activate def test_response_headers(self): """Request response headers should be available in Response.headers property""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, status=200, adding_headers={ "x-test-1": "foo", "x-test-2": "bar" }, content_type="application/json", ) response = self.resource.get(self.dict_query) self.assertEqual(response.headers["x-test-1"], "foo") self.assertEqual(response.headers["x-test-2"], "bar") @httpretty.activate def test_response_count(self): """:prop:`count` of :class:`pysnow.Response` should raise an exception if count is set to non-integer""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, status=200, content_type="application/json", ) response = self.resource.get(self.dict_query) self.assertRaises(TypeError, setattr, response, "count", "foo") self.assertRaises(TypeError, setattr, response, "count", True) self.assertRaises(TypeError, setattr, response, "count", {"foo": "bar"}) @httpretty.activate def test_response_error(self): """:class:`pysnow.Response` should raise an exception if an error is encountered in the response body""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_error(self.error_message_body), status=200, content_type="application/json", ) response = self.resource.get(self.dict_query, stream=True) expected_str = "Error in response. Message: %s, Details: %s" % ( self.error_message_body["message"], self.error_message_body["detail"], ) try: response.first() except ResponseError as e: self.assertEquals(str(e), expected_str) @httpretty.activate def test_get_request_fields(self): """:meth:`get_request` should return a :class:`pysnow.Response` object""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, status=200, content_type="application/json", ) response = self.resource.get(self.dict_query, fields=self.get_fields) qs = qs_as_dict(response._response.request.url) str_fields = ",".join(self.get_fields) # List of fields should end up as comma-separated string self.assertEquals(type(response), Response) self.assertEquals(qs["sysparm_fields"], str_fields) @httpretty.activate def test_get_offset(self): """offset passed to :meth:`get` should set sysparm_offset in query""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json", ) offset = 5 response = self.resource.get(self.dict_query, offset=offset) qs = qs_as_dict(response._response.request.url) self.assertEquals(int(qs["sysparm_offset"]), offset) @httpretty.activate def test_get_limit(self): """limit passed to :meth:`get` should set sysparm_limit in QS""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json", ) limit = 2 response = self.resource.get(self.dict_query, limit=limit) qs = qs_as_dict(response._response.request.url) self.assertEquals(int(qs["sysparm_limit"]), limit) @httpretty.activate def test_get_one(self): """:meth:`one` of :class:`pysnow.Response` should raise an exception if more than one match was found""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json", ) response = self.resource.get(self.dict_query) result = response.one() self.assertEquals(result["sys_id"], self.record_response_get_one[0]["sys_id"]) @httpretty.activate def test_get_all_empty(self): """:meth:`all` generator of :class:`pysnow.Response` should return an empty list if there are no matches""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result([]), status=200, content_type="application/json", ) response = self.resource.get(self.dict_query, stream=True) result = list(response.all()) self.assertEquals(result, []) @httpretty.activate def test_get_nocontent(self): """Result.one should raise EmptyContent for GET 202""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=202, content_type="application/json", ) result = self.resource.get(self.dict_query) self.assertRaises(EmptyContent, result.one) @httpretty.activate def test_get_all_single(self): """Single items with all() using the stream parser should return a list containing the item""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_dict), status=200, content_type="application/json", ) response = self.resource.get(self.dict_query, stream=True) result = list(response.all())[0] self.assertEquals(result, self.record_response_get_dict) @httpretty.activate def test_get_buffer_missing_result_keys(self): """:meth:`one` of :class:`pysnow.Response` should raise an exception if none of the expected keys was found in the result""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=json.dumps({}), status=200, content_type="application/json", ) response = self.resource.get(self.dict_query) self.assertRaises(MissingResult, response.one) @httpretty.activate def test_get_stream_missing_result_keys(self): """:meth:`one` of :class:`pysnow.Response` should raise an exception if none of the expected keys was found in the result""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=json.dumps({}), status=200, content_type="application/json", ) response = self.resource.get(self.dict_query, stream=True) self.assertRaises(MissingResult, response.first) @httpretty.activate def test_http_error_get_one(self): """:meth:`one` of :class:`pysnow.Response` should raise an HTTPError exception if a non-200 response code was encountered""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, status=500, content_type="application/json", ) response = self.resource.get(self.dict_query) self.assertRaises(HTTPError, response.one) @httpretty.activate def test_get_one_many(self): """:meth:`one` of :class:`pysnow.Response` should raise an exception if more than one match was found""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_three), status=200, content_type="application/json", ) response = self.resource.get(self.dict_query) self.assertRaises(MultipleResults, response.one) @httpretty.activate def test_get_one_empty(self): """:meth:`one` of :class:`pysnow.Response` should raise an exception if no matches were found""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result([]), status=200, content_type="application/json", ) response = self.resource.get(self.dict_query) self.assertRaises(NoResults, response.one) @httpretty.activate def test_get_one_or_none_empty(self): """:meth:`one_or_none` of :class:`pysnow.Response` should return `None` if no matches were found """ httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result([]), status=200, content_type="application/json", ) response = self.resource.get(self.dict_query) result = response.one_or_none() self.assertEquals(result, None) @httpretty.activate def test_get_first_or_none_empty(self): """:meth:`first_or_none` of :class:`pysnow.Response` should return None if no records were found""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result([]), status=200, content_type="application/json", ) response = self.resource.get(self.dict_query, stream=True) result = response.first_or_none() self.assertEquals(result, None) @httpretty.activate def test_get_first_or_none(self): """:meth:`first_or_none` of :class:`pysnow.Response` should return first match if multiple records were found""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_three), status=200, content_type="application/json", ) response = self.resource.get(self.dict_query, stream=True) result = response.first_or_none() self.assertEquals(result, self.record_response_get_three[0]) @httpretty.activate def test_get_first(self): """:meth:`first` of :class:`pysnow.Response` should return first match if multiple records were found""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_three), status=200, content_type="application/json", ) response = self.resource.get(self.dict_query, stream=True) result = response.first() self.assertEquals(result, self.record_response_get_three[0]) @httpretty.activate def test_get_first_empty(self): """:meth:`first` of :class:`pysnow.Response` should raise an exception if matches were found""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result([]), status=200, content_type="application/json", ) response = self.resource.get(self.dict_query, stream=True) self.assertRaises(NoResults, response.first) @httpretty.activate def test_create(self): """:meth:`create` should return a dictionary of the new record""" httpretty.register_uri( httpretty.POST, self.mock_url_builder_base, body=get_serialized_result(self.record_response_create), status=200, content_type="application/json", ) response = self.resource.create(self.record_response_create) self.assertEquals(type(response.one()), dict) self.assertEquals(response.one(), self.record_response_create) @httpretty.activate def test_update(self): """:meth:`update` should return a dictionary of the updated record""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json", ) httpretty.register_uri( httpretty.PUT, self.mock_url_builder_sys_id, body=get_serialized_result(self.record_response_update), status=200, content_type="application/json", ) response = self.resource.update(self.dict_query, self.record_response_update) result = response.one() self.assertEquals(type(result), dict) self.assertEquals(self.record_response_update["attr1"], result["attr1"]) @httpretty.activate def test_update_invalid_payload(self): """:meth:`update` should raise an exception if payload is of invalid type""" self.assertRaises(InvalidUsage, self.resource.update, self.dict_query, "foo") self.assertRaises(InvalidUsage, self.resource.update, self.dict_query, False) self.assertRaises(InvalidUsage, self.resource.update, self.dict_query, 1) self.assertRaises(InvalidUsage, self.resource.update, self.dict_query, ("foo", "bar")) self.assertRaises(InvalidUsage, self.resource.update, self.dict_query, ["foo", "bar"]) @httpretty.activate def test_delete(self): """:meth:`delete` should return a dictionary containing status""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json", ) httpretty.register_uri( httpretty.DELETE, self.mock_url_builder_sys_id, body=get_serialized_result(self.record_response_delete), status=204, content_type="application/json", ) result = self.resource.delete(self.dict_query) self.assertEquals(type(result), dict) self.assertEquals(result["status"], "record deleted") @httpretty.activate def test_delete_chained(self): """:meth:`Response.delete` should return a dictionary containing status""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json", ) httpretty.register_uri( httpretty.DELETE, self.mock_url_builder_sys_id, body=get_serialized_result(self.record_response_delete), status=204, content_type="application/json", ) result = self.resource.get(query={}).delete() self.assertEquals(type(result), dict) self.assertEquals(result["status"], "record deleted") @httpretty.activate def test_custom(self): """:meth:`custom` should return a :class:`pysnow.Response` object""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json", ) method = "GET" response = self.resource.request(method) self.assertEquals(response._response.request.method, method) self.assertEquals(type(response), Response) @httpretty.activate def test_custom_with_headers(self): """Headers provided to :meth:`custom` should end up in the request""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json", ) headers = {"foo": "bar"} response = self.resource.request("GET", headers=headers) self.assertEquals(response._response.request.headers["foo"], headers["foo"]) @httpretty.activate def test_custom_with_path(self): """path_append passed to :meth:`custom` should get appended to the request path""" path_append = "/foo" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base + path_append, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json", ) response = self.resource.request("GET", path_append="/foo") self.assertEquals(response._response.status_code, 200) @httpretty.activate def test_custom_with_path_invalid(self): """:meth:`custom` should raise an exception if the provided path is invalid""" self.assertRaises(InvalidUsage, self.resource.request, "GET", path_append={"foo": "bar"}) self.assertRaises(InvalidUsage, self.resource.request, "GET", path_append="foo/") self.assertRaises(InvalidUsage, self.resource.request, "GET", path_append=True) @httpretty.activate def test_response_repr(self): """:meth:`get` should result in response obj repr describing the response""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json", ) response = self.resource.get(query={}) response_repr = repr(response) self.assertEquals(response_repr, "<Response [200 - GET]>") def test_attachment_non_table(self): """Accessing `Resource.attachments` from a non-table API should fail""" resource = self.client.resource(base_path=self.base_path, api_path="/invalid") self.assertRaises(InvalidUsage, getattr, resource, "attachments") def test_attachment_type(self): """`Resource.attachments` should be of type Attachment""" attachment_type = type(self.resource.attachments) self.assertEqual(attachment_type, Attachment) def test_get_record_link(self): """`Resource.get_record_link()` should return full URL to the record""" record_link = self.resource.get_record_link( "98ace1a537ea2a00cf5c9c9953990e19") self.assertEqual(record_link, self.mock_url_builder_sys_id) @httpretty.activate def test_get_response_item(self): """Accessing the response as a dict should work""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json", ) response = self.resource.get(query={}) self.assertEquals(response["sys_id"], self.record_response_get_one[0].get("sys_id")) @httpretty.activate def test_get_buffered_first(self): """Using Response.first() without stream=True should fail""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json", ) response = self.resource.get(query={}) self.assertRaises(InvalidUsage, response.first) @httpretty.activate def test_response_update(self): """Using Response.update should update the queried record""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json", ) httpretty.register_uri( httpretty.PUT, self.mock_url_builder_sys_id, body=get_serialized_result(self.record_response_update), status=200, content_type="application/json", ) response = self.resource.get(query={}).update( self.record_response_update) self.assertEqual(self.record_response_update["sys_id"], response["sys_id"]) @httpretty.activate def test_response_upload(self): """Using Response.upload() should attach the file to the queried record and return metadata""" httpretty.register_uri( httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json", ) httpretty.register_uri( httpretty.POST, self.attachment_upload_url, body=get_serialized_result(self.attachment), status=201, content_type="application/json", ) response = self.resource.get(query={}).upload( file_path=self.attachment_path) self.assertEqual(self.attachment["file_name"], response["file_name"])
def test_client_instance(self): """Client instance property should match instance passed to constructor""" instance = "foo" c = Client(user="******", password="******", instance=instance) self.assertEqual(c.instance, instance)
def setUp(self): self.error_message_body = { "message": "test_message", "detail": "test_details" } self.record_response_get_dict = { "sys_id": "98ace1a537ea2a00cf5c9c9953990e19", "attr1": "foo", "attr2": "bar", } self.record_response_get_one = [{ "sys_id": "98ace1a537ea2a00cf5c9c9953990e19", "attr1": "foo", "attr2": "bar", }] self.record_response_get_three = [ { "sys_id": "37ea2a00cf5c9c995399098ace1a5e19", "attr1": "foo1", "attr2": "bar1", }, { "sys_id": "98ace1a537ea2a00cf5c9c9953990e19", "attr1": "foo2", "attr2": "bar2", }, { "sys_id": "a00cf5c9c9953990e1998ace1a537ea2", "attr1": "foo3", "attr2": "bar3", }, ] self.record_response_create = { "sys_id": "90e11a537ea2a00cf598ace9c99539c9", "attr1": "foo_create", "attr2": "bar_create", } self.record_response_update = { "sys_id": "2a00cf5c9c99539998ace1a537ea0e19", "attr1": "foo_updated", "attr2": "bar_updated", } self.record_response_delete = {"status": "record deleted"} self.client_kwargs = { "user": "******", "password": "******", "instance": "mock_instance", } self.attachment = { "sys_id": "attachment_sys_id", "size_bytes": "512", "file_name": "test1.txt", } self.attachment_path = "tests/data/attachment.txt" self.base_path = "/api/now" self.api_path = "/table/incident" self.client = Client(**self.client_kwargs) self.resource = self.client.resource(base_path=self.base_path, api_path=self.api_path) self.mock_url_builder = self.resource._url_builder self.attachment_upload_url = (self.resource._base_url + self.resource._base_path + "/attachment/file") self.mock_url_builder_base = self.resource._url_builder.get_url() self.mock_url_builder_sys_id = self.mock_url_builder.get_appended_custom( "/{0}".format(self.record_response_get_one[0]["sys_id"])) self.dict_query = {"sys_id": self.record_response_get_one[0]["sys_id"]} self.get_fields = ["foo", "bar"]
def setUp(self): self.error_message_body = { 'message': 'test_message', 'detail': 'test_details' } self.record_response_get_dict = { 'sys_id': '98ace1a537ea2a00cf5c9c9953990e19', 'attr1': 'foo', 'attr2': 'bar' } self.record_response_get_one = [{ 'sys_id': '98ace1a537ea2a00cf5c9c9953990e19', 'attr1': 'foo', 'attr2': 'bar' }] self.record_response_get_three = [{ 'sys_id': '37ea2a00cf5c9c995399098ace1a5e19', 'attr1': 'foo1', 'attr2': 'bar1' }, { 'sys_id': '98ace1a537ea2a00cf5c9c9953990e19', 'attr1': 'foo2', 'attr2': 'bar2' }, { 'sys_id': 'a00cf5c9c9953990e1998ace1a537ea2', 'attr1': 'foo3', 'attr2': 'bar3' }] self.record_response_create = { 'sys_id': '90e11a537ea2a00cf598ace9c99539c9', 'attr1': 'foo_create', 'attr2': 'bar_create' } self.record_response_update = { 'sys_id': '2a00cf5c9c99539998ace1a537ea0e19', 'attr1': 'foo_updated', 'attr2': 'bar_updated' } self.record_response_delete = {'status': 'record deleted'} self.client_kwargs = { 'user': '******', 'password': '******', 'instance': 'mock_instance' } self.attachment = { 'sys_id': 'attachment_sys_id', 'size_bytes': '512', 'file_name': 'test1.txt' } self.attachment_path = 'tests/data/attachment.txt' self.base_path = '/api/now' self.api_path = '/table/incident' self.client = Client(**self.client_kwargs) self.resource = self.client.resource(base_path=self.base_path, api_path=self.api_path) self.mock_url_builder = self.resource._url_builder self.attachment_upload_url = self.resource._base_url + self.resource._base_path + '/attachment/file' self.mock_url_builder_base = self.resource._url_builder.get_url() self.mock_url_builder_sys_id = ( self.mock_url_builder.get_appended_custom('/{0}'.format( self.record_response_get_one[0]['sys_id']))) self.dict_query = {'sys_id': self.record_response_get_one[0]['sys_id']} self.get_fields = ['foo', 'bar']
class TestResourceRequest(unittest.TestCase): """Performs resource-request tests""" def setUp(self): self.error_message_body = { 'message': 'test_message', 'detail': 'test_details' } self.record_response_get_dict = { 'sys_id': '98ace1a537ea2a00cf5c9c9953990e19', 'attr1': 'foo', 'attr2': 'bar' } self.record_response_get_one = [{ 'sys_id': '98ace1a537ea2a00cf5c9c9953990e19', 'attr1': 'foo', 'attr2': 'bar' }] self.record_response_get_three = [ { 'sys_id': '37ea2a00cf5c9c995399098ace1a5e19', 'attr1': 'foo1', 'attr2': 'bar1' }, { 'sys_id': '98ace1a537ea2a00cf5c9c9953990e19', 'attr1': 'foo2', 'attr2': 'bar2' }, { 'sys_id': 'a00cf5c9c9953990e1998ace1a537ea2', 'attr1': 'foo3', 'attr2': 'bar3' } ] self.record_response_create = { 'sys_id': '90e11a537ea2a00cf598ace9c99539c9', 'attr1': 'foo_create', 'attr2': 'bar_create' } self.record_response_update = { 'sys_id': '2a00cf5c9c99539998ace1a537ea0e19', 'attr1': 'foo_updated', 'attr2': 'bar_updated' } self.record_response_delete = { 'status': 'record deleted' } self.client_kwargs = { 'user': '******', 'password': '******', 'instance': 'mock_instance' } self.attachment = { 'sys_id': 'attachment_sys_id', 'size_bytes': '512', 'file_name': 'test1.txt' } self.attachment_path = 'tests/data/attachment.txt' self.base_path = '/api/now' self.api_path = '/table/incident' self.client = Client(**self.client_kwargs) self.resource = self.client.resource(base_path=self.base_path, api_path=self.api_path) self.mock_url_builder = self.resource._url_builder self.attachment_upload_url = self.resource._base_url + self.resource._base_path + '/attachment/file' self.mock_url_builder_base = self.resource._url_builder.get_url() self.mock_url_builder_sys_id = (self.mock_url_builder .get_appended_custom('/{0}'.format(self.record_response_get_one[0]['sys_id']))) self.dict_query = {'sys_id': self.record_response_get_one[0]['sys_id']} self.get_fields = ['foo', 'bar'] def test_create_resource(self): """:class:`Resource` object repr type should be string, and its path should be set to api_path + base_path """ r = self.client.resource(base_path=self.base_path, api_path=self.api_path) resource_repr = type(repr(r)) self.assertEquals(resource_repr, str) self.assertEquals(r._base_path, self.base_path) self.assertEquals(r._api_path, self.api_path) self.assertEquals(r.path, self.base_path + self.api_path) @httpretty.activate def test_response_headers(self): """Request response headers should be available in Response.headers property""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, status=200, adding_headers={'x-test-1': 'foo', 'x-test-2': 'bar'}, content_type="application/json") response = self.resource.get(self.dict_query) self.assertEqual(response.headers['x-test-1'], 'foo') self.assertEqual(response.headers['x-test-2'], 'bar') @httpretty.activate def test_response_count(self): """:prop:`count` of :class:`pysnow.Response` should raise an exception if count is set to non-integer""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, status=200, content_type="application/json") response = self.resource.get(self.dict_query) self.assertRaises(TypeError, setattr, response, 'count', 'foo') self.assertRaises(TypeError, setattr, response, 'count', True) self.assertRaises(TypeError, setattr, response, 'count', {'foo': 'bar'}) @httpretty.activate def test_response_error(self): """:class:`pysnow.Response` should raise an exception if an error is encountered in the response body""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_error(self.error_message_body), status=200, content_type="application/json") response = self.resource.get(self.dict_query, stream=True) expected_str = "Error in response. Message: %s, Details: %s" % (self.error_message_body['message'], self.error_message_body['detail']) try: response.first() except ResponseError as e: self.assertEquals(str(e), expected_str) @httpretty.activate def test_get_request_fields(self): """:meth:`get_request` should return a :class:`pysnow.Response` object""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, status=200, content_type="application/json") response = self.resource.get(self.dict_query, fields=self.get_fields) qs = qs_as_dict(response._response.request.url) str_fields = ','.join(self.get_fields) # List of fields should end up as comma-separated string self.assertEquals(type(response), Response) self.assertEquals(qs['sysparm_fields'], str_fields) @httpretty.activate def test_get_offset(self): """offset passed to :meth:`get` should set sysparm_offset in query""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json") offset = 5 response = self.resource.get(self.dict_query, offset=offset) qs = qs_as_dict(response._response.request.url) self.assertEquals(int(qs['sysparm_offset']), offset) @httpretty.activate def test_get_limit(self): """limit passed to :meth:`get` should set sysparm_limit in QS""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json") limit = 2 response = self.resource.get(self.dict_query, limit=limit) qs = qs_as_dict(response._response.request.url) self.assertEquals(int(qs['sysparm_limit']), limit) @httpretty.activate def test_get_one(self): """:meth:`one` of :class:`pysnow.Response` should raise an exception if more than one match was found""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json") response = self.resource.get(self.dict_query) result = response.one() self.assertEquals(result['sys_id'], self.record_response_get_one[0]['sys_id']) @httpretty.activate def test_get_all_empty(self): """:meth:`all` generator of :class:`pysnow.Response` should return an empty list if there are no matches""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result([]), status=200, content_type="application/json") response = self.resource.get(self.dict_query, stream=True) result = list(response.all()) self.assertEquals(result, []) @httpretty.activate def test_get_all_single(self): """Single items with all() using the stream parser should return a list containing the item""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_dict), status=200, content_type="application/json") response = self.resource.get(self.dict_query, stream=True) result = list(response.all())[0] self.assertEquals(result, self.record_response_get_dict) @httpretty.activate def test_get_buffer_missing_result_keys(self): """:meth:`one` of :class:`pysnow.Response` should raise an exception if none of the expected keys was found in the result""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=json.dumps({}), status=200, content_type="application/json") response = self.resource.get(self.dict_query) self.assertRaises(MissingResult, response.one) @httpretty.activate def test_get_stream_missing_result_keys(self): """:meth:`one` of :class:`pysnow.Response` should raise an exception if none of the expected keys was found in the result""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=json.dumps({}), status=200, content_type="application/json") response = self.resource.get(self.dict_query, stream=True) self.assertRaises(MissingResult, response.first) @httpretty.activate def test_http_error_get_one(self): """:meth:`one` of :class:`pysnow.Response` should raise an HTTPError exception if a non-200 response code was encountered""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, status=500, content_type="application/json") response = self.resource.get(self.dict_query) self.assertRaises(HTTPError, response.one) @httpretty.activate def test_get_one_many(self): """:meth:`one` of :class:`pysnow.Response` should raise an exception if more than one match was found""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_three), status=200, content_type="application/json") response = self.resource.get(self.dict_query) self.assertRaises(MultipleResults, response.one) @httpretty.activate def test_get_one_empty(self): """:meth:`one` of :class:`pysnow.Response` should raise an exception if no matches were found""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result([]), status=200, content_type="application/json") response = self.resource.get(self.dict_query) self.assertRaises(NoResults, response.one) @httpretty.activate def test_get_one_or_none_empty(self): """:meth:`one_or_none` of :class:`pysnow.Response` should return `None` if no matches were found """ httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result([]), status=200, content_type="application/json") response = self.resource.get(self.dict_query) result = response.one_or_none() self.assertEquals(result, None) @httpretty.activate def test_get_first_or_none_empty(self): """:meth:`first_or_none` of :class:`pysnow.Response` should return None if no records were found""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result([]), status=200, content_type="application/json") response = self.resource.get(self.dict_query, stream=True) result = response.first_or_none() self.assertEquals(result, None) @httpretty.activate def test_get_first_or_none(self): """:meth:`first_or_none` of :class:`pysnow.Response` should return first match if multiple records were found""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_three), status=200, content_type="application/json") response = self.resource.get(self.dict_query, stream=True) result = response.first_or_none() self.assertEquals(result, self.record_response_get_three[0]) @httpretty.activate def test_get_first(self): """:meth:`first` of :class:`pysnow.Response` should return first match if multiple records were found""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_three), status=200, content_type="application/json") response = self.resource.get(self.dict_query, stream=True) result = response.first() self.assertEquals(result, self.record_response_get_three[0]) @httpretty.activate def test_get_first_empty(self): """:meth:`first` of :class:`pysnow.Response` should raise an exception if matches were found""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result([]), status=200, content_type="application/json") response = self.resource.get(self.dict_query, stream=True) self.assertRaises(NoResults, response.first) @httpretty.activate def test_create(self): """:meth:`create` should return a dictionary of the new record""" httpretty.register_uri(httpretty.POST, self.mock_url_builder_base, body=get_serialized_result(self.record_response_create), status=200, content_type="application/json") response = self.resource.create(self.record_response_create) self.assertEquals(type(response.one()), dict) self.assertEquals(response.one(), self.record_response_create) @httpretty.activate def test_update(self): """:meth:`update` should return a dictionary of the updated record""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json") httpretty.register_uri(httpretty.PUT, self.mock_url_builder_sys_id, body=get_serialized_result(self.record_response_update), status=200, content_type="application/json") response = self.resource.update(self.dict_query, self.record_response_update) result = response.one() self.assertEquals(type(result), dict) self.assertEquals(self.record_response_update['attr1'], result['attr1']) @httpretty.activate def test_update_invalid_payload(self): """:meth:`update` should raise an exception if payload is of invalid type""" self.assertRaises(InvalidUsage, self.resource.update, self.dict_query, 'foo') self.assertRaises(InvalidUsage, self.resource.update, self.dict_query, False) self.assertRaises(InvalidUsage, self.resource.update, self.dict_query, 1) self.assertRaises(InvalidUsage, self.resource.update, self.dict_query, ('foo', 'bar')) self.assertRaises(InvalidUsage, self.resource.update, self.dict_query, ['foo', 'bar']) @httpretty.activate def test_delete(self): """:meth:`delete` should return a dictionary containing status""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json") httpretty.register_uri(httpretty.DELETE, self.mock_url_builder_sys_id, body=get_serialized_result(self.record_response_delete), status=204, content_type="application/json") result = self.resource.delete(self.dict_query) self.assertEquals(type(result), dict) self.assertEquals(result['status'], 'record deleted') @httpretty.activate def test_delete_chained(self): """:meth:`Response.delete` should return a dictionary containing status""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json") httpretty.register_uri(httpretty.DELETE, self.mock_url_builder_sys_id, body=get_serialized_result(self.record_response_delete), status=204, content_type="application/json") result = self.resource.get(query={}).delete() self.assertEquals(type(result), dict) self.assertEquals(result['status'], 'record deleted') @httpretty.activate def test_custom(self): """:meth:`custom` should return a :class:`pysnow.Response` object""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json") method = 'GET' response = self.resource.request(method) self.assertEquals(response._response.request.method, method) self.assertEquals(type(response), Response) @httpretty.activate def test_custom_with_headers(self): """Headers provided to :meth:`custom` should end up in the request""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json") headers = {'foo': 'bar'} response = self.resource.request('GET', headers=headers) self.assertEquals(response._response.request.headers['foo'], headers['foo']) @httpretty.activate def test_custom_with_path(self): """path_append passed to :meth:`custom` should get appended to the request path""" path_append = '/foo' httpretty.register_uri(httpretty.GET, self.mock_url_builder_base + path_append, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json") response = self.resource.request('GET', path_append='/foo') self.assertEquals(response._response.status_code, 200) @httpretty.activate def test_custom_with_path_invalid(self): """:meth:`custom` should raise an exception if the provided path is invalid""" self.assertRaises(InvalidUsage, self.resource.request, 'GET', path_append='foo') self.assertRaises(InvalidUsage, self.resource.request, 'GET', path_append={'foo': 'bar'}) self.assertRaises(InvalidUsage, self.resource.request, 'GET', path_append='foo/') self.assertRaises(InvalidUsage, self.resource.request, 'GET', path_append=True) @httpretty.activate def test_response_repr(self): """:meth:`get` should result in response obj repr describing the response""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json") response = self.resource.get(query={}) response_repr = repr(response) self.assertEquals(response_repr, '<Response [200 - GET]>') def test_attachment_non_table(self): """Accessing `Resource.attachments` from a non-table API should fail""" resource = self.client.resource(base_path=self.base_path, api_path='/invalid') self.assertRaises(InvalidUsage, getattr, resource, 'attachments') def test_attachment_type(self): """`Resource.attachments` should be of type Attachment""" attachment_type = type(self.resource.attachments) self.assertEqual(attachment_type, Attachment) def test_get_record_link(self): """`Resource.get_record_link()` should return full URL to the record""" record_link = self.resource.get_record_link('98ace1a537ea2a00cf5c9c9953990e19') self.assertEqual(record_link, self.mock_url_builder_sys_id) @httpretty.activate def test_get_response_item(self): """Accessing the response as a dict should work""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json") response = self.resource.get(query={}) self.assertEquals(response['sys_id'], self.record_response_get_one[0].get('sys_id')) @httpretty.activate def test_get_buffered_first(self): """Using Response.first() without stream=True should fail""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json") response = self.resource.get(query={}) self.assertRaises(InvalidUsage, response.first) @httpretty.activate def test_response_update(self): """Using Response.update should update the queried record""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json") httpretty.register_uri(httpretty.PUT, self.mock_url_builder_sys_id, body=get_serialized_result(self.record_response_update), status=200, content_type="application/json") response = self.resource.get(query={}).update(self.record_response_update) self.assertEqual(self.record_response_update['sys_id'], response['sys_id']) @httpretty.activate def test_response_upload(self): """Using Response.upload() should attach the file to the queried record and return metadata""" httpretty.register_uri(httpretty.GET, self.mock_url_builder_base, body=get_serialized_result(self.record_response_get_one), status=200, content_type="application/json") httpretty.register_uri(httpretty.POST, self.attachment_upload_url, body=get_serialized_result(self.attachment), status=201, content_type="application/json") response = self.resource.get(query={}).upload(file_path=self.attachment_path) self.assertEqual(self.attachment['file_name'], response['file_name'])