import mock
import libvirt
import difflib
import unittest

from see.context.resources import lxc


def compare(text1, text2):
    """Utility function for comparing text and returining differences."""
    diff = difflib.ndiff(text1.splitlines(True), text2.splitlines(True))
    return '\n' + '\n'.join(diff)


class DomainXMLTest(unittest.TestCase):
    def test_domain_xml(self):
        """LXC XML with no network and no filesystem."""
        config = """<domain></domain>"""
        expected = """<domain><name>foo</name><uuid>foo</uuid><devices /></domain>"""
        results = lxc.domain_xml('foo', config, [])
        self.assertEqual(results, expected, compare(results, expected))

    def test_domain_xml_filesystem(self):
        """LXC XML with filesystem."""
        config = """<domain></domain>"""
        expected = """<domain><name>foo</name><uuid>foo</uuid><devices><filesystem type="mount">""" +\
                   """<source dir="foo" /><target dir="bar" /></filesystem></devices></domain>"""
        results = lxc.domain_xml('foo', config, [('foo', 'bar')])
        self.assertEqual(results, expected, compare(results, expected))

    def test_domain_xml_modifies(self):
        """LXC Fields are modified if existing."""
        config = """<domain><name>bar</name><uuid>bar</uuid></domain>"""
        expected = """<domain><name>foo</name><uuid>foo</uuid><devices><filesystem type="mount">""" +\
                   """<source dir="foo" /><target dir="bar" /></filesystem></devices></domain>"""
        results = lxc.domain_xml('foo', config, [('foo', 'bar')])
        self.assertEqual(results, expected, compare(results, expected))

    def test_domain_xml_network(self):
        """LXC XML with network fields are modified if existing."""
        config = """<domain></domain>"""
        expected = """<domain><name>foo</name><uuid>foo</uuid><devices><filesystem type="mount">""" +\
                   """<source dir="foo" /><target dir="bar" /></filesystem><interface type="network">""" +\
                   """<source network="foo" /></interface></devices></domain>"""
        results = lxc.domain_xml('foo', config, [('foo', 'bar')], network_name='foo')
        self.assertEqual(results, expected, compare(results, expected))

    def test_domain_xml_network_modifies(self):
        """LXC XML with network."""
        config = """<domain><devices><interface type="network">""" +\
                 """<source network="bar"/></interface></devices></domain>"""
        expected = """<domain><devices><interface type="network"><source network="foo" /></interface>""" +\
                   """<filesystem type="mount"><source dir="foo" /><target dir="bar" /></filesystem>""" +\
                   """</devices><name>foo</name><uuid>foo</uuid></domain>"""
        results = lxc.domain_xml('foo', config, [('foo', 'bar')], network_name='foo')
        self.assertEqual(results, expected, compare(results, expected))


class DomainCreateTest(unittest.TestCase):
    def test_create(self):
        """LXC Create with no network and no filesystem."""
        xml = """<domain></domain>"""
        expected = """<domain><name>foo</name><uuid>foo</uuid><devices /></domain>"""
        hypervisor = mock.Mock()
        hypervisor.listNetworks.return_value = []
        with mock.patch('see.context.resources.lxc.open', mock.mock_open(read_data=xml), create=True):
            lxc.domain_create(hypervisor, 'foo', {'configuration': '/foo'})
        results = hypervisor.defineXML.call_args_list[0][0][0]
        self.assertEqual(results, expected, compare(results, expected))

    def test_create_filesystem(self):
        """LXC Create with single filesystem."""
        xml = """<domain></domain>"""
        expected = """<domain><name>foo</name><uuid>foo</uuid><devices><filesystem type="mount">""" +\
                   """<source dir="/bar/foo" /><target dir="/baz" /></filesystem></devices></domain>"""
        hypervisor = mock.Mock()