""" Test class for AccountingDB
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

# pylint: disable=protected-access

# imports
import unittest
from mock import MagicMock

import DIRAC.AccountingSystem.DB.AccountingDB as moduleTested


class TestCase(unittest.TestCase):
    """Base class for the AccountingDB test cases"""

    def setUp(self):

        self.moduleTested = moduleTested
        self.testClass = self.moduleTested.AccountingDB

        self.moduleTested.DB = MagicMock()
        self.moduleTested.DB.fullname = "AccountingDB"

        mock_getDatabaseSection = MagicMock()
        mock_getDatabaseSection.return_value = "/Systems/AccountingSystem/Certification/Databases/AccountingDB"
        self.moduleTested.DB.getDatabaseSection = mock_getDatabaseSection

        self.moduleTested.AccountingDB.fullname = MagicMock()

        mock_getCSOption = MagicMock()
        mock_getCSOption.return_value = "10"
        self.moduleTested.AccountingDB.getCSOption = mock_getCSOption

        mock_ThreadPool = MagicMock()
        self.moduleTested.ThreadPool = mock_ThreadPool

        mock_createTables = MagicMock()
        mock_createTables.return_value = {"OK": True}
        self.moduleTested.AccountingDB._createTables = mock_createTables

        mock_loadCatalogFromDB = MagicMock()
        mock_loadCatalogFromDB.return_value = {"OK": True}
        self.moduleTested.AccountingDB._AccountingDB__loadCatalogFromDB = mock_loadCatalogFromDB

        mock_registerTypes = MagicMock()
        mock_registerTypes.return_value = {"OK": True}
        self.moduleTested.AccountingDB._AccountingDB__registerTypes = mock_registerTypes
        mock_log = MagicMock()
        mock_log.return_value = {"OK": True}
        self.moduleTested.AccountingDB.log = mock_log


class MakeQuery(TestCase):
    """testing making a query"""

    def query(self, cmd, conn):  # pylint: disable=no-self-use,unused-argument
        """Because we are not able to execute the query, the method returns the query"""
        return cmd

    ################################################################################
    def test_instantiate(self):
        """tests that we can instantiate one object of the tested class"""

        module = self.testClass()
        self.assertEqual("AccountingDB", module.__class__.__name__)

    def test_calculateBuckets(self):
        """
        Test the method used to calculate the bucket size
        """

        module = self.testClass()
        module.dbCatalog = {
            "LHCb-Certification_DataOperation": {
                "definition": {
                    "keys": [
                        ("OperationType", "VARCHAR(32)"),
                        ("User", "VARCHAR(32)"),
                        ("ExecutionSite", "VARCHAR(32)"),
                        ("Source", "VARCHAR(32)"),
                        ("Destination", "VARCHAR(32)"),
                        ("Protocol", "VARCHAR(32)"),
                        ("FinalStatus", "VARCHAR(32)"),
                    ],
                    "values": [
                        ("TransferSize", "BIGINT UNSIGNED"),
                        ("TransferTime", "FLOAT"),
                        ("RegistrationTime", "FLOAT"),
                        ("TransferOK", "INT UNSIGNED"),
                        ("TransferTotal", "INT UNSIGNED"),
                        ("RegistrationOK", "INT UNSIGNED"),
                        ("RegistrationTotal", "INT UNSIGNED"),
                    ],
                },
                "bucketFields": [
                    "OperationType",
                    "User",
                    "ExecutionSite",
                    "Source",
                    "Destination",
                    "Protocol",
                    "FinalStatus",
                    "TransferSize",
                    "TransferTime",
                    "RegistrationTime",
                    "TransferOK",
                    "TransferTotal",
                    "RegistrationOK",
                    "RegistrationTotal",
                    "entriesInBucket",
                    "startTime",
                    "bucketLength",
                ],
                "keys": ["OperationType", "User", "ExecutionSite", "Source", "Destination", "Protocol", "FinalStatus"],
                "typeFields": [
                    "OperationType",
                    "User",
                    "ExecutionSite",
                    "Source",
                    "Destination",
                    "Protocol",
                    "FinalStatus",
                    "TransferSize",
                    "TransferTime",
                    "RegistrationTime",
                    "TransferOK",
                    "TransferTotal",
                    "RegistrationOK",
                    "RegistrationTotal",
                    "startTime",
                    "endTime",
                ],
                "values": [
                    "TransferSize",
                    "TransferTime",
                    "RegistrationTime",
                    "TransferOK",
                    "TransferTotal",
                    "RegistrationOK",
                    "RegistrationTotal",
                ],
                "dataTimespan": 0,
            }
        }

        module.dbBucketsLength["LHCb-Certification_DataOperation"] = [
            (259200, 900),
            (691200, 3600),
            (15552000, 86400),
            (31104000, 604800),
        ]
        retVal = module.calculateBuckets("LHCb-Certification_DataOperation", 1495328400, 1495328400)[0][0]
        self.assertTrue(retVal)

        retVal = module.calculateBuckets("LHCb-Certification_DataOperation", 1497964315, 1497964315)[0][0]
        self.assertTrue(retVal)
        self.assertTrue(retVal)

        retVal = module.calculateBuckets("LHCb-Certification_DataOperation", 1495414800, 1495414800)[0][0]
        self.assertTrue(retVal)

        retVal = module.calculateBuckets("LHCb-Certification_DataOperation", 1498047038, 1498047038)[0][0]
        self.assertTrue(retVal)

    def test__queryType1(self):
        """
        Test the query creation for a given condition
        """
        module = self.testClass()
        module.dbCatalog = {
            "LHCb-Certification_DataOperation": {
                "definition": {
                    "keys": [
                        ("OperationType", "VARCHAR(32)"),
                        ("User", "VARCHAR(32)"),
                        ("ExecutionSite", "VARCHAR(32)"),
                        ("Source", "VARCHAR(32)"),
                        ("Destination", "VARCHAR(32)"),
                        ("Protocol", "VARCHAR(32)"),
                        ("FinalStatus", "VARCHAR(32)"),
                    ],
                    "values": [
                        ("TransferSize", "BIGINT UNSIGNED"),
                        ("TransferTime", "FLOAT"),
                        ("RegistrationTime", "FLOAT"),
                        ("TransferOK", "INT UNSIGNED"),
                        ("TransferTotal", "INT UNSIGNED"),
                        ("RegistrationOK", "INT UNSIGNED"),
                        ("RegistrationTotal", "INT UNSIGNED"),
                    ],
                },
                "bucketFields": [
                    "OperationType",
                    "User",
                    "ExecutionSite",
                    "Source",
                    "Destination",
                    "Protocol",
                    "FinalStatus",
                    "TransferSize",
                    "TransferTime",
                    "RegistrationTime",
                    "TransferOK",
                    "TransferTotal",
                    "RegistrationOK",
                    "RegistrationTotal",
                    "entriesInBucket",
                    "startTime",
                    "bucketLength",
                ],
                "keys": ["OperationType", "User", "ExecutionSite", "Source", "Destination", "Protocol", "FinalStatus"],
                "typeFields": [
                    "OperationType",
                    "User",
                    "ExecutionSite",
                    "Source",
                    "Destination",
                    "Protocol",
                    "FinalStatus",
                    "TransferSize",
                    "TransferTime",
                    "RegistrationTime",
                    "TransferOK",
                    "TransferTotal",
                    "RegistrationOK",
                    "RegistrationTotal",
                    "startTime",
                    "endTime",
                ],
                "values": [
                    "TransferSize",
                    "TransferTime",
                    "RegistrationTime",
                    "TransferOK",
                    "TransferTotal",
                    "RegistrationOK",
                    "RegistrationTotal",
                ],
                "dataTimespan": 0,
            }
        }

        module.dbBucketsLength["LHCb-Certification_DataOperation"] = [
            (259200, 900),
            (691200, 3600),
            (15552000, 86400),
            (31104000, 604800),
        ]
        module._query = self.query
        startTime = 1495324800
        endTime = 1497960715
        retVal = module.calculateBuckets("LHCb-Certification_DataOperation", startTime + 3600, startTime + 3600)[0][0]
        self.assertTrue(retVal)
        expectedStartTime = retVal

        retVal = module.calculateBuckets("LHCb-Certification_DataOperation", endTime + 3600, endTime + 3600)[0][0]
        self.assertTrue(retVal)
        expectedEndTime = retVal

        expectedQuery = (
            "SELECT `ac_key_LHCb-Certification_DataOperation_Source`.`value`, \
`ac_bucket_LHCb-Certification_DataOperation`.`startTime`, \
`ac_bucket_LHCb-Certification_DataOperation`.`bucketLength`, \
SUM(`ac_bucket_LHCb-Certification_DataOperation`.`TransferOK`), \
SUM(`ac_bucket_LHCb-Certification_DataOperation`.`TransferTotal`)-\
SUM(`ac_bucket_LHCb-Certification_DataOperation`.`TransferOK`) \
FROM `ac_bucket_LHCb-Certification_DataOperation`, \
`ac_key_LHCb-Certification_DataOperation_Source` \
WHERE `ac_bucket_LHCb-Certification_DataOperation`.`startTime` >= %s \
AND `ac_bucket_LHCb-Certification_DataOperation`.`startTime` <= %s \
AND `ac_bucket_LHCb-Certification_DataOperation`.`Source` = `ac_key_LHCb-Certification_DataOperation_Source`.`id` \
GROUP BY startTime, `ac_key_LHCb-Certification_DataOperation_Source`.Value, bucketlength \
ORDER BY startTime"
            % (expectedStartTime, expectedEndTime)
        )
        retVal = module._AccountingDB__queryType(
            "LHCb-Certification_DataOperation",  # pylint: disable=no-member
            startTime,
            endTime,
            (
                "%s, %s, %s, SUM(%s), SUM(%s)-SUM(%s)",
                ["Source", "startTime", "bucketLength", "TransferOK", "TransferTotal", "TransferOK"],
            ),
            {},
            ("%s, %s", ["startTime", "Source"]),
            ("%s", ["startTime"]),
            "bucket",
        )

        self.assertTrue(retVal)
        self.assertEqual(retVal, expectedQuery)

    def test_queryType2(self):
        """Test the query creation for a given condition"""
        module = self.testClass()
        module.dbCatalog = {
            "LHCb-Certification_DataOperation": {
                "definition": {
                    "keys": [
                        ("OperationType", "VARCHAR(32)"),
                        ("User", "VARCHAR(32)"),
                        ("ExecutionSite", "VARCHAR(32)"),
                        ("Source", "VARCHAR(32)"),
                        ("Destination", "VARCHAR(32)"),
                        ("Protocol", "VARCHAR(32)"),
                        ("FinalStatus", "VARCHAR(32)"),
                    ],
                    "values": [
                        ("TransferSize", "BIGINT UNSIGNED"),
                        ("TransferTime", "FLOAT"),
                        ("RegistrationTime", "FLOAT"),
                        ("TransferOK", "INT UNSIGNED"),
                        ("TransferTotal", "INT UNSIGNED"),
                        ("RegistrationOK", "INT UNSIGNED"),
                        ("RegistrationTotal", "INT UNSIGNED"),
                    ],
                },
                "bucketFields": [
                    "OperationType",
                    "User",
                    "ExecutionSite",
                    "Source",
                    "Destination",
                    "Protocol",
                    "FinalStatus",
                    "TransferSize",
                    "TransferTime",
                    "RegistrationTime",
                    "TransferOK",
                    "TransferTotal",
                    "RegistrationOK",
                    "RegistrationTotal",
                    "entriesInBucket",
                    "startTime",
                    "bucketLength",
                ],
                "keys": ["OperationType", "User", "ExecutionSite", "Source", "Destination", "Protocol", "FinalStatus"],
                "typeFields": [
                    "OperationType",
                    "User",
                    "ExecutionSite",
                    "Source",
                    "Destination",
                    "Protocol",
                    "FinalStatus",
                    "TransferSize",
                    "TransferTime",
                    "RegistrationTime",
                    "TransferOK",
                    "TransferTotal",
                    "RegistrationOK",
                    "RegistrationTotal",
                    "startTime",
                    "endTime",
                ],
                "values": [
                    "TransferSize",
                    "TransferTime",
                    "RegistrationTime",
                    "TransferOK",
                    "TransferTotal",
                    "RegistrationOK",
                    "RegistrationTotal",
                ],
                "dataTimespan": 0,
            }
        }

        module.dbBucketsLength["LHCb-Certification_DataOperation"] = [
            (259200, 900),
            (691200, 3600),
            (15552000, 86400),
            (31104000, 604800),
        ]
        module._query = self.query
        startTime = 1495411200
        endTime = 1498043438
        retVal = module.calculateBuckets("LHCb-Certification_DataOperation", startTime + 3600, startTime + 3600)[0][0]
        self.assertTrue(retVal)
        expectedStartTime = retVal

        retVal = module.calculateBuckets("LHCb-Certification_DataOperation", endTime + 3600, endTime + 3600)[0][0]
        self.assertTrue(retVal)
        expectedEndTime = retVal

        expectedQuery = (
            "SELECT `ac_key_LHCb-Certification_DataOperation_Source`.`value`, \
`ac_bucket_LHCb-Certification_DataOperation`.`startTime`, \
`ac_bucket_LHCb-Certification_DataOperation`.`bucketLength`, \
SUM(`ac_bucket_LHCb-Certification_DataOperation`.`TransferOK`), \
SUM(`ac_bucket_LHCb-Certification_DataOperation`.`TransferTotal`)-\
SUM(`ac_bucket_LHCb-Certification_DataOperation`.`TransferOK`) \
FROM `ac_bucket_LHCb-Certification_DataOperation`, \
`ac_key_LHCb-Certification_DataOperation_Source` \
WHERE `ac_bucket_LHCb-Certification_DataOperation`.`startTime` >= %s \
AND `ac_bucket_LHCb-Certification_DataOperation`.`startTime` <= %s \
AND `ac_bucket_LHCb-Certification_DataOperation`.`Source` = `ac_key_LHCb-Certification_DataOperation_Source`.`id` \
GROUP BY startTime, `ac_key_LHCb-Certification_DataOperation_Source`.Value, bucketlength \
ORDER BY startTime"
            % (expectedStartTime, expectedEndTime)
        )

        retVal = module._AccountingDB__queryType(
            "LHCb-Certification_DataOperation",  # pylint: disable=no-member
            startTime,
            endTime,
            (
                "%s, %s, %s, SUM(%s), SUM(%s)-SUM(%s)",
                ["Source", "startTime", "bucketLength", "TransferOK", "TransferTotal", "TransferOK"],
            ),
            {},
            ("%s, %s", ["startTime", "Source"]),
            ("%s", ["startTime"]),
            "bucket",
        )

        self.assertTrue(retVal)
        self.assertEqual(retVal, expectedQuery)


#############################################################################
# Test Suite run
#############################################################################


if __name__ == "__main__":
    suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestCase)
    suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(MakeQuery))
    testResult = unittest.TextTestRunner(verbosity=2).run(suite)
