# -*- coding: utf-8 -*-
'''
Test module for syslog_ng state
'''

# Import python libs
from __future__ import absolute_import
import yaml
import re
import tempfile
import os

from salttesting import skipIf, TestCase
from salttesting.helpers import ensure_in_syspath
from salttesting.mock import NO_MOCK, NO_MOCK_REASON, MagicMock, patch

ensure_in_syspath('../../')

import salt.utils
from salt.states import syslog_ng
from salt.modules import syslog_ng as syslog_ng_module

syslog_ng.__salt__ = {}
syslog_ng_module.__salt__ = {}
syslog_ng_module.__opts__ = {'test': False}

SOURCE_1_CONFIG = {
    "id": "s_tail",
    "config": (
        """
        source:
            - file:
              - '"/var/log/apache/access.log"'
              - follow_freq : 1
              - flags:
                - no-parse
                - validate-utf8
        """)
}

SOURCE_1_EXPECTED = (
"""
source s_tail {
   file(
         "/var/log/apache/access.log",
         follow_freq(1),
         flags(no-parse, validate-utf8)
   );
};
"""
)

SOURCE_2_CONFIG = {
    "id": "s_gsoc2014",
    "config": (
        """
        source:
          - tcp:
            - ip: '"0.0.0.0"'
            - port: 1234
            - flags: no-parse
        """
    )
}

SOURCE_2_EXPECTED = (
"""
source s_gsoc2014 {
   tcp(
         ip("0.0.0.0"),
         port(1234),
         flags(no-parse)
   );
};"""
)

FILTER_1_CONFIG = {
    "id": "f_json",
    "config": (
        """
        filter:
          - match:
            - '"@json:"'
        """
    )
}

FILTER_1_EXPECTED = (
    """
    filter f_json {
       match(
             "@json:"
       );
    };
    """
)

TEMPLATE_1_CONFIG = {
    "id": "t_demo_filetemplate",
    "config": (
        """
        template:
          - template:
            - '"$ISODATE $HOST $MSG\n"'
          - template_escape:
            - "no"
        """
    )
}

TEMPLATE_1_EXPECTED = (
    """
    template t_demo_filetemplate {
       template(
             "$ISODATE $HOST $MSG "
       );
       template_escape(
             no
       );
    };
    """
)

REWRITE_1_CONFIG = {
    "id": "r_set_message_to_MESSAGE",
    "config": (
        """
        rewrite:
          - set:
            - '"${.json.message}"'
            - value : '"$MESSAGE"'
        """
    )
}

REWRITE_1_EXPECTED = (
    """
    rewrite r_set_message_to_MESSAGE {
       set(
             "${.json.message}",
             value("$MESSAGE")
       );
    };
    """
)

LOG_1_CONFIG = {
    "id": "l_gsoc2014",
    "config": (
        """
        log:
          - source: s_gsoc2014
          - junction:
            - channel:
              - filter: f_json
              - parser: p_json
              - rewrite: r_set_json_tag
              - rewrite: r_set_message_to_MESSAGE
              - destination:
                - file:
                  - '"/tmp/json-input.log"'
                  - template: t_gsoc2014
              - flags: final
            - channel:
              - filter: f_not_json
              - parser:
                - syslog-parser: []
              - rewrite: r_set_syslog_tag
              - flags: final
          - destination:
            - file:
              - '"/tmp/all.log"'
              - template: t_gsoc2014
        """
    )
}

LOG_1_EXPECTED = (
    """
    log {
       source(s_gsoc2014);
       junction {
          channel {
             filter(f_json);
             parser(p_json);
             rewrite(r_set_json_tag);
             rewrite(r_set_message_to_MESSAGE);
             destination {
                file(
                      "/tmp/json-input.log",
                      template(t_gsoc2014)
                );
             };
             flags(final);
          };
          channel {
             filter(f_not_json);
             parser {
                syslog-parser(

                );
             };
             rewrite(r_set_syslog_tag);
             flags(final);
          };
       };
       destination {
          file(
                "/tmp/all.log",
                template(t_gsoc2014)
          );
       };
    };
    """
)

OPTIONS_1_CONFIG = {
    "id": "global_options",
    "config": (
        """
        options:
          - time_reap: 30
          - mark_freq: 10
          - keep_hostname: "yes"
        """
    )
}

OPTIONS_1_EXPECTED = (
    """
    options {
        time_reap(30);
        mark_freq(10);
        keep_hostname(yes);
    };
    """
)

SHORT_FORM_CONFIG = {
    "id": "source.s_gsoc",
    "config": (
        """
          - tcp:
            - ip: '"0.0.0.0"'
            - port: 1234
            - flags: no-parse
        """
    )
}

SHORT_FORM_EXPECTED = (
    """
    source s_gsoc {
        tcp(
            ip(
                "0.0.0.0"
            ),
            port(
                1234
            ),
            flags(
              no-parse
            )
        );
    };
    """
)

GIVEN_CONFIG = {
    'id': "config.some_name",
    'config': (
        """
               source s_gsoc {
                  tcp(
                      ip(
                          "0.0.0.0"
                      ),
                      port(
                          1234
                      ),
                      flags(
                        no-parse
                      )
                  );
               };
        """
    )
}

_SALT_VAR_WITH_MODULE_METHODS = {
    'syslog_ng.config': syslog_ng_module.config,
    'syslog_ng.start': syslog_ng_module.start,
    'syslog_ng.reload': syslog_ng_module.reload_,
    'syslog_ng.stop': syslog_ng_module.stop,
    'syslog_ng.write_version': syslog_ng_module.write_version,
    'syslog_ng.write_config': syslog_ng_module.write_config
}


def remove_whitespaces(source):
    return re.sub(r"\s+", "", source.strip())


@skipIf(NO_MOCK, NO_MOCK_REASON)
# @skipIf(syslog_ng.__virtual__() is False, 'Syslog-ng must be installed')
class SyslogNGTestCase(TestCase):
    def test_generate_source_config(self):
        self._config_generator_template(SOURCE_1_CONFIG, SOURCE_1_EXPECTED)

    def test_generate_log_config(self):
        self._config_generator_template(LOG_1_CONFIG, LOG_1_EXPECTED)

    def test_generate_tcp_source_config(self):
        self._config_generator_template(SOURCE_2_CONFIG, SOURCE_2_EXPECTED)

    def test_generate_filter_config(self):
        self._config_generator_template(FILTER_1_CONFIG, FILTER_1_EXPECTED)

    def test_generate_template_config(self):
        self._config_generator_template(TEMPLATE_1_CONFIG, TEMPLATE_1_EXPECTED)

    def test_generate_rewrite_config(self):
        self._config_generator_template(REWRITE_1_CONFIG, REWRITE_1_EXPECTED)

    def test_generate_global_options_config(self):
        self._config_generator_template(OPTIONS_1_CONFIG, OPTIONS_1_EXPECTED)

    def test_generate_short_form_statement(self):
        self._config_generator_template(SHORT_FORM_CONFIG, SHORT_FORM_EXPECTED)

    def test_generate_given_config(self):
        self._config_generator_template(GIVEN_CONFIG, SHORT_FORM_EXPECTED)

    def _config_generator_template(self, yaml_input, expected):
        parsed_yaml_config = yaml.load(yaml_input["config"])
        id = yaml_input["id"]

        with patch.dict(syslog_ng.__salt__, _SALT_VAR_WITH_MODULE_METHODS):
            got = syslog_ng.config(id, config=parsed_yaml_config, write=False)
            config = got["changes"]["new"]
            self.assertEqual(remove_whitespaces(expected), remove_whitespaces(config))
            self.assertEqual(False, got["result"])

    def test_write_config(self):
        yaml_inputs = (
            SOURCE_2_CONFIG, SOURCE_1_CONFIG, FILTER_1_CONFIG, TEMPLATE_1_CONFIG, REWRITE_1_CONFIG, LOG_1_CONFIG
        )
        expected_outputs = (
            SOURCE_2_EXPECTED, SOURCE_1_EXPECTED, FILTER_1_EXPECTED, TEMPLATE_1_EXPECTED, REWRITE_1_EXPECTED,
            LOG_1_EXPECTED
        )
        config_file_fd, config_file_name = tempfile.mkstemp()
        os.close(config_file_fd)

        with patch.dict(syslog_ng.__salt__, _SALT_VAR_WITH_MODULE_METHODS):
            syslog_ng_module.set_config_file(config_file_name)
            syslog_ng_module.write_version("3.6")
            syslog_ng_module.write_config(config='@include "scl.conf"')

            for i in yaml_inputs:
                parsed_yaml_config = yaml.load(i["config"])
                id = i["id"]
                got = syslog_ng.config(id, config=parsed_yaml_config, write=True)

            written_config = ""
            with salt.utils.fopen(config_file_name, "r") as f:
                written_config = f.read()

            config_without_whitespaces = remove_whitespaces(written_config)
            for i in expected_outputs:
                without_whitespaces = remove_whitespaces(i)
                self.assertIn(without_whitespaces, config_without_whitespaces)

            syslog_ng_module.set_config_file("")
            os.remove(config_file_name)

    def test_started_state_generate_valid_cli_command(self):
        mock_func = MagicMock(return_value={"retcode": 0, "stdout": "", "pid": 1000})

        with patch.dict(syslog_ng.__salt__, _SALT_VAR_WITH_MODULE_METHODS):
            with patch.dict(syslog_ng_module.__salt__, {'cmd.run_all': mock_func}):
                got = syslog_ng.started(user="joe", group="users", enable_core=True)
                command = got["changes"]["new"]
                self.assertTrue(
                    command.endswith("syslog-ng --user=joe --group=users --enable-core --cfgfile=/etc/syslog-ng.conf"))


if __name__ == '__main__':
    from integration import run_tests

    run_tests(SyslogNGTestCase, needs_daemon=False)
