import unittest

from flexmock import flexmock_teardown
import mock

from tests.util.global_reactor import cisco_privileged_password
from tests.util.global_reactor import cisco_switch_ssh_port, cisco_switch_telnet_port, cisco_switch_ip
from tests.util.protocol_util import SshTester, TelnetTester, with_protocol


class TestCiscoSwitchProtocol(unittest.TestCase):
    __test__ = False

    def create_client(self):
        raise NotImplemented()

    def setUp(self):
        self.protocol = self.create_client()

    def tearDown(self):
        flexmock_teardown()

    @with_protocol
    def test_enable_command_requires_a_password(self, t):
        t.write("enable")
        t.read("Password: ")
        t.write_invisible(cisco_privileged_password)
        t.read("my_switch#")

    @with_protocol
    def test_wrong_password(self, t):
        t.write("enable")
        t.read("Password: ")
        t.write_invisible("hello_world")
        t.readln("% Access denied")
        t.readln("")
        t.read("my_switch>")

    @with_protocol
    def test_no_password_works_for_legacy_reasons(self, t):
        t.write("enable")
        t.read("Password: ")
        t.write_invisible("")
        t.read("my_switch#")

    @with_protocol
    def test_exiting_loses_the_connection(self, t):
        t.write("enable")
        t.read("Password: ")
        t.write_invisible(cisco_privileged_password)
        t.read("my_switch#")
        t.write("exit")
        t.read_eof()

    @with_protocol
    def test_no_such_command_return_to_prompt(self, t):
        enable(t)

        t.write("shizzle")
        t.readln("No such command : shizzle")
        t.read("my_switch#")

    @with_protocol
    @mock.patch("fake_switches.adapters.tftp_reader.read_tftp")
    def test_command_copy_failing(self, t, read_tftp):
        read_tftp.side_effect = Exception("Stuff")

        enable(t)

        t.write("copy tftp://1.2.3.4/my-file system:/running-config")
        t.read("Destination filename [running-config]? ")
        t.write("gneh")
        t.readln("Accessing tftp://1.2.3.4/my-file...")
        t.readln("Error opening tftp://1.2.3.4/my-file (Timed out)")
        t.read("my_switch#")

        read_tftp.assert_called_with("1.2.3.4", "my-file")

    @with_protocol
    @mock.patch("fake_switches.adapters.tftp_reader.read_tftp")
    def test_command_copy_success(self, t, read_tftp):
        enable(t)

        t.write("copy tftp://1.2.3.4/my-file system:/running-config")
        t.read("Destination filename [running-config]? ")
        t.write_raw("\r")
        t.wait_for("\r\n")
        t.readln("Accessing tftp://1.2.3.4/my-file...")
        t.readln("Done (or some official message...)")
        t.read("my_switch#")

        read_tftp.assert_called_with("1.2.3.4", "my-file")

    @with_protocol
    def test_command_show_run_int_vlan_empty(self, t):
        enable(t)

        t.write("terminal length 0")
        t.read("my_switch#")
        t.write("show run vlan 120")
        t.readln("Building configuration...")
        t.readln("")
        t.readln("Current configuration:")
        t.readln("end")
        t.readln("")
        t.read("my_switch#")

    @with_protocol
    def test_command_add_vlan(self, t):
        enable(t)

        t.write("conf t")
        t.readln("Enter configuration commands, one per line.  End with CNTL/Z.")
        t.read("my_switch(config)#")
        t.write("vlan 123")
        t.read("my_switch(config-vlan)#")
        t.write("name shizzle")
        t.read("my_switch(config-vlan)#")
        t.write("exit")
        t.read("my_switch(config)#")
        t.write("exit")
        t.read("my_switch#")
        t.write("show run vlan 123")
        t.readln("Building configuration...")
        t.readln("")
        t.readln("Current configuration:")
        t.readln("!")
        t.readln("vlan 123")
        t.readln(" name shizzle")
        t.readln("end")
        t.readln("")
        t.read("my_switch#")

        remove_vlan(t, "123")

        t.write("show running-config vlan 123")
        t.readln("Building configuration...")
        t.readln("")
        t.readln("Current configuration:")
        t.readln("end")
        t.read("")

    @with_protocol
    def test_command_assign_access_vlan_to_port(self, t):
        enable(t)
        create_vlan(t, "123")
        set_interface_on_vlan(t, "FastEthernet0/1", "123")

        assert_interface_configuration(t, "Fa0/1", [
            "interface FastEthernet0/1",
            " switchport access vlan 123",
            " switchport mode access",
            "end"])

        configuring_interface(t, "FastEthernet0/1", do="no switchport access vlan")

        assert_interface_configuration(t, "Fa0/1", [
            "interface FastEthernet0/1",
            " switchport mode access",
            "end"])

        configuring_interface(t, "FastEthernet0/1", do="no switchport mode access")

        assert_interface_configuration(t, "Fa0/1", [
            "interface FastEthernet0/1",
            "end"])

        remove_vlan(t, "123")

    @with_protocol
    def test_show_vlan_brief(self, t):
        enable(t)
        create_vlan(t, "123")
        create_vlan(t, "3333", "some-name")
        create_vlan(t, "2222", "your-name-is-way-too-long-for-this-pretty-printed-interface-man")

        set_interface_on_vlan(t, "FastEthernet0/1", "123")

        t.write("show vlan brief")
        t.readln("")
        t.readln("VLAN Name                             Status    Ports")
        t.readln("---- -------------------------------- --------- -------------------------------")
        t.readln("1    default                          active    Fa0/2, Fa0/3, Fa0/4")
        t.readln("123  VLAN123                          active    Fa0/1")
        t.readln("2222 your-name-is-way-too-long-for-th active")
        t.readln("3333 some-name                        active")
        t.read("my_switch#")

        revert_switchport_mode_access(t, "FastEthernet0/1")
        remove_vlan(t, "123")
        remove_vlan(t, "2222")
        remove_vlan(t, "3333")

    @with_protocol
    def test_show_vlan(self, t):
        enable(t)
        create_vlan(t, "123")
        create_vlan(t, "3333", "some-name")
        create_vlan(t, "2222", "your-name-is-way-too-long-for-this-pretty-printed-interface-man")

        set_interface_on_vlan(t, "FastEthernet0/1", "123")

        t.write("show vlan")
        t.readln("")
        t.readln("VLAN Name                             Status    Ports")
        t.readln("---- -------------------------------- --------- -------------------------------")
        t.readln("1    default                          active    Fa0/2, Fa0/3, Fa0/4")
        t.readln("123  VLAN123                          active    Fa0/1")
        t.readln("2222 your-name-is-way-too-long-for-th active")
        t.readln("3333 some-name                        active")
        t.readln("")
        t.readln("VLAN Type  SAID       MTU   Parent RingNo BridgeNo Stp  BrdgMode Trans1 Trans2")
        t.readln("---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------")
        t.readln("1    enet  100001     1500  -      -      -        -    -        0      0")
        t.readln("123  enet  100123     1500  -      -      -        -    -        0      0")
        t.readln("2222 enet  102222     1500  -      -      -        -    -        0      0")
        t.readln("3333 enet  103333     1500  -      -      -        -    -        0      0")
        t.readln("")
        t.readln("Remote SPAN VLANs")
        t.readln("------------------------------------------------------------------------------")
        t.readln("")
        t.readln("")
        t.readln("Primary Secondary Type              Ports")
        t.readln("------- --------- ----------------- ------------------------------------------")
        t.readln("")
        t.read("my_switch#")

        revert_switchport_mode_access(t, "FastEthernet0/1")
        remove_vlan(t, "123")
        remove_vlan(t, "2222")
        remove_vlan(t, "3333")

    @with_protocol
    def test_shutting_down(self, t):
        enable(t)

        configuring_interface(t, "FastEthernet 0/3", do="shutdown")

        assert_interface_configuration(t, "FastEthernet0/3", [
            "interface FastEthernet0/3",
            " shutdown",
            "end"])

        configuring_interface(t, "FastEthernet 0/3", do="no shutdown")

        assert_interface_configuration(t, "FastEthernet0/3", [
            "interface FastEthernet0/3",
            "end"])

    @with_protocol
    def test_configure_trunk_port(self, t):
        enable(t)

        configuring_interface(t, "Fa0/3", do="switchport mode trunk")

        assert_interface_configuration(t, "FastEthernet0/3", [
            "interface FastEthernet0/3",
            " switchport mode trunk",
            "end"])

        # not really added because all vlan are in trunk by default on cisco
        configuring_interface(t, "Fa0/3", do="switchport trunk allowed vlan add 123")

        assert_interface_configuration(t, "FastEthernet0/3", [