#!/usr/bin/env python -ttB
"""
This contains valid functional tests for pytan.

These functional tests require a connection to a Tanium server in order to run.
The connection info is pulled from the SERVER_INFO dictionary in test/API_INFO.py.

These tests all use :mod:`ddt`, a package that provides for data driven tests via JSON files.
"""
from __future__ import print_function

import sys

# disable python from creating .pyc files everywhere
sys.dont_write_bytecode = True

import os
import glob
import unittest
import json  # noqa
import csv
import StringIO
import tempfile

my_file = os.path.abspath(sys.argv[0])
my_dir = os.path.dirname(my_file)
root_dir = os.path.join(my_dir, os.pardir)
root_dir = os.path.abspath(root_dir)
lib_dir = os.path.join(root_dir, 'lib')
path_adds = [my_dir, lib_dir]
[sys.path.insert(0, aa) for aa in path_adds if aa not in sys.path]

import pytan
import taniumpy
import ddt

# get our server connection info
from API_INFO import SERVER_INFO

# where the output files from the tests will be stored
TEST_OUT = os.path.join(tempfile.gettempdir(), 'TEST_OUT')


def chew_csv(c):
    i = StringIO.StringIO(c)
    r = csv.reader(i)
    l = list(r)
    return l


def spew(m, l=3):
    if SERVER_INFO["testlevel"] >= l:
        print(m, file=sys.stdout)


@ddt.ddt
class ValidServerTests(unittest.TestCase):

    @classmethod
    def setUpClass(cls): # noqa
        cls.handler = pytan.Handler(**SERVER_INFO)
        m = "{}\n{}: PyTan v'{}' against Tanium v'{}' -- Valid Tests Starting\n".format
        spew(m(
            '*' * 100,
            pytan.utils.seconds_from_now(),
            pytan.__version__,
            cls.handler.session.get_server_version(),
        ), 2)

        if not hasattr(cls, 'base_type_objs'):
            # fetch objects for export tests
            kwargs = {
                'name': [
                    "Computer Name", "IP Route Details", "IP Address",
                    'Folder Contents',
                ],
                'objtype': 'sensor',
            }
            spew("TESTSETUP: Getting sensor objects for export tests of BaseType")
            cls.base_type_objs = cls.handler.get(**kwargs)

        if not hasattr(cls, 'wlus'):
            # create whitelisted_urls for getobject tests
            cls.wlus = ['test1', 'test2', 'test3']
            spew("TESTSETUP: Creating whitelisted URLs for get object tests")
            for wlu in cls.wlus:
                try:
                    cls.handler.create_whitelisted_url(url=wlu)
                except:
                    pass

        if not hasattr(cls, 'result_set_objs'):
            # ask questions for export tests
            kwargs = {
                'qtype': 'manual',
                'sensors': [
                    "Computer Name", "IP Route Details", "IP Address",
                    'Folder Contents{folderPath=C:\\Program Files}',
                ],
            }
            spew("TESTSETUP: Asking a question for export tests of ResultSet")
            cls.result_set_objs = cls.handler.ask(**kwargs)

        spew('\n' + str(cls.handler))

    @classmethod
    def tearDownClass(cls): # noqa
        m = "{}\n{}: PyTan v'{}' against Tanium v'{}' -- Valid Tests Finished".format
        spew(m(
            '*' * 100,
            pytan.utils.seconds_from_now(),
            pytan.__version__,
            cls.handler.session.get_server_version(),
        ), 2)

    def setup_test(self):
        spew("")
        return self.handler

    @ddt.file_data('ddt/ddt_valid_export_resultset.json')
    def test_valid_export_resultset(self, value):
        handler = self.setup_test()

        self.assertTrue(self.result_set_objs)
        self.assertIsInstance(self.result_set_objs['question_object'], taniumpy.Question)
        self.assertIsInstance(self.result_set_objs['question_results'], taniumpy.ResultSet)
        self.assertGreaterEqual(len(self.result_set_objs['question_results'].rows), 1)
        self.assertGreaterEqual(len(self.result_set_objs['question_results'].columns), 1)

        kwargs = {'obj': self.result_set_objs['question_results']}
        kwargs.update(value['args'])

        tests = value['tests']

        s = (
            "+++ TESTING EXPECTED EXPORT OBJECT ResultSet SUCCESS Handler.{}() with kwargs {}"
        ).format
        spew(s('export_obj', kwargs))

        export_str = handler.export_obj(**kwargs)

        self.assertTrue(export_str)
        self.assertIsInstance(export_str, (str, unicode))
        export_str_list = chew_csv(export_str)
        spew(export_str_list[0])
        for x in tests:
            spew("+++ EVAL TEST: %s" % x)
            try:
                self.assertTrue(eval(x))
            except Exception:
                spew("!!! EVAL TEST FAILED: '%s' - Against export string list:\n%s" % (x, export_str_list))
                raise

    @ddt.file_data('ddt/ddt_valid_export_basetype.json')
    def test_valid_export_basetype(self, value):
        handler = self.setup_test()

        self.assertTrue(self.base_type_objs)
        self.assertIsInstance(self.base_type_objs, taniumpy.BaseType)
        self.assertEquals(len(self.base_type_objs), 4)

        kwargs = {'obj': self.base_type_objs}
        kwargs.update(value['args'])

        tests = value['tests']

        s = (
            "+++ TESTING EXPECTED EXPORT OBJECT BaseType SUCCESS Handler.{}() with kwargs {}"
        ).format
        spew(s('export_obj', kwargs))

        export_str = handler.export_obj(**kwargs)

        self.assertTrue(export_str)
        self.assertIsInstance(export_str, (str, unicode))
        for x in tests:
            spew("+++ EVAL TEST: %s" % x)
            self.assertTrue(eval(x))

    @ddt.file_data('ddt/ddt_valid_deploy_action.json')
    def test_valid_deploy_action(self, value):
        handler = self.setup_test()