Example #1
0
    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")
Example #2
0
    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')
Example #3
0
    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')
Example #4
0
 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)
Example #5
0
 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)
Example #6
0
    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)
Example #7
0
    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')
Example #8
0
 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)
Example #9
0
    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")
Example #10
0
 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="/")
Example #11
0
    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")
Example #12
0
    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')
Example #13
0
 def test_client_user_password(self):
     """Should be able to create a client given user name and password."""
     Client("snow.example.com", user="******", password="******")
Example #14
0
    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']
Example #15
0
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'])
Example #16
0
 def test_client_context_manager(self):
     with Client("snow.example.com", user="******", password="******") as c:
         assert isinstance(c, Client)
         assert c.session
Example #17
0
 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)
Example #18
0
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)
Example #19
0
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)
Example #20
0
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)
Example #21
0
 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)
Example #22
0
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"])
Example #23
0
 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)
Example #24
0
    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"]
Example #25
0
    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']
Example #26
0
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'])