Exemplo n.º 1
0
    def setUp(self):

        # logging
        self.logger = logging.getLogger(self.__class__.__name__)

        # NIPAP
        self.cfg = NipapConfig('/etc/nipap/nipap.conf')
        self.nipap = Nipap()

        # create dummy auth object
        # As the authentication is performed before the query hits the Nipap
        # class, it does not matter what user we use here
        self.auth = SqliteAuth('local', 'unittest', 'unittest', 'unittest')
        self.auth.authenticated_as = 'unittest'
        self.auth.full_name = 'Unit test'

        # have to delete hosts before we can delete the rest
        self.nipap._execute(
            "DELETE FROM ip_net_plan WHERE masklen(prefix) = 32")
        # the rest
        self.nipap._execute("DELETE FROM ip_net_plan")
        # delete all except for the default VRF with id 0
        self.nipap._execute("DELETE FROM ip_net_vrf WHERE id > 0")
        # set default info for VRF 0
        self.nipap._execute(
            "UPDATE ip_net_vrf SET name = 'default', description = 'The default VRF, typically the Internet.' WHERE id = 0"
        )
        self.nipap._execute("DELETE FROM ip_net_pool")
        self.nipap._execute("DELETE FROM ip_net_asn")
Exemplo n.º 2
0
    def setUp(self):

        # logging
        self.logger = logging.getLogger(self.__class__.__name__)

        # NIPAP
        self.cfg = NipapConfig('/etc/nipap/nipap.conf')
        self.nipap = Nipap()

        # create dummy auth object
        # As the authentication is performed before the query hits the Nipap
        # class, it does not matter what user we use here
        self.auth = SqliteAuth('local', 'unittest', 'unittest', 'unittest')
        self.auth.authenticated_as = 'unittest'
        self.auth.full_name = 'Unit test'

        # have to delete hosts before we can delete the rest
        self.nipap._execute("DELETE FROM ip_net_plan WHERE masklen(prefix) = 32")
        # the rest
        self.nipap._execute("DELETE FROM ip_net_plan")
        # delete all except for the default VRF with id 0
        self.nipap._execute("DELETE FROM ip_net_vrf WHERE id > 0")
        # set default info for VRF 0
        self.nipap._execute("UPDATE ip_net_vrf SET name = 'default', description = 'The default VRF, typically the Internet.' WHERE id = 0")
        self.nipap._execute("DELETE FROM ip_net_pool")
        self.nipap._execute("DELETE FROM ip_net_asn")
Exemplo n.º 3
0
    def clear_database(cls):
        cfg = NipapConfig('/etc/nipap/nipap.conf')
        n = Nipap()

        # have to delete hosts before we can delete the rest
        n._execute("DELETE FROM ip_net_plan WHERE masklen(prefix) = 32")
        # the rest
        n._execute("DELETE FROM ip_net_plan")
        # delete all except for the default VRF with id 0
        n._execute("DELETE FROM ip_net_vrf WHERE id > 0")
        # set default info for VRF 0
        n._execute(
            "UPDATE ip_net_vrf SET name = 'default', description = 'The default VRF, typically the Internet.' WHERE id = 0"
        )
        n._execute("DELETE FROM ip_net_pool")
        n._execute("DELETE FROM ip_net_asn")
Exemplo n.º 4
0
    def clear_database(cls):
        cfg = NipapConfig('/etc/nipap/nipap.conf')
        n = Nipap()

        # have to delete hosts before we can delete the rest
        n._execute("DELETE FROM ip_net_plan WHERE masklen(prefix) = 32")
        # the rest
        n._execute("DELETE FROM ip_net_plan")
        # delete all except for the default VRF with id 0
        n._execute("DELETE FROM ip_net_vrf WHERE id > 0")
        # set default info for VRF 0
        n._execute("UPDATE ip_net_vrf SET name = 'default', description = 'The default VRF, typically the Internet.' WHERE id = 0")
        n._execute("DELETE FROM ip_net_pool")
        n._execute("DELETE FROM ip_net_asn")
Exemplo n.º 5
0
class NipapCliTest(unittest.TestCase):
    """ Tests the NIPAP CLI

        We presume the database is empty
    """
    maxDiff = None

    logger = None
    cfg = None
    nipap = None

    def setUp(self):

        # logging
        self.logger = logging.getLogger(self.__class__.__name__)

        # NIPAP
        self.cfg = NipapConfig('/etc/nipap/nipap.conf')
        self.nipap = Nipap()

        # create dummy auth object
        # As the authentication is performed before the query hits the Nipap
        # class, it does not matter what user we use here
        self.auth = SqliteAuth('local', 'unittest', 'unittest', 'unittest')
        self.auth.authenticated_as = 'unittest'
        self.auth.full_name = 'Unit test'

        # have to delete hosts before we can delete the rest
        self.nipap._execute("DELETE FROM ip_net_plan WHERE masklen(prefix) = 32")
        # the rest
        self.nipap._execute("DELETE FROM ip_net_plan")
        # delete all except for the default VRF with id 0
        self.nipap._execute("DELETE FROM ip_net_vrf WHERE id > 0")
        # set default info for VRF 0
        self.nipap._execute("UPDATE ip_net_vrf SET name = 'default', description = 'The default VRF, typically the Internet.' WHERE id = 0")
        self.nipap._execute("DELETE FROM ip_net_pool")
        self.nipap._execute("DELETE FROM ip_net_asn")



    def _mangle_prefix_result(self, res):
        """ Mangle prefix result for easier testing

            We can never predict the values of things like the ID (okay, that
            one is actually kind of doable) or the added and last_modified
            timestamp. This function will make sure the values are present but
            then strip them to make it easier to test against an expected
            result.
        """

        if isinstance(res, list):
            # res from list_prefix
            for p in res:
                self.assertIn('added', p)
                self.assertIn('last_modified', p)
                del(p['added'])
                del(p['last_modified'])
                del(p['total_addresses'])
                del(p['used_addresses'])
                del(p['free_addresses'])

        elif isinstance(res, dict) and 'result' in res:
            # res from smart search
            for p in res['result']:
                self.assertIn('added', p)
                self.assertIn('last_modified', p)
                del(p['added'])
                del(p['last_modified'])
                del(p['total_addresses'])
                del(p['used_addresses'])
                del(p['free_addresses'])

        elif isinstance(res, dict):
            # just one single prefix
            self.assertIn('added', p)
            self.assertIn('last_modified', p)
            del(p['added'])
            del(p['last_modified'])
            del(res['total_addresses'])
            del(res['used_addresses'])
            del(res['free_addresses'])

        return res


    def _run_cmd(self, cmd):
        """ Run a command
        """
        import subprocess
        return subprocess.check_output(cmd)


    def test_prefix_add_list(self):
        """ Add a prefix and verify result in database
        """
        ref = {
                'prefix': '1.3.3.0/24',
                'type': 'assignment',
                'description': 'foo description',
                'comment': 'comment bar',
                'country': 'AB',
                'alarm_priority': 'high',
                'monitor': 'true',
                'order_id': '123',
                'customer_id': '66'
                }

        cmd = [nipap_bin, 'address', 'add']
        for key in ref:
            cmd.append(key)
            cmd.append(ref[key])

        ref['display_prefix'] = '1.3.3.0/24'
        ref['indent'] = 0
        ref['family'] = 4
        ref['monitor'] = True
        ref['pool_id'] = None
        ref['pool_name'] = None
        ref['vrf_id'] = 0
        ref['vrf_name'] = 'default'
        ref['vrf_rt'] = None
        ref['external_key'] = None
        ref['node'] = None
        ref['authoritative_source'] = 'nipap'
        ref['vlan'] = None
        ref['inherited_tags'] = []
        ref['tags'] = []

        self._run_cmd(cmd)

        res = self._mangle_prefix_result(s.list_prefix({ 'auth': ad, 'spec': {} }))
        del(res[0]['id'])

        self.assertEqual(res, [ ref, ])
Exemplo n.º 6
0
class NipapCliTest(unittest.TestCase):
    """ Tests the NIPAP CLI

        We presume the database is empty
    """
    maxDiff = None

    logger = None
    cfg = None
    nipap = None

    def setUp(self):

        # logging
        self.logger = logging.getLogger(self.__class__.__name__)

        # NIPAP
        self.cfg = NipapConfig('/etc/nipap/nipap.conf')
        self.nipap = Nipap()

        # create dummy auth object
        # As the authentication is performed before the query hits the Nipap
        # class, it does not matter what user we use here
        self.auth = SqliteAuth('local', 'unittest', 'unittest', 'unittest')
        self.auth.authenticated_as = 'unittest'
        self.auth.full_name = 'Unit test'

        # have to delete hosts before we can delete the rest
        self.nipap._execute(
            "DELETE FROM ip_net_plan WHERE masklen(prefix) = 32")
        # the rest
        self.nipap._execute("DELETE FROM ip_net_plan")
        # delete all except for the default VRF with id 0
        self.nipap._execute("DELETE FROM ip_net_vrf WHERE id > 0")
        # set default info for VRF 0
        self.nipap._execute(
            "UPDATE ip_net_vrf SET name = 'default', description = 'The default VRF, typically the Internet.' WHERE id = 0"
        )
        self.nipap._execute("DELETE FROM ip_net_pool")
        self.nipap._execute("DELETE FROM ip_net_asn")

    def _mangle_prefix_result(self, res):
        """ Mangle prefix result for easier testing

            We can never predict the values of things like the ID (okay, that
            one is actually kind of doable) or the added and last_modified
            timestamp. This function will make sure the values are present but
            then strip them to make it easier to test against an expected
            result.
        """

        if isinstance(res, list):
            # res from list_prefix
            for p in res:
                self.assertIn('added', p)
                self.assertIn('last_modified', p)
                del (p['added'])
                del (p['last_modified'])
                del (p['total_addresses'])
                del (p['used_addresses'])
                del (p['free_addresses'])

        elif isinstance(res, dict) and 'result' in res:
            # res from smart search
            for p in res['result']:
                self.assertIn('added', p)
                self.assertIn('last_modified', p)
                del (p['added'])
                del (p['last_modified'])
                del (p['total_addresses'])
                del (p['used_addresses'])
                del (p['free_addresses'])

        elif isinstance(res, dict):
            # just one single prefix
            self.assertIn('added', p)
            self.assertIn('last_modified', p)
            del (p['added'])
            del (p['last_modified'])
            del (res['total_addresses'])
            del (res['used_addresses'])
            del (res['free_addresses'])

        return res

    def _run_cmd(self, cmd):
        """ Run a command
        """
        import subprocess
        return subprocess.check_output(cmd)

    def test_prefix_add_list(self):
        """ Add a prefix and verify result in database
        """
        ref = {
            'prefix': '1.3.3.0/24',
            'type': 'assignment',
            'status': 'assigned',
            'description': 'foo description',
            'comment': 'comment bar',
            'country': 'AB',
            'alarm_priority': 'high',
            'monitor': 'true',
            'order_id': '123',
            'customer_id': '66'
        }

        cmd = [nipap_bin, 'address', 'add']
        for key in ref:
            cmd.append(key)
            cmd.append(ref[key])

        ref['display_prefix'] = '1.3.3.0/24'
        ref['indent'] = 0
        ref['family'] = 4
        ref['monitor'] = True
        ref['pool_id'] = None
        ref['pool_name'] = None
        ref['vrf_id'] = 0
        ref['vrf_name'] = 'default'
        ref['vrf_rt'] = None
        ref['external_key'] = None
        ref['node'] = None
        ref['authoritative_source'] = 'nipap'
        ref['vlan'] = None
        ref['inherited_tags'] = []
        ref['tags'] = []
        ref['avps'] = {}
        ref['expires'] = None

        self._run_cmd(cmd)

        res = self._mangle_prefix_result(
            s.list_prefix({
                'auth': ad,
                'spec': {}
            }))
        del (res[0]['id'])

        self.assertEqual(res, [
            ref,
        ])
Exemplo n.º 7
0
    def setUp(self):
        """ Better start from a clean slate!
        """

        cfg = NipapConfig('/etc/nipap/nipap.conf')
        self.nipap = Nipap()

        # create dummy auth object
        # As the authentication is performed before the query hits the Nipap
        # class, it does not matter what user we use here
        self.auth = SqliteAuth('local', 'unittest', 'unittest', 'unittest')
        self.auth.authenticated_as = 'unittest'
        self.auth.full_name = 'Unit test'

        self.nipap._execute("TRUNCATE ip_net_plan, ip_net_pool, ip_net_vrf, ip_net_log, ip_net_asn")

        self.schema_attrs = {
                'name': 'test-schema1',
                'description': 'Test schema numero uno!'
                }
        self.schema_attrs['id'] = self.nipap.add_schema(self.auth, self.schema_attrs)
        self.schema_attrs2 = {
                'name': 'test-schema2',
                'description': 'Test schema numero dos!'
                }
        self.schema_attrs2['id'] = self.nipap.add_schema(self.auth, self.schema_attrs2)
        self.pool_attrs = {
                'name': 'test-pool1',
                'description': 'Test pool numero uno!',
                'default_type': 'assignment',
                'ipv4_default_prefix_length': 30,
                'ipv6_default_prefix_length': 112
                }
        self.pool_attrs['id'] = self.nipap.add_pool(self.auth, {'id': self.schema_attrs['id']}, self.pool_attrs)
        self.prefix_attrs1 = {
                'authoritative_source': 'nipaptest',
                'prefix': '1.3.3.0/24',
                'type': 'assignment',
                'description': ''
                }
        self.prefix_attrs1['id'] = self.nipap.add_prefix(self.auth, {'id': self.schema_attrs['id']}, self.prefix_attrs1)
        self.prefix_attrs = {
                'authoritative_source': 'nipaptest',
                'prefix': '1.3.3.1/32',
                'type': 'host',
                'description': 'Test prefix numero uno!'
                }
        self.prefix_attrs['id'] = self.nipap.add_prefix(self.auth, {'id': self.schema_attrs['id']}, self.prefix_attrs)
        self.prefix_attrs2 = {
                'authoritative_source': 'nipaptest',
                'prefix': '1.3.2.0/23',
                'type': 'reservation',
                'description': ''
                }
        self.prefix_attrs2['id'] = self.nipap.add_prefix(self.auth, {'id': self.schema_attrs['id']}, self.prefix_attrs2)
        self.prefix_attrs3 = {
                'authoritative_source': 'nipaptest',
                'prefix': '1.3.0.0/16',
                'type': 'reservation',
                'description': ''
                }
        self.prefix_attrs3['id'] = self.nipap.add_prefix(self.auth, {'id': self.schema_attrs['id']}, self.prefix_attrs3)
        self.prefix_attrs4 = {
                'authoritative_source': 'nipaptest',
                'prefix': '1.3.0.0/17',
                'type': 'reservation',
                'description': ''
                }
        self.prefix_attrs4['id'] = self.nipap.add_prefix(self.auth, {'id': self.schema_attrs2['id']}, self.prefix_attrs4)

        self.prefix6_attrs1 = {
                'authoritative_source': 'nipaptest',
                'prefix': '2001:0db8:3:3::/112',
                'type': 'assignment',
                'description': ''
                }
        self.prefix6_attrs1['id'] = self.nipap.add_prefix(self.auth, {'id': self.schema_attrs['id']}, self.prefix6_attrs1)
        self.prefix6_attrs = {
                'authoritative_source': 'nipaptest',
                'prefix': '2001:0db8:3:3::1/128',
                'type': 'host',
                'description': 'Test prefix numero uno!'
                }
        self.prefix6_attrs['id'] = self.nipap.add_prefix(self.auth, {'id': self.schema_attrs['id']}, self.prefix6_attrs)
        self.prefix6_attrs2 = {
                'authoritative_source': 'nipaptest',
                'prefix': '2001:0db8:3:3::/64',
                'type': 'reservation',
                'description': ''
                }
        self.prefix6_attrs2['id'] = self.nipap.add_prefix(self.auth, {'id': self.schema_attrs['id']}, self.prefix6_attrs2)
        self.prefix6_attrs3 = {
                'authoritative_source': 'nipaptest',
                'prefix': '2001:0db8:3:0::/48',
                'type': 'reservation',
                'description': ''
                }
        self.prefix6_attrs3['id'] = self.nipap.add_prefix(self.auth, {'id': self.schema_attrs['id']}, self.prefix6_attrs3)
        self.prefix6_attrs4 = {
                'authoritative_source': 'nipaptest',
                'prefix': '2001:0db8:3:0::/56',
                'type': 'reservation',
                'description': ''
                }
        self.prefix6_attrs4['id'] = self.nipap.add_prefix(self.auth, {'id': self.schema_attrs2['id']}, self.prefix6_attrs4)
Exemplo n.º 8
0
class NipapRestTest(unittest.TestCase):
    """ Tests the NIPAP REST API

        We presume the database is empty
    """
    maxDiff = None

    logger = None
    cfg = None
    nipap = None

    server_url = "http://*****:*****@127.0.0.1:1337/rest/v1/prefixes"
    headers = {
        "NIPAP-Authoritative-Source": "nipap",
        "NIPAP-Username": "******",
        "NIPAP-Full-Name": "unit tester"
    }

    def setUp(self):
        # logging
        self.logger = logging.getLogger(self.__class__.__name__)

        # NIPAP
        self.cfg = NipapConfig('/etc/nipap/nipap.conf')
        self.nipap = Nipap()

        # create dummy auth object
        # As the authentication is performed before the query hits the Nipap
        # class, it does not matter what user we use here
        self.auth = SqliteAuth('local', 'unittest', 'unittest', 'unittest')
        self.auth.authenticated_as = 'unittest'
        self.auth.full_name = 'Unit test'

        # have to delete hosts before we can delete the rest
        self.nipap._execute(
            "DELETE FROM ip_net_plan WHERE masklen(prefix) = 32")
        # the rest
        self.nipap._execute("DELETE FROM ip_net_plan")
        # delete all except for the default VRF with id 0
        self.nipap._execute("DELETE FROM ip_net_vrf WHERE id > 0")
        # set default info for VRF 0
        self.nipap._execute(
            "UPDATE ip_net_vrf SET name = 'default', description = 'The default VRF, typically the Internet.' WHERE id = 0"
        )
        self.nipap._execute("DELETE FROM ip_net_pool")
        self.nipap._execute("DELETE FROM ip_net_asn")

    def _mangle_prefix_result(self, res):
        """ Mangle prefix result for easier testing

            We can never predict the values of things like the ID (okay, that
            one is actually kind of doable) or the added and last_modified
            timestamp. This function will make sure the values are present but
            then strip them to make it easier to test against an expected
            result.

            All testing of statistics is done in nipaptest.py so we strip that
            from the result here to make things simple.
        """

        if isinstance(res, list):
            # res from list_prefix
            for p in res:
                self.assertIn('added', p)
                self.assertIn('last_modified', p)
                self.assertIn('total_addresses', p)
                self.assertIn('used_addresses', p)
                self.assertIn('free_addresses', p)
                self.assertIn('expires', p)
                del (p['added'])
                del (p['last_modified'])
                del (p['total_addresses'])
                del (p['used_addresses'])
                del (p['free_addresses'])
                del (p['expires'])

        elif isinstance(res, dict) and 'result' in res:
            # res from smart search
            for p in res['result']:
                self.assertIn('added', p)
                self.assertIn('last_modified', p)
                self.assertIn('total_addresses', p)
                self.assertIn('used_addresses', p)
                self.assertIn('free_addresses', p)
                self.assertIn('expires', p)
                del (p['added'])
                del (p['last_modified'])
                del (p['total_addresses'])
                del (p['used_addresses'])
                del (p['free_addresses'])
                del (res['expires'])

        if isinstance(res, dict):
            # just one single prefix
            self.assertIn('added', res)
            self.assertIn('last_modified', res)
            self.assertIn('total_addresses', res)
            self.assertIn('used_addresses', res)
            self.assertIn('free_addresses', res)
            self.assertIn('expires', res)
            del (res['added'])
            del (res['last_modified'])
            del (res['total_addresses'])
            del (res['used_addresses'])
            del (res['free_addresses'])
            del (res['expires'])

        return res

    def _convert_list_of_unicode_to_str(self, list_of_items):
        """ Converts list of unicode values to string

            This helper function converts keys and values in unicode to string for a list containing nested dictionaries.

            When converting JSON respons back to Python dict the keys and values are
            added as unicode. This helper function handles the problem, but all types get replaced to strings. Is used for assertEqual.
        """
        result = []
        for item in list_of_items:
            item = dict([(str(k), str(v)) for k, v in item.items()])
            result.append(item)

        return result

    def test_prefix_add(self):
        """ Add a prefix and list
        """

        # check that some error / sanity checking is there
        attr = {}

        request = requests.post(self.server_url,
                                headers=self.headers,
                                json=attr)
        text = request.text
        self.assertRegexpMatches(text, "'attr' must be a dict")

        attr['prefix'] = '1.3.3.0/24'
        request = requests.post(self.server_url,
                                headers=self.headers,
                                json=attr)
        text = request.text
        self.assertRegexpMatches(
            text, "Either description or node must be specified.")

        attr['description'] = 'test prefix'
        request = requests.post(self.server_url,
                                headers=self.headers,
                                json=attr)
        text = request.text
        self.assertRegexpMatches(text, "Unknown prefix type")

        attr['type'] = 'assignment'
        attr['order_id'] = 'test'

        # add 1.3.3.0/24
        request = requests.post(self.server_url,
                                headers=self.headers,
                                json=attr)
        text = request.text
        result = json.loads(text)
        result = dict([(str(k), str(v)) for k, v in result.items()])
        attr['id'] = result['id']
        self.assertGreater(attr['id'], 0)

        # what we expect the above prefix to look like
        expected = {
            'alarm_priority': None,
            'authoritative_source': 'nipap',
            'avps': {},
            'comment': None,
            'country': None,
            'description': 'test prefix',
            'display_prefix': '1.3.3.0/24',
            'external_key': None,
            'family': 4,
            'id': int(attr['id']),
            'indent': 0,
            'inherited_tags': [],
            'monitor': None,
            'node': None,
            'order_id': 'test',
            'customer_id': None,
            'pool_name': None,
            'pool_id': None,
            'tags': [],
            'status': 'assigned',
            'vrf_rt': None,
            'vrf_id': 0,
            'vrf_name': 'default',
            'vlan': None
        }

        expected = dict([(str(k), str(v)) for k, v in expected.items()])
        expected.update(attr)

        # list of prefixes through GET request
        parameters = {'order_id': 'test'}
        list_prefix_request = request = requests.get(self.server_url,
                                                     headers=self.headers,
                                                     params=parameters)
        list_prefix = json.loads(list_prefix_request.text)
        list_prefix = self._convert_list_of_unicode_to_str(list_prefix)

        self.assertEqual(self._mangle_prefix_result(list_prefix), [expected])

        attr = {}
        attr['description'] = 'test for from-prefix 1.3.3.0/24'
        attr['type'] = 'host'
        attr['order_id'] = 'test'

        parameters = {'fromPrefix': '1.3.3.0/24', 'prefixLength': 32}

        # add a host in 1.3.3.0/24
        request = requests.post(self.server_url,
                                headers=self.headers,
                                json=attr,
                                params=parameters)
        text = request.text
        result = json.loads(text)
        result = dict([(str(k), str(v)) for k, v in result.items()])

        # copy expected from 1.3.3.0/24 since we expect most things to look the
        # same for the new prefix (1.3.3.1/32) from 1.3.3.0/24
        expected_host = expected.copy()
        expected_host.update(attr)
        expected_host['id'] = result['id']
        expected_host['prefix'] = '1.3.3.1/32'
        expected_host['display_prefix'] = '1.3.3.1/24'
        expected_host['indent'] = 1

        # build list of expected
        expected_list = []
        expected_list.append(expected)
        expected_list.append(expected_host)
        expected_list = self._convert_list_of_unicode_to_str(expected_list)

        # add another prefix, try with vrf_id = None
        attr['vrf_id'] = None
        request = requests.post(self.server_url,
                                headers=self.headers,
                                json=attr,
                                params=parameters)
        text = request.text
        result = json.loads(text)
        result = dict([(str(k), str(v)) for k, v in result.items()])
        # update expected list
        expected_host2 = expected_host.copy()
        expected_host2['id'] = result['id']
        expected_host2['prefix'] = '1.3.3.2/32'
        expected_host2['display_prefix'] = '1.3.3.2/24'
        expected_list.append(expected_host2)
        expected_list = self._convert_list_of_unicode_to_str(expected_list)

        # add another prefix, this time completely without VRF info
        del (attr['vrf_id'])
        request = requests.post(self.server_url,
                                headers=self.headers,
                                json=attr,
                                params=parameters)
        text = request.text
        result = json.loads(text)
        result = dict([(str(k), str(v)) for k, v in result.items()])
        # update expected list
        expected_host3 = expected_host.copy()
        expected_host3['id'] = result['id']
        expected_host3['prefix'] = '1.3.3.3/32'
        expected_host3['display_prefix'] = '1.3.3.3/24'
        expected_list.append(expected_host3)
        expected_list = self._convert_list_of_unicode_to_str(expected_list)

        # list of prefixes through GET request
        parameters = {'order_id': 'test'}
        list_prefix_request = request = requests.get(self.server_url,
                                                     headers=self.headers,
                                                     params=parameters)
        list_prefix = json.loads(list_prefix_request.text)
        list_prefix = self._convert_list_of_unicode_to_str(list_prefix)

        mangled_result = self._mangle_prefix_result(list_prefix)

        # make sure the result looks like we expect it too! :D
        self.assertEqual(mangled_result, expected_list)

    def test_prefix_remove(self):
        """ Removes a prefix
        """

        # add 1.3.3.4/24
        attr = {}
        attr['prefix'] = '1.3.4.0/24'
        attr['description'] = 'test delete prefix'
        attr['type'] = 'assignment'
        attr['order_id'] = 'test'

        request = requests.post(self.server_url,
                                headers=self.headers,
                                json=attr)
        text = request.text
        result = json.loads(text)
        result = dict([(str(k), str(v)) for k, v in result.items()])

        prefix_id = result['id']

        # delete prefix
        parameters = {'id': prefix_id}
        request = requests.delete(self.server_url,
                                  headers=self.headers,
                                  params=parameters)
        text = request.text
        result = json.loads(text)
        result = dict([(str(k), str(v)) for k, v in result.items()])

        expected = {
            'prefix': '1.3.4.0/24',
            'vrf_id': '0',
        }

        self.assertEqual(result, expected)
Exemplo n.º 9
0
class NipapSql(unittest.TestCase):
    nipap = Nipap()

    def clean_up(self):
        self.nipap._execute("TRUNCATE ip_net_plan CASCADE")
        self.nipap._execute("TRUNCATE ip_net_pool CASCADE")
        self.nipap._execute("TRUNCATE ip_net_schema CASCADE")



    def setUp(self):
        self.clean_up()
        self.schema_id = self.nipap.add_schema({ 'name': 'test-schema', 'description': '' })



    def test_calc_indent(self):
        """ Test automatic calculation of indent level

            Insert baseline data, namely 192.0.2.0/24
            Verify indent level is 0, since it should be a root prefix
            Insert 192.0.2.0/27
            Verify indent level is 1 for 192.0.2.0/27
            Insert 192.0.2.0/32
            Insert 192.0.2.1/32
            Insert 192.0.2.2/32
            Insert 192.0.2.3/32
            Verify indent level is 2 for 192.0.2.[0-3]/32
            Insert 192.0.2.32/32
            Insert 192.0.2.33/32
            Insert 192.0.2.34/32
            Insert 192.0.2.35/32
            Verify indent level is 1 for 192.0.2.3[2-5]/32
            Insert 192.0.2.32/27
            Verify indent level is 1 for 192.0.2.32/27
            Verify indent level is 2 for 192.0.2.3[2-5]/32
            Remove 192.0.2.0/27
            Verify indent level is 1 for 192.0.2.[0-3]/32
        """

    def test_db_constraints(self):
        """

            INSERT 1.3.0.0/16    r    allow
            INSERT 1.3.0.0/16    r    deny    duplicate
            INSERT 1.3.3.0/24    r    allow
            INSERT 1.3.3.0/27    a    allow
            INSERT 1.3.3.0/32    h    allow
            INSERT 1.3.3.1/32    h    allow
            INSERT 1.3.3.2/32    a    deny    assignment within assignment not allowed
            DELETE 1.3.3.0/27    a    deny    hosts inside assignment
        """
        self.assertEqual(self._inspre('1.3.0.0/16', 'reservation'), True, 'Unable to insert prefix 1.3.0.0/16')
        self.assertRaises(NipapDuplicateError, self._inspre, '1.3.0.0/16', 'reservation') # Duplicate prefix detection not working
        self.assertEqual(self._inspre('1.3.3.0/24', 'reservation'), True)
        self.assertEqual(self._inspre('1.3.3.0/27', 'assignment'), True)
        self.assertEqual(self._inspre('1.3.3.0/32', 'host'), True)
        self.assertEqual(self._inspre('1.3.3.1/32', 'host'), True)
        self.assertRaises(NipapValueError, self._inspre, '1.3.3.2/31', 'host')    # do not allow /31 as type 'host'
        self.assertRaises(NipapValueError, self._inspre, '1.3.3.3/32', 'assignment') # Able to create assignment within assignment - we should not
        self.assertRaises(NipapValueError, self._delpre, '1.3.3.0/27') # Able to delete assignment containing hosts - we should not
        self.assertRaises(NipapValueError, self._updpre, '1.3.3.0/24', 'assignment')



    def _inspre(self, prefix, prefix_type):
        """ Insert a prefix

            Return true on success, exception otherwise
        """
        self.nipap._execute("INSERT INTO ip_net_plan (authoritative_source, schema, prefix, type) VALUES ('nipaptest', %(schema)s, %(prefix)s, %(prefix_type)s)", { 'schema': self.schema_id, 'prefix': prefix, 'prefix_type': prefix_type })
        return True



    def _updpre(self, prefix, prefix_type):
        """ Update a prefix

            Return true on success, exception otherwise
        """
        self.nipap._execute("UPDATE ip_net_plan SET type=%(prefix_type)s WHERE schema = %(schema)s AND prefix = %(prefix)s", { 'schema': self.schema_id, 'prefix': prefix, 'prefix_type': prefix_type })
        return True



    def _delpre(self, prefix):
        """ Delete a prefix

            Return true on success, exception otherwise
        """
        self.nipap._execute("DELETE FROM ip_net_plan WHERE schema = %(schema)s AND prefix = %(prefix)s", { 'schema': self.schema_id, 'prefix': prefix })
        return True
Exemplo n.º 10
0
class NipapTest(unittest.TestCase):
    """ Tests the NIPAP class
    """

    nipap = None

    def setUp(self):
        """ Better start from a clean slate!
        """

        cfg = NipapConfig('/etc/nipap/nipap.conf')
        self.nipap = Nipap()

        # create dummy auth object
        # As the authentication is performed before the query hits the Nipap
        # class, it does not matter what user we use here
        self.auth = SqliteAuth('local', 'unittest', 'unittest', 'unittest')
        self.auth.authenticated_as = 'unittest'
        self.auth.full_name = 'Unit test'

        self.nipap._execute("TRUNCATE ip_net_plan, ip_net_pool, ip_net_vrf, ip_net_log, ip_net_asn")

        self.schema_attrs = {
                'name': 'test-schema1',
                'description': 'Test schema numero uno!'
                }
        self.schema_attrs['id'] = self.nipap.add_schema(self.auth, self.schema_attrs)
        self.schema_attrs2 = {
                'name': 'test-schema2',
                'description': 'Test schema numero dos!'
                }
        self.schema_attrs2['id'] = self.nipap.add_schema(self.auth, self.schema_attrs2)
        self.pool_attrs = {
                'name': 'test-pool1',
                'description': 'Test pool numero uno!',
                'default_type': 'assignment',
                'ipv4_default_prefix_length': 30,
                'ipv6_default_prefix_length': 112
                }
        self.pool_attrs['id'] = self.nipap.add_pool(self.auth, {'id': self.schema_attrs['id']}, self.pool_attrs)
        self.prefix_attrs1 = {
                'authoritative_source': 'nipaptest',
                'prefix': '1.3.3.0/24',
                'type': 'assignment',
                'description': ''
                }
        self.prefix_attrs1['id'] = self.nipap.add_prefix(self.auth, {'id': self.schema_attrs['id']}, self.prefix_attrs1)
        self.prefix_attrs = {
                'authoritative_source': 'nipaptest',
                'prefix': '1.3.3.1/32',
                'type': 'host',
                'description': 'Test prefix numero uno!'
                }
        self.prefix_attrs['id'] = self.nipap.add_prefix(self.auth, {'id': self.schema_attrs['id']}, self.prefix_attrs)
        self.prefix_attrs2 = {
                'authoritative_source': 'nipaptest',
                'prefix': '1.3.2.0/23',
                'type': 'reservation',
                'description': ''
                }
        self.prefix_attrs2['id'] = self.nipap.add_prefix(self.auth, {'id': self.schema_attrs['id']}, self.prefix_attrs2)
        self.prefix_attrs3 = {
                'authoritative_source': 'nipaptest',
                'prefix': '1.3.0.0/16',
                'type': 'reservation',
                'description': ''
                }
        self.prefix_attrs3['id'] = self.nipap.add_prefix(self.auth, {'id': self.schema_attrs['id']}, self.prefix_attrs3)
        self.prefix_attrs4 = {
                'authoritative_source': 'nipaptest',
                'prefix': '1.3.0.0/17',
                'type': 'reservation',
                'description': ''
                }
        self.prefix_attrs4['id'] = self.nipap.add_prefix(self.auth, {'id': self.schema_attrs2['id']}, self.prefix_attrs4)

        self.prefix6_attrs1 = {
                'authoritative_source': 'nipaptest',
                'prefix': '2001:0db8:3:3::/112',
                'type': 'assignment',
                'description': ''
                }
        self.prefix6_attrs1['id'] = self.nipap.add_prefix(self.auth, {'id': self.schema_attrs['id']}, self.prefix6_attrs1)
        self.prefix6_attrs = {
                'authoritative_source': 'nipaptest',
                'prefix': '2001:0db8:3:3::1/128',
                'type': 'host',
                'description': 'Test prefix numero uno!'
                }
        self.prefix6_attrs['id'] = self.nipap.add_prefix(self.auth, {'id': self.schema_attrs['id']}, self.prefix6_attrs)
        self.prefix6_attrs2 = {
                'authoritative_source': 'nipaptest',
                'prefix': '2001:0db8:3:3::/64',
                'type': 'reservation',
                'description': ''
                }
        self.prefix6_attrs2['id'] = self.nipap.add_prefix(self.auth, {'id': self.schema_attrs['id']}, self.prefix6_attrs2)
        self.prefix6_attrs3 = {
                'authoritative_source': 'nipaptest',
                'prefix': '2001:0db8:3:0::/48',
                'type': 'reservation',
                'description': ''
                }
        self.prefix6_attrs3['id'] = self.nipap.add_prefix(self.auth, {'id': self.schema_attrs['id']}, self.prefix6_attrs3)
        self.prefix6_attrs4 = {
                'authoritative_source': 'nipaptest',
                'prefix': '2001:0db8:3:0::/56',
                'type': 'reservation',
                'description': ''
                }
        self.prefix6_attrs4['id'] = self.nipap.add_prefix(self.auth, {'id': self.schema_attrs2['id']}, self.prefix6_attrs4)


    def test_schema_basic(self):
        """ Basic schema test

            1. Add a new schema
            2. List with filters to get newly created schema
            3. Verify listed schema coincides with input args for added schema
            4. Remove schema
        """
        attrs = {
                'name': 'test-schema-wrong',
                'description': 'A simple test schema with incorrect name!'
                }
        attrs['id'] = self.nipap.add_schema(self.auth, attrs)
        schema = self.nipap.list_schema(self.auth, { 'id': attrs['id'] })
        for a in attrs:
            self.assertEqual(schema[0][a], attrs[a], 'Added object differ from listed on attribute: ' + a)



    def test_schema_add_crap_input(self):
        """ Try to input junk into add_schema and expect error

        """
        attrs = {
                'name': 'test-schema-crap',
                'description': 'A simple test schema with incorrect name!',
                'crap': 'this is just some crap'
                }
        # missing everything
        self.assertRaises(NipapMissingInputError, self.nipap.add_schema, self.auth, { })
        # missing description
        self.assertRaises(NipapMissingInputError, self.nipap.add_schema, self.auth, { 'name': 'crapson' })
        # have required and extra crap
        self.assertRaises(NipapExtraneousInputError, self.nipap.add_schema, self.auth, attrs)



    def test_expand_schema_spec(self):
        """ Test the expand_schema_spec()

            The _expand_schema_spec() function is used throughout the schema
            functions to expand the schema specification input and so we test
            the separately.
        """
        # wrong type
        self.assertRaises(NipapInputError, self.nipap._expand_schema_spec, 'string')
        # wrong type
        self.assertRaises(NipapInputError, self.nipap._expand_schema_spec, 1)
        # wrong type
        self.assertRaises(NipapInputError, self.nipap._expand_schema_spec, [])
        # missing keys
        self.assertRaises(NipapMissingInputError, self.nipap._expand_schema_spec, { })
        # crap key
        self.assertRaises(NipapExtraneousInputError, self.nipap._expand_schema_spec, { 'crap': self.schema_attrs['name'] })
        # required keys and extra crap
        self.assertRaises(NipapExtraneousInputError, self.nipap._expand_schema_spec, { 'name': self.schema_attrs['name'], 'crap': 'crap' })
        # proper key but incorrect value (int vs string)
        self.assertRaises(NipapValueError, self.nipap._expand_schema_spec, { 'id': '3' })
        # proper key but incorrect value (int vs string)
        self.assertRaises(NipapValueError, self.nipap._expand_schema_spec, { 'name': 3 })
        # both id and name
        self.assertRaises(NipapExtraneousInputError, self.nipap._expand_schema_spec, { 'id': 3, 'name': '3' })
        # proper key - id
        where, params = self.nipap._expand_schema_spec({ 'id': 3 })
        self.assertEqual(where, 'id = %(spec_id)s', "Improperly expanded WHERE clause")
        self.assertEqual(params, {'spec_id': 3}, "Improperly expanded params dict")
        # proper spec - name
        where, params = self.nipap._expand_schema_spec({ 'name': 'test' })



    def test_schema_edit_crap_input(self):
        """ Try to input junk into edit_schema and expect error

        """
        attrs = {
                'name': 'test-schema-crap',
                'description': 'A simple test schema with incorrect name!'
                }
        crap_attrs = {
                'name': 'test-schema-crap',
                'description': 'A simple test schema with incorrect name!',
                'crap': 'this is just some crap'
                }
        # spec is tested elsewhere, just test attrs part
        self.assertRaises(NipapExtraneousInputError, self.nipap.edit_schema, self.auth, { 'name': self.schema_attrs['name'] }, crap_attrs)



    def test_schema_list_crap_input(self):
        """ Try to input junk into list_schema and expect error

        """
        # TODO: what do we really expect?
        self.assertRaises(NipapExtraneousInputError, self.nipap.list_schema, self.auth, { 'crap': 'crap crap' })



    def test_schema_dupe(self):
        """ Check so we can't create duplicate schemas

            There are unique indices in the database that should prevent us
            from creating duplicate schema (ie, with the same name).
        """
        schema_attrs = {
                'name': 'test-schema-dupe',
                'description': 'Testing dupe'
                }
        self.nipap.add_schema(self.auth, schema_attrs)
        self.assertRaises(NipapDuplicateError, self.nipap.add_schema, self.auth, schema_attrs)



    def test_schema_rename(self):
        """ Rename a schema

            Uses the edit_schema() functionality to rename our previously
            created and incorrectly named schema so it hereafter has the
            correct name. Also tests the list_schema() functionality since we
            use that to list the modified schema.
        """
        spec = { 'name': 'test-schema1' }
        attrs = {
                'name': 'test-schema',
                'description': 'A simple test schema with correct name!'
                }
        self.nipap.edit_schema(self.auth, spec, attrs)
        # check that search for old record doesn't return anything
        schema = self.nipap.list_schema(self.auth, spec)
        self.assertEqual(schema, [], 'Old entry still exists')
        schema = self.nipap.list_schema(self.auth, { 'name': 'test-schema' })
        for a in attrs:
            self.assertEqual(schema[0][a], attrs[a], 'Modified schema differ from listed on attribute: ' + a)



    def test_schema_remove(self):
        """ Remove a schema

            Remove the schema previously modified and make sure it's not there.
        """
        spec = { 'name': 'test-schema' }
        self.nipap.remove_schema(self.auth, spec)
        # check that search for old record doesn't return anything
        schema = self.nipap.list_schema(self.auth, spec)
        self.assertEqual(schema, [], 'Old entry still exists')



    def test_expand_pool_spec(self):
        """ Test the function which expands pool spec to SQL.
        """

        schema = {'id': self.schema_attrs['id']}

        # wrong type
        self.assertRaises(NipapInputError, self.nipap._expand_pool_spec, 'string')
        # wrong type
        self.assertRaises(NipapInputError, self.nipap._expand_pool_spec, 1)
        # wrong type
        self.assertRaises(NipapInputError, self.nipap._expand_pool_spec, [])
        # missing keys
        self.assertRaises(NipapMissingInputError, self.nipap._expand_pool_spec, { })
        # crap key
        self.assertRaises(NipapExtraneousInputError, self.nipap._expand_pool_spec, { 'crap': self.pool_attrs['name'] })
        # required keys and extra crap
        self.assertRaises(NipapExtraneousInputError, self.nipap._expand_pool_spec, { 'id': self.pool_attrs['id'], 'schema': self.schema_attrs['id'], 'crap': 'crap' })
        # proper key but incorrect value (int vs string)
        self.assertRaises(NipapValueError, self.nipap._expand_pool_spec, { 'id': '3', 'schema': self.schema_attrs['id'] })
        # proper key but incorrect value (int vs string)
        self.assertRaises(NipapValueError, self.nipap._expand_pool_spec, { 'name': 3, 'schema': self.schema_attrs['id'] })
        # both id and name
        self.assertRaises(NipapExtraneousInputError, self.nipap._expand_pool_spec, { 'id': 3, 'name': '3', 'schema': self.schema_attrs['id'] })
        # proper key - id
        where, params = self.nipap._expand_pool_spec({ 'id': 3, 'schema': self.schema_attrs['id'] })
        self.assertEqual(where, 'po.id = %(spec_id)s AND po.schema = %(spec_schema)s', "Improperly expanded WHERE clause")
        self.assertEqual(params, {'spec_id': 3, 'spec_schema': self.schema_attrs['id']}, "Improperly expanded params dict")
        # proper spec - name
        where, params = self.nipap._expand_pool_spec({ 'name': 'test', 'schema': self.schema_attrs['id'] })
        self.assertEqual(where, 'po.name = %(spec_name)s AND po.schema = %(spec_schema)s', "Improperly expanded WHERE clause")
        self.assertEqual(params, {'spec_name': 'test', 'spec_schema': self.schema_attrs['id'] }, "Improperly expanded params dict")



    def test_pool_add1(self):
        """ Add a pool and check it's there using list functions

            Refer to schema by id
        """
        attrs = {
                'name': 'test-pool-wrong',
                'description': 'A simple test pool with incorrect name!',
                'default_type': 'reservation',
                'ipv4_default_prefix_length': 30,
                'ipv6_default_prefix_length': 112
                }
        schema = {'id': self.schema_attrs['id']}
        pool_id = self.nipap.add_pool(self.auth, schema, attrs)
        pool = self.nipap.list_pool(self.auth, schema, { 'id': pool_id })
        for a in attrs:
            self.assertEqual(pool[0][a], attrs[a], 'Added object differ from listed on attribute: %s  %s!=%s' % (a, attrs[a], pool[0][a]))



    def test_pool_add2(self):
        """ Add a pool and check it's there using list functions

            Refer to schema by name
        """
        schema = {'id': self.schema_attrs['id']}
        attrs = {
                'name': 'test-pool-wrong',
                'default_type': 'reservation',
                'description': 'A simple test pool with incorrect name!'
                }
        pool_id = self.nipap.add_pool(self.auth, schema, attrs)
        pool = self.nipap.list_pool(self.auth, schema, { 'id': pool_id })
        for a in attrs:
            self.assertEqual(pool[0][a], attrs[a], 'Added object differ from listed on attribute: ' + a)



    def test_edit_pool_by_name(self):
        """ Try to rename a pool using edit_pool() function

            Pool is not uniquely identified (empty spec) so this should raise an error
        """
        schema = {'id': self.schema_attrs['id']}
        spec = {  }
        attrs = {
                'name': self.pool_attrs['name'],
                'default_type': 'assignment',
                'description': 'A simple test pool with correct name!'
                }
        self.assertRaises(NipapInputError, self.nipap.edit_pool, self.auth, schema, spec, attrs)



    def test_edit_pool(self):
        """ Rename a pool using edit_pool() function
        """
        schema = {'id': self.schema_attrs['id']}
        spec = { 'id': self.pool_attrs['id'] }
        attrs = {
                'name': 'test-pool',
                'default_type': 'assignment',
                'description': 'A simple test pool with correct name!',
                'ipv4_default_prefix_length': 32,
                'ipv6_default_prefix_length': 128
                }
        self.nipap.edit_pool(self.auth, schema, spec, attrs)
        # check that search for old record doesn't return anything
        pool = self.nipap.list_pool(self.auth, schema, { 'name': self.pool_attrs['name'] })
        self.assertEqual(pool, [], 'Old entry still exists')
        pool = self.nipap.list_pool(self.auth, schema, { 'name': attrs['name'] })
        for a in attrs:
            self.assertEqual(pool[0][a], attrs[a], 'Added object differ from listed on attribute: ' + a)



    def test_remove_pool_by_id(self):
        """ Remove a pool by id
        """
        schema = {'id': self.schema_attrs['id']}
        pool = self.nipap.list_pool(self.auth, schema, { 'id': self.pool_attrs['id'] })
        # first make sure our pool exists
        self.assertNotEqual(pool[0], [], 'Record must exist before we can delete it')
        for a in self.pool_attrs:
            self.assertEqual(pool[0][a], self.pool_attrs[a], 'Listed attribute differ from original')
        # remove the pool
        self.nipap.remove_pool(self.auth, schema, { 'id': self.pool_attrs['id'] })
        # check that search for old record doesn't return anything
        pool = self.nipap.list_pool(self.auth, schema, { 'id': self.pool_attrs['id'] })
        self.assertEqual(pool, [], 'Old entry still exists')



    def test_prefix_in_a_pool(self):
        """ Add prefixes to a poll and list!
        """
        schema = {'id': self.schema_attrs['id']}
        pool = self.nipap.list_pool(self.auth, schema, { 'id': self.pool_attrs['id'] })
        # first make sure our pool exists
        self.assertNotEqual(pool[0], [], 'Pool must exist!')
        pfxs = [
                '1.2.2.0/32',
                '1.2.2.1/32',
                '1.2.2.2/32',
                '1.2.2.3/32',
                '1.2.2.4/32',
                '1.2.2.5/32'
                ]
        for p in pfxs:
            prefix_attrs = {
                    'authoritative_source': 'nipap-test',
                    'prefix': p,
                    'type': 'host',
                    'description': 'test prefix',
                    'pool_id': self.pool_attrs['id'],
                    'comment': 'test comment, please remove! ;)'
                    }
            self.nipap.add_prefix(self.auth, schema, prefix_attrs)

        # list again
        pool = self.nipap.list_pool(self.auth, schema, { 'id': self.pool_attrs['id'] })
        self.assertNotEqual(pool[0], [], 'Pool must exist!')
        self.assertEqual(set(pfxs), set(pool[0]['prefixes']), 'Returned prefixes do not match added ones')



    def test_prefix_basic(self):
        """ Test basic prefix functions
        """
        schema = {'id': self.schema_attrs['id']}
        prefix_attrs = {
                'authoritative_source': 'nipap-test',
                'prefix': '1.3.3.7/32',
                'type': 'host',
                'description': 'test prefix',
                'comment': 'test comment, please remove! ;)'
                }
        self.nipap.add_prefix(self.auth, schema, prefix_attrs)
        prefix = self.nipap.list_prefix(self.auth, schema, { 'prefix': prefix_attrs['prefix'] })
        for a in prefix_attrs:
            self.assertEqual(prefix[0][a], prefix_attrs[a], 'Added object differ from listed on attribute: ' + a)

        # fetch many prefixes - all in a schema
        prefix = self.nipap.list_prefix(self.auth, schema, {})
        self.assertNotEqual(len(prefix), 0, 'Found 0 prefixes in schema ' + self.schema_attrs['name'])



    def test_add_prefix(self):
        """ Test add_prefix in a bit more detail
        """
        schema = {'id': self.schema_attrs['id']}
        # we need a bloody pool first!
        pool = self.nipap.list_pool(self.auth, schema, { 'id': self.pool_attrs['id'] })
        # first make sure our pool exists
        self.assertNotEqual(pool[0], [], 'Pool must exist!')
        pfxs = [
                '10.0.0.0/24',
                '10.0.1.0/24',
                '10.0.2.0/24',
                '10.0.3.0/24',
                '10.0.4.0/24'
                ]
        for p in pfxs:
            prefix_attrs = {
                    'authoritative_source': 'nipap-test',
                    'prefix': p,
                    'type': 'reservation',
                    'description': 'test prefix',
                    'pool_id': self.pool_attrs['id'],
                    'comment': 'test comment, please remove! ;)'
                    }
            self.nipap.add_prefix(self.auth, schema, prefix_attrs)

        # get an address based on from-prefix
        prefix_attrs = {
                'type': 'assignment',
                'authoritative_source': 'nipap-test',
                'description': 'test prefix',
                'comment': 'test comment, please remove! ;)'
                }
        res = self.nipap.add_prefix(self.auth, schema, prefix_attrs, { 'from-prefix': ['10.0.0.0/24'], 'prefix_length': 30 })
        p = self.nipap.list_prefix(self.auth, schema, { 'id': res })
        self.assertEqual(p[0]['prefix'], '10.0.0.0/30', "New prefix differ from what it should be!")

        self.nipap.add_schema(self.auth, { 'name': 'testtest', 'description': 'another test schema!' })
        # pass different schemas in attr and args
        # TODO: Find something similar?
        #self.assertRaises(NipapInputError, self.nipap.add_prefix, schema, { 'authoritative_source': 'nipap-test', 'description': 'tjong' }, { 'from-prefix': ['10.0.0.0/24'], 'prefix_length': 30 })



    def test_prefix_search_simple(self):
        """ Test the simple prefix search function.
        """

        schema = {'id': self.schema_attrs['id']}

        # First, perform e few tests to verify search string expansion.
        query_keys = dict()
        query_keys['testing testing'] = "description"
        query_keys['1.2.3.4'] = "prefix"

        # build query string
        query_str = ""
        for key, val in query_keys.items():
            if val == "description":
                query_str += "\"%s\" " % key
            else:
                query_str += "%s " % key

        res = self.nipap.smart_search_prefix(self.auth, schema, query_str)
        for interp in res['interpretation']:
            self.assertEqual(interp['string'] in query_keys, True, "Function returned unknown interpreted string %s" % interp['string'])

        prefix_attrs = {
                'authoritative_source': 'nipap-test',
                'prefix': '1.3.3.77/32',
                'type': 'host',
                'description': 'test-ish prefix',
                'comment': 'Test prefix #77! ;)'
                }

        self.nipap.add_prefix(self.auth, schema, prefix_attrs)
        res = self.nipap.smart_search_prefix(self.auth, schema, r"""1.3.3.77 "-ish" """)
        self.assertEqual(res['result'][-1]['prefix'], '1.3.3.77/32', 'Prefix not found')



    def test_prefix_search_smart(self):
        """ Test the smart prefix search function.
        """
        schema = {'id': self.schema_attrs['id']}

        # test full ipv4 address
        res = self.nipap.smart_search_prefix(self.auth, schema, '1.3.3.7')
        self.assertEqual(res['interpretation'][0]['interpretation'], 'IPv4 address')

        res = self.nipap.smart_search_prefix(self.auth, schema, '1.1')
        self.assertEqual(res['interpretation'][0]['interpretation'], 'text', "Incorrectly interpreted '1.1' as : " + res['interpretation'][0]['interpretation'])

        res = self.nipap.smart_search_prefix(self.auth, schema, '10/8')
        self.assertEqual(res['interpretation'][0]['interpretation'], 'IPv4 prefix')

        res = self.nipap.smart_search_prefix(self.auth, schema, '2000:0::01')
        self.assertEqual(res['interpretation'][0]['interpretation'], 'IPv6 address')



    def test_prefix_remove(self):
        """ Remove a prefix
        """
        schema = {'id': self.schema_attrs['id']}
        prefix = self.nipap.list_prefix(self.auth, schema, { 'id': self.prefix_attrs['id'] })
        # first make sure our prefix exists
        self.assertEqual(prefix[0]['id'], self.prefix_attrs['id'], 'Record must exist before we can delete it')
        # remove the prefix, by id
        self.nipap.remove_prefix(self.auth, schema, { 'id': self.prefix_attrs['id'] })
        # check that search for old record doesn't return anything
        prefix = self.nipap.list_prefix(self.auth, schema, { 'id': self.prefix_attrs['id'] })
        self.assertEqual(prefix, [], 'Old entry still exists')



    def test_prefix_indent_ipv4(self):
        """ Check that our indentation calculation is working for IPv4

            Prefixes gets an indent value automatically assigned to help in
            displaying prefix information. The indent value is written on
            updates to the table and this test is to make sure it is correctly
            calculated.
        """
        schema = {'id': self.schema_attrs['id']}
        p1 = self.nipap.list_prefix(self.auth, schema, { 'prefix': '1.3.3.1/32' })[0]
        p2 = self.nipap.list_prefix(self.auth, schema, { 'prefix': '1.3.3.0/24' })[0]
        p3 = self.nipap.list_prefix(self.auth, schema, { 'prefix': '1.3.0.0/16' })[0]
        self.assertEqual(p1['indent'], 4, "Indent calc on add failed")
        self.assertEqual(p2['indent'], 3, "Indent calc on add failed")
        self.assertEqual(p3['indent'], 0, "Indent calc on add failed")
        # remove middle prefix
        self.nipap.remove_prefix(self.auth, schema, { 'id': self.prefix_attrs2['id'] })
        # check that child prefix indent level has decreased
        p1 = self.nipap.list_prefix(self.auth, schema, { 'prefix': '1.3.3.1/32' })[0]
        p3 = self.nipap.list_prefix(self.auth, schema, { 'prefix': '1.3.0.0/16' })[0]
        self.assertEqual(p1['indent'], 3, "Indent calc on remove failed")
        self.assertEqual(p3['indent'], 0, "Indent calc on remove failed")



    def test_prefix_indent_ipv6(self):
        """ Check that our indentation calculation is working for IPv6

            Prefixes gets an indent value automatically assigned to help in
            displaying prefix information. The indent value is written on
            updates to the table and this test is to make sure it is correctly
            calculated.
        """
        schema = {'id': self.schema_attrs['id']}
        p1 = self.nipap.list_prefix(self.auth, schema, { 'prefix': '2001:0db8:3:3::1/128' })[0]
        p2 = self.nipap.list_prefix(self.auth, schema, { 'prefix': '2001:0db8:3:3::/64' })[0]
        p3 = self.nipap.list_prefix(self.auth, schema, { 'prefix': '2001:0db8:3:0::/48' })[0]
        self.assertEqual(p1['indent'], 4, "Indent calc on add failed")
        self.assertEqual(p2['indent'], 2, "Indent calc on add failed")
        self.assertEqual(p3['indent'], 0, "Indent calc on add failed")
        # remove middle prefix
        self.nipap.remove_prefix(self.auth, schema, { 'id': self.prefix6_attrs2['id'] })
        # check that child prefix indent level has decreased
        p1 = self.nipap.list_prefix(self.auth, schema, { 'prefix': '2001:0db8:3:3::1/128' })[0]
        p3 = self.nipap.list_prefix(self.auth, schema, { 'prefix': '2001:0db8:3:0::/48' })[0]
        self.assertEqual(p1['indent'], 3, "Indent calc on remove failed for " + p1['prefix'] + " indent: " + str(p1['indent']))
        self.assertEqual(p3['indent'], 0, "Indent calc on remove failed for " + p3['prefix'] + " indent: " + str(p3['indent']))



    def test_find_free_prefix_input(self):
        """ Mostly input testing of find_free_prefix

            Try to stress find_free_prefix and send a lot of junk..
        """
        schema = {'id': self.schema_attrs['id']}
        # set up a prefix not used elsewhere so we have a known good state
        prefix_attrs = {
                'authoritative_source': 'nipap-test',
                'prefix': '100.0.0.0/16',
                'type': 'reservation',
                'description': 'test prefix',
                'comment': 'test comment, please remove! ;)'
                }
        self.nipap.add_prefix(self.auth, schema, prefix_attrs)

        # no schema, should raise error!
        self.assertRaises(NipapInputError, self.nipap.find_free_prefix, self.auth, schema, { 'from-prefix': ['100.0.0.0/16'] })

        # incorrect from-prefix type, string instead of list of strings (looking like an IP address)
        self.assertRaises(NipapInputError, self.nipap.find_free_prefix, self.auth, schema, { 'from-prefix': '100.0.0.0/16' })

        # missing prefix_length
        self.assertRaises(NipapMissingInputError, self.nipap.find_free_prefix, self.auth, schema, { 'from-prefix': [ '100.0.0.0/16' ], 'count': 1 })

        # try giving both IPv4 and IPv6 in from-prefix which shouldn't work
        self.assertRaises(NipapInputError, self.nipap.find_free_prefix, self.auth, schema, { 'from-prefix': [ '100.0.0.0/16', '2a00:800::0/25' ], 'prefix_length': 24, 'count': 1 })

        # try giving non-integer as wanted prefix length
        self.assertRaises(NipapValueError, self.nipap.find_free_prefix, self.auth, schema, { 'from-prefix': [ '100.0.0.0/16'], 'prefix_length': '24', 'count': 1 })

        # try giving to high a number as wanted prefix length for IPv4
        self.assertRaises(NipapValueError, self.nipap.find_free_prefix, self.auth, schema, { 'from-prefix': [ '100.0.0.0/16'], 'prefix_length': 35, 'count': 1 })

        # try giving to high a number as wanted prefix length for IPv6
        self.assertRaises(NipapValueError, self.nipap.find_free_prefix, self.auth, schema, { 'from-prefix': [ '2a00:800::1/25'], 'prefix_length': 150, 'count': 1 })

        # try giving a high number for result count (max is 1000)
        self.assertRaises(NipapValueError, self.nipap.find_free_prefix, self.auth, schema, { 'from-prefix': [ '100.0.0.0/16'], 'prefix_length': 30, 'count': 55555 })

        # don't pass 'family', which is required when specifying 'from-pool'
        self.assertRaises(NipapMissingInputError, self.nipap.find_free_prefix, self.auth, schema, { 'from-pool': { 'name': self.pool_attrs['name'] }, 'prefix_length': 24, 'count': 1 })

        # pass crap as family, wrong type even
        self.assertRaises(ValueError, self.nipap.find_free_prefix, self.auth, schema, { 'from-pool': { 'name': self.pool_attrs['name'] }, 'prefix_length': 24, 'count': 1, 'family': 'crap' })

        # pass 7 as family
        self.assertRaises(NipapValueError, self.nipap.find_free_prefix, self.auth, schema, { 'from-pool': { 'name': self.pool_attrs['name'] }, 'prefix_length': 24, 'count': 1, 'family': 7 })

        # pass non existent pool
        self.assertRaises(NipapNonExistentError, self.nipap.find_free_prefix, self.auth, schema, { 'from-pool': { 'name': 'crap' }, 'prefix_length': 24, 'count': 1, 'family': 4 })



    def test_find_free_prefix1(self):
        """ Functionality testing of find_free_prefix

            Mostly based on 'from-prefix'
        """
        schema = { 'id': self.schema_attrs['id'] }
        # set up a prefix not used elsewhere so we have a known good state
        prefix_attrs = {
                'authoritative_source': 'nipap-test',
                'prefix': '100.0.0.0/16',
                'type': 'assignment',
                'description': 'test prefix',
                'comment': 'test comment, please remove! ;)'
                }
        self.nipap.add_prefix(self.auth, schema, prefix_attrs)

        # simple test
        res = self.nipap.find_free_prefix(self.auth, schema, { 'from-prefix': [ '100.0.0.0/16', '1.3.3.0/24' ], 'prefix_length': 24, 'count': 1 })
        self.assertEqual(res, ['100.0.0.0/24'], "Incorrect prefix set returned")

        # simple test - only one input prefix (which did cause a bug, thus keeping it)
        res = self.nipap.find_free_prefix(self.auth, schema, { 'from-prefix': [ '100.0.0.0/16' ], 'prefix_length': 24, 'count': 1 })
        self.assertEqual(res, ['100.0.0.0/24'], "Incorrect prefix set returned")

        res = self.nipap.find_free_prefix(self.auth, schema, { 'from-prefix': [ '100.0.0.0/16', '1.3.3.0/24' ], 'prefix_length': 24, 'count': 999 })
        self.assertEqual(len(res), 256, "Incorrect prefix set returned")



    def test_find_free_prefix2(self):
        """ Functionality testing of find_free_prefix

            Mostly based on 'from-pool'
        """
        schema = { 'id': self.schema_attrs['id'] }
        # we need a bloody pool first!
        pool = self.nipap.list_pool(self.auth, schema, { 'id': self.pool_attrs['id'] })
        # first make sure our pool exists
        self.assertNotEqual(pool[0], [], 'Pool must exist!')
        pfxs = [
                '10.0.0.0/24',
                '10.0.1.0/24',
                '10.0.2.0/24',
                '10.0.3.0/24',
                '10.0.4.0/24'
                ]
        for p in pfxs:
            prefix_attrs = {
                    'type': 'reservation',
                    'authoritative_source': 'nipap-test',
                    'prefix': p,
                    'description': 'test prefix',
                    'pool_id': self.pool_attrs['id'],
                    'comment': 'test comment, please remove! ;)'
                    }
            self.nipap.add_prefix(self.auth, schema, prefix_attrs)

        # from-pool test
        res = self.nipap.find_free_prefix(self.auth, schema, { 'from-pool': { 'name': self.pool_attrs['name'] }, 'count': 1, 'family': 4})
        self.assertEqual(res, ['10.0.1.0/30'], "Incorrect prefix set returned when requesting default prefix-length")

        # from-pool test, specify wanted prefix length
        res = self.nipap.find_free_prefix(self.auth, schema, { 'from-pool': { 'name': self.pool_attrs['name'] }, 'count': 1, 'family': 4, 'prefix_length': 31})
        self.assertEqual(res, ['10.0.1.0/31'], "Incorrect prefix set returned with explicit prefix-length")



    def test_edit_prefix(self):
        """ Functionality testing of edit_prefix.
        """

        schema = { 'id': self.schema_attrs['id'] }
        data = {
            'prefix': '192.0.2.0/24',
            'description': 'foo',
            'comment': 'bar',
            'order_id': '0xBEEF',
            'customer_id': 'CUST-EEF-DERP',
            'alarm_priority': 'low',
            'type': 'assignment',
            'node': 'TOK-CORE-1',
            'country': 'EE',
            'authoritative_source': 'unittest',
            'pool': self.pool_attrs['id']
            }

        # basic edit
        self.nipap.edit_prefix(self.auth, schema, { 'id': self.prefix_attrs['id'] }, data)
        p = self.nipap.list_prefix(self.auth, schema, {'id': self.prefix_attrs['id']})[0]
        # remove what we did not touch
        for k, v in data.keys():
            if k not in p:
                del p[k]
        self.assertEqual(data, p, "Prefix data incorrect after edit.")

        # create a collision
        self.assertRaises(NipapError, self.nipap.edit_prefix, self.auth, schema, {'id': self.prefix_attrs2['id']}, {'prefix': data['prefix']})

        # try to change schema - disallowed
        self.assertRaises(NipapExtraneousInputError, self.nipap_edit_prefix, self.auth, schema, {'id': self.prefix_attrs2['id']}, {'schema': self.schema_attrs2['id']})



    def test_add_asn(self):
        """ Test adding ASNs to NIPAP.
        """

        data = {
            'asn': 1,
            'name': 'Test ASN #1'
        }

        self.assertEqual(self.nipap.add_asn(self.auth, data), 1, "add_asn did not return correct ASN.")
        asn = self.nipap.list_asn(self.auth, { 'asn': 1 })[0]
        self.assertEquals(data, asn, "ASN in database not equal to what was added.")
        self.assertRaises(NipapDuplicateError, self.nipap.add_asn, self.auth, data)


    def test_remove_asn(self):
        """ Test removing ASNs from NIPAP.
        """

        data = {
            'asn': 2,
            'name': 'Test ASN #2'
        }

        asn = self.nipap.add_asn(self.auth, data)
        self.nipap.remove_asn(self.auth, asn)
        self.assertEquals(0, len(self.nipap.list_asn(self.auth, { 'asn': 2 })), "Removed ASN still in database")



    def test_edit_asn(self):
        """ Test editing ASNs.
        """

        data = {
            'asn': 3,
            'name': 'Test ASN #3'
        }

        asn = self.nipap.add_asn(self.auth, data)
        self.nipap.edit_asn(self.auth, data['asn'], { 'name': 'b0rk' })
        self.assertEquals(self.nipap.list_asn(self.auth, { 'asn': 3 })[0]['name'], 'b0rk', "Edited ASN still has it's old name.")
        self.assertRaises(NipapExtraneousInputError, self.nipap.edit_asn, self.auth, {'asn': 3}, {'asn': 4, 'name': 'Test ASN #4'})



    def test_search_asn(self):
        """ Test searching ASNs.
        """

        data = {
            'asn': 4,
            'name': 'This is AS number 4'
        }

        asn = self.nipap.add_asn(self.auth, data)
        q = {
            'operator': 'equals',
            'val1': 'asn',
            'val2': data['asn']
        }
        res = self.nipap.search_asn(self.auth, q)
        self.assertEquals(len(res['result']), 1, "equal search resulted in wrong number of hits")
        self.assertEquals(res['result'][0]['name'], data['name'], "search hit got wrong name")

        q = {
            'operator': 'regex_match',
            'val1': 'name',
            'val2': 'number'
        }
        res = self.nipap.search_asn(self.auth, q)
        self.assertEquals(len(res['result']), 1, "regex search resulted in wrong number of hits")
        self.assertEquals(res['result'][0]['asn'], data['asn'], "search hit got wrong asn")



    def test_smart_search_asn(self):
        """ Test smart_search_asn function.
        """

        data = {
            'asn': 5,
            'name': 'Autonomous System Number 5'
        }

        asn = self.nipap.add_asn(self.auth, data)
        res = self.nipap.smart_search_asn(self.auth, "Autonomous")
        self.assertEquals(len(res['result']), 1, "search resulted in wrong number of hits")
        self.assertEquals(res['result'][0]['asn'], data['asn'], "search hit got wrong asn")
        self.assertEquals(res['interpretation'][0]['attribute'], 'name', "search term interpretated as wrong type")

        res = self.nipap.smart_search_asn(self.auth, "5")
        self.assertEquals(len(res['result']), 1, "search resulted in wrong number of hits")
        self.assertEquals(res['result'][0]['asn'], data['asn'], "search hit got wrong asn")
        self.assertEquals(res['interpretation'][0]['attribute'], 'asn', "search term interpretated as wrong type")
Exemplo n.º 11
0
class NipapXmlTest(unittest.TestCase):
    """ Tests the NIPAP XML-RPC daemon

        We presume the database is empty
    """
    maxDiff = None

    logger = None
    cfg = None
    nipap = None

    def setUp(self):

        # logging
        self.logger = logging.getLogger(self.__class__.__name__)

        # NIPAP
        self.cfg = NipapConfig('/etc/nipap/nipap.conf')
        self.nipap = Nipap()

        # create dummy auth object
        # As the authentication is performed before the query hits the Nipap
        # class, it does not matter what user we use here
        self.auth = SqliteAuth('local', 'unittest', 'unittest', 'unittest')
        self.auth.authenticated_as = 'unittest'
        self.auth.full_name = 'Unit test'

        # have to delete hosts before we can delete the rest
        self.nipap._execute("DELETE FROM ip_net_plan WHERE masklen(prefix) = 32")
        # the rest
        self.nipap._execute("DELETE FROM ip_net_plan")
        # delete all except for the default VRF with id 0
        self.nipap._execute("DELETE FROM ip_net_vrf WHERE id > 0")
        # set default info for VRF 0
        self.nipap._execute("UPDATE ip_net_vrf SET name = 'default', description = 'The default VRF, typically the Internet.' WHERE id = 0")
        self.nipap._execute("DELETE FROM ip_net_pool")
        self.nipap._execute("DELETE FROM ip_net_asn")


    def _mangle_pool_result(self, res):
        """ Mangle pool result for easier testing

            We can never predict the values of things like the ID (okay, that
            one is actually kind of doable) or the added and last_modified
            timestamp. This function will make sure the values are present but
            then strip them to make it easier to test against an expected
            result.

            All testing of statistics is done in nipaptest.py so we strip that
            from the result here to make things simple.
        """

        if isinstance(res, list):
            # res from list_pool
            for p in res:
                self.assertIn('total_addresses_v4', p)
                self.assertIn('total_addresses_v6', p)
                self.assertIn('used_addresses_v4', p)
                self.assertIn('used_addresses_v6', p)
                self.assertIn('free_addresses_v4', p)
                self.assertIn('free_addresses_v6', p)
                self.assertIn('member_prefixes_v4', p)
                self.assertIn('member_prefixes_v6', p)
                self.assertIn('used_prefixes_v4', p)
                self.assertIn('used_prefixes_v6', p)
                self.assertIn('free_prefixes_v4', p)
                self.assertIn('free_prefixes_v6', p)
                self.assertIn('total_prefixes_v4', p)
                self.assertIn('total_prefixes_v6', p)
                del(p['total_addresses_v4'])
                del(p['total_addresses_v6'])
                del(p['used_addresses_v4'])
                del(p['used_addresses_v6'])
                del(p['free_addresses_v4'])
                del(p['free_addresses_v6'])
                del(p['member_prefixes_v4'])
                del(p['member_prefixes_v6'])
                del(p['used_prefixes_v4'])
                del(p['used_prefixes_v6'])
                del(p['free_prefixes_v4'])
                del(p['free_prefixes_v6'])
                del(p['total_prefixes_v4'])
                del(p['total_prefixes_v6'])

        elif isinstance(res, dict) and 'result' in res:
            # res from smart search
            for p in res['result']:
                self.assertIn('total_addresses_v4', p)
                self.assertIn('total_addresses_v6', p)
                self.assertIn('used_addresses_v4', p)
                self.assertIn('used_addresses_v6', p)
                self.assertIn('free_addresses_v4', p)
                self.assertIn('free_addresses_v6', p)
                self.assertIn('member_prefixes_v4', p)
                self.assertIn('member_prefixes_v6', p)
                self.assertIn('used_prefixes_v4', p)
                self.assertIn('used_prefixes_v6', p)
                self.assertIn('free_prefixes_v4', p)
                self.assertIn('free_prefixes_v6', p)
                self.assertIn('total_prefixes_v4', p)
                self.assertIn('total_prefixes_v6', p)
                del(p['total_addresses_v4'])
                del(p['total_addresses_v6'])
                del(p['used_addresses_v4'])
                del(p['used_addresses_v6'])
                del(p['free_addresses_v4'])
                del(p['free_addresses_v6'])
                del(p['member_prefixes_v4'])
                del(p['member_prefixes_v6'])
                del(p['used_prefixes_v4'])
                del(p['used_prefixes_v6'])
                del(p['free_prefixes_v4'])
                del(p['free_prefixes_v6'])
                del(p['total_prefixes_v4'])
                del(p['total_prefixes_v6'])

        elif isinstance(res, dict):
            # just one single pool
            self.assertIn('total_addresses_v4', res)
            self.assertIn('total_addresses_v6', res)
            self.assertIn('used_addresses_v4', res)
            self.assertIn('used_addresses_v6', res)
            self.assertIn('free_addresses_v4', res)
            self.assertIn('free_addresses_v6', res)
            self.assertIn('member_prefixes_v4', res)
            self.assertIn('member_prefixes_v6', res)
            self.assertIn('used_prefixes_v4', res)
            self.assertIn('used_prefixes_v6', res)
            self.assertIn('free_prefixes_v4', res)
            self.assertIn('free_prefixes_v6', res)
            self.assertIn('total_prefixes_v4', res)
            self.assertIn('total_prefixes_v6', res)
            del(res['total_addresses_v4'])
            del(res['total_addresses_v6'])
            del(res['used_addresses_v4'])
            del(res['used_addresses_v6'])
            del(res['free_addresses_v4'])
            del(res['free_addresses_v6'])
            del(res['member_prefixes_v4'])
            del(res['member_prefixes_v6'])
            del(res['used_prefixes_v4'])
            del(res['used_prefixes_v6'])
            del(res['free_prefixes_v4'])
            del(res['free_prefixes_v6'])
            del(res['total_prefixes_v4'])
            del(res['total_prefixes_v6'])

        return res


    def _mangle_prefix_result(self, res):
        """ Mangle prefix result for easier testing

            We can never predict the values of things like the ID (okay, that
            one is actually kind of doable) or the added and last_modified
            timestamp. This function will make sure the values are present but
            then strip them to make it easier to test against an expected
            result.

            All testing of statistics is done in nipaptest.py so we strip that
            from the result here to make things simple.
        """

        if isinstance(res, list):
            # res from list_prefix
            for p in res:
                self.assertIn('added', p)
                self.assertIn('last_modified', p)
                self.assertIn('total_addresses', p)
                self.assertIn('used_addresses', p)
                self.assertIn('free_addresses', p)
                del(p['added'])
                del(p['last_modified'])
                del(p['total_addresses'])
                del(p['used_addresses'])
                del(p['free_addresses'])

        elif isinstance(res, dict) and 'result' in res:
            # res from smart search
            for p in res['result']:
                self.assertIn('added', p)
                self.assertIn('last_modified', p)
                self.assertIn('total_addresses', p)
                self.assertIn('used_addresses', p)
                self.assertIn('free_addresses', p)
                del(p['added'])
                del(p['last_modified'])
                del(p['total_addresses'])
                del(p['used_addresses'])
                del(p['free_addresses'])

        elif isinstance(res, dict):
            # just one single prefix
            self.assertIn('added', res)
            self.assertIn('last_modified', res)
            self.assertIn('total_addresses', res)
            self.assertIn('used_addresses', res)
            self.assertIn('free_addresses', res)
            del(res['added'])
            del(res['last_modified'])
            del(res['total_addresses'])
            del(res['used_addresses'])
            del(res['free_addresses'])

        return res



    def _mangle_vrf_result(self, res):
        """ Mangle vrf result for easier testing

            We can never predict the values of things like the ID (okay, that
            one is actually kind of doable) or the added and last_modified
            timestamp. This function will make sure the values are present but
            then strip them to make it easier to test against an expected
            result.

            All testing of statistics is done in nipaptest.py so we strip that
            from the result here to make things simple.
        """

        if isinstance(res, list):
            # res from list_vrf
            for p in res:
                #self.assertIn('added', p)
                #self.assertIn('last_modified', p)
                self.assertIn('total_addresses_v4', p)
                self.assertIn('total_addresses_v6', p)
                self.assertIn('used_addresses_v4', p)
                self.assertIn('used_addresses_v6', p)
                self.assertIn('free_addresses_v4', p)
                self.assertIn('free_addresses_v6', p)
                self.assertIn('num_prefixes_v4', p)
                self.assertIn('num_prefixes_v6', p)
                #del(p['added'])
                #del(p['last_modified'])
                del(p['total_addresses_v4'])
                del(p['total_addresses_v6'])
                del(p['used_addresses_v4'])
                del(p['used_addresses_v6'])
                del(p['free_addresses_v4'])
                del(p['free_addresses_v6'])
                del(p['num_prefixes_v4'])
                del(p['num_prefixes_v6'])

        elif isinstance(res, dict) and 'result' in res:
            # res from smart search
            for p in res['result']:
                #self.assertIn('added', p)
                #self.assertIn('last_modified', p)
                self.assertIn('total_addresses_v4', p)
                self.assertIn('total_addresses_v6', p)
                self.assertIn('used_addresses_v4', p)
                self.assertIn('used_addresses_v6', p)
                self.assertIn('free_addresses_v4', p)
                self.assertIn('free_addresses_v6', p)
                self.assertIn('num_prefixes_v4', p)
                self.assertIn('num_prefixes_v6', p)
                #del(p['added'])
                #del(p['last_modified'])
                del(p['total_addresses_v4'])
                del(p['total_addresses_v6'])
                del(p['used_addresses_v4'])
                del(p['used_addresses_v6'])
                del(p['free_addresses_v4'])
                del(p['free_addresses_v6'])
                del(p['num_prefixes_v4'])
                del(p['num_prefixes_v6'])

        elif isinstance(res, dict):
            # just one single vrf
            #self.assertIn('added', res)
            #self.assertIn('last_modified', res)
            self.assertIn('total_addresses_v4', res)
            self.assertIn('total_addresses_v6', res)
            self.assertIn('used_addresses_v4', res)
            self.assertIn('used_addresses_v6', res)
            self.assertIn('free_addresses_v4', res)
            self.assertIn('free_addresses_v6', res)
            self.assertIn('num_prefixes_v4', res)
            self.assertIn('num_prefixes_v6', res)
            #del(res['added'])
            #del(res['last_modified'])
            del(res['total_addresses_v4'])
            del(res['total_addresses_v6'])
            del(res['used_addresses_v4'])
            del(res['used_addresses_v6'])
            del(res['free_addresses_v4'])
            del(res['free_addresses_v6'])
            del(res['num_prefixes_v4'])
            del(res['num_prefixes_v6'])

        return res




    def test_vrf_add_list(self):
        """ Add a VRF and verify result in database
        """
        attr = {}
        with self.assertRaisesRegexp(xmlrpclib.Fault, 'missing attribute rt'):
            s.add_vrf({ 'auth': ad, 'attr': attr })

        attr['rt'] = '123:456'
        with self.assertRaisesRegexp(xmlrpclib.Fault, 'missing attribute name'):
            s.add_vrf({ 'auth': ad, 'attr': attr })
        attr['name'] = 'test'
        attr['tags'] = []

        attr['description'] = 'my test vrf'
        vrf = s.add_vrf({ 'auth': ad, 'attr': attr })

        self.assertGreater(vrf['id'], 0)

        ref = attr.copy()
        ref['id'] = vrf['id']
        self.assertEqual(self._mangle_vrf_result(vrf), ref)
        self.assertEqual(self._mangle_vrf_result(s.list_vrf({ 'auth': ad, 'vrf': { 'id': vrf['id'] } })), [ ref, ])

        attr['rt'] = '123:abc'
        with self.assertRaisesRegexp(xmlrpclib.Fault, '.'): # TODO: specify exception string
            s.add_vrf({ 'auth': ad, 'attr': attr })



    def test_vrf_edit_default(self):
        """ Edit the default VRF and verify the change
        """
        # try to set an RT, which should fail on the default VRF
        with self.assertRaisesRegexp(xmlrpclib.Fault, 'Invalid input for column rt, must be NULL for VRF id 0'):
            s.edit_vrf({ 'auth': ad, 'vrf': { 'id': 0 }, 'attr': { 'rt': '123:456a' }})

        res_edit = s.edit_vrf({ 'auth': ad, 'vrf': { 'id': 0 }, 'attr': {
            'name': 'FOO', 'description': 'BAR', 'tags': [] }})
        res_list = s.list_vrf({ 'auth': ad, 'vrf': { } })[0]
        del(res_list['id'])
        self.assertEqual(self._mangle_vrf_result(res_list), { 'rt': None,
            'name': 'FOO', 'description': 'BAR', 'tags': [] }, 'VRF change incorrect')



    def test_vrf_edit(self):
        """ Edit VRF and verify the change
        """
        attr = {
            'rt': '65000:123',
            'name': '65k:123',
            'description': 'VRF 65000:123',
            'tags': []
        }
        spec = { 'rt': '65000:123' }
        vrf = s.add_vrf({ 'auth': ad, 'attr': attr })

        # omitting VRF spec
        with self.assertRaisesRegexp(xmlrpclib.Fault, 'vrf specification must be a dict'):
            s.edit_vrf({ 'auth': ad, 'attr': { 'name': 'test_vrf_edit' } })

        # omitting VRF attributes
        with self.assertRaisesRegexp(xmlrpclib.Fault, 'invalid input type, must be dict'):
            s.edit_vrf({ 'auth': ad, 'vrf': spec })

        # specifying too many attributes in spec
        with self.assertRaisesRegexp(xmlrpclib.Fault, 'specification contains too many keys'):
            s.edit_vrf({ 'auth': ad, 'vrf': { 'rt': '65000:123', 'name': '65k:123' }, 'attr': {} })

        # test changing ID
        with self.assertRaisesRegexp(xmlrpclib.Fault, 'extraneous attribute'):
            s.edit_vrf({ 'auth': ad, 'vrf': spec, 'attr': { 'id': 1337 } })

        # empty attribute list
        with self.assertRaisesRegexp(xmlrpclib.Fault, "'attr' must not be empty."):
            s.edit_vrf({ 'auth': ad, 'vrf': spec, 'attr': {} })
        res = s.list_vrf({ 'auth': ad, 'vrf': spec })
        self.assertEquals(len(res), 1, 'wrong number of VRFs returned')
        res = res[0]
        del(res['id'])
        self.assertEqual(self._mangle_vrf_result(res), attr)

        # valid change
        attr['rt'] = '65000:1234'
        attr['name'] = '65k:1234'
        attr['description'] = 'VRF 65000:1234'
        attr['tags'] = []
        s.edit_vrf({ 'auth': ad, 'vrf': spec, 'attr': attr })

        # verify result of valid change
        res = s.list_vrf({ 'auth': ad, 'vrf': { 'rt': attr['rt'] } })
        self.assertEquals(len(res), 1, 'wrong number of VRFs returned')
        res = res[0]
        # ignore the ID
        del(res['id'])
        self.assertEqual(self._mangle_vrf_result(res), attr, 'VRF change incorrect')



    def test_vrf_add_search(self):
        """ Add VRF and search for it
        """

        # add VRF
        attr = {
            'rt': '65000:1235',
            'name': '65k:1235',
            'description': 'Virtual Routing and Forwarding instance 65000:123',
            'tags': []
        }
        vrf = s.add_vrf({ 'auth': ad, 'attr': attr })
        attr['id'] = vrf['id']

        # equal match
        q = {
            'operator': 'equals',
            'val1': 'rt',
            'val2': attr['rt']
        }
        res = self._mangle_vrf_result(s.search_vrf({ 'auth': ad, 'query': q }))
        self.assertEquals(res['result'], [ attr, ], 'Search result from equal match did not match')

        # regex match
        q = {
            'operator': 'regex_match',
            'val1': 'description',
            'val2': 'instance 65000'
        }
        res = self._mangle_vrf_result(s.search_vrf({ 'auth': ad, 'query': q }))
        self.assertEquals(res['result'], [ attr, ], 'Search result from regex match did not match')

        # smart search
        res = self._mangle_vrf_result(s.smart_search_vrf({ 'auth': ad, 'query_string': 'forwarding instance' }))
        self.assertEquals(res['result'], [ attr, ], 'Smart search result did not match')



    def test_prefix_add(self):
        """ Add a prefix and list
        """
        # check that some error / sanity checking is there
        attr = {}
        with self.assertRaisesRegexp(xmlrpclib.Fault, "specify 'prefix' or 'from-prefix' or 'from-pool'"):
            s.add_prefix({ 'auth': ad, 'attr': attr })

        attr['prefix'] = '1.3.3.0/24'
        with self.assertRaisesRegexp(xmlrpclib.Fault, "Either description or node must be specified."):
            s.add_prefix({ 'auth': ad, 'attr': attr })

        attr['description'] = 'test prefix'
        with self.assertRaisesRegexp(xmlrpclib.Fault, "Unknown prefix type"):
            s.add_prefix({ 'auth': ad, 'attr': attr })

        attr['type'] = 'assignment'

        # add 1.3.3.0/24
        prefix = s.add_prefix({ 'auth': ad, 'attr': attr })
        attr['id'] = prefix['id']
        self.assertGreater(attr['id'], 0)

        # what we expect the above prefix to look like
        expected = {
                'alarm_priority': None,
                'authoritative_source': 'nipap',
                'comment': None,
                'country': None,
                'description': 'test prefix',
                'display_prefix': '1.3.3.0/24',
                'external_key': None,
                'family': 4,
                'id': 131,
                'indent': 0,
                'inherited_tags': [],
                'monitor': None,
                'node': None,
                'order_id': None,
                'customer_id': None,
                'pool_name': None,
                'pool_id': None,
                'tags': [],
                'vrf_rt': None,
                'vrf_id': 0,
                'vrf_name': 'default',
                'vlan': None
            }
        expected.update(attr)
        self.assertEqual(
                self._mangle_prefix_result(s.list_prefix({ 'auth': ad })),
                [expected])

        attr = {
                'description': 'test for from-prefix 1.3.3.0/24',
                'type': 'host'
            }
        args = { 'from-prefix': ['1.3.3.0/24'], 'prefix_length': 32 }
        # add a host in 1.3.3.0/24
        res = s.add_prefix({ 'auth': ad, 'attr': attr, 'args': args })

        # copy expected from 1.3.3.0/24 since we expect most things to look the
        # same for the new prefix (1.3.3.1/32) from 1.3.3.0/24
        expected_host = expected.copy()
        expected_host.update(attr)
        expected_host['id'] = res['id']
        expected_host['prefix'] = '1.3.3.1/32'
        expected_host['display_prefix'] = '1.3.3.1/24'
        expected_host['indent'] = 1

        # build list of expected
        expected_list = []
        expected_list.append(expected)
        expected_list.append(expected_host)

        # add another prefix, try with vrf_id = None
        attr['vrf_id'] = None
        res = s.add_prefix({ 'auth': ad, 'attr': attr, 'args': args })
        # update expected list
        expected_host2 = expected_host.copy()
        expected_host2['id'] = res['id']
        expected_host2['prefix'] = '1.3.3.2/32'
        expected_host2['display_prefix'] = '1.3.3.2/24'
        expected_list.append(expected_host2)

        # add another prefix, this time completely without VRF info
        del(attr['vrf_id'])
        res = s.add_prefix({ 'auth': ad, 'attr': attr, 'args': args })
        # update expected list
        expected_host3 = expected_host.copy()
        expected_host3['id'] = res['id']
        expected_host3['prefix'] = '1.3.3.3/32'
        expected_host3['display_prefix'] = '1.3.3.3/24'
        expected_list.append(expected_host3)

        # add another prefix, based on VRF name
        attr['vrf_name'] = 'default'
        res = s.add_prefix({ 'auth': ad, 'attr': attr, 'args': args })
        # update expected list
        expected_host4 = expected_host.copy()
        expected_host4['id'] = res['id']
        expected_host4['prefix'] = '1.3.3.4/32'
        expected_host4['display_prefix'] = '1.3.3.4/24'
        expected_list.append(expected_host4)

        # make sure the result looks like we expect it too! :D
        self.assertEqual(
                self._mangle_prefix_result(s.list_prefix({ 'auth': ad })),
                expected_list)



    def test_prefix_add_vrf(self):
        """ Test adding prefixes to VRF
        """

        args = { 'from-prefix': ['1.3.3.0/24'], 'prefix_length': 32 }
        expected = {
                'alarm_priority': None,
                'authoritative_source': 'nipap',
                'comment': None,
                'country': None,
                'description': 'test prefix',
                'display_prefix': '1.3.3.0/24',
                'external_key': None,
                'family': 4,
                'id': 131,
                'indent': 0,
                'monitor': None,
                'node': None,
                'order_id': None,
                'customer_id': None,
                'pool_id': None,
                'pool_name': None,
                'vrf_id': 0,
                'vrf_rt': None,
                'vrf_name': None,
                'vlan': None,
                'inherited_tags': [],
                'tags': []
            }

        # add VRF
        vrf_attr = {
            'rt': '123:4567',
            'name': 'test_prefix_add_vrf1',
        }
        vrf = s.add_vrf({ 'auth': ad, 'attr': vrf_attr })
        vrf_attr['id'] = vrf['id']

        # add prefix to VRF by specifying ID
        vrf_pref_attr = {
            'prefix': '1.3.3.0/24',
            'vrf_id': vrf['id'],
            'type': 'assignment',
            'description': 'Test prefix 1.3.3.0/24 in vrf 123:4567'
        }
        prefix = s.add_prefix({ 'auth': ad, 'attr': vrf_pref_attr })
        expected['id'] = prefix['id']
        expected['vrf_rt'] = vrf_attr['rt']
        expected['vrf_name'] = vrf_attr['name']
        expected['display_prefix'] = '1.3.3.0/24'
        expected['indent'] = 0
        expected.update(vrf_pref_attr)

        vrf_pref = s.list_prefix({ 'auth': ad, 'prefix': { 'id': expected['id'] } })[0]
        vrf_pref = self._mangle_prefix_result(vrf_pref)
        self.assertEqual(vrf_pref, expected, 'Prefix added with VRF ID reference not equal')

        # add prefix to VRF by specifying VRF
        vrf_pref_attr = {
            'vrf_rt': vrf_attr['rt'],
            'type': 'host',
            'description': 'Test host 1.3.3.1/32 in vrf 123:4567'
        }
        prefix = s.add_prefix({ 'auth': ad, 'attr': vrf_pref_attr, 'args': args })
        expected['id'] = prefix['id']
        expected['vrf_id'] = vrf_attr['id']
        expected['vrf_name'] = vrf_attr['name']
        expected['display_prefix'] = '1.3.3.1/24'
        expected['prefix'] = '1.3.3.1/32'
        expected['indent'] = 1
        expected.update(vrf_pref_attr)

        vrf_pref = s.list_prefix({ 'auth': ad, 'prefix': { 'id': expected['id'] } })[0]
        vrf_pref = self._mangle_prefix_result(vrf_pref)
        self.assertEqual(vrf_pref, expected, 'Prefix added with VRF reference not equal')

        # add prefix to VRF by specifying VRF name
        vrf_pref_attr = {
            'vrf_name': vrf_attr['name'],
            'type': 'host',
            'description': 'Test host 1.3.3.2/32 in vrf 123:4567'
        }
        prefix = s.add_prefix({ 'auth': ad, 'attr': vrf_pref_attr, 'args': args })
        expected['id'] = prefix['id']
        expected['vrf_rt'] = vrf_attr['rt']
        expected['vrf_id'] = vrf_attr['id']
        expected['display_prefix'] = '1.3.3.2/24'
        expected['prefix'] = '1.3.3.2/32'
        expected['indent'] = 1
        expected.update(vrf_pref_attr)

        vrf_pref = s.list_prefix({ 'auth': ad, 'prefix': { 'id': expected['id'] } })[0]
        vrf_pref = self._mangle_prefix_result(vrf_pref)
        self.assertEqual(vrf_pref, expected, 'Prefix added with VRF name reference not equal')



    def test_prefix_add_tags(self):
        """ Verify tag inheritance works correctly
        """
        expected = []
        expected_top = {
                'alarm_priority': None,
                'authoritative_source': 'nipap',
                'comment': None,
                'country': None,
                'display_prefix': '1.0.0.0/8',
                'external_key': None,
                'family': 4,
                'id': 131,
                'indent': 0,
                'monitor': None,
                'node': None,
                'order_id': None,
                'customer_id': None,
                'pool_id': None,
                'pool_name': None,
                'vrf_id': 0,
                'vrf_rt': None,
                'vrf_name': 'default',
                'inherited_tags': [],
                'vlan': None
            }

        # add the "top" prefix - 1.0.0.0/8
        attr = {
                'prefix': '1.0.0.0/8',
                'description': 'top prefix',
                'type': 'reservation',
                'tags': ['top']
                }
        prefix = s.add_prefix({ 'auth': ad, 'attr': attr })
        expected_top.update(attr)
        expected_top['id'] = prefix['id']

        # add the "bottom" prefix 1.3.3.0/24
        attr = {
                'prefix': '1.3.3.0/24',
                'description': 'bottom prefix',
                'type': 'assignment',
                'tags': ['bottom'],
                }
        prefix = s.add_prefix({ 'auth': ad, 'attr': attr })
        expected_bottom = expected_top.copy()
        expected_bottom.update(attr)
        expected_bottom['id'] = prefix['id']
        expected_bottom['display_prefix'] = '1.3.3.0/24'
        expected_bottom['inherited_tags'] = ['top']
        expected_bottom['indent'] = 1

        # check the list is correct!
        expected = [ expected_top, expected_bottom ]
        self.assertEqual(
                self._mangle_prefix_result(s.list_prefix({ 'auth': ad })),
                expected)

        # add the "middle" prefix 1.3.0.0/16
        attr = {
                'prefix': '1.3.0.0/16',
                'description': 'middle prefix',
                'type': 'reservation',
                'tags': ['middle'],
                }
        prefix = s.add_prefix({ 'auth': ad, 'attr': attr })
        expected_middle = expected_top.copy()
        expected_middle.update(attr)
        expected_middle['id'] = prefix['id']
        expected_middle['display_prefix'] = '1.3.0.0/16'
        expected_middle['inherited_tags'] = ['top']
        expected_middle['indent'] = 1

        expected_bottom['inherited_tags'] = ['middle', 'top']
        expected_bottom['indent'] = 2

        # check the list is correct!
        expected = [ expected_top, expected_middle, expected_bottom ]
        self.assertEqual(
                self._mangle_prefix_result(s.list_prefix({ 'auth': ad })),
                expected)

        # remove middle prefix
        s.remove_prefix({ 'auth': ad, 'prefix': { 'id': expected_middle['id'] } })
        expected_bottom['inherited_tags'] = ['top']
        expected_bottom['indent'] = 1

        # check the list is correct!
        expected = [ expected_top, expected_bottom ]
        self.assertEqual(
                self._mangle_prefix_result(s.list_prefix({ 'auth': ad })),
                expected)

        # remove top prefix
        s.remove_prefix({ 'auth': ad, 'prefix': { 'id': expected_top['id'] } })
        expected_bottom['inherited_tags'] = []
        expected_bottom['indent'] = 0

        # check the list is correct!
        expected = [ expected_bottom ]
        self.assertEqual(
                self._mangle_prefix_result(s.list_prefix({ 'auth': ad })),
                expected)



    def test_prefix_node(self):
        """ Test node constraints

            Setting the node value is not allowed for all prefix types. Make
            sure the constraints are working correctly.
        """
        expected = {
                'alarm_priority': None,
                'authoritative_source': 'nipap',
                'comment': None,
                'country': None,
                'type': 'assignment',
                'description': 'test prefix',
                'display_prefix': '1.3.2.0/24',
                'external_key': None,
                'family': 4,
                'indent': 0,
                'inherited_tags': [],
                'monitor': None,
                'node': None,
                'order_id': None,
                'customer_id': None,
                'pool_name': None,
                'pool_id': None,
                'tags': [],
                'vrf_rt': None,
                'vrf_id': 0,
                'vrf_name': 'default',
                'vlan': None
            }
        expected_list = []

        attr = {}
        attr['prefix'] = '1.3.2.0/24'
        attr['description'] = 'test prefix'
        attr['type'] = 'assignment'
        # add an assignment which we need later on
        res = s.add_prefix({ 'auth': ad, 'attr': attr })
        exp1 = expected.copy()
        exp1.update(attr)
        exp1['id'] = res['id']

        attr['prefix'] = '1.3.3.0/24'

        # set node
        attr['node'] = 'test'

        # node value is not allowed at all for prefixes of type reservation
        attr['type'] = 'reservation'
        with self.assertRaisesRegexp(xmlrpclib.Fault, "Not allowed to set 'node' value for prefixes of type 'reservation'."):
            s.add_prefix({ 'auth': ad, 'attr': attr })

        # node value is only allowed for assignments when prefix-length is max
        # (/24 for IPv4 or /128 for IPv6).
        attr['type'] = 'assignment'
        with self.assertRaisesRegexp(xmlrpclib.Fault, "Not allowed to set 'node' value for prefixes of type 'assignment' which do not have all bits set in netmask."):
            s.add_prefix({ 'auth': ad, 'attr': attr })

        # correct prefix length
        attr['prefix'] = '1.3.3.0/32'
        res = s.add_prefix({ 'auth': ad, 'attr': attr })

        exp2 = expected.copy()
        exp2.update(attr)
        exp2['id'] = res['id']
        exp2['display_prefix'] = '1.3.3.0'

        # let's add a host too
        attr['type'] = 'host'
        attr['prefix'] = '1.3.2.1/32'
        res = s.add_prefix({ 'auth': ad, 'attr': attr })

        exp3 = expected.copy()
        exp3.update(attr)
        exp3['id'] = res['id']
        exp3['display_prefix'] = '1.3.2.1/24'
        exp3['indent'] = 1

        # note the non-intuitive order
        expected_list.append(exp1)
        expected_list.append(exp3)
        expected_list.append(exp2)

        res = self._mangle_prefix_result(s.list_prefix({ 'auth': ad }))
        self.assertEqual(res, expected_list)



    def test_prefix_add_to_pool(self):
        """ Test adding prefixes to a pool
        """
        # Add a pool
        pool_attr = {
            'name'          : 'pool_1',
            'description'   : 'Test pool #1',
            'default_type'  : 'assignment',
            'ipv4_default_prefix_length' : 24
        }
        pool = s.add_pool({ 'auth': ad, 'attr': pool_attr })

        # Add prefix to pool
        prefix_attr = {
                'prefix': '1.3.0.0/16',
                'type': 'reservation',
                'description': 'FOO',
                'pool_id': pool['id']
            }
        s.add_prefix({ 'auth': ad, 'attr': prefix_attr })

        # Add prefix to pool
        prefix_attr = {
                'prefix': '1.4.0.0/16',
                'type': 'reservation',
                'description': 'FOO',
                'pool_name': 'pool_1'
            }
        s.add_prefix({ 'auth': ad, 'attr': prefix_attr })

        # add a prefix
        prefix_attr = {
                'prefix': '1.5.0.0/16',
                'type': 'reservation',
                'description': 'FOO'
            }
        prefix = s.add_prefix({ 'auth': ad, 'attr': prefix_attr })
        # modify prefix so that it's part of pool
        s.edit_prefix({ 'auth': ad, 'prefix': { 'id': prefix['id'] }, 'attr': { 'pool_id': pool['id'] } })

        # add a prefix
        prefix_attr = {
                'prefix': '1.6.0.0/16',
                'type': 'reservation',
                'description': 'FOO'
            }
        prefix = s.add_prefix({ 'auth': ad, 'attr': prefix_attr })
        # modify prefix so that it's part of pool
        s.edit_prefix({ 'auth': ad, 'prefix': { 'id': prefix['id'] }, 'attr': { 'pool_name': 'pool_1' } })

        res = s.list_pool({ 'auth': ad, 'pool': { 'id': pool['id'] } })
        self.assertEquals(res[0]['prefixes'], ['1.3.0.0/16', '1.4.0.0/16',
        '1.5.0.0/16', '1.6.0.0/16'])



    def test_prefix_from_pool(self):
        """ Add a prefix from a pool
        """

        # Add a pool
        pool_attr = {
            'name'          : 'pool_1',
            'description'   : 'Test pool #1',
            'default_type'  : 'assignment',
            'ipv4_default_prefix_length' : 24
        }
        pool = s.add_pool({ 'auth': ad, 'attr': pool_attr })

        # Add prefix to pool
        parent_prefix_attr = {
                'prefix': '1.3.0.0/16',
                'type': 'reservation',
                'description': 'FOO',
                'pool_id': pool['id']
            }
        s.add_prefix({ 'auth': ad, 'attr': parent_prefix_attr })

        args = { 'from-pool': { 'name': 'pool_1' },
                'family': 4 }
        prefix_attr = {
                'description': 'BAR'
                }
        expected = {
                'prefix': '1.3.0.0/24',
                'display_prefix': '1.3.0.0/24',
                'description': 'BAR',
                'type': 'assignment',
                'comment': None,
                'country': None,
                'monitor': None,
                'node': None,
                'order_id': None,
                'customer_id': None,
                'pool_id': None,
                'pool_name': None,
                'vrf_id': 0,
                'vrf_rt': None,
                'vrf_name': 'default',
                'external_key': None,
                'family': 4,
                'indent': 1,
                'alarm_priority': None,
                'authoritative_source': 'nipap'
                }
        child = s.add_prefix({ 'auth': ad, 'attr': prefix_attr, 'args': args })
        #expected['id'] = child['id']
        #p = s.list_prefix({ 'auth': ad, 'attr': { 'id': child['id'] } })[1]
        #self.assertEquals(p, expected)



    def test_prefix_from_pool_vrf(self):
        """ Add a prefix from a pool in a VRF
        """

        # Add a VRF
        vrf_attr = {
            'name'          : 'vrf_1',
            'description'   : 'Test VRF #1',
            'rt'            : '123:123'
        }
        vrf = s.add_vrf({ 'auth': ad, 'attr': vrf_attr })

        # Add a pool
        pool_attr = {
            'name'          : 'pool_1',
            'description'   : 'Test pool for from-pool test',
            'default_type'  : 'assignment',
            'ipv4_default_prefix_length' : 24
        }
        pool = s.add_pool({ 'auth': ad, 'attr': pool_attr })

        # Add prefix to pool
        parent_prefix_attr = {
                'prefix': '1.3.0.0/16',
                'vrf_rt': '123:123',
                'type': 'reservation',
                'description': 'FOO',
                'pool_id': pool['id']
            }
        s.add_prefix({ 'auth': ad, 'attr': parent_prefix_attr })

        args = { 'from-pool': { 'name': 'pool_1' },
                'family': 4 }
        prefix_attr = {
                'description': 'BAR'
                }
        expected = {
                'prefix': '1.3.0.0/24',
                'display_prefix': '1.3.0.0/24',
                'description': 'BAR',
                'type': 'assignment',
                'comment': None,
                'country': None,
                'monitor': None,
                'node': None,
                'order_id': None,
                'customer_id': None,
                'pool_id': None,
                'pool_name': None,
                'vrf_id': vrf['id'],
                'vrf_rt': '123:123',
                'vrf_name': 'vrf_1',
                'external_key': None,
                'family': 4,
                'indent': 1,
                'alarm_priority': None,
                'authoritative_source': 'nipap',
                'vlan': None,
                'inherited_tags': [],
                'tags': []
                }
        child = s.add_prefix({ 'auth': ad, 'attr': prefix_attr, 'args': args })
        expected['id'] = child['id']
        p = s.list_prefix({ 'auth': ad, 'attr': { 'id': child['id'] } })[1]
        p = self._mangle_prefix_result(p)
        self.assertEquals(p, expected)



    def test_prefix_edit_return(self):
        """ Check return value of edit_prefix
        """
        p1 = s.add_prefix({ 'auth': ad, 'attr': {
                'prefix': '1.3.3.0/24',
                'type': 'assignment',
                'description': 'FOO'
            } })
        p2 = s.add_prefix({ 'auth': ad, 'attr': {
                'prefix': '1.3.3.1/32',
                'type': 'host',
                'description': 'child 1'
            } })
        p3 = s.add_prefix({ 'auth': ad, 'attr': {
                'prefix': '1.3.3.2/32',
                'type': 'host',
                'description': 'child 2'
            } })
        p4 = s.add_prefix({ 'auth': ad, 'attr': {
                'prefix': '1.3.3.3/32',
                'type': 'host',
                'description': 'child 3'
            } })

        ss_res = s.smart_search_prefix({ 'auth': ad, 'query_string': 'child 2'
            })['result'][0]
        edit_res = s.edit_prefix({ 'auth': ad,
            'prefix': { 'prefix': '1.3.3.2/32' },
            'attr': { 'description': 'Kid 2' } })[0]
        del(edit_res['added'])
        del(edit_res['last_modified'])
        del(ss_res['added'])
        del(ss_res['last_modified'])
        ss_res['description'] = 'Kid 2'
        self.assertEqual(ss_res, edit_res)



    def test_prefix_smart_search(self):
        """ Test the prefix smart search
        """
        p1 = s.add_prefix({ 'auth': ad, 'attr': {
                'prefix': '1.3.3.0/24',
                'type': 'assignment',
                'description': 'FOO'
            } })

        s.add_prefix({ 'auth': ad, 'attr': {
                'prefix': '1.3.3.0/32',
                'type': 'host',
                'description': 'BAR'
            } })

        res = s.smart_search_prefix({ 'auth': ad, 'query_string': 'F' })
        expected = {
                'interpretation': [{'operator': 'regex', 'attribute':
                    'description or comment or node or order_id or customer_id', 'interpretation':
                    'text', 'string': 'F'}],
                'search_options': {'include_all_children':
                False, 'max_result': 50, 'include_all_parents': False,
                'parents_depth': 0, 'offset': 0, 'children_depth': 0,
                'parent_prefix': None, 'include_neighbors': False },
                'result': [
                    {'comment': None,
                        'external_key': None,
                        'family': 4,
                        'prefix': '1.3.3.0/24',
                        'authoritative_source': 'nipap',
                        'id': p1['id'],
                        'display_prefix': '1.3.3.0/24',
                        'monitor': None,
                        'children': 1,
                        'prefix_length': 24,
                        'type': 'assignment',
                        'match': True,
                        'node': None,
                        'description': 'FOO',
                        'order_id': None,
                        'customer_id': None,
                        'vrf_id': 0,
                        'vrf_rt': None,
                        'vrf_name': 'default',
                        'pool_id': None,
                        'pool_name': None,
                        'alarm_priority': None,
                        'indent': 0,
                        'country': None,
                        'display': True,
                        'vlan': None,
                        'inherited_tags': [],
                        'tags': []
                        }
                    ]
            }
        res = self._mangle_prefix_result(res)
        self.assertEqual(res, expected)



    def test_asn_add_list(self):
        """ Add ASN to NIPAP and list it
        """

        attr = {
            'asn': 1,
            'name': 'Test ASN #1'
        }

        # add ASN
        self.assertEqual(s.add_asn({ 'auth': ad, 'attr': attr}), attr, "add_asn did not return correct ASN.")

        # make sure that it got added
        asn = s.list_asn({ 'auth': ad, 'asn': { 'asn': 1 } })
        self.assertEqual(len(asn), 1, "Wrong number of ASNs returned.")
        asn = asn[0]
        self.assertEquals(attr, asn, "ASN in database not equal to what was added.")

        # adding the same ASN again should result in duplicate key error
        with self.assertRaisesRegexp(xmlrpclib.Fault, 'Duplicate value for'):
            s.add_asn({ 'auth': ad, 'attr': attr })



    def test_remove_asn(self):
        """ Remove ASN from NIPAP
        """

        attr = {
            'asn': 2,
            'name': 'Test ASN #2'
        }

        asn = s.add_asn({ 'auth': ad, 'attr': attr })
        s.remove_asn({ 'auth': ad, 'asn': { 'asn': asn['asn'] } })
        self.assertEquals(0, len(s.list_asn({ 'auth': ad, 'asn': { 'asn': 2 } })), "Removed ASN still in database")



    def test_edit_asn(self):
        """ Edit ASNs
        """

        attr = {
            'asn': 3,
            'name': 'Test ASN #3'
        }

        asn = s.add_asn({ 'auth': ad, 'attr': attr })
        s.edit_asn({ 'auth': ad, 'asn': { 'asn': attr['asn'] }, 'attr': { 'name': 'b0rk' } })
        self.assertEquals(s.list_asn({ 'auth': ad, 'asn': { 'asn': 3 } })[0]['name'], 'b0rk', "Edited ASN still has it's old name.")
        with self.assertRaisesRegexp(xmlrpclib.Fault, 'extraneous attribute'):
            s.edit_asn({ 'auth': ad, 'asn': { 'asn': 3 }, 'attr': {'asn': 4, 'name': 'Test ASN #4'} })



    def test_search_asn(self):
        """ Search ASNs
        """

        attr = {
            'asn': 4,
            'name': 'This is AS number 4'
        }

        asn = s.add_asn({ 'auth': ad, 'attr': attr })

        # equal match
        q = {
            'operator': 'equals',
            'val1': 'asn',
            'val2': attr['asn']
        }
        res = s.search_asn({ 'auth': ad, 'query': q })
        self.assertEquals(len(res['result']), 1, "equal search resulted in wrong number of hits")
        self.assertEquals(res['result'][0]['name'], attr['name'], "search hit got wrong name")

        # regexp match
        q = {
            'operator': 'regex_match',
            'val1': 'name',
            'val2': 'number'
        }
        res = s.search_asn({ 'auth': ad, 'query': q })
        self.assertEquals(len(res['result']), 1, "regex search resulted in wrong number of hits")
        self.assertEquals(res['result'][0]['asn'], attr['asn'], "search hit got wrong asn")



    def test_smart_search_asn(self):
        """ Test smart_search_asn function.
        """

        attr = {
            'asn': 5,
            'name': 'Autonomous System Number 5'
        }

        asn = s.add_asn({ 'auth': ad, 'attr': attr })
        res = s.smart_search_asn({ 'auth': ad, 'query_string': "Autonomous" })
        self.assertEquals(len(res['result']), 1, "search resulted in wrong number of hits")
        self.assertEquals(res['result'][0]['asn'], attr['asn'], "search hit got wrong asn")
        self.assertEquals(res['interpretation'][0]['attribute'], 'name', "search term interpretated as wrong type")

        res = s.smart_search_asn({ 'auth': ad, 'query_string': "5" })
        self.assertEquals(len(res['result']), 1, "search resulted in wrong number of hits")
        self.assertEquals(res['result'][0]['asn'], attr['asn'], "search hit got wrong asn")
        self.assertEquals(res['interpretation'][0]['attribute'], 'asn', "search term interpretated as wrong type")



    def test_pool_add_list(self):
        """ Test adding a pool and verifying it
        """

        # Add a pool
        attr = {
            'description': 'Test pool #1',
            'default_type': 'assignment',
            'ipv4_default_prefix_length': 31,
            'ipv6_default_prefix_length': 112
        }

        with self.assertRaisesRegexp(xmlrpclib.Fault, 'missing attribute name'):
            s.add_pool({ 'auth': ad, 'attr': attr })

        attr['name'] = 'pool_1'
        attr['ipv4_default_prefix_length'] = 50
        with self.assertRaisesRegexp(xmlrpclib.Fault, '1200: \'Default IPv4 prefix length must be an integer between 1 and 32.'):
            s.add_pool({ 'auth': ad, 'attr': attr })

        attr['ipv4_default_prefix_length'] = 31
        attr['ipv6_default_prefix_length'] = 'over 9000'
        with self.assertRaisesRegexp(xmlrpclib.Fault, '1200: \'Default IPv6 prefix length must be an integer between 1 and 128.'):
            s.add_pool({ 'auth': ad, 'attr': attr })

        attr['ipv6_default_prefix_length'] = 112

        res = s.add_pool({ 'auth': ad, 'attr': attr })
        expected = attr.copy()
        expected['id'] = res['id']
        expected['prefixes'] = []
        expected['vrf_id'] = None
        expected['vrf_rt'] = None
        expected['vrf_name'] = None
        expected['tags'] = []

        # list pool and verify data in NIPAP
        p = s.list_pool({ 'auth': ad, 'pool': { 'id': expected['id'] } })
        self.assertEquals(1, len(p), 'Wrong number of pools returned')
        p = p[0]

        self.assertEquals(self._mangle_pool_result(p), expected, 'Received pool differs from added pool')


    def test_edit_pool(self):
        """ Test editing a pool
        """

        # add a pool, we need something to edit
        attr = {
            'name': 'test_pool_2',
            'description': 'Test pool #2',
            'default_type': 'reservation',
            'ipv4_default_prefix_length': 31,
            'ipv6_default_prefix_length': 112
        }

        attr2 = {
            'name': 'test_pool_2_edit',
            'description': 'Test pool #2 edit',
            'default_type': 'assignment',
            'ipv4_default_prefix_length': 30,
            'ipv6_default_prefix_length': 96
        }

        res = s.add_pool({ 'auth': ad, 'attr': attr })
        s.edit_pool({ 'auth': ad, 'pool': { 'id': res['id'] }, 'attr': attr2 })

        expected = attr2.copy()
        expected['id'] = res['id']
        expected['prefixes'] = []
        expected['vrf_id'] = None
        expected['vrf_rt'] = None
        expected['vrf_name'] = None
        expected['tags'] = []

        self.assertEquals(self._mangle_pool_result(s.list_pool({ 'auth': ad,
            'pool': { 'id': res['id'] } })[0]), expected)


    def test_search_pool(self):
        """ Test searching pools
        """


    def test_smart_search_pool(self):
        """ Test smart searching among pools
        """


    def test_remove_pool(self):
        """ Test removing pools
Exemplo n.º 12
0
class NipapXmlTest(unittest.TestCase):
    """ Tests the NIPAP XML-RPC daemon

        We presume the database is empty
    """
    maxDiff = None

    logger = None
    cfg = None
    nipap = None

    def setUp(self):

        # logging
        self.logger = logging.getLogger(self.__class__.__name__)

        # NIPAP
        self.cfg = NipapConfig('/etc/nipap/nipap.conf')
        self.nipap = Nipap()

        # create dummy auth object
        # As the authentication is performed before the query hits the Nipap
        # class, it does not matter what user we use here
        self.auth = SqliteAuth('local', 'unittest', 'unittest', 'unittest')
        self.auth.authenticated_as = 'unittest'
        self.auth.full_name = 'Unit test'

        # have to delete hosts before we can delete the rest
        self.nipap._execute("DELETE FROM ip_net_plan WHERE masklen(prefix) = 32")
        # the rest
        self.nipap._execute("DELETE FROM ip_net_plan")
        # delete all except for the default VRF with id 0
        self.nipap._execute("DELETE FROM ip_net_vrf WHERE id > 0")
        # set default info for VRF 0
        self.nipap._execute("UPDATE ip_net_vrf SET name = 'default', description = 'The default VRF, typically the Internet.' WHERE id = 0")
        self.nipap._execute("DELETE FROM ip_net_pool")
        self.nipap._execute("DELETE FROM ip_net_asn")


    def _mangle_pool_result(self, res):
        """ Mangle pool result for easier testing

            We can never predict the values of things like the ID (okay, that
            one is actually kind of doable) or the added and last_modified
            timestamp. This function will make sure the values are present but
            then strip them to make it easier to test against an expected
            result.

            All testing of statistics is done in nipaptest.py so we strip that
            from the result here to make things simple.
        """

        if isinstance(res, list):
            # res from list_pool
            for p in res:
                self.assertIn('total_addresses_v4', p)
                self.assertIn('total_addresses_v6', p)
                self.assertIn('used_addresses_v4', p)
                self.assertIn('used_addresses_v6', p)
                self.assertIn('free_addresses_v4', p)
                self.assertIn('free_addresses_v6', p)
                self.assertIn('member_prefixes_v4', p)
                self.assertIn('member_prefixes_v6', p)
                self.assertIn('used_prefixes_v4', p)
                self.assertIn('used_prefixes_v6', p)
                del(p['total_addresses_v4'])
                del(p['total_addresses_v6'])
                del(p['used_addresses_v4'])
                del(p['used_addresses_v6'])
                del(p['free_addresses_v4'])
                del(p['free_addresses_v6'])
                del(p['member_prefixes_v4'])
                del(p['member_prefixes_v6'])
                del(p['used_prefixes_v4'])
                del(p['used_prefixes_v6'])

        elif isinstance(res, dict) and 'result' in res:
            # res from smart search
            for p in res['result']:
                self.assertIn('total_addresses_v4', p)
                self.assertIn('total_addresses_v6', p)
                self.assertIn('used_addresses_v4', p)
                self.assertIn('used_addresses_v6', p)
                self.assertIn('free_addresses_v4', p)
                self.assertIn('free_addresses_v6', p)
                self.assertIn('member_prefixes_v4', p)
                self.assertIn('member_prefixes_v6', p)
                self.assertIn('used_prefixes_v4', p)
                self.assertIn('used_prefixes_v6', p)
                del(p['total_addresses_v4'])
                del(p['total_addresses_v6'])
                del(p['used_addresses_v4'])
                del(p['used_addresses_v6'])
                del(p['free_addresses_v4'])
                del(p['free_addresses_v6'])
                del(p['member_prefixes_v4'])
                del(p['member_prefixes_v6'])
                del(p['used_prefixes_v4'])
                del(p['used_prefixes_v6'])

        elif isinstance(res, dict):
            # just one single pool
            self.assertIn('total_addresses_v4', res)
            self.assertIn('total_addresses_v6', res)
            self.assertIn('used_addresses_v4', res)
            self.assertIn('used_addresses_v6', res)
            self.assertIn('free_addresses_v4', res)
            self.assertIn('free_addresses_v6', res)
            self.assertIn('member_prefixes_v4', res)
            self.assertIn('member_prefixes_v6', res)
            self.assertIn('used_prefixes_v4', res)
            self.assertIn('used_prefixes_v6', res)
            del(res['total_addresses_v4'])
            del(res['total_addresses_v6'])
            del(res['used_addresses_v4'])
            del(res['used_addresses_v6'])
            del(res['free_addresses_v4'])
            del(res['free_addresses_v6'])
            del(res['member_prefixes_v4'])
            del(res['member_prefixes_v6'])
            del(res['used_prefixes_v4'])
            del(res['used_prefixes_v6'])

        return res


    def _mangle_prefix_result(self, res):
        """ Mangle prefix result for easier testing

            We can never predict the values of things like the ID (okay, that
            one is actually kind of doable) or the added and last_modified
            timestamp. This function will make sure the values are present but
            then strip them to make it easier to test against an expected
            result.

            All testing of statistics is done in nipaptest.py so we strip that
            from the result here to make things simple.
        """

        if isinstance(res, list):
            # res from list_prefix
            for p in res:
                self.assertIn('added', p)
                self.assertIn('last_modified', p)
                self.assertIn('total_addresses', p)
                self.assertIn('used_addresses', p)
                self.assertIn('free_addresses', p)
                del(p['added'])
                del(p['last_modified'])
                del(p['total_addresses'])
                del(p['used_addresses'])
                del(p['free_addresses'])

        elif isinstance(res, dict) and 'result' in res:
            # res from smart search
            for p in res['result']:
                self.assertIn('added', p)
                self.assertIn('last_modified', p)
                self.assertIn('total_addresses', p)
                self.assertIn('used_addresses', p)
                self.assertIn('free_addresses', p)
                del(p['added'])
                del(p['last_modified'])
                del(p['total_addresses'])
                del(p['used_addresses'])
                del(p['free_addresses'])

        elif isinstance(res, dict):
            # just one single prefix
            self.assertIn('added', res)
            self.assertIn('last_modified', res)
            self.assertIn('total_addresses', res)
            self.assertIn('used_addresses', res)
            self.assertIn('free_addresses', res)
            del(res['added'])
            del(res['last_modified'])
            del(res['total_addresses'])
            del(res['used_addresses'])
            del(res['free_addresses'])

        return res



    def _mangle_vrf_result(self, res):
        """ Mangle vrf result for easier testing

            We can never predict the values of things like the ID (okay, that
            one is actually kind of doable) or the added and last_modified
            timestamp. This function will make sure the values are present but
            then strip them to make it easier to test against an expected
            result.

            All testing of statistics is done in nipaptest.py so we strip that
            from the result here to make things simple.
        """

        if isinstance(res, list):
            # res from list_vrf
            for p in res:
                #self.assertIn('added', p)
                #self.assertIn('last_modified', p)
                self.assertIn('total_addresses_v4', p)
                self.assertIn('total_addresses_v6', p)
                self.assertIn('used_addresses_v4', p)
                self.assertIn('used_addresses_v6', p)
                self.assertIn('free_addresses_v4', p)
                self.assertIn('free_addresses_v6', p)
                self.assertIn('num_prefixes_v4', p)
                self.assertIn('num_prefixes_v6', p)
                #del(p['added'])
                #del(p['last_modified'])
                del(p['total_addresses_v4'])
                del(p['total_addresses_v6'])
                del(p['used_addresses_v4'])
                del(p['used_addresses_v6'])
                del(p['free_addresses_v4'])
                del(p['free_addresses_v6'])
                del(p['num_prefixes_v4'])
                del(p['num_prefixes_v6'])

        elif isinstance(res, dict) and 'result' in res:
            # res from smart search
            for p in res['result']:
                #self.assertIn('added', p)
                #self.assertIn('last_modified', p)
                self.assertIn('total_addresses_v4', p)
                self.assertIn('total_addresses_v6', p)
                self.assertIn('used_addresses_v4', p)
                self.assertIn('used_addresses_v6', p)
                self.assertIn('free_addresses_v4', p)
                self.assertIn('free_addresses_v6', p)
                self.assertIn('num_prefixes_v4', p)
                self.assertIn('num_prefixes_v6', p)
                #del(p['added'])
                #del(p['last_modified'])
                del(p['total_addresses_v4'])
                del(p['total_addresses_v6'])
                del(p['used_addresses_v4'])
                del(p['used_addresses_v6'])
                del(p['free_addresses_v4'])
                del(p['free_addresses_v6'])
                del(p['num_prefixes_v4'])
                del(p['num_prefixes_v6'])

        elif isinstance(res, dict):
            # just one single vrf
            #self.assertIn('added', res)
            #self.assertIn('last_modified', res)
            self.assertIn('total_addresses_v4', res)
            self.assertIn('total_addresses_v6', res)
            self.assertIn('used_addresses_v4', res)
            self.assertIn('used_addresses_v6', res)
            self.assertIn('free_addresses_v4', res)
            self.assertIn('free_addresses_v6', res)
            self.assertIn('num_prefixes_v4', res)
            self.assertIn('num_prefixes_v6', res)
            #del(res['added'])
            #del(res['last_modified'])
            del(res['total_addresses_v4'])
            del(res['total_addresses_v6'])
            del(res['used_addresses_v4'])
            del(res['used_addresses_v6'])
            del(res['free_addresses_v4'])
            del(res['free_addresses_v6'])
            del(res['num_prefixes_v4'])
            del(res['num_prefixes_v6'])

        return res




    def test_vrf_add_list(self):
        """ Add a VRF and verify result in database
        """
        attr = {}
        with self.assertRaisesRegexp(xmlrpclib.Fault, 'missing attribute rt'):
            s.add_vrf({ 'auth': ad, 'attr': attr })

        attr['rt'] = '123:456'
        with self.assertRaisesRegexp(xmlrpclib.Fault, 'missing attribute name'):
            s.add_vrf({ 'auth': ad, 'attr': attr })
        attr['name'] = 'test'

        attr['description'] = 'my test vrf'
        vrf = s.add_vrf({ 'auth': ad, 'attr': attr })

        self.assertGreater(vrf['id'], 0)

        ref = attr.copy()
        ref['id'] = vrf['id']
        self.assertEqual(self._mangle_vrf_result(vrf), ref)
        self.assertEqual(self._mangle_vrf_result(s.list_vrf({ 'auth': ad, 'vrf': { 'id': vrf['id'] } })), [ ref, ])

        attr['rt'] = '123:abc'
        with self.assertRaisesRegexp(xmlrpclib.Fault, '.'): # TODO: specify exception string
            s.add_vrf({ 'auth': ad, 'attr': attr })



    def test_vrf_edit_default(self):
        """ Edit the default VRF and verify the change
        """
        # try to set an RT, which should fail on the default VRF
        with self.assertRaisesRegexp(xmlrpclib.Fault, 'Invalid input for column rt, must be NULL for VRF id 0'):
            s.edit_vrf({ 'auth': ad, 'vrf': { 'id': 0 }, 'attr': { 'rt': '123:456a' }})

        res_edit = s.edit_vrf({ 'auth': ad, 'vrf': { 'id': 0 }, 'attr': { 'name': 'FOO', 'description': 'BAR' }})
        res_list = s.list_vrf({ 'auth': ad, 'vrf': { } })[0]
        del(res_list['id'])
        self.assertEqual(self._mangle_vrf_result(res_list), { 'rt': None, 'name': 'FOO', 'description': 'BAR' }, 'VRF change incorrect')



    def test_vrf_edit(self):
        """ Edit VRF and verify the change
        """
        attr = {
            'rt': '65000:123',
            'name': '65k:123',
            'description': 'VRF 65000:123'
        }
        spec = { 'rt': '65000:123' }
        vrf = s.add_vrf({ 'auth': ad, 'attr': attr })

        # omitting VRF spec
        with self.assertRaisesRegexp(xmlrpclib.Fault, 'vrf specification must be a dict'):
            s.edit_vrf({ 'auth': ad, 'attr': { 'name': 'test_vrf_edit' } })

        # omitting VRF attributes
        with self.assertRaisesRegexp(xmlrpclib.Fault, 'invalid input type, must be dict'):
            s.edit_vrf({ 'auth': ad, 'vrf': spec })

        # specifying too many attributes in spec
        with self.assertRaisesRegexp(xmlrpclib.Fault, 'specification contains too many keys'):
            s.edit_vrf({ 'auth': ad, 'vrf': { 'rt': '65000:123', 'name': '65k:123' }, 'attr': {} })

        # test changing ID
        with self.assertRaisesRegexp(xmlrpclib.Fault, 'extraneous attribute'):
            s.edit_vrf({ 'auth': ad, 'vrf': spec, 'attr': { 'id': 1337 } })

        # empty attribute list
        with self.assertRaisesRegexp(xmlrpclib.Fault, "'attr' must not be empty."):
            s.edit_vrf({ 'auth': ad, 'vrf': spec, 'attr': {} })
        res = s.list_vrf({ 'auth': ad, 'vrf': spec })
        self.assertEquals(len(res), 1, 'wrong number of VRFs returned')
        res = res[0]
        del(res['id'])
        self.assertEqual(self._mangle_vrf_result(res), attr)

        # valid change
        attr['rt'] = '65000:1234'
        attr['name'] = '65k:1234'
        attr['description'] = 'VRF 65000:1234'
        s.edit_vrf({ 'auth': ad, 'vrf': spec, 'attr': attr })

        # verify result of valid change
        res = s.list_vrf({ 'auth': ad, 'vrf': { 'rt': attr['rt'] } })
        self.assertEquals(len(res), 1, 'wrong number of VRFs returned')
        res = res[0]
        # ignore the ID
        del(res['id'])
        self.assertEqual(self._mangle_vrf_result(res), attr, 'VRF change incorrect')



    def test_vrf_add_search(self):
        """ Add VRF and search for it
        """

        # add VRF
        attr = {
            'rt': '65000:1235',
            'name': '65k:1235',
            'description': 'Virtual Routing and Forwarding instance 65000:123'
        }
        vrf = s.add_vrf({ 'auth': ad, 'attr': attr })
        attr['id'] = vrf['id']

        # equal match
        q = {
            'operator': 'equals',
            'val1': 'rt',
            'val2': attr['rt']
        }
        res = self._mangle_vrf_result(s.search_vrf({ 'auth': ad, 'query': q }))
        self.assertEquals(res['result'], [ attr, ], 'Search result from equal match did not match')

        # regex match
        q = {
            'operator': 'regex_match',
            'val1': 'description',
            'val2': 'instance 65000'
        }
        res = self._mangle_vrf_result(s.search_vrf({ 'auth': ad, 'query': q }))
        self.assertEquals(res['result'], [ attr, ], 'Search result from regex match did not match')

        # smart search
        res = self._mangle_vrf_result(s.smart_search_vrf({ 'auth': ad, 'query_string': 'forwarding instance' }))
        self.assertEquals(res['result'], [ attr, ], 'Smart search result did not match')



    def test_prefix_add(self):
        """ Add a prefix and list
        """
        # check that some error / sanity checking is there
        attr = {}
        with self.assertRaisesRegexp(xmlrpclib.Fault, "specify 'prefix' or 'from-prefix' or 'from-pool'"):
            s.add_prefix({ 'auth': ad, 'attr': attr })

        attr['prefix'] = '1.3.3.0/24'
        with self.assertRaisesRegexp(xmlrpclib.Fault, "Either description or node must be specified."):
            s.add_prefix({ 'auth': ad, 'attr': attr })

        attr['description'] = 'test prefix'
        with self.assertRaisesRegexp(xmlrpclib.Fault, "Unknown prefix type"):
            s.add_prefix({ 'auth': ad, 'attr': attr })

        attr['type'] = 'assignment'

        # add 1.3.3.0/24
        prefix = s.add_prefix({ 'auth': ad, 'attr': attr })
        attr['id'] = prefix['id']
        self.assertGreater(attr['id'], 0)

        # what we expect the above prefix to look like
        expected = {
                'alarm_priority': None,
                'authoritative_source': 'nipap',
                'comment': None,
                'country': None,
                'description': 'test prefix',
                'display_prefix': '1.3.3.0/24',
                'external_key': None,
                'family': 4,
                'id': 131,
                'indent': 0,
                'inherited_tags': [],
                'monitor': None,
                'node': None,
                'order_id': None,
                'customer_id': None,
                'pool_name': None,
                'pool_id': None,
                'tags': [],
                'vrf_rt': None,
                'vrf_id': 0,
                'vrf_name': 'default',
                'vlan': None
            }
        expected.update(attr)
        self.assertEqual(
                self._mangle_prefix_result(s.list_prefix({ 'auth': ad })),
                [expected])

        attr = {
                'description': 'test for from-prefix 1.3.3.0/24',
                'type': 'host'
            }
        args = { 'from-prefix': ['1.3.3.0/24'], 'prefix_length': 32 }
        # add a host in 1.3.3.0/24
        res = s.add_prefix({ 'auth': ad, 'attr': attr, 'args': args })

        # copy expected from 1.3.3.0/24 since we expect most things to look the
        # same for the new prefix (1.3.3.1/32) from 1.3.3.0/24
        expected_host = expected.copy()
        expected_host.update(attr)
        expected_host['id'] = res['id']
        expected_host['prefix'] = '1.3.3.1/32'
        expected_host['display_prefix'] = '1.3.3.1/24'
        expected_host['indent'] = 1

        # build list of expected
        expected_list = []
        expected_list.append(expected)
        expected_list.append(expected_host)

        # add another prefix, try with vrf_id = None
        attr['vrf_id'] = None
        res = s.add_prefix({ 'auth': ad, 'attr': attr, 'args': args })
        # update expected list
        expected_host2 = expected_host.copy()
        expected_host2['id'] = res['id']
        expected_host2['prefix'] = '1.3.3.2/32'
        expected_host2['display_prefix'] = '1.3.3.2/24'
        expected_list.append(expected_host2)

        # add another prefix, this time completely without VRF info
        del(attr['vrf_id'])
        res = s.add_prefix({ 'auth': ad, 'attr': attr, 'args': args })
        # update expected list
        expected_host3 = expected_host.copy()
        expected_host3['id'] = res['id']
        expected_host3['prefix'] = '1.3.3.3/32'
        expected_host3['display_prefix'] = '1.3.3.3/24'
        expected_list.append(expected_host3)

        # add another prefix, based on VRF name
        attr['vrf_name'] = 'default'
        res = s.add_prefix({ 'auth': ad, 'attr': attr, 'args': args })
        # update expected list
        expected_host4 = expected_host.copy()
        expected_host4['id'] = res['id']
        expected_host4['prefix'] = '1.3.3.4/32'
        expected_host4['display_prefix'] = '1.3.3.4/24'
        expected_list.append(expected_host4)

        # make sure the result looks like we expect it too! :D
        self.assertEqual(
                self._mangle_prefix_result(s.list_prefix({ 'auth': ad })),
                expected_list)



    def test_prefix_add_vrf(self):
        """ Test adding prefixes to VRF
        """

        args = { 'from-prefix': ['1.3.3.0/24'], 'prefix_length': 32 }
        expected = {
                'alarm_priority': None,
                'authoritative_source': 'nipap',
                'comment': None,
                'country': None,
                'description': 'test prefix',
                'display_prefix': '1.3.3.0/24',
                'external_key': None,
                'family': 4,
                'id': 131,
                'indent': 0,
                'monitor': None,
                'node': None,
                'order_id': None,
                'customer_id': None,
                'pool_id': None,
                'pool_name': None,
                'vrf_id': 0,
                'vrf_rt': None,
                'vrf_name': None,
                'vlan': None,
                'inherited_tags': [],
                'tags': []
            }

        # add VRF
        vrf_attr = {
            'rt': '123:4567',
            'name': 'test_prefix_add_vrf1',
        }
        vrf = s.add_vrf({ 'auth': ad, 'attr': vrf_attr })
        vrf_attr['id'] = vrf['id']

        # add prefix to VRF by specifying ID
        vrf_pref_attr = {
            'prefix': '1.3.3.0/24',
            'vrf_id': vrf['id'],
            'type': 'assignment',
            'description': 'Test prefix 1.3.3.0/24 in vrf 123:4567'
        }
        prefix = s.add_prefix({ 'auth': ad, 'attr': vrf_pref_attr })
        expected['id'] = prefix['id']
        expected['vrf_rt'] = vrf_attr['rt']
        expected['vrf_name'] = vrf_attr['name']
        expected['display_prefix'] = '1.3.3.0/24'
        expected['indent'] = 0
        expected.update(vrf_pref_attr)

        vrf_pref = s.list_prefix({ 'auth': ad, 'prefix': { 'id': expected['id'] } })[0]
        vrf_pref = self._mangle_prefix_result(vrf_pref)
        self.assertEqual(vrf_pref, expected, 'Prefix added with VRF ID reference not equal')

        # add prefix to VRF by specifying VRF
        vrf_pref_attr = {
            'vrf_rt': vrf_attr['rt'],
            'type': 'host',
            'description': 'Test host 1.3.3.1/32 in vrf 123:4567'
        }
        prefix = s.add_prefix({ 'auth': ad, 'attr': vrf_pref_attr, 'args': args })
        expected['id'] = prefix['id']
        expected['vrf_id'] = vrf_attr['id']
        expected['vrf_name'] = vrf_attr['name']
        expected['display_prefix'] = '1.3.3.1/24'
        expected['prefix'] = '1.3.3.1/32'
        expected['indent'] = 1
        expected.update(vrf_pref_attr)

        vrf_pref = s.list_prefix({ 'auth': ad, 'prefix': { 'id': expected['id'] } })[0]
        vrf_pref = self._mangle_prefix_result(vrf_pref)
        self.assertEqual(vrf_pref, expected, 'Prefix added with VRF reference not equal')

        # add prefix to VRF by specifying VRF name
        vrf_pref_attr = {
            'vrf_name': vrf_attr['name'],
            'type': 'host',
            'description': 'Test host 1.3.3.2/32 in vrf 123:4567'
        }
        prefix = s.add_prefix({ 'auth': ad, 'attr': vrf_pref_attr, 'args': args })
        expected['id'] = prefix['id']
        expected['vrf_rt'] = vrf_attr['rt']
        expected['vrf_id'] = vrf_attr['id']
        expected['display_prefix'] = '1.3.3.2/24'
        expected['prefix'] = '1.3.3.2/32'
        expected['indent'] = 1
        expected.update(vrf_pref_attr)

        vrf_pref = s.list_prefix({ 'auth': ad, 'prefix': { 'id': expected['id'] } })[0]
        vrf_pref = self._mangle_prefix_result(vrf_pref)
        self.assertEqual(vrf_pref, expected, 'Prefix added with VRF name reference not equal')



    def test_prefix_add_tags(self):
        """ Verify tag inheritance works correctly
        """
        expected = []
        expected_top = {
                'alarm_priority': None,
                'authoritative_source': 'nipap',
                'comment': None,
                'country': None,
                'display_prefix': '1.0.0.0/8',
                'external_key': None,
                'family': 4,
                'id': 131,
                'indent': 0,
                'monitor': None,
                'node': None,
                'order_id': None,
                'customer_id': None,
                'pool_id': None,
                'pool_name': None,
                'vrf_id': 0,
                'vrf_rt': None,
                'vrf_name': 'default',
                'inherited_tags': [],
                'vlan': None
            }

        # add the "top" prefix - 1.0.0.0/8
        attr = {
                'prefix': '1.0.0.0/8',
                'description': 'top prefix',
                'type': 'reservation',
                'tags': ['top']
                }
        prefix = s.add_prefix({ 'auth': ad, 'attr': attr })
        expected_top.update(attr)
        expected_top['id'] = prefix['id']

        # add the "bottom" prefix 1.3.3.0/24
        attr = {
                'prefix': '1.3.3.0/24',
                'description': 'bottom prefix',
                'type': 'assignment',
                'tags': ['bottom'],
                }
        prefix = s.add_prefix({ 'auth': ad, 'attr': attr })
        expected_bottom = expected_top.copy()
        expected_bottom.update(attr)
        expected_bottom['id'] = prefix['id']
        expected_bottom['display_prefix'] = '1.3.3.0/24'
        expected_bottom['inherited_tags'] = ['top']
        expected_bottom['indent'] = 1

        # check the list is correct!
        expected = [ expected_top, expected_bottom ]
        self.assertEqual(
                self._mangle_prefix_result(s.list_prefix({ 'auth': ad })),
                expected)

        # add the "middle" prefix 1.3.0.0/16
        attr = {
                'prefix': '1.3.0.0/16',
                'description': 'middle prefix',
                'type': 'reservation',
                'tags': ['middle'],
                }
        prefix = s.add_prefix({ 'auth': ad, 'attr': attr })
        expected_middle = expected_top.copy()
        expected_middle.update(attr)
        expected_middle['id'] = prefix['id']
        expected_middle['display_prefix'] = '1.3.0.0/16'
        expected_middle['inherited_tags'] = ['top']
        expected_middle['indent'] = 1

        expected_bottom['inherited_tags'] = ['middle', 'top']
        expected_bottom['indent'] = 2

        # check the list is correct!
        expected = [ expected_top, expected_middle, expected_bottom ]
        self.assertEqual(
                self._mangle_prefix_result(s.list_prefix({ 'auth': ad })),
                expected)

        # remove middle prefix
        s.remove_prefix({ 'auth': ad, 'prefix': { 'id': expected_middle['id'] } })
        expected_bottom['inherited_tags'] = ['top']
        expected_bottom['indent'] = 1

        # check the list is correct!
        expected = [ expected_top, expected_bottom ]
        self.assertEqual(
                self._mangle_prefix_result(s.list_prefix({ 'auth': ad })),
                expected)

        # remove top prefix
        s.remove_prefix({ 'auth': ad, 'prefix': { 'id': expected_top['id'] } })
        expected_bottom['inherited_tags'] = []
        expected_bottom['indent'] = 0

        # check the list is correct!
        expected = [ expected_bottom ]
        self.assertEqual(
                self._mangle_prefix_result(s.list_prefix({ 'auth': ad })),
                expected)



    def test_prefix_node(self):
        """ Test node constraints

            Setting the node value is not allowed for all prefix types. Make
            sure the constraints are working correctly.
        """
        expected = {
                'alarm_priority': None,
                'authoritative_source': 'nipap',
                'comment': None,
                'country': None,
                'type': 'assignment',
                'description': 'test prefix',
                'display_prefix': '1.3.2.0/24',
                'external_key': None,
                'family': 4,
                'indent': 0,
                'inherited_tags': [],
                'monitor': None,
                'node': None,
                'order_id': None,
                'customer_id': None,
                'pool_name': None,
                'pool_id': None,
                'tags': [],
                'vrf_rt': None,
                'vrf_id': 0,
                'vrf_name': 'default',
                'vlan': None
            }
        expected_list = []

        attr = {}
        attr['prefix'] = '1.3.2.0/24'
        attr['description'] = 'test prefix'
        attr['type'] = 'assignment'
        # add an assignment which we need later on
        res = s.add_prefix({ 'auth': ad, 'attr': attr })
        exp1 = expected.copy()
        exp1.update(attr)
        exp1['id'] = res['id']

        attr['prefix'] = '1.3.3.0/24'

        # set node
        attr['node'] = 'test'

        # node value is not allowed at all for prefixes of type reservation
        attr['type'] = 'reservation'
        with self.assertRaisesRegexp(xmlrpclib.Fault, "Not allowed to set 'node' value for prefixes of type 'reservation'."):
            s.add_prefix({ 'auth': ad, 'attr': attr })

        # node value is only allowed for assignments when prefix-length is max
        # (/24 for IPv4 or /128 for IPv6).
        attr['type'] = 'assignment'
        with self.assertRaisesRegexp(xmlrpclib.Fault, "Not allowed to set 'node' value for prefixes of type 'assignment' which do not have all bits set in netmask."):
            s.add_prefix({ 'auth': ad, 'attr': attr })

        # correct prefix length
        attr['prefix'] = '1.3.3.0/32'
        res = s.add_prefix({ 'auth': ad, 'attr': attr })

        exp2 = expected.copy()
        exp2.update(attr)
        exp2['id'] = res['id']
        exp2['display_prefix'] = '1.3.3.0'

        # let's add a host too
        attr['type'] = 'host'
        attr['prefix'] = '1.3.2.1/32'
        res = s.add_prefix({ 'auth': ad, 'attr': attr })

        exp3 = expected.copy()
        exp3.update(attr)
        exp3['id'] = res['id']
        exp3['display_prefix'] = '1.3.2.1/24'
        exp3['indent'] = 1

        # note the non-intuitive order
        expected_list.append(exp1)
        expected_list.append(exp3)
        expected_list.append(exp2)

        res = self._mangle_prefix_result(s.list_prefix({ 'auth': ad }))
        self.assertEqual(res, expected_list)



    def test_prefix_add_to_pool(self):
        """ Test adding prefixes to a pool
        """
        # Add a pool
        pool_attr = {
            'name'          : 'pool_1',
            'description'   : 'Test pool #1',
            'default_type'  : 'assignment',
            'ipv4_default_prefix_length' : 24
        }
        pool = s.add_pool({ 'auth': ad, 'attr': pool_attr })

        # Add prefix to pool
        prefix_attr = {
                'prefix': '1.3.0.0/16',
                'type': 'reservation',
                'description': 'FOO',
                'pool_id': pool['id']
            }
        s.add_prefix({ 'auth': ad, 'attr': prefix_attr })

        # Add prefix to pool
        prefix_attr = {
                'prefix': '1.4.0.0/16',
                'type': 'reservation',
                'description': 'FOO',
                'pool_name': 'pool_1'
            }
        s.add_prefix({ 'auth': ad, 'attr': prefix_attr })

        # add a prefix
        prefix_attr = {
                'prefix': '1.5.0.0/16',
                'type': 'reservation',
                'description': 'FOO'
            }
        prefix = s.add_prefix({ 'auth': ad, 'attr': prefix_attr })
        # modify prefix so that it's part of pool
        s.edit_prefix({ 'auth': ad, 'prefix': { 'id': prefix['id'] }, 'attr': { 'pool_id': pool['id'] } })

        # add a prefix
        prefix_attr = {
                'prefix': '1.6.0.0/16',
                'type': 'reservation',
                'description': 'FOO'
            }
        prefix = s.add_prefix({ 'auth': ad, 'attr': prefix_attr })
        # modify prefix so that it's part of pool
        s.edit_prefix({ 'auth': ad, 'prefix': { 'id': prefix['id'] }, 'attr': { 'pool_name': 'pool_1' } })

        res = s.list_pool({ 'auth': ad, 'pool': { 'id': pool['id'] } })
        self.assertEquals(res[0]['prefixes'], ['1.3.0.0/16', '1.4.0.0/16',
        '1.5.0.0/16', '1.6.0.0/16'])



    def test_prefix_from_pool(self):
        """ Add a prefix from a pool
        """

        # Add a pool
        pool_attr = {
            'name'          : 'pool_1',
            'description'   : 'Test pool #1',
            'default_type'  : 'assignment',
            'ipv4_default_prefix_length' : 24
        }
        pool = s.add_pool({ 'auth': ad, 'attr': pool_attr })

        # Add prefix to pool
        parent_prefix_attr = {
                'prefix': '1.3.0.0/16',
                'type': 'reservation',
                'description': 'FOO',
                'pool_id': pool['id']
            }
        s.add_prefix({ 'auth': ad, 'attr': parent_prefix_attr })

        args = { 'from-pool': { 'name': 'pool_1' },
                'family': 4 }
        prefix_attr = {
                'description': 'BAR'
                }
        expected = {
                'prefix': '1.3.0.0/24',
                'display_prefix': '1.3.0.0/24',
                'description': 'BAR',
                'type': 'assignment',
                'comment': None,
                'country': None,
                'monitor': None,
                'node': None,
                'order_id': None,
                'customer_id': None,
                'pool_id': None,
                'pool_name': None,
                'vrf_id': 0,
                'vrf_rt': None,
                'vrf_name': 'default',
                'external_key': None,
                'family': 4,
                'indent': 1,
                'alarm_priority': None,
                'authoritative_source': 'nipap'
                }
        child = s.add_prefix({ 'auth': ad, 'attr': prefix_attr, 'args': args })
        #expected['id'] = child['id']
        #p = s.list_prefix({ 'auth': ad, 'attr': { 'id': child['id'] } })[1]
        #self.assertEquals(p, expected)



    def test_prefix_from_pool_vrf(self):
        """ Add a prefix from a pool in a VRF
        """

        # Add a VRF
        vrf_attr = {
            'name'          : 'vrf_1',
            'description'   : 'Test VRF #1',
            'rt'            : '123:123'
        }
        vrf = s.add_vrf({ 'auth': ad, 'attr': vrf_attr })

        # Add a pool
        pool_attr = {
            'name'          : 'pool_1',
            'description'   : 'Test pool for from-pool test',
            'default_type'  : 'assignment',
            'ipv4_default_prefix_length' : 24
        }
        pool = s.add_pool({ 'auth': ad, 'attr': pool_attr })

        # Add prefix to pool
        parent_prefix_attr = {
                'prefix': '1.3.0.0/16',
                'vrf_rt': '123:123',
                'type': 'reservation',
                'description': 'FOO',
                'pool_id': pool['id']
            }
        s.add_prefix({ 'auth': ad, 'attr': parent_prefix_attr })

        args = { 'from-pool': { 'name': 'pool_1' },
                'family': 4 }
        prefix_attr = {
                'description': 'BAR'
                }
        expected = {
                'prefix': '1.3.0.0/24',
                'display_prefix': '1.3.0.0/24',
                'description': 'BAR',
                'type': 'assignment',
                'comment': None,
                'country': None,
                'monitor': None,
                'node': None,
                'order_id': None,
                'customer_id': None,
                'pool_id': None,
                'pool_name': None,
                'vrf_id': vrf['id'],
                'vrf_rt': '123:123',
                'vrf_name': 'vrf_1',
                'external_key': None,
                'family': 4,
                'indent': 1,
                'alarm_priority': None,
                'authoritative_source': 'nipap',
                'vlan': None,
                'inherited_tags': [],
                'tags': []
                }
        child = s.add_prefix({ 'auth': ad, 'attr': prefix_attr, 'args': args })
        expected['id'] = child['id']
        p = s.list_prefix({ 'auth': ad, 'attr': { 'id': child['id'] } })[1]
        p = self._mangle_prefix_result(p)
        self.assertEquals(p, expected)



    def test_prefix_edit_return(self):
        """ Check return value of edit_prefix
        """
        p1 = s.add_prefix({ 'auth': ad, 'attr': {
                'prefix': '1.3.3.0/24',
                'type': 'assignment',
                'description': 'FOO'
            } })
        p2 = s.add_prefix({ 'auth': ad, 'attr': {
                'prefix': '1.3.3.1/32',
                'type': 'host',
                'description': 'child 1'
            } })
        p3 = s.add_prefix({ 'auth': ad, 'attr': {
                'prefix': '1.3.3.2/32',
                'type': 'host',
                'description': 'child 2'
            } })
        p4 = s.add_prefix({ 'auth': ad, 'attr': {
                'prefix': '1.3.3.3/32',
                'type': 'host',
                'description': 'child 3'
            } })

        ss_res = s.smart_search_prefix({ 'auth': ad, 'query_string': 'child 2'
            })['result'][0]
        edit_res = s.edit_prefix({ 'auth': ad,
            'prefix': { 'prefix': '1.3.3.2/32' },
            'attr': { 'description': 'Kid 2' } })[0]
        del(edit_res['added'])
        del(edit_res['last_modified'])
        del(ss_res['added'])
        del(ss_res['last_modified'])
        ss_res['description'] = 'Kid 2'
        self.assertEqual(ss_res, edit_res)



    def test_prefix_smart_search(self):
        """ Test the prefix smart search
        """
        p1 = s.add_prefix({ 'auth': ad, 'attr': {
                'prefix': '1.3.3.0/24',
                'type': 'assignment',
                'description': 'FOO'
            } })

        s.add_prefix({ 'auth': ad, 'attr': {
                'prefix': '1.3.3.0/32',
                'type': 'host',
                'description': 'BAR'
            } })

        res = s.smart_search_prefix({ 'auth': ad, 'query_string': 'F' })
        expected = {
                'interpretation': [{'operator': 'regex', 'attribute':
                    'description or comment or node or order_id or customer_id', 'interpretation':
                    'text', 'string': 'F'}],
                'search_options': {'include_all_children':
                False, 'max_result': 50, 'include_all_parents': False,
                'parents_depth': 0, 'offset': 0, 'children_depth': 0,
                'parent_prefix': None, 'include_neighbors': False },
                'result': [
                    {'comment': None,
                        'external_key': None,
                        'family': 4,
                        'prefix': '1.3.3.0/24',
                        'authoritative_source': 'nipap',
                        'id': p1['id'],
                        'display_prefix': '1.3.3.0/24',
                        'monitor': None,
                        'children': 1,
                        'prefix_length': 24,
                        'type': 'assignment',
                        'match': True,
                        'node': None,
                        'description': 'FOO',
                        'order_id': None,
                        'customer_id': None,
                        'vrf_id': 0,
                        'vrf_rt': None,
                        'vrf_name': 'default',
                        'pool_id': None,
                        'pool_name': None,
                        'alarm_priority': None,
                        'indent': 0,
                        'country': None,
                        'display': True,
                        'vlan': None,
                        'inherited_tags': [],
                        'tags': []
                        }
                    ]
            }
        res = self._mangle_prefix_result(res)
        self.assertEqual(res, expected)



    def test_asn_add_list(self):
        """ Add ASN to NIPAP and list it
        """

        attr = {
            'asn': 1,
            'name': 'Test ASN #1'
        }

        # add ASN
        self.assertEqual(s.add_asn({ 'auth': ad, 'attr': attr}), attr, "add_asn did not return correct ASN.")

        # make sure that it got added
        asn = s.list_asn({ 'auth': ad, 'asn': { 'asn': 1 } })
        self.assertEqual(len(asn), 1, "Wrong number of ASNs returned.")
        asn = asn[0]
        self.assertEquals(attr, asn, "ASN in database not equal to what was added.")

        # adding the same ASN again should result in duplicate key error
        with self.assertRaisesRegexp(xmlrpclib.Fault, 'Duplicate value for'):
            s.add_asn({ 'auth': ad, 'attr': attr })



    def test_remove_asn(self):
        """ Remove ASN from NIPAP
        """

        attr = {
            'asn': 2,
            'name': 'Test ASN #2'
        }

        asn = s.add_asn({ 'auth': ad, 'attr': attr })
        s.remove_asn({ 'auth': ad, 'asn': { 'asn': asn['asn'] } })
        self.assertEquals(0, len(s.list_asn({ 'auth': ad, 'asn': { 'asn': 2 } })), "Removed ASN still in database")



    def test_edit_asn(self):
        """ Edit ASNs
        """

        attr = {
            'asn': 3,
            'name': 'Test ASN #3'
        }

        asn = s.add_asn({ 'auth': ad, 'attr': attr })
        s.edit_asn({ 'auth': ad, 'asn': { 'asn': attr['asn'] }, 'attr': { 'name': 'b0rk' } })
        self.assertEquals(s.list_asn({ 'auth': ad, 'asn': { 'asn': 3 } })[0]['name'], 'b0rk', "Edited ASN still has it's old name.")
        with self.assertRaisesRegexp(xmlrpclib.Fault, 'extraneous attribute'):
            s.edit_asn({ 'auth': ad, 'asn': { 'asn': 3 }, 'attr': {'asn': 4, 'name': 'Test ASN #4'} })



    def test_search_asn(self):
        """ Search ASNs
        """

        attr = {
            'asn': 4,
            'name': 'This is AS number 4'
        }

        asn = s.add_asn({ 'auth': ad, 'attr': attr })

        # equal match
        q = {
            'operator': 'equals',
            'val1': 'asn',
            'val2': attr['asn']
        }
        res = s.search_asn({ 'auth': ad, 'query': q })
        self.assertEquals(len(res['result']), 1, "equal search resulted in wrong number of hits")
        self.assertEquals(res['result'][0]['name'], attr['name'], "search hit got wrong name")

        # regexp match
        q = {
            'operator': 'regex_match',
            'val1': 'name',
            'val2': 'number'
        }
        res = s.search_asn({ 'auth': ad, 'query': q })
        self.assertEquals(len(res['result']), 1, "regex search resulted in wrong number of hits")
        self.assertEquals(res['result'][0]['asn'], attr['asn'], "search hit got wrong asn")



    def test_smart_search_asn(self):
        """ Test smart_search_asn function.
        """

        attr = {
            'asn': 5,
            'name': 'Autonomous System Number 5'
        }

        asn = s.add_asn({ 'auth': ad, 'attr': attr })
        res = s.smart_search_asn({ 'auth': ad, 'query_string': "Autonomous" })
        self.assertEquals(len(res['result']), 1, "search resulted in wrong number of hits")
        self.assertEquals(res['result'][0]['asn'], attr['asn'], "search hit got wrong asn")
        self.assertEquals(res['interpretation'][0]['attribute'], 'name', "search term interpretated as wrong type")

        res = s.smart_search_asn({ 'auth': ad, 'query_string': "5" })
        self.assertEquals(len(res['result']), 1, "search resulted in wrong number of hits")
        self.assertEquals(res['result'][0]['asn'], attr['asn'], "search hit got wrong asn")
        self.assertEquals(res['interpretation'][0]['attribute'], 'asn', "search term interpretated as wrong type")



    def test_pool_add_list(self):
        """ Test adding a pool and verifying it
        """

        # Add a pool
        attr = {
            'description': 'Test pool #1',
            'default_type': 'assignment',
            'ipv4_default_prefix_length': 31,
            'ipv6_default_prefix_length': 112
        }

        with self.assertRaisesRegexp(xmlrpclib.Fault, 'missing attribute name'):
            s.add_pool({ 'auth': ad, 'attr': attr })

        attr['name'] = 'pool_1'
        attr['ipv4_default_prefix_length'] = 50
        with self.assertRaisesRegexp(xmlrpclib.Fault, '1200: \'Default IPv4 prefix length must be an integer between 1 and 32.'):
            s.add_pool({ 'auth': ad, 'attr': attr })

        attr['ipv4_default_prefix_length'] = 31
        attr['ipv6_default_prefix_length'] = 'over 9000'
        with self.assertRaisesRegexp(xmlrpclib.Fault, '1200: \'Default IPv6 prefix length must be an integer between 1 and 128.'):
            s.add_pool({ 'auth': ad, 'attr': attr })

        attr['ipv6_default_prefix_length'] = 112

        res = s.add_pool({ 'auth': ad, 'attr': attr })
        expected = attr.copy()
        expected['id'] = res['id']
        expected['prefixes'] = []
        expected['vrf_id'] = None
        expected['vrf_rt'] = None
        expected['vrf_name'] = None

        # list pool and verify data in NIPAP
        p = s.list_pool({ 'auth': ad, 'pool': { 'id': expected['id'] } })
        self.assertEquals(1, len(p), 'Wrong number of pools returned')
        p = p[0]

        self.assertEquals(self._mangle_pool_result(p), expected, 'Received pool differs from added pool')


    def test_edit_pool(self):
        """ Test editing a pool
        """

        # add a pool, we need something to edit
        attr = {
            'name': 'test_pool_2',
            'description': 'Test pool #2',
            'default_type': 'reservation',
            'ipv4_default_prefix_length': 31,
            'ipv6_default_prefix_length': 112
        }

        attr2 = {
            'name': 'test_pool_2_edit',
            'description': 'Test pool #2 edit',
            'default_type': 'assignment',
            'ipv4_default_prefix_length': 30,
            'ipv6_default_prefix_length': 96
        }

        res = s.add_pool({ 'auth': ad, 'attr': attr })
        s.edit_pool({ 'auth': ad, 'pool': { 'id': res['id'] }, 'attr': attr2 })

        expected = attr2.copy()
        expected['id'] = res['id']
        expected['prefixes'] = []
        expected['vrf_id'] = None
        expected['vrf_rt'] = None
        expected['vrf_name'] = None

        self.assertEquals(self._mangle_pool_result(s.list_pool({ 'auth': ad,
            'pool': { 'id': res['id'] } })[0]), expected)


    def test_search_pool(self):
        """ Test searching pools
        """


    def test_smart_search_pool(self):
        """ Test smart searching among pools
        """


    def test_remove_pool(self):
        """ Test removing pools
Exemplo n.º 13
0
    def setUp(self):
        """ Better start from a clean slate!
        """

        cfg = NipapConfig('/etc/nipap/nipap.conf')
        self.nipap = Nipap()

        # create dummy auth object
        # As the authentication is performed before the query hits the Nipap
        # class, it does not matter what user we use here
        self.auth = SqliteAuth('local', 'unittest', 'unittest', 'unittest')
        self.auth.authenticated_as = 'unittest'
        self.auth.full_name = 'Unit test'

        self.nipap._execute(
            "TRUNCATE ip_net_plan, ip_net_pool, ip_net_vrf, ip_net_log, ip_net_asn"
        )

        self.schema_attrs = {
            'name': 'test-schema1',
            'description': 'Test schema numero uno!'
        }
        self.schema_attrs['id'] = self.nipap.add_schema(
            self.auth, self.schema_attrs)
        self.schema_attrs2 = {
            'name': 'test-schema2',
            'description': 'Test schema numero dos!'
        }
        self.schema_attrs2['id'] = self.nipap.add_schema(
            self.auth, self.schema_attrs2)
        self.pool_attrs = {
            'name': 'test-pool1',
            'description': 'Test pool numero uno!',
            'default_type': 'assignment',
            'ipv4_default_prefix_length': 30,
            'ipv6_default_prefix_length': 112
        }
        self.pool_attrs['id'] = self.nipap.add_pool(
            self.auth, {'id': self.schema_attrs['id']}, self.pool_attrs)
        self.prefix_attrs1 = {
            'authoritative_source': 'nipaptest',
            'prefix': '1.3.3.0/24',
            'type': 'assignment',
            'description': ''
        }
        self.prefix_attrs1['id'] = self.nipap.add_prefix(
            self.auth, {'id': self.schema_attrs['id']}, self.prefix_attrs1)
        self.prefix_attrs = {
            'authoritative_source': 'nipaptest',
            'prefix': '1.3.3.1/32',
            'type': 'host',
            'description': 'Test prefix numero uno!'
        }
        self.prefix_attrs['id'] = self.nipap.add_prefix(
            self.auth, {'id': self.schema_attrs['id']}, self.prefix_attrs)
        self.prefix_attrs2 = {
            'authoritative_source': 'nipaptest',
            'prefix': '1.3.2.0/23',
            'type': 'reservation',
            'description': ''
        }
        self.prefix_attrs2['id'] = self.nipap.add_prefix(
            self.auth, {'id': self.schema_attrs['id']}, self.prefix_attrs2)
        self.prefix_attrs3 = {
            'authoritative_source': 'nipaptest',
            'prefix': '1.3.0.0/16',
            'type': 'reservation',
            'description': ''
        }
        self.prefix_attrs3['id'] = self.nipap.add_prefix(
            self.auth, {'id': self.schema_attrs['id']}, self.prefix_attrs3)
        self.prefix_attrs4 = {
            'authoritative_source': 'nipaptest',
            'prefix': '1.3.0.0/17',
            'type': 'reservation',
            'description': ''
        }
        self.prefix_attrs4['id'] = self.nipap.add_prefix(
            self.auth, {'id': self.schema_attrs2['id']}, self.prefix_attrs4)

        self.prefix6_attrs1 = {
            'authoritative_source': 'nipaptest',
            'prefix': '2001:0db8:3:3::/112',
            'type': 'assignment',
            'description': ''
        }
        self.prefix6_attrs1['id'] = self.nipap.add_prefix(
            self.auth, {'id': self.schema_attrs['id']}, self.prefix6_attrs1)
        self.prefix6_attrs = {
            'authoritative_source': 'nipaptest',
            'prefix': '2001:0db8:3:3::1/128',
            'type': 'host',
            'description': 'Test prefix numero uno!'
        }
        self.prefix6_attrs['id'] = self.nipap.add_prefix(
            self.auth, {'id': self.schema_attrs['id']}, self.prefix6_attrs)
        self.prefix6_attrs2 = {
            'authoritative_source': 'nipaptest',
            'prefix': '2001:0db8:3:3::/64',
            'type': 'reservation',
            'description': ''
        }
        self.prefix6_attrs2['id'] = self.nipap.add_prefix(
            self.auth, {'id': self.schema_attrs['id']}, self.prefix6_attrs2)
        self.prefix6_attrs3 = {
            'authoritative_source': 'nipaptest',
            'prefix': '2001:0db8:3:0::/48',
            'type': 'reservation',
            'description': ''
        }
        self.prefix6_attrs3['id'] = self.nipap.add_prefix(
            self.auth, {'id': self.schema_attrs['id']}, self.prefix6_attrs3)
        self.prefix6_attrs4 = {
            'authoritative_source': 'nipaptest',
            'prefix': '2001:0db8:3:0::/56',
            'type': 'reservation',
            'description': ''
        }
        self.prefix6_attrs4['id'] = self.nipap.add_prefix(
            self.auth, {'id': self.schema_attrs2['id']}, self.prefix6_attrs4)
Exemplo n.º 14
0
class NipapTest(unittest.TestCase):
    """ Tests the NIPAP class
    """

    nipap = None

    def setUp(self):
        """ Better start from a clean slate!
        """

        cfg = NipapConfig('/etc/nipap/nipap.conf')
        self.nipap = Nipap()

        # create dummy auth object
        # As the authentication is performed before the query hits the Nipap
        # class, it does not matter what user we use here
        self.auth = SqliteAuth('local', 'unittest', 'unittest', 'unittest')
        self.auth.authenticated_as = 'unittest'
        self.auth.full_name = 'Unit test'

        self.nipap._execute(
            "TRUNCATE ip_net_plan, ip_net_pool, ip_net_vrf, ip_net_log, ip_net_asn"
        )

        self.schema_attrs = {
            'name': 'test-schema1',
            'description': 'Test schema numero uno!'
        }
        self.schema_attrs['id'] = self.nipap.add_schema(
            self.auth, self.schema_attrs)
        self.schema_attrs2 = {
            'name': 'test-schema2',
            'description': 'Test schema numero dos!'
        }
        self.schema_attrs2['id'] = self.nipap.add_schema(
            self.auth, self.schema_attrs2)
        self.pool_attrs = {
            'name': 'test-pool1',
            'description': 'Test pool numero uno!',
            'default_type': 'assignment',
            'ipv4_default_prefix_length': 30,
            'ipv6_default_prefix_length': 112
        }
        self.pool_attrs['id'] = self.nipap.add_pool(
            self.auth, {'id': self.schema_attrs['id']}, self.pool_attrs)
        self.prefix_attrs1 = {
            'authoritative_source': 'nipaptest',
            'prefix': '1.3.3.0/24',
            'type': 'assignment',
            'description': ''
        }
        self.prefix_attrs1['id'] = self.nipap.add_prefix(
            self.auth, {'id': self.schema_attrs['id']}, self.prefix_attrs1)
        self.prefix_attrs = {
            'authoritative_source': 'nipaptest',
            'prefix': '1.3.3.1/32',
            'type': 'host',
            'description': 'Test prefix numero uno!'
        }
        self.prefix_attrs['id'] = self.nipap.add_prefix(
            self.auth, {'id': self.schema_attrs['id']}, self.prefix_attrs)
        self.prefix_attrs2 = {
            'authoritative_source': 'nipaptest',
            'prefix': '1.3.2.0/23',
            'type': 'reservation',
            'description': ''
        }
        self.prefix_attrs2['id'] = self.nipap.add_prefix(
            self.auth, {'id': self.schema_attrs['id']}, self.prefix_attrs2)
        self.prefix_attrs3 = {
            'authoritative_source': 'nipaptest',
            'prefix': '1.3.0.0/16',
            'type': 'reservation',
            'description': ''
        }
        self.prefix_attrs3['id'] = self.nipap.add_prefix(
            self.auth, {'id': self.schema_attrs['id']}, self.prefix_attrs3)
        self.prefix_attrs4 = {
            'authoritative_source': 'nipaptest',
            'prefix': '1.3.0.0/17',
            'type': 'reservation',
            'description': ''
        }
        self.prefix_attrs4['id'] = self.nipap.add_prefix(
            self.auth, {'id': self.schema_attrs2['id']}, self.prefix_attrs4)

        self.prefix6_attrs1 = {
            'authoritative_source': 'nipaptest',
            'prefix': '2001:0db8:3:3::/112',
            'type': 'assignment',
            'description': ''
        }
        self.prefix6_attrs1['id'] = self.nipap.add_prefix(
            self.auth, {'id': self.schema_attrs['id']}, self.prefix6_attrs1)
        self.prefix6_attrs = {
            'authoritative_source': 'nipaptest',
            'prefix': '2001:0db8:3:3::1/128',
            'type': 'host',
            'description': 'Test prefix numero uno!'
        }
        self.prefix6_attrs['id'] = self.nipap.add_prefix(
            self.auth, {'id': self.schema_attrs['id']}, self.prefix6_attrs)
        self.prefix6_attrs2 = {
            'authoritative_source': 'nipaptest',
            'prefix': '2001:0db8:3:3::/64',
            'type': 'reservation',
            'description': ''
        }
        self.prefix6_attrs2['id'] = self.nipap.add_prefix(
            self.auth, {'id': self.schema_attrs['id']}, self.prefix6_attrs2)
        self.prefix6_attrs3 = {
            'authoritative_source': 'nipaptest',
            'prefix': '2001:0db8:3:0::/48',
            'type': 'reservation',
            'description': ''
        }
        self.prefix6_attrs3['id'] = self.nipap.add_prefix(
            self.auth, {'id': self.schema_attrs['id']}, self.prefix6_attrs3)
        self.prefix6_attrs4 = {
            'authoritative_source': 'nipaptest',
            'prefix': '2001:0db8:3:0::/56',
            'type': 'reservation',
            'description': ''
        }
        self.prefix6_attrs4['id'] = self.nipap.add_prefix(
            self.auth, {'id': self.schema_attrs2['id']}, self.prefix6_attrs4)

    def test_schema_basic(self):
        """ Basic schema test

            1. Add a new schema
            2. List with filters to get newly created schema
            3. Verify listed schema coincides with input args for added schema
            4. Remove schema
        """
        attrs = {
            'name': 'test-schema-wrong',
            'description': 'A simple test schema with incorrect name!'
        }
        attrs['id'] = self.nipap.add_schema(self.auth, attrs)
        schema = self.nipap.list_schema(self.auth, {'id': attrs['id']})
        for a in attrs:
            self.assertEqual(
                schema[0][a], attrs[a],
                'Added object differ from listed on attribute: ' + a)

    def test_schema_add_crap_input(self):
        """ Try to input junk into add_schema and expect error

        """
        attrs = {
            'name': 'test-schema-crap',
            'description': 'A simple test schema with incorrect name!',
            'crap': 'this is just some crap'
        }
        # missing everything
        self.assertRaises(NipapMissingInputError, self.nipap.add_schema,
                          self.auth, {})
        # missing description
        self.assertRaises(NipapMissingInputError, self.nipap.add_schema,
                          self.auth, {'name': 'crapson'})
        # have required and extra crap
        self.assertRaises(NipapExtraneousInputError, self.nipap.add_schema,
                          self.auth, attrs)

    def test_expand_schema_spec(self):
        """ Test the expand_schema_spec()

            The _expand_schema_spec() function is used throughout the schema
            functions to expand the schema specification input and so we test
            the separately.
        """
        # wrong type
        self.assertRaises(NipapInputError, self.nipap._expand_schema_spec,
                          'string')
        # wrong type
        self.assertRaises(NipapInputError, self.nipap._expand_schema_spec, 1)
        # wrong type
        self.assertRaises(NipapInputError, self.nipap._expand_schema_spec, [])
        # missing keys
        self.assertRaises(NipapMissingInputError,
                          self.nipap._expand_schema_spec, {})
        # crap key
        self.assertRaises(NipapExtraneousInputError,
                          self.nipap._expand_schema_spec,
                          {'crap': self.schema_attrs['name']})
        # required keys and extra crap
        self.assertRaises(NipapExtraneousInputError,
                          self.nipap._expand_schema_spec, {
                              'name': self.schema_attrs['name'],
                              'crap': 'crap'
                          })
        # proper key but incorrect value (int vs string)
        self.assertRaises(NipapValueError, self.nipap._expand_schema_spec,
                          {'id': '3'})
        # proper key but incorrect value (int vs string)
        self.assertRaises(NipapValueError, self.nipap._expand_schema_spec,
                          {'name': 3})
        # both id and name
        self.assertRaises(NipapExtraneousInputError,
                          self.nipap._expand_schema_spec, {
                              'id': 3,
                              'name': '3'
                          })
        # proper key - id
        where, params = self.nipap._expand_schema_spec({'id': 3})
        self.assertEqual(where, 'id = %(spec_id)s',
                         "Improperly expanded WHERE clause")
        self.assertEqual(params, {'spec_id': 3},
                         "Improperly expanded params dict")
        # proper spec - name
        where, params = self.nipap._expand_schema_spec({'name': 'test'})

    def test_schema_edit_crap_input(self):
        """ Try to input junk into edit_schema and expect error

        """
        attrs = {
            'name': 'test-schema-crap',
            'description': 'A simple test schema with incorrect name!'
        }
        crap_attrs = {
            'name': 'test-schema-crap',
            'description': 'A simple test schema with incorrect name!',
            'crap': 'this is just some crap'
        }
        # spec is tested elsewhere, just test attrs part
        self.assertRaises(NipapExtraneousInputError, self.nipap.edit_schema,
                          self.auth, {'name': self.schema_attrs['name']},
                          crap_attrs)

    def test_schema_list_crap_input(self):
        """ Try to input junk into list_schema and expect error

        """
        # TODO: what do we really expect?
        self.assertRaises(NipapExtraneousInputError, self.nipap.list_schema,
                          self.auth, {'crap': 'crap crap'})

    def test_schema_dupe(self):
        """ Check so we can't create duplicate schemas

            There are unique indices in the database that should prevent us
            from creating duplicate schema (ie, with the same name).
        """
        schema_attrs = {
            'name': 'test-schema-dupe',
            'description': 'Testing dupe'
        }
        self.nipap.add_schema(self.auth, schema_attrs)
        self.assertRaises(NipapDuplicateError, self.nipap.add_schema,
                          self.auth, schema_attrs)

    def test_schema_rename(self):
        """ Rename a schema

            Uses the edit_schema() functionality to rename our previously
            created and incorrectly named schema so it hereafter has the
            correct name. Also tests the list_schema() functionality since we
            use that to list the modified schema.
        """
        spec = {'name': 'test-schema1'}
        attrs = {
            'name': 'test-schema',
            'description': 'A simple test schema with correct name!'
        }
        self.nipap.edit_schema(self.auth, spec, attrs)
        # check that search for old record doesn't return anything
        schema = self.nipap.list_schema(self.auth, spec)
        self.assertEqual(schema, [], 'Old entry still exists')
        schema = self.nipap.list_schema(self.auth, {'name': 'test-schema'})
        for a in attrs:
            self.assertEqual(
                schema[0][a], attrs[a],
                'Modified schema differ from listed on attribute: ' + a)

    def test_schema_remove(self):
        """ Remove a schema

            Remove the schema previously modified and make sure it's not there.
        """
        spec = {'name': 'test-schema'}
        self.nipap.remove_schema(self.auth, spec)
        # check that search for old record doesn't return anything
        schema = self.nipap.list_schema(self.auth, spec)
        self.assertEqual(schema, [], 'Old entry still exists')

    def test_expand_pool_spec(self):
        """ Test the function which expands pool spec to SQL.
        """

        schema = {'id': self.schema_attrs['id']}

        # wrong type
        self.assertRaises(NipapInputError, self.nipap._expand_pool_spec,
                          'string')
        # wrong type
        self.assertRaises(NipapInputError, self.nipap._expand_pool_spec, 1)
        # wrong type
        self.assertRaises(NipapInputError, self.nipap._expand_pool_spec, [])
        # missing keys
        self.assertRaises(NipapMissingInputError, self.nipap._expand_pool_spec,
                          {})
        # crap key
        self.assertRaises(NipapExtraneousInputError,
                          self.nipap._expand_pool_spec,
                          {'crap': self.pool_attrs['name']})
        # required keys and extra crap
        self.assertRaises(
            NipapExtraneousInputError, self.nipap._expand_pool_spec, {
                'id': self.pool_attrs['id'],
                'schema': self.schema_attrs['id'],
                'crap': 'crap'
            })
        # proper key but incorrect value (int vs string)
        self.assertRaises(NipapValueError, self.nipap._expand_pool_spec, {
            'id': '3',
            'schema': self.schema_attrs['id']
        })
        # proper key but incorrect value (int vs string)
        self.assertRaises(NipapValueError, self.nipap._expand_pool_spec, {
            'name': 3,
            'schema': self.schema_attrs['id']
        })
        # both id and name
        self.assertRaises(NipapExtraneousInputError,
                          self.nipap._expand_pool_spec, {
                              'id': 3,
                              'name': '3',
                              'schema': self.schema_attrs['id']
                          })
        # proper key - id
        where, params = self.nipap._expand_pool_spec({
            'id':
            3,
            'schema':
            self.schema_attrs['id']
        })
        self.assertEqual(
            where, 'po.id = %(spec_id)s AND po.schema = %(spec_schema)s',
            "Improperly expanded WHERE clause")
        self.assertEqual(params, {
            'spec_id': 3,
            'spec_schema': self.schema_attrs['id']
        }, "Improperly expanded params dict")
        # proper spec - name
        where, params = self.nipap._expand_pool_spec({
            'name':
            'test',
            'schema':
            self.schema_attrs['id']
        })
        self.assertEqual(
            where, 'po.name = %(spec_name)s AND po.schema = %(spec_schema)s',
            "Improperly expanded WHERE clause")
        self.assertEqual(params, {
            'spec_name': 'test',
            'spec_schema': self.schema_attrs['id']
        }, "Improperly expanded params dict")

    def test_pool_add1(self):
        """ Add a pool and check it's there using list functions

            Refer to schema by id
        """
        attrs = {
            'name': 'test-pool-wrong',
            'description': 'A simple test pool with incorrect name!',
            'default_type': 'reservation',
            'ipv4_default_prefix_length': 30,
            'ipv6_default_prefix_length': 112
        }
        schema = {'id': self.schema_attrs['id']}
        pool_id = self.nipap.add_pool(self.auth, schema, attrs)
        pool = self.nipap.list_pool(self.auth, schema, {'id': pool_id})
        for a in attrs:
            self.assertEqual(
                pool[0][a], attrs[a],
                'Added object differ from listed on attribute: %s  %s!=%s' %
                (a, attrs[a], pool[0][a]))

    def test_pool_add2(self):
        """ Add a pool and check it's there using list functions

            Refer to schema by name
        """
        schema = {'id': self.schema_attrs['id']}
        attrs = {
            'name': 'test-pool-wrong',
            'default_type': 'reservation',
            'description': 'A simple test pool with incorrect name!'
        }
        pool_id = self.nipap.add_pool(self.auth, schema, attrs)
        pool = self.nipap.list_pool(self.auth, schema, {'id': pool_id})
        for a in attrs:
            self.assertEqual(
                pool[0][a], attrs[a],
                'Added object differ from listed on attribute: ' + a)

    def test_edit_pool_by_name(self):
        """ Try to rename a pool using edit_pool() function

            Pool is not uniquely identified (empty spec) so this should raise an error
        """
        schema = {'id': self.schema_attrs['id']}
        spec = {}
        attrs = {
            'name': self.pool_attrs['name'],
            'default_type': 'assignment',
            'description': 'A simple test pool with correct name!'
        }
        self.assertRaises(NipapInputError, self.nipap.edit_pool, self.auth,
                          schema, spec, attrs)

    def test_edit_pool(self):
        """ Rename a pool using edit_pool() function
        """
        schema = {'id': self.schema_attrs['id']}
        spec = {'id': self.pool_attrs['id']}
        attrs = {
            'name': 'test-pool',
            'default_type': 'assignment',
            'description': 'A simple test pool with correct name!',
            'ipv4_default_prefix_length': 32,
            'ipv6_default_prefix_length': 128
        }
        self.nipap.edit_pool(self.auth, schema, spec, attrs)
        # check that search for old record doesn't return anything
        pool = self.nipap.list_pool(self.auth, schema,
                                    {'name': self.pool_attrs['name']})
        self.assertEqual(pool, [], 'Old entry still exists')
        pool = self.nipap.list_pool(self.auth, schema, {'name': attrs['name']})
        for a in attrs:
            self.assertEqual(
                pool[0][a], attrs[a],
                'Added object differ from listed on attribute: ' + a)

    def test_remove_pool_by_id(self):
        """ Remove a pool by id
        """
        schema = {'id': self.schema_attrs['id']}
        pool = self.nipap.list_pool(self.auth, schema,
                                    {'id': self.pool_attrs['id']})
        # first make sure our pool exists
        self.assertNotEqual(pool[0], [],
                            'Record must exist before we can delete it')
        for a in self.pool_attrs:
            self.assertEqual(pool[0][a], self.pool_attrs[a],
                             'Listed attribute differ from original')
        # remove the pool
        self.nipap.remove_pool(self.auth, schema,
                               {'id': self.pool_attrs['id']})
        # check that search for old record doesn't return anything
        pool = self.nipap.list_pool(self.auth, schema,
                                    {'id': self.pool_attrs['id']})
        self.assertEqual(pool, [], 'Old entry still exists')

    def test_prefix_in_a_pool(self):
        """ Add prefixes to a poll and list!
        """
        schema = {'id': self.schema_attrs['id']}
        pool = self.nipap.list_pool(self.auth, schema,
                                    {'id': self.pool_attrs['id']})
        # first make sure our pool exists
        self.assertNotEqual(pool[0], [], 'Pool must exist!')
        pfxs = [
            '1.2.2.0/32', '1.2.2.1/32', '1.2.2.2/32', '1.2.2.3/32',
            '1.2.2.4/32', '1.2.2.5/32'
        ]
        for p in pfxs:
            prefix_attrs = {
                'authoritative_source': 'nipap-test',
                'prefix': p,
                'type': 'host',
                'description': 'test prefix',
                'pool_id': self.pool_attrs['id'],
                'comment': 'test comment, please remove! ;)'
            }
            self.nipap.add_prefix(self.auth, schema, prefix_attrs)

        # list again
        pool = self.nipap.list_pool(self.auth, schema,
                                    {'id': self.pool_attrs['id']})
        self.assertNotEqual(pool[0], [], 'Pool must exist!')
        self.assertEqual(set(pfxs), set(pool[0]['prefixes']),
                         'Returned prefixes do not match added ones')

    def test_prefix_basic(self):
        """ Test basic prefix functions
        """
        schema = {'id': self.schema_attrs['id']}
        prefix_attrs = {
            'authoritative_source': 'nipap-test',
            'prefix': '1.3.3.7/32',
            'type': 'host',
            'description': 'test prefix',
            'comment': 'test comment, please remove! ;)'
        }
        self.nipap.add_prefix(self.auth, schema, prefix_attrs)
        prefix = self.nipap.list_prefix(self.auth, schema,
                                        {'prefix': prefix_attrs['prefix']})
        for a in prefix_attrs:
            self.assertEqual(
                prefix[0][a], prefix_attrs[a],
                'Added object differ from listed on attribute: ' + a)

        # fetch many prefixes - all in a schema
        prefix = self.nipap.list_prefix(self.auth, schema, {})
        self.assertNotEqual(
            len(prefix), 0,
            'Found 0 prefixes in schema ' + self.schema_attrs['name'])

    def test_add_prefix(self):
        """ Test add_prefix in a bit more detail
        """
        schema = {'id': self.schema_attrs['id']}
        # we need a bloody pool first!
        pool = self.nipap.list_pool(self.auth, schema,
                                    {'id': self.pool_attrs['id']})
        # first make sure our pool exists
        self.assertNotEqual(pool[0], [], 'Pool must exist!')
        pfxs = [
            '10.0.0.0/24', '10.0.1.0/24', '10.0.2.0/24', '10.0.3.0/24',
            '10.0.4.0/24'
        ]
        for p in pfxs:
            prefix_attrs = {
                'authoritative_source': 'nipap-test',
                'prefix': p,
                'type': 'reservation',
                'description': 'test prefix',
                'pool_id': self.pool_attrs['id'],
                'comment': 'test comment, please remove! ;)'
            }
            self.nipap.add_prefix(self.auth, schema, prefix_attrs)

        # get an address based on from-prefix
        prefix_attrs = {
            'type': 'assignment',
            'authoritative_source': 'nipap-test',
            'description': 'test prefix',
            'comment': 'test comment, please remove! ;)'
        }
        res = self.nipap.add_prefix(self.auth, schema, prefix_attrs, {
            'from-prefix': ['10.0.0.0/24'],
            'prefix_length': 30
        })
        p = self.nipap.list_prefix(self.auth, schema, {'id': res})
        self.assertEqual(p[0]['prefix'], '10.0.0.0/30',
                         "New prefix differ from what it should be!")

        self.nipap.add_schema(self.auth, {
            'name': 'testtest',
            'description': 'another test schema!'
        })
        # pass different schemas in attr and args
        # TODO: Find something similar?
        #self.assertRaises(NipapInputError, self.nipap.add_prefix, schema, { 'authoritative_source': 'nipap-test', 'description': 'tjong' }, { 'from-prefix': ['10.0.0.0/24'], 'prefix_length': 30 })

    def test_prefix_search_simple(self):
        """ Test the simple prefix search function.
        """

        schema = {'id': self.schema_attrs['id']}

        # First, perform e few tests to verify search string expansion.
        query_keys = dict()
        query_keys['testing testing'] = "description"
        query_keys['1.2.3.4'] = "prefix"

        # build query string
        query_str = ""
        for key, val in query_keys.items():
            if val == "description":
                query_str += "\"%s\" " % key
            else:
                query_str += "%s " % key

        res = self.nipap.smart_search_prefix(self.auth, schema, query_str)
        for interp in res['interpretation']:
            self.assertEqual(
                interp['string'] in query_keys, True,
                "Function returned unknown interpreted string %s" %
                interp['string'])

        prefix_attrs = {
            'authoritative_source': 'nipap-test',
            'prefix': '1.3.3.77/32',
            'type': 'host',
            'description': 'test-ish prefix',
            'comment': 'Test prefix #77! ;)'
        }

        self.nipap.add_prefix(self.auth, schema, prefix_attrs)
        res = self.nipap.smart_search_prefix(self.auth, schema,
                                             r"""1.3.3.77 "-ish" """)
        self.assertEqual(res['result'][-1]['prefix'], '1.3.3.77/32',
                         'Prefix not found')

    def test_prefix_search_smart(self):
        """ Test the smart prefix search function.
        """
        schema = {'id': self.schema_attrs['id']}

        # test full ipv4 address
        res = self.nipap.smart_search_prefix(self.auth, schema, '1.3.3.7')
        self.assertEqual(res['interpretation'][0]['interpretation'],
                         'IPv4 address')

        res = self.nipap.smart_search_prefix(self.auth, schema, '1.1')
        self.assertEqual(
            res['interpretation'][0]['interpretation'], 'text',
            "Incorrectly interpreted '1.1' as : " +
            res['interpretation'][0]['interpretation'])

        res = self.nipap.smart_search_prefix(self.auth, schema, '10/8')
        self.assertEqual(res['interpretation'][0]['interpretation'],
                         'IPv4 prefix')

        res = self.nipap.smart_search_prefix(self.auth, schema, '2000:0::01')
        self.assertEqual(res['interpretation'][0]['interpretation'],
                         'IPv6 address')

    def test_prefix_remove(self):
        """ Remove a prefix
        """
        schema = {'id': self.schema_attrs['id']}
        prefix = self.nipap.list_prefix(self.auth, schema,
                                        {'id': self.prefix_attrs['id']})
        # first make sure our prefix exists
        self.assertEqual(prefix[0]['id'], self.prefix_attrs['id'],
                         'Record must exist before we can delete it')
        # remove the prefix, by id
        self.nipap.remove_prefix(self.auth, schema,
                                 {'id': self.prefix_attrs['id']})
        # check that search for old record doesn't return anything
        prefix = self.nipap.list_prefix(self.auth, schema,
                                        {'id': self.prefix_attrs['id']})
        self.assertEqual(prefix, [], 'Old entry still exists')

    def test_prefix_indent_ipv4(self):
        """ Check that our indentation calculation is working for IPv4

            Prefixes gets an indent value automatically assigned to help in
            displaying prefix information. The indent value is written on
            updates to the table and this test is to make sure it is correctly
            calculated.
        """
        schema = {'id': self.schema_attrs['id']}
        p1 = self.nipap.list_prefix(self.auth, schema,
                                    {'prefix': '1.3.3.1/32'})[0]
        p2 = self.nipap.list_prefix(self.auth, schema,
                                    {'prefix': '1.3.3.0/24'})[0]
        p3 = self.nipap.list_prefix(self.auth, schema,
                                    {'prefix': '1.3.0.0/16'})[0]
        self.assertEqual(p1['indent'], 4, "Indent calc on add failed")
        self.assertEqual(p2['indent'], 3, "Indent calc on add failed")
        self.assertEqual(p3['indent'], 0, "Indent calc on add failed")
        # remove middle prefix
        self.nipap.remove_prefix(self.auth, schema,
                                 {'id': self.prefix_attrs2['id']})
        # check that child prefix indent level has decreased
        p1 = self.nipap.list_prefix(self.auth, schema,
                                    {'prefix': '1.3.3.1/32'})[0]
        p3 = self.nipap.list_prefix(self.auth, schema,
                                    {'prefix': '1.3.0.0/16'})[0]
        self.assertEqual(p1['indent'], 3, "Indent calc on remove failed")
        self.assertEqual(p3['indent'], 0, "Indent calc on remove failed")

    def test_prefix_indent_ipv6(self):
        """ Check that our indentation calculation is working for IPv6

            Prefixes gets an indent value automatically assigned to help in
            displaying prefix information. The indent value is written on
            updates to the table and this test is to make sure it is correctly
            calculated.
        """
        schema = {'id': self.schema_attrs['id']}
        p1 = self.nipap.list_prefix(self.auth, schema,
                                    {'prefix': '2001:0db8:3:3::1/128'})[0]
        p2 = self.nipap.list_prefix(self.auth, schema,
                                    {'prefix': '2001:0db8:3:3::/64'})[0]
        p3 = self.nipap.list_prefix(self.auth, schema,
                                    {'prefix': '2001:0db8:3:0::/48'})[0]
        self.assertEqual(p1['indent'], 4, "Indent calc on add failed")
        self.assertEqual(p2['indent'], 2, "Indent calc on add failed")
        self.assertEqual(p3['indent'], 0, "Indent calc on add failed")
        # remove middle prefix
        self.nipap.remove_prefix(self.auth, schema,
                                 {'id': self.prefix6_attrs2['id']})
        # check that child prefix indent level has decreased
        p1 = self.nipap.list_prefix(self.auth, schema,
                                    {'prefix': '2001:0db8:3:3::1/128'})[0]
        p3 = self.nipap.list_prefix(self.auth, schema,
                                    {'prefix': '2001:0db8:3:0::/48'})[0]
        self.assertEqual(
            p1['indent'], 3, "Indent calc on remove failed for " +
            p1['prefix'] + " indent: " + str(p1['indent']))
        self.assertEqual(
            p3['indent'], 0, "Indent calc on remove failed for " +
            p3['prefix'] + " indent: " + str(p3['indent']))

    def test_find_free_prefix_input(self):
        """ Mostly input testing of find_free_prefix

            Try to stress find_free_prefix and send a lot of junk..
        """
        schema = {'id': self.schema_attrs['id']}
        # set up a prefix not used elsewhere so we have a known good state
        prefix_attrs = {
            'authoritative_source': 'nipap-test',
            'prefix': '100.0.0.0/16',
            'type': 'reservation',
            'description': 'test prefix',
            'comment': 'test comment, please remove! ;)'
        }
        self.nipap.add_prefix(self.auth, schema, prefix_attrs)

        # no schema, should raise error!
        self.assertRaises(NipapInputError, self.nipap.find_free_prefix,
                          self.auth, schema, {'from-prefix': ['100.0.0.0/16']})

        # incorrect from-prefix type, string instead of list of strings (looking like an IP address)
        self.assertRaises(NipapInputError, self.nipap.find_free_prefix,
                          self.auth, schema, {'from-prefix': '100.0.0.0/16'})

        # missing prefix_length
        self.assertRaises(NipapMissingInputError, self.nipap.find_free_prefix,
                          self.auth, schema, {
                              'from-prefix': ['100.0.0.0/16'],
                              'count': 1
                          })

        # try giving both IPv4 and IPv6 in from-prefix which shouldn't work
        self.assertRaises(
            NipapInputError, self.nipap.find_free_prefix, self.auth, schema, {
                'from-prefix': ['100.0.0.0/16', '2a00:800::0/25'],
                'prefix_length': 24,
                'count': 1
            })

        # try giving non-integer as wanted prefix length
        self.assertRaises(NipapValueError, self.nipap.find_free_prefix,
                          self.auth, schema, {
                              'from-prefix': ['100.0.0.0/16'],
                              'prefix_length': '24',
                              'count': 1
                          })

        # try giving to high a number as wanted prefix length for IPv4
        self.assertRaises(NipapValueError, self.nipap.find_free_prefix,
                          self.auth, schema, {
                              'from-prefix': ['100.0.0.0/16'],
                              'prefix_length': 35,
                              'count': 1
                          })

        # try giving to high a number as wanted prefix length for IPv6
        self.assertRaises(NipapValueError, self.nipap.find_free_prefix,
                          self.auth, schema, {
                              'from-prefix': ['2a00:800::1/25'],
                              'prefix_length': 150,
                              'count': 1
                          })

        # try giving a high number for result count (max is 1000)
        self.assertRaises(NipapValueError, self.nipap.find_free_prefix,
                          self.auth, schema, {
                              'from-prefix': ['100.0.0.0/16'],
                              'prefix_length': 30,
                              'count': 55555
                          })

        # don't pass 'family', which is required when specifying 'from-pool'
        self.assertRaises(
            NipapMissingInputError, self.nipap.find_free_prefix, self.auth,
            schema, {
                'from-pool': {
                    'name': self.pool_attrs['name']
                },
                'prefix_length': 24,
                'count': 1
            })

        # pass crap as family, wrong type even
        self.assertRaises(
            ValueError, self.nipap.find_free_prefix, self.auth, schema, {
                'from-pool': {
                    'name': self.pool_attrs['name']
                },
                'prefix_length': 24,
                'count': 1,
                'family': 'crap'
            })

        # pass 7 as family
        self.assertRaises(
            NipapValueError, self.nipap.find_free_prefix, self.auth, schema, {
                'from-pool': {
                    'name': self.pool_attrs['name']
                },
                'prefix_length': 24,
                'count': 1,
                'family': 7
            })

        # pass non existent pool
        self.assertRaises(
            NipapNonExistentError, self.nipap.find_free_prefix, self.auth,
            schema, {
                'from-pool': {
                    'name': 'crap'
                },
                'prefix_length': 24,
                'count': 1,
                'family': 4
            })

    def test_find_free_prefix1(self):
        """ Functionality testing of find_free_prefix

            Mostly based on 'from-prefix'
        """
        schema = {'id': self.schema_attrs['id']}
        # set up a prefix not used elsewhere so we have a known good state
        prefix_attrs = {
            'authoritative_source': 'nipap-test',
            'prefix': '100.0.0.0/16',
            'type': 'assignment',
            'description': 'test prefix',
            'comment': 'test comment, please remove! ;)'
        }
        self.nipap.add_prefix(self.auth, schema, prefix_attrs)

        # simple test
        res = self.nipap.find_free_prefix(
            self.auth, schema, {
                'from-prefix': ['100.0.0.0/16', '1.3.3.0/24'],
                'prefix_length': 24,
                'count': 1
            })
        self.assertEqual(res, ['100.0.0.0/24'],
                         "Incorrect prefix set returned")

        # simple test - only one input prefix (which did cause a bug, thus keeping it)
        res = self.nipap.find_free_prefix(self.auth, schema, {
            'from-prefix': ['100.0.0.0/16'],
            'prefix_length': 24,
            'count': 1
        })
        self.assertEqual(res, ['100.0.0.0/24'],
                         "Incorrect prefix set returned")

        res = self.nipap.find_free_prefix(
            self.auth, schema, {
                'from-prefix': ['100.0.0.0/16', '1.3.3.0/24'],
                'prefix_length': 24,
                'count': 999
            })
        self.assertEqual(len(res), 256, "Incorrect prefix set returned")

    def test_find_free_prefix2(self):
        """ Functionality testing of find_free_prefix

            Mostly based on 'from-pool'
        """
        schema = {'id': self.schema_attrs['id']}
        # we need a bloody pool first!
        pool = self.nipap.list_pool(self.auth, schema,
                                    {'id': self.pool_attrs['id']})
        # first make sure our pool exists
        self.assertNotEqual(pool[0], [], 'Pool must exist!')
        pfxs = [
            '10.0.0.0/24', '10.0.1.0/24', '10.0.2.0/24', '10.0.3.0/24',
            '10.0.4.0/24'
        ]
        for p in pfxs:
            prefix_attrs = {
                'type': 'reservation',
                'authoritative_source': 'nipap-test',
                'prefix': p,
                'description': 'test prefix',
                'pool_id': self.pool_attrs['id'],
                'comment': 'test comment, please remove! ;)'
            }
            self.nipap.add_prefix(self.auth, schema, prefix_attrs)

        # from-pool test
        res = self.nipap.find_free_prefix(
            self.auth, schema, {
                'from-pool': {
                    'name': self.pool_attrs['name']
                },
                'count': 1,
                'family': 4
            })
        self.assertEqual(
            res, ['10.0.1.0/30'],
            "Incorrect prefix set returned when requesting default prefix-length"
        )

        # from-pool test, specify wanted prefix length
        res = self.nipap.find_free_prefix(
            self.auth, schema, {
                'from-pool': {
                    'name': self.pool_attrs['name']
                },
                'count': 1,
                'family': 4,
                'prefix_length': 31
            })
        self.assertEqual(
            res, ['10.0.1.0/31'],
            "Incorrect prefix set returned with explicit prefix-length")

    def test_edit_prefix(self):
        """ Functionality testing of edit_prefix.
        """

        schema = {'id': self.schema_attrs['id']}
        data = {
            'prefix': '192.0.2.0/24',
            'description': 'foo',
            'comment': 'bar',
            'order_id': '0xBEEF',
            'customer_id': 'CUST-EEF-DERP',
            'alarm_priority': 'low',
            'type': 'assignment',
            'node': 'TOK-CORE-1',
            'country': 'EE',
            'authoritative_source': 'unittest',
            'pool': self.pool_attrs['id']
        }

        # basic edit
        self.nipap.edit_prefix(self.auth, schema,
                               {'id': self.prefix_attrs['id']}, data)
        p = self.nipap.list_prefix(self.auth, schema,
                                   {'id': self.prefix_attrs['id']})[0]
        # remove what we did not touch
        for k, v in data.keys():
            if k not in p:
                del p[k]
        self.assertEqual(data, p, "Prefix data incorrect after edit.")

        # create a collision
        self.assertRaises(NipapError, self.nipap.edit_prefix, self.auth,
                          schema, {'id': self.prefix_attrs2['id']},
                          {'prefix': data['prefix']})

        # try to change schema - disallowed
        self.assertRaises(NipapExtraneousInputError, self.nipap_edit_prefix,
                          self.auth, schema, {'id': self.prefix_attrs2['id']},
                          {'schema': self.schema_attrs2['id']})

    def test_add_asn(self):
        """ Test adding ASNs to NIPAP.
        """

        data = {'asn': 1, 'name': 'Test ASN #1'}

        self.assertEqual(self.nipap.add_asn(self.auth, data), 1,
                         "add_asn did not return correct ASN.")
        asn = self.nipap.list_asn(self.auth, {'asn': 1})[0]
        self.assertEquals(data, asn,
                          "ASN in database not equal to what was added.")
        self.assertRaises(NipapDuplicateError, self.nipap.add_asn, self.auth,
                          data)

    def test_remove_asn(self):
        """ Test removing ASNs from NIPAP.
        """

        data = {'asn': 2, 'name': 'Test ASN #2'}

        asn = self.nipap.add_asn(self.auth, data)
        self.nipap.remove_asn(self.auth, asn)
        self.assertEquals(0, len(self.nipap.list_asn(self.auth, {'asn': 2})),
                          "Removed ASN still in database")

    def test_edit_asn(self):
        """ Test editing ASNs.
        """

        data = {'asn': 3, 'name': 'Test ASN #3'}

        asn = self.nipap.add_asn(self.auth, data)
        self.nipap.edit_asn(self.auth, data['asn'], {'name': 'b0rk'})
        self.assertEquals(
            self.nipap.list_asn(self.auth, {'asn': 3})[0]['name'], 'b0rk',
            "Edited ASN still has it's old name.")
        self.assertRaises(NipapExtraneousInputError, self.nipap.edit_asn,
                          self.auth, {'asn': 3}, {
                              'asn': 4,
                              'name': 'Test ASN #4'
                          })

    def test_search_asn(self):
        """ Test searching ASNs.
        """

        data = {'asn': 4, 'name': 'This is AS number 4'}

        asn = self.nipap.add_asn(self.auth, data)
        q = {'operator': 'equals', 'val1': 'asn', 'val2': data['asn']}
        res = self.nipap.search_asn(self.auth, q)
        self.assertEquals(len(res['result']), 1,
                          "equal search resulted in wrong number of hits")
        self.assertEquals(res['result'][0]['name'], data['name'],
                          "search hit got wrong name")

        q = {'operator': 'regex_match', 'val1': 'name', 'val2': 'number'}
        res = self.nipap.search_asn(self.auth, q)
        self.assertEquals(len(res['result']), 1,
                          "regex search resulted in wrong number of hits")
        self.assertEquals(res['result'][0]['asn'], data['asn'],
                          "search hit got wrong asn")

    def test_smart_search_asn(self):
        """ Test smart_search_asn function.
        """

        data = {'asn': 5, 'name': 'Autonomous System Number 5'}

        asn = self.nipap.add_asn(self.auth, data)
        res = self.nipap.smart_search_asn(self.auth, "Autonomous")
        self.assertEquals(len(res['result']), 1,
                          "search resulted in wrong number of hits")
        self.assertEquals(res['result'][0]['asn'], data['asn'],
                          "search hit got wrong asn")
        self.assertEquals(res['interpretation'][0]['attribute'], 'name',
                          "search term interpretated as wrong type")

        res = self.nipap.smart_search_asn(self.auth, "5")
        self.assertEquals(len(res['result']), 1,
                          "search resulted in wrong number of hits")
        self.assertEquals(res['result'][0]['asn'], data['asn'],
                          "search hit got wrong asn")
        self.assertEquals(res['interpretation'][0]['attribute'], 'asn',
                          "search term interpretated as wrong type")
Exemplo n.º 15
0
class NipapCliTest(unittest.TestCase):
    """ Tests the NIPAP CLI

        We presume the database is empty
    """
    maxDiff = None

    logger = None
    cfg = None
    nipap = None

    def setUp(self):

        # logging
        self.logger = logging.getLogger(self.__class__.__name__)

        # NIPAP
        self.cfg = NipapConfig('/etc/nipap/nipap.conf')
        self.nipap = Nipap()

        # create dummy auth object
        # As the authentication is performed before the query hits the Nipap
        # class, it does not matter what user we use here
        self.auth = SqliteAuth('local', 'unittest', 'unittest', 'unittest')
        self.auth.authenticated_as = 'unittest'
        self.auth.full_name = 'Unit test'

        # have to delete hosts before we can delete the rest
        self.nipap._execute("DELETE FROM ip_net_plan WHERE masklen(prefix) = 32")
        # the rest
        self.nipap._execute("DELETE FROM ip_net_plan")
        # delete all except for the default VRF with id 0
        self.nipap._execute("DELETE FROM ip_net_vrf WHERE id > 0")
        # set default info for VRF 0
        self.nipap._execute("UPDATE ip_net_vrf SET name = 'default', description = 'The default VRF, typically the Internet.' WHERE id = 0")
        self.nipap._execute("DELETE FROM ip_net_pool")
        self.nipap._execute("DELETE FROM ip_net_asn")


    def _run_cmd(self, cmd):
        """ Run a command
        """
        import subprocess
        return subprocess.check_output(cmd)


    def test_prefix_add_list(self):
        """ Add a prefix and verify result in database
        """
        ref = {
                'prefix': '1.3.3.0/24',
                'type': 'assignment',
                'description': 'foo description',
                'comment': 'comment bar',
                'country': 'AB',
                'alarm_priority': 'high',
                'monitor': 'true',
                'order_id': '123'
                }

        cmd = [nipap_bin, 'address', 'add']
        for key in ref:
            cmd.append(key)
            cmd.append(ref[key])

        ref['display_prefix'] = '1.3.3.0/24'
        ref['indent'] = 0
        ref['family'] = 4
        ref['monitor'] = True
        ref['pool_id'] = None
        ref['pool_name'] = None
        ref['vrf_id'] = 0
        ref['vrf_name'] = 'default'
        ref['vrf_rt'] = None
        ref['external_key'] = None
        ref['node'] = None
        ref['authoritative_source'] = 'nipap'
        ref['vlan'] = None
        ref['inherited_tags'] = []
        ref['tags'] = []

        self._run_cmd(cmd)

        res = s.list_prefix({ 'auth': ad, 'spec': {} })
        del(res[0]['id'])

        self.assertEqual(res, [ ref, ])