from helpers import unittest

from luigi.configuration import LuigiConfigParser, LuigiTomlParser, get_config
from luigi.setup_logging import DaemonLogging, InterfaceLogging


class TestDaemonLogging(unittest.TestCase):
    cls = DaemonLogging

    def setUp(self):
        self.cls._configured = False

    def tearDown(self):
        self.cls._configured = False
        self.cls.config = get_config()

    def test_cli(self):
        opts = type("opts", (), {})

        opts.background = True
        result = self.cls._cli(opts)
        self.assertTrue(result)

        opts.background = False
        opts.logdir = "./tests/"
        result = self.cls._cli(opts)
        self.assertTrue(result)

        opts.background = False
        opts.logdir = False
        result = self.cls._cli(opts)
        self.assertFalse(result)

    def test_section(self):
        self.cls.config = {
            "logging": {
                "version": 1,
                "disable_existing_loggers": False,
                "formatters": {
                    "mockformatter": {
                        "format": "{levelname}: {message}",
                        "style": "{",
                        "datefmt": "%Y-%m-%d %H:%M:%S",
                    },
                },
                "handlers": {
                    "mockhandler": {
                        "class": "logging.StreamHandler",
                        "level": "INFO",
                        "formatter": "mockformatter",
                    },
                },
                "loggers": {
                    "mocklogger": {
                        "handlers": ("mockhandler",),
                        "level": "INFO",
                        "disabled": False,
                        "propagate": False,
                    },
                },
            },
        }
        result = self.cls._section(None)
        self.assertTrue(result)

        self.cls.config = LuigiTomlParser()
        self.cls.config.read(["./test/testconfig/luigi_logging.toml"])
        result = self.cls._section(None)
        self.assertTrue(result)

        self.cls.config = {}
        result = self.cls._section(None)
        self.assertFalse(result)

    def test_section_cfg(self):
        self.cls.config = LuigiConfigParser.instance()
        result = self.cls._section(None)
        self.assertFalse(result)

    def test_cfg(self):
        self.cls.config = LuigiTomlParser()
        self.cls.config.data = {}
        result = self.cls._conf(None)
        self.assertFalse(result)

        self.cls.config.data = {"core": {"logging_conf_file": "./blah"}}
        with self.assertRaises(OSError):
            self.cls._conf(None)

        self.cls.config.data = {
            "core": {
                "logging_conf_file": "./test/testconfig/logging.cfg",
            }
        }
        result = self.cls._conf(None)
        self.assertTrue(result)

    def test_default(self):
        result = self.cls._default(None)
        self.assertTrue(result)


class TestInterfaceLogging(TestDaemonLogging):
    cls = InterfaceLogging

    def test_cli(self):
        opts = type("opts", (), {})
        result = self.cls._cli(opts)
        self.assertFalse(result)

    # test_section inherited from TestDaemonLogging

    def test_cfg(self):
        self.cls.config = LuigiTomlParser()
        self.cls.config.data = {}

        opts = type("opts", (), {})
        opts.logging_conf_file = ""
        result = self.cls._conf(opts)
        self.assertFalse(result)

        opts.logging_conf_file = "./blah"
        with self.assertRaises(OSError):
            self.cls._conf(opts)

        opts.logging_conf_file = "./test/testconfig/logging.cfg"
        result = self.cls._conf(opts)
        self.assertTrue(result)

    def test_default(self):
        opts = type("opts", (), {})
        opts.log_level = "INFO"
        result = self.cls._default(opts)
        self.assertTrue(result)


class PatchedLogging(InterfaceLogging):
    @classmethod
    def _cli(cls, *args):
        cls.calls.append("_cli")
        return "_cli" not in cls.patched

    @classmethod
    def _conf(cls, *args):
        cls.calls.append("_conf")
        return "_conf" not in cls.patched

    @classmethod
    def _section(cls, *args):
        cls.calls.append("_section")
        return "_section" not in cls.patched

    @classmethod
    def _default(cls, *args):
        cls.calls.append("_default")
        return "_default" not in cls.patched


class TestSetup(unittest.TestCase):
    def setUp(self):
        self.opts = type("opts", (), {})
        self.cls = PatchedLogging
        self.cls.calls = []
        self.cls.config = LuigiTomlParser()
        self.cls._configured = False
        self.cls.patched = "_cli", "_conf", "_section", "_default"

    def tearDown(self):
        self.cls.config = get_config()

    def test_configured(self):
        self.cls._configured = True
        result = self.cls.setup(self.opts)
        self.assertEqual(self.cls.calls, [])
        self.assertFalse(result)

    def test_disabled(self):
        self.cls.config.data = {"core": {"no_configure_logging": True}}
        result = self.cls.setup(self.opts)
        self.assertEqual(self.cls.calls, [])
        self.assertFalse(result)

    def test_order(self):
        self.cls.setup(self.opts)
        self.assertEqual(self.cls.calls, ["_cli", "_conf", "_section", "_default"])

    def test_cli(self):
        self.cls.patched = ()
        result = self.cls.setup(self.opts)
        self.assertTrue(result)
        self.assertEqual(self.cls.calls, ["_cli"])

    def test_conf(self):
        self.cls.patched = ("_cli",)
        result = self.cls.setup(self.opts)
        self.assertTrue(result)
        self.assertEqual(self.cls.calls, ["_cli", "_conf"])

    def test_section(self):
        self.cls.patched = ("_cli", "_conf")
        result = self.cls.setup(self.opts)
        self.assertTrue(result)
        self.assertEqual(self.cls.calls, ["_cli", "_conf", "_section"])

    def test_default(self):
        self.cls.patched = ("_cli", "_conf", "_section")
        result = self.cls.setup(self.opts)
        self.assertTrue(result)
        self.assertEqual(self.cls.calls, ["_cli", "_conf", "_section", "_default"])
