# Copyright 2015-2018 Capital One Services, LLC
#
# 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 azure_common import BaseTest, arm_template


class RouteTableTest(BaseTest):

    route_table_name = 'cctestroutetable'
    vnet_name = 'ccroutetablevnet'
    allowed_subnet_name = 'cctestsubnet1'
    disallowed_subnet_name = 'cctestsubnet2'

    @staticmethod
    def _subnet_id_suffix(subnet):
        return '{}/subnets/{}'.format(RouteTableTest.vnet_name, subnet)

    def test_route_table_schema_validate(self):
        with self.sign_out_patch():
            p = self.load_policy({
                'name': 'test-azure-route-table',
                'resource': 'azure.routetable'
            }, validate=True)
            self.assertTrue(p)

    @arm_template('route-table-and-vnet.json')
    def test_find_route_table_by_name(self):

        p = self.load_policy({
            'name': 'test-find-route-table-by-name',
            'resource': 'azure.routetable',
            'filters': [
                {
                    'type': 'value',
                    'key': 'name',
                    'op': 'eq',
                    'value': RouteTableTest.route_table_name
                }
            ]
        })

        resources = p.run()
        self._assert_only_route_table_in_resources(resources)

    @arm_template('route-table-and-vnet.json')
    def test_detect_route_table_is_routing_to_correct_subnet(self):

        p = self.load_policy({
            'name': 'test-detect-route-table-is-routing-to-correct-subnet',
            'resource': 'azure.routetable',
            'filters': [
                {
                    'type': 'value',
                    'key': 'name',
                    'op': 'eq',
                    'value': RouteTableTest.route_table_name
                },
                {
                    'type': 'value',
                    'key': 'properties.subnets[?ends_with(id, \'{}\')] | [0]'.format(
                        RouteTableTest._subnet_id_suffix(RouteTableTest.allowed_subnet_name)
                    ),
                    'value': 'not-null'
                }
            ]
        })

        resources = p.run()
        self._assert_only_route_table_in_resources(resources)

    @arm_template('route-table-and-vnet.json')
    def test_detect_route_table_not_routing_to_incorrect_subnet(self):

        p = self.load_policy({
            'name': 'test-detect-route-table-not-routing-to-incorrect-subnet',
            'resource': 'azure.routetable',
            'filters': [
                {
                    'type': 'value',
                    'key': 'name',
                    'op': 'eq',
                    'value': RouteTableTest.route_table_name
                },
                {
                    'type': 'value',
                    'key': 'properties.subnets[?ends_with(id, \'{}\')] | [0]'.format(
                        RouteTableTest._subnet_id_suffix(RouteTableTest.disallowed_subnet_name)
                    ),
                    'value': 'not-null'
                }
            ]
        })

        resources = p.run()
        self.assertEqual(len(resources), 0, "A route table is routing to a disallowed subnet")

    @arm_template('route-table-and-vnet.json')
    def test_detect_route_only_routes_to_specific_subnets(self):

        p = self.load_policy({
            'name': 'test-detect-route-only-routes-to-specific-subnets',
            'resource': 'azure.routetable',
            'filters': [
                {
                    'type': 'value',
                    'key': 'name',
                    'op': 'eq',
                    'value': RouteTableTest.route_table_name
                },
                {
                    'type': 'value',
                    'key': 'properties.subnets[?ends_with(id, \'{}\')] | [0]'.format(
                        RouteTableTest._subnet_id_suffix(RouteTableTest.allowed_subnet_name)
                    ),
                    'value': 'not-null'
                },
                {
                    'type': 'value',
                    'key': 'length(properties.subnets)',
                    'op': 'eq',
                    'value': 1
                }
            ]
        })

        resources = p.run()
        self._assert_only_route_table_in_resources(resources)

    def _assert_only_route_table_in_resources(self, resources):

        self.assertEqual(len(resources), 1, "Only one route table should be found")

        route_table = resources[0]
        self.assertEqual(RouteTableTest.route_table_name, route_table.get('name'),
                         "The wrong route table was found")

        properties = route_table.get('properties')
        self.assertIsNotNone(properties, "Missing properties")

        subnets = properties.get('subnets')
        self.assertIsNotNone(subnets, "Missing subnets")
        self.assertEqual(1, len(subnets), "There should only be one subnet")

        subnet = subnets[0]
        self.assertIn(RouteTableTest.allowed_subnet_name, subnet.get('id'), "Incorrect subnet")

[((37, 5, 37, 46), 'azure_common.arm_template', 'arm_template', ({(37, 18, 37, 45): '"""route-table-and-vnet.json"""'}, {}), "('route-table-and-vnet.json')", False, 'from azure_common import BaseTest, arm_template\n'), ((56, 5, 56, 46), 'azure_common.arm_template', 'arm_template', ({(56, 18, 56, 45): '"""route-table-and-vnet.json"""'}, {}), "('route-table-and-vnet.json')", False, 'from azure_common import BaseTest, arm_template\n'), ((82, 5, 82, 46), 'azure_common.arm_template', 'arm_template', ({(82, 18, 82, 45): '"""route-table-and-vnet.json"""'}, {}), "('route-table-and-vnet.json')", False, 'from azure_common import BaseTest, arm_template\n'), ((108, 5, 108, 46), 'azure_common.arm_template', 'arm_template', ({(108, 18, 108, 45): '"""route-table-and-vnet.json"""'}, {}), "('route-table-and-vnet.json')", False, 'from azure_common import BaseTest, arm_template\n')]