#!/usr/bin/python2.7
"""Unit test for univention.management.console.modules.setup.netconf.ChangeSet"""
# pylint: disable-msg=C0103,E0611,R0904
import unittest
import os

import univention.management.console.modules
try:
	univention.management.console.modules.__path__.insert(0, os.path.join(os.path.dirname(__file__), os.path.pardir, 'umc/python'))
except AttributeError:
	pass
from univention.management.console.modules.setup.netconf import ChangeSet  # noqa: E402
from univention.management.console.modules.setup.netconf.common import AddressMap  # noqa: E402

from ipaddress import IPv6Interface, IPv4Interface


class IPv4Network(IPv4Interface):
	def __init__(self, address, strict=True):
		IPv4Interface.__init__(self, address)


class IPv6Network(IPv6Interface):
	def __init__(self, address, strict=True):
		IPv6Interface.__init__(self, address)


class DummyOption(object):

	def __init__(self):
		self.no_act = True


class TestChangeSetEmpty(unittest.TestCase):

	"""
	No old and no new addresses.
	"""

	def setUp(self):
		ucr = {}
		profile = {}
		options = DummyOption()
		self.cs = ChangeSet(ucr, profile, options)

	def test_cs(self):
		self.assertEqual(set(), self.cs.old_names)
		self.assertEqual(set(), self.cs.new_names)
		self.assertEqual([], self.cs.old_ipv4s)
		self.assertEqual([], self.cs.new_ipv4s)
		self.assertEqual([], self.cs.old_ipv6s)
		self.assertEqual([], self.cs.new_ipv6s)

	def test_am(self):
		am = AddressMap(self.cs)
		self.assertEqual({}, am.net_changes)


class TestChangeSetRemoved(unittest.TestCase):

	"""
	Old address removed.
	"""

	def setUp(self):
		ucr = {
			"interfaces/eth0/type": "static",
			"interfaces/eth0/start": "true",
			"interfaces/eth0/address": "1.2.3.4",
			"interfaces/eth0/network": "1.2.0.0",
			"interfaces/eth0/netmask": "255.255.0.0",
			"interfaces/eth0/broadcast": "1.2.255.255",
			"interfaces/eth0/ipv6/default/address": "1111:2222::3333",
			"interfaces/eth0/ipv6/default/prefix": "64",
		}
		profile = dict((key, None) for key in ucr.keys() if key.startswith("interfaces/"))
		options = DummyOption()
		self.cs = ChangeSet(ucr, profile, options)

	def test_cs(self):
		self.assertEqual(set(["eth0"]), self.cs.old_names)
		self.assertEqual(set(), self.cs.new_names)
		self.assertEqual([IPv4Network(u"1.2.3.4/16", False)], self.cs.old_ipv4s)
		self.assertEqual([], self.cs.new_ipv4s)
		self.assertEqual([IPv6Network(u"1111:2222::3333/64", False)], self.cs.old_ipv6s)
		self.assertEqual([], self.cs.new_ipv6s)

	def test_am(self):
		am = AddressMap(self.cs)
		ipv4 = IPv4Network(u"1.2.3.4/16", False)
		ipv6 = IPv6Network(u"1111:2222::3333/64", False)
		self.assertEqual({
			ipv4: None,
			ipv6: None,
		}, am.net_changes)


class TestChangeSetAdded(unittest.TestCase):

	"""
	New address added.
	"""

	def setUp(self):
		ucr = {}
		profile = {
			"interfaces/eth0/type": "static",
			"interfaces/eth0/start": "true",
			"interfaces/eth0/address": "1.2.3.4",
			"interfaces/eth0/network": "1.2.0.0",
			"interfaces/eth0/netmask": "255.255.0.0",
			"interfaces/eth0/broadcast": "1.2.255.255",
			"interfaces/eth0/ipv6/default/address": "1111:2222::3333",
			"interfaces/eth0/ipv6/default/prefix": "64",
		}
		options = DummyOption()
		self.cs = ChangeSet(ucr, profile, options)

	def test_cs(self):
		self.assertEqual(set(), self.cs.old_names)
		self.assertEqual(set(["eth0"]), self.cs.new_names)
		self.assertEqual([], self.cs.old_ipv4s)
		self.assertEqual([IPv4Network(u"1.2.3.4/16", False)], self.cs.new_ipv4s)
		self.assertEqual([], self.cs.old_ipv6s)
		self.assertEqual([IPv6Network(u"1111:2222::3333/64", False)], self.cs.new_ipv6s)

	def test_am(self):
		am = AddressMap(self.cs)
		self.assertEqual({}, am.net_changes)


class TestChangeSetChanged(unittest.TestCase):

	"""
	Old address changed to new address.
	"""

	def setUp(self):
		ucr = {
			"interfaces/eth0/type": "static",
			"interfaces/eth0/start": "true",
			"interfaces/eth0/address": "1.2.3.4",
			"interfaces/eth0/network": "1.2.0.0",
			"interfaces/eth0/netmask": "255.255.0.0",
			"interfaces/eth0/broadcast": "1.2.255.255",
			"interfaces/eth0/ipv6/default/address": "1111:2222::3333",
			"interfaces/eth0/ipv6/default/prefix": "64",
		}
		profile = dict((key, None) for key in ucr.keys() if key.startswith("interfaces/"))
		profile.update({
			"interfaces/eth0/type": "static",
			"interfaces/eth0/start": "true",
			"interfaces/eth0/address": "2.3.4.5",
			"interfaces/eth0/network": "2.3.0.0",
			"interfaces/eth0/netmask": "255.255.255.0",
			"interfaces/eth0/broadcast": "2.3.4.255",
			"interfaces/eth0/ipv6/default/address": "2222:3333:4444::5555",
			"interfaces/eth0/ipv6/default/prefix": "80",
		})
		options = DummyOption()
		self.cs = ChangeSet(ucr, profile, options)

	def test_cs(self):
		self.assertEqual(set(["eth0"]), self.cs.old_names)
		self.assertEqual(set(["eth0"]), self.cs.new_names)
		self.assertEqual([IPv4Network(u"1.2.3.4/16", False)], self.cs.old_ipv4s)
		self.assertEqual([IPv4Network(u"2.3.4.5/24", False)], self.cs.new_ipv4s)
		self.assertEqual([IPv6Network(u"1111:2222::3333/64", False)], self.cs.old_ipv6s)
		self.assertEqual([IPv6Network(u"2222:3333:4444::5555/80", False)], self.cs.new_ipv6s)

	def test_am(self):
		am = AddressMap(self.cs)
		ipv4_old = IPv4Network(u"1.2.3.4/16", False)
		ipv4_new = IPv4Network(u"2.3.4.5/24", False)
		ipv6_old = IPv6Network(u"1111:2222::3333/64", False)
		ipv6_new = IPv6Network(u"2222:3333:4444::5555/80", False)
		self.assertEqual({
			ipv4_old: ipv4_new,
			ipv6_old: ipv6_new,
		}, am.net_changes)


class TestChangeSetMoved(unittest.TestCase):

	"""
	Old address moved to new interface.
	"""

	def setUp(self):
		ucr = {
			"interfaces/eth0/type": "static",
			"interfaces/eth0/start": "true",
			"interfaces/eth0/address": "1.2.3.4",
			"interfaces/eth0/network": "1.2.0.0",
			"interfaces/eth0/netmask": "255.255.0.0",
			"interfaces/eth0/broadcast": "1.2.255.255",
			"interfaces/eth0/ipv6/default/address": "1111:2222::3333",
			"interfaces/eth0/ipv6/default/prefix": "64",
		}
		profile = dict((key, None) for key in ucr.keys() if key.startswith("interfaces/"))
		profile.update({
			"interfaces/br0/type": "static",
			"interfaces/br0/start": "true",
			"interfaces/br0/address": "1.2.3.4",
			"interfaces/br0/network": "1.2.0.0",
			"interfaces/br0/netmask": "255.255.0.0",
			"interfaces/br0/broadcast": "1.2.255.255",
			"interfaces/br0/ipv6/default/address": "1111:2222::3333",
			"interfaces/br0/ipv6/default/prefix": "64",
		})
		options = DummyOption()
		self.cs = ChangeSet(ucr, profile, options)

	def test_cs(self):
		self.assertEqual(set(["eth0"]), self.cs.old_names)
		self.assertEqual(set(["br0"]), self.cs.new_names)
		self.assertEqual([IPv4Network(u"1.2.3.4/16", False)], self.cs.old_ipv4s)
		self.assertEqual([IPv4Network(u"1.2.3.4/16", False)], self.cs.new_ipv4s)
		self.assertEqual([IPv6Network(u"1111:2222::3333/64", False)], self.cs.old_ipv6s)
		self.assertEqual([IPv6Network(u"1111:2222::3333/64", False)], self.cs.new_ipv6s)

	def test_am(self):
		am = AddressMap(self.cs)
		self.assertEqual({}, am.net_changes)


class TestChangeSetMultipleSameSubnet(unittest.TestCase):

	"""
	Test multiple addresses in the same subnet.
	"""

	def setUp(self):
		ucr = {}
		profile = {
			"interfaces/eth0/type": "static",
			"interfaces/eth0/start": "true",
			"interfaces/eth0/address": "1.2.3.4",
			"interfaces/eth0/network": "1.2.0.0",
			"interfaces/eth0/netmask": "255.255.0.0",
			"interfaces/eth0/broadcast": "1.2.255.255",
			"interfaces/eth0/ipv6/default/address": "1111:2222::3333",
			"interfaces/eth0/ipv6/default/prefix": "64",
			"interfaces/eth1/type": "static",
			"interfaces/eth1/start": "true",
			"interfaces/eth1/address": "1.2.3.5",
			"interfaces/eth1/network": "1.2.0.0",
			"interfaces/eth1/netmask": "255.255.0.0",
			"interfaces/eth1/broadcast": "1.2.255.255",
			"interfaces/eth1/ipv6/default/address": "1111:2222::4444",
			"interfaces/eth1/ipv6/default/prefix": "64",
		}
		options = DummyOption()
		self.cs = ChangeSet(ucr, profile, options)

	def test_cs(self):
		self.assertEqual(set(), self.cs.old_names)
		self.assertEqual(set(["eth0", "eth1"]), self.cs.new_names)
		self.assertEqual([], self.cs.old_ipv4s)
		self.assertEqual([IPv4Network(u"1.2.3.4/16", False), IPv4Network(u"1.2.3.5/16", False)], sorted(self.cs.new_ipv4s))
		self.assertEqual([], self.cs.old_ipv6s)
		self.assertEqual([IPv6Network(u"1111:2222::3333/64", False), IPv6Network(u"1111:2222::4444/64", False)], sorted(self.cs.new_ipv6s))

	def test_am(self):
		am = AddressMap(self.cs)
		self.assertEqual({}, am.net_changes)


if __name__ == '__main__':
	unittest.main()
