# Copyright (C) 2014,2015 VA Linux Systems Japan K.K.
# Copyright (C) 2014,2015 YAMAMOTO Takashi <yamamoto at valinux co jp>
# All Rights Reserved.
#
#    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.

import mock
import netaddr

import neutron.plugins.openvswitch.common.constants as ovs_const
from neutron.tests.unit.plugins.openvswitch.agent.openflow.ovs_ofctl \
    import ovs_bridge_test_base


call = mock.call  # short hand


class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
                          ovs_bridge_test_base.OVSDVRProcessTestMixin):
    dvr_process_table_id = ovs_const.DVR_PROCESS
    dvr_process_next_table_id = ovs_const.PATCH_LV_TO_TUN

    def setUp(self):
        super(OVSTunnelBridgeTest, self).setUp()
        self.setup_bridge_mock('br-tun', self.br_tun_cls)

    def test_setup_default_table(self):
        patch_int_ofport = 5555
        arp_responder_enabled = False
        self.br.setup_default_table(patch_int_ofport=patch_int_ofport,
            arp_responder_enabled=arp_responder_enabled)
        expected = [
            call.add_flow(priority=1, in_port=patch_int_ofport,
                          actions='resubmit(,2)'),
            call.add_flow(priority=0, actions='drop'),
            call.add_flow(priority=0, table=2,
                          dl_dst='00:00:00:00:00:00/01:00:00:00:00:00',
                          actions='resubmit(,20)'),
            call.add_flow(priority=0, table=2,
                          dl_dst='01:00:00:00:00:00/01:00:00:00:00:00',
                          actions='resubmit(,22)'),
            call.add_flow(priority=0, table=3, actions='drop'),
            call.add_flow(priority=0, table=4, actions='drop'),
            call.add_flow(priority=1, table=10,
                          actions='learn(table=20,priority=1,'
                          'hard_timeout=300,NXM_OF_VLAN_TCI[0..11],'
                          'NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],'
                          'load:0->NXM_OF_VLAN_TCI[],'
                          'load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[],'
                          'output:NXM_OF_IN_PORT[]),'
                          'output:%s' % patch_int_ofport),
            call.add_flow(priority=0, table=20, actions='resubmit(,22)'),
            call.add_flow(priority=0, table=22, actions='drop'),
        ]
        self.assertEqual(expected, self.mock.mock_calls)

    def test_setup_default_table_arp_responder_enabled(self):
        patch_int_ofport = 5555
        arp_responder_enabled = True
        self.br.setup_default_table(patch_int_ofport=patch_int_ofport,
            arp_responder_enabled=arp_responder_enabled)
        expected = [
            call.add_flow(priority=1, in_port=patch_int_ofport,
                          actions='resubmit(,2)'),
            call.add_flow(priority=0, actions='drop'),
            call.add_flow(priority=1, table=2, dl_dst='ff:ff:ff:ff:ff:ff',
                          actions='resubmit(,21)', proto='arp'),
            call.add_flow(priority=0, table=2,
                          dl_dst='00:00:00:00:00:00/01:00:00:00:00:00',
                          actions='resubmit(,20)'),
            call.add_flow(priority=0, table=2,
                          dl_dst='01:00:00:00:00:00/01:00:00:00:00:00',
                          actions='resubmit(,22)'),
            call.add_flow(priority=0, table=3, actions='drop'),
            call.add_flow(priority=0, table=4, actions='drop'),
            call.add_flow(priority=1, table=10,
                          actions='learn(table=20,priority=1,'
                          'hard_timeout=300,NXM_OF_VLAN_TCI[0..11],'
                          'NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],'
                          'load:0->NXM_OF_VLAN_TCI[],'
                          'load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[],'
                          'output:NXM_OF_IN_PORT[]),'
                          'output:%s' % patch_int_ofport),
            call.add_flow(priority=0, table=20, actions='resubmit(,22)'),
            call.add_flow(priority=0, table=21, actions='resubmit(,22)'),
            call.add_flow(priority=0, table=22, actions='drop'),
        ]
        self.assertEqual(expected, self.mock.mock_calls)

    def test_provision_local_vlan(self):
        network_type = 'vxlan'
        lvid = 888
        segmentation_id = 777
        distributed = False
        self.br.provision_local_vlan(network_type=network_type, lvid=lvid,
                                     segmentation_id=segmentation_id,
                                     distributed=distributed)
        expected = [
            call.add_flow(priority=1, tun_id=segmentation_id,
                          actions='mod_vlan_vid:%s,resubmit(,10)' % lvid,
                          table=4),
        ]
        self.assertEqual(expected, self.mock.mock_calls)

    def test_reclaim_local_vlan(self):
        network_type = 'vxlan'
        segmentation_id = 777
        self.br.reclaim_local_vlan(network_type=network_type,
                                   segmentation_id=segmentation_id)
        expected = [
            call.delete_flows(tun_id=segmentation_id, table=4),