# Copyright 2013 Hewlett-Packard Development Company, L.P.
#
# Author: Kiall Mac Innes <kiall@hp.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import log as logging

from designate.tests import TestCase
from designate.schema import format


LOG = logging.getLogger(__name__)


class SchemaFormatTest(TestCase):
    def test_is_ipv4(self):
        valid_ipaddresses = [
            '0.0.0.1',
            '127.0.0.1',
            '10.0.0.1',
            '192.0.2.2',
        ]

        invalid_ipaddresses = [
            '0.0.0.0',
            '0.0.0.256',
            '0.0.256.0',
            '0.256.0.0',
            '256.0.0.0',
            '127.0.0',
            '127.0.0.999',
            '127.0.0.256',
            '127.0..1',
            '-1.0.0.1',
            '1.0.-0.1',
            '1.0.0.-1',
            'ABCDEF',
            'ABC/DEF',
            'ABC\\DEF',
            # Trailing newline - Bug 1471158
            "127.0.0.1\n",
        ]

        for ipaddress in valid_ipaddresses:
            self.assertTrue(format.is_ipv4(ipaddress))

        for ipaddress in invalid_ipaddresses:
            self.assertFalse(format.is_ipv4(ipaddress))

    def test_is_ipv6(self):
        valid_ipaddresses = [
            '2001:db8::0',
            '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
            '2001:db8:85a3:0000:0000:8a2e:0370:7334',
            '2001:db8:85a3::8a2e:0370:7334',
        ]

        invalid_ipaddresses = [
            # Invalid characters
            'hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh'
            # Trailing newline - Bug 1471158
            "2001:db8::0\n",
        ]

        for ipaddress in valid_ipaddresses:
            self.assertTrue(format.is_ipv6(ipaddress),
                            'Expected Valid: %s' % ipaddress)

        for ipaddress in invalid_ipaddresses:
            self.assertFalse(format.is_ipv6(ipaddress),
                             'Expected Invalid: %s' % ipaddress)

    def test_is_hostname(self):
        valid_hostnames = [
            'example.com.',
            'www.example.com.',
            '*.example.com.',
            '12345.example.com.',
            '192-0-2-1.example.com.',
            'ip192-0-2-1.example.com.',
            'www.ip192-0-2-1.example.com.',
            'ip192-0-2-1.www.example.com.',
            'abc-123.example.com.',
            '_tcp.example.com.',
            '_service._tcp.example.com.',
            ('1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2'
             '.ip6.arpa.'),
            '1.1.1.1.in-addr.arpa.',
            'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.',
            ('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi.'),
        ]

        invalid_hostnames = [
            '**.example.com.',
            '*.*.example.org.',
            'a.*.example.org.',
            # Exceeds single lable length limit
            ('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkL'
             '.'),
            ('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkL'
             '.'),
            # Exceeds total length limit
            ('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopq.'),
            # Empty label part
            'abc..def.',
            '..',
            # Invalid character
            'abc$.def.',
            'abc.def$.',
            # Labels must not start with a -
            '-abc.',
            'abc.-def.',
            'abc.-def.ghi.',
            # Labels must not end with a -
            'abc-.',
            'abc.def-.',
            'abc.def-.ghi.',
            # Labels must not start or end with a -
            '-abc-.',
            'abc.-def-.',
            'abc.-def-.ghi.',
            # Trailing newline - Bug 1471158
            "www.example.com.\n",
        ]

        for hostname in valid_hostnames:
            self.assertTrue(format.is_hostname(hostname))

        for hostname in invalid_hostnames:
            self.assertFalse(format.is_hostname(hostname))

    def test_is_domainname(self):
        valid_domainnames = [
            'example.com.',
            'www.example.com.',
            '12345.example.com.',
            '192-0-2-1.example.com.',
            'ip192-0-2-1.example.com.',
            'www.ip192-0-2-1.example.com.',
            'ip192-0-2-1.www.example.com.',
            'abc-123.example.com.',
            '_tcp.example.com.',
            '_service._tcp.example.com.',
            ('1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2'
             '.ip6.arpa.'),
            '1.1.1.1.in-addr.arpa.',
            'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.',
            ('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi.'),
        ]

        invalid_domainnames = [
            '*.example.com.',
            '**.example.com.',
            '*.*.example.org.',
            'a.*.example.org.',
            # Exceeds single lable length limit
            ('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkL'
             '.'),
            ('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkL'
             '.'),
            ('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkL'
             '.'),
            # Exceeds total length limit
            ('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopq.'),
            # Empty label part
            'abc..def.',
            '..',
            # Invalid character
            'abc$.def.',
            'abc.def$.',
            # Labels must not start with a -
            '-abc.',
            'abc.-def.',
            'abc.-def.ghi.',
            # Labels must not end with a -
            'abc-.',
            'abc.def-.',
            'abc.def-.ghi.',
            # Labels must not start or end with a -
            '-abc-.',
            'abc.-def-.',
            'abc.-def-.ghi.',
            # Trailing newline - Bug 1471158
            "example.com.\n",
        ]

        for domainname in valid_domainnames:
            self.assertTrue(format.is_domainname(domainname), domainname)

        for domainname in invalid_domainnames:
            self.assertFalse(format.is_domainname(domainname), domainname)

    def test_is_srv_hostname(self):
        valid_hostnames = [
            '_sip._tcp.example.com.',
            '_sip._udp.example.com.',
        ]

        invalid_hostnames = [
            # Invalid Formats
            '_tcp.example.com.',
            'sip._udp.example.com.',
            '_sip.udp.example.com.',
            'sip.udp.example.com.',
            # Trailing newline - Bug 1471158
            "_sip._tcp.example.com.\n",
        ]

        for hostname in valid_hostnames:
            self.assertTrue(format.is_srv_hostname(hostname),
                            'Expected Valid: %s' % hostname)

        for hostname in invalid_hostnames:
            self.assertFalse(format.is_srv_hostname(hostname),
                             'Expected Invalid: %s' % hostname)

    def test_is_tldname(self):
        valid_tldnames = [
            'com',
            'net',
            'org',
            'co.uk',
        ]

        invalid_tldnames = [
            # Invalid Formats
            'com.',
            '.com',
            # Trailing newline - Bug 1471158
            "com\n",
        ]

        for tldname in valid_tldnames:
            self.assertTrue(format.is_tldname(tldname),
                            'Expected Valid: %s' % tldname)

        for tldname in invalid_tldnames:
            self.assertFalse(format.is_tldname(tldname),
                             'Expected Invalid: %s' % tldname)

    def test_is_email(self):
        valid_emails = [
            'user@example.com',
            'user@emea.example.com',
            'user@example.com',
            'first.last@example.com',
        ]

        invalid_emails = [
            # We use the email addr for the SOA RNAME field, this means the
            # entire address, excluding the @ must be chacracters valid
            # as a DNS name. i.e. + and % addressing is invalid.
            'user+plus@example.com',
            'user%example.org@example.com',
            'example.org',
            '@example.org',
            'user@*.example.org',
            'user',
            'user@',
            'user+plus',
            'user+plus@',
            'user%example.org',
            'user%example.org@',
            'user@example.org.',
            # Exceeds total length limit
            ('user@fghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.'
             'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopq.'),
            # Exceeds single lable length limit
            ('user@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg'
             'hijkL.'),
            ('user@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg'
             'hijk.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg'
             'hijkL.'),
            # Exceeds single lable length limit in username part
            ('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkL'
             '@example.com.'),
        ]

        for email in valid_emails:
            LOG.debug('Expecting success for: %s' % email)
            self.assertTrue(format.is_email(email))

        for email in invalid_emails:
            LOG.debug('Expecting failure for: %s' % email)
            self.assertFalse(format.is_email(email))

    def test_is_sshfp(self):
        valid_sshfps = [
            '72d30d211ce8c464de2811e534de23b9be9b4dc4',
        ]

        invalid_sshfps = [
            # Invalid Formats
            'P2d30d211ce8c464de2811e534de23b9be9b4dc4',  # "P" !IN [A-F]
            '72d30d211',
            # Trailing newline - Bug 1471158
            "72d30d211ce8c464de2811e534de23b9be9b4dc4\n",
        ]

        for sshfp in valid_sshfps:
            self.assertTrue(format.is_sshfp(sshfp),
                            'Expected Valid: %s' % sshfp)

        for sshfp in invalid_sshfps:
            self.assertFalse(format.is_sshfp(sshfp),
                             'Expected Invalid: %s' % sshfp)

    def test_is_uuid(self):
        valid_uuids = [
            'd3693ef8-2188-11e5-bf77-676ff9eb39dd',
        ]

        invalid_uuids = [
            # Invalid Formats
            'p3693ef8-2188-11e5-bf77-676ff9eb39dd',  # "p" !IN [A-F]
            'd3693ef8218811e5bf77676ff9eb39dd',
            # Trailing newline - Bug 1471158
            "d3693ef8-2188-11e5-bf77-676ff9eb39dd\n",
        ]

        for uuid in valid_uuids:
            self.assertTrue(format.is_uuid(uuid),
                            'Expected Valid: %s' % uuid)

        for uuid in invalid_uuids:
            self.assertFalse(format.is_uuid(uuid),
                             'Expected Invalid: %s' % uuid)

    def test_is_fip_id(self):
        valid_fip_ids = [
            'region-a:d3693ef8-2188-11e5-bf77-676ff9eb39dd',
        ]

        invalid_fip_ids = [
            # Invalid Formats
            'region-a:p3693ef8-2188-11e5-bf77-676ff9eb39dd',  # "p" !IN [A-F]
            # Trailing newline - Bug 1471158
            "region-a:d3693ef8-2188-11e5-bf77-676ff9eb39dd\n",
        ]

        for fip_id in valid_fip_ids:
            self.assertTrue(format.is_floating_ip_id(fip_id),
                            'Expected Valid: %s' % fip_id)

        for fip_id in invalid_fip_ids:
            self.assertFalse(format.is_floating_ip_id(fip_id),
                             'Expected Invalid: %s' % fip_id)

    def test_is_ip_and_port(self):
        valid_ip_and_ports = [
            '192.0.2.1:80',
            '192.0.2.1:1',
            '192.0.2.1:65535',
        ]

        invalid_ip_and_ports = [
            '192.0.2.1:65536',
            # Trailing newline - Bug 1471158
            "192.0.2.1:80\n",
        ]

        for ip_and_port in valid_ip_and_ports:
            self.assertTrue(format.is_ip_and_port(ip_and_port),
                            'Expected Valid: %s' % ip_and_port)

        for ip_and_port in invalid_ip_and_ports:
            self.assertFalse(format.is_ip_and_port(ip_and_port),
                             'Expected Invalid: %s' % ip_and_port)
