# (c) cavaliba.com - tests / pipeline bulk

import yaml

from django.test import TestCase
from django.core.cache import cache as cache_django

from tests import helper

import app_home.cache as cache

from app_data.loader import load_broker
from app_data.data import Instance


class PipelineBulkTest(TestCase):

    fixtures = ["init"]

    def setUp(self):
        helper.add_admin_user(login="unittest")
        cache.clear()
        cache_django.clear()

        helper.add_schema(
            classname="test",
            field_definition={
                "mystring": {"dataformat": "string", "displayname": "MyString"}
            }
        )

        helper.add_instance(classname="test", keyname="inst01", fields={"mystring": "active", "displayname": "inst01"})
        helper.add_instance(classname="test", keyname="inst02", fields={"mystring": "active", "displayname": "inst02"})
        helper.add_instance(classname="test", keyname="inst03", fields={"mystring": "inactive", "displayname": "inst03"})


    def test_pipeline_bulk_disable_on_criteria(self):

        datalist = yaml.safe_load('''
            - classname: _pipeline
              keyname: pipeline_bulk_disable
              displayname: pipeline_bulk_disable
              description: disable instances where mystring=inactive
              is_enabled: True
              content: |
                  tasks:
                  - set_condition: [IS_INACTIVE, field_match, mystring, '^inactive$']
                  - field_set: [IS_INACTIVE, _action, disable]
            ''')
        aaa = {'perms': ['p_pipeline_create']}
        load_broker(datalist=datalist, aaa=aaa)

        aaa = {'perms': ['p_data_admin', 'p_pipeline_run']}
        count_ok, count_discarded, errors = helper.run_pipeline("pipeline_bulk_disable", ["test"], aaa=aaa)

        self.assertEqual(errors, [])
        self.assertEqual(count_discarded, 0)
        self.assertEqual(count_ok, 3)

        inst01 = Instance.from_keyname(classname="test", keyname="inst01")
        inst02 = Instance.from_keyname(classname="test", keyname="inst02")
        inst03 = Instance.from_keyname(classname="test", keyname="inst03")

        self.assertTrue(inst01.is_enabled)
        self.assertTrue(inst02.is_enabled)
        self.assertFalse(inst03.is_enabled)


class PipelineBuiltinDisableOutOfSyncTest(TestCase):

    fixtures = ["init"]

    def setUp(self):
        helper.add_admin_user(login="unittest")
        cache.clear()
        cache_django.clear()

        helper.add_schema(
            classname="test",
            field_definition={
                "last_sync": {"dataformat": "datetime", "displayname": "Last Sync"}
            }
        )

    def test_bulk_disable_stale_asset(self):

        helper.add_instance(classname="test", keyname="stale", fields={
            "last_sync": "2020-01-01 00:00:00"
        })

        aaa = {'perms': ['p_data_admin', 'p_pipeline_run']}
        count_ok, count_discarded, errors = helper.run_pipeline("bulk_disable_out_of_sync", ["test"], aaa=aaa)

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 1)
        self.assertEqual(count_discarded, 0)

        inst = Instance.from_keyname(classname="test", keyname="stale")
        self.assertFalse(inst.is_enabled)


    def test_bulk_keep_recent_asset(self):

        helper.add_instance(classname="test", keyname="recent", fields={
            "last_sync": "2099-12-31 23:59:59"
        })

        aaa = {'perms': ['p_data_admin', 'p_pipeline_run']}
        count_ok, count_discarded, errors = helper.run_pipeline("bulk_disable_out_of_sync", ["test"], aaa=aaa)

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 0)
        self.assertEqual(count_discarded, 1)

        inst = Instance.from_keyname(classname="test", keyname="recent")
        self.assertTrue(inst.is_enabled)


    def test_bulk_skip_asset_without_last_sync(self):

        helper.add_instance(classname="test", keyname="nosync", fields={})

        aaa = {'perms': ['p_data_admin', 'p_pipeline_run']}
        count_ok, count_discarded, errors = helper.run_pipeline("bulk_disable_out_of_sync", ["test"], aaa=aaa)

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 0)
        self.assertEqual(count_discarded, 1)

        inst = Instance.from_keyname(classname="test", keyname="nosync")
        self.assertTrue(inst.is_enabled)


    def test_bulk_mixed_assets(self):

        helper.add_instance(classname="test", keyname="stale", fields={
            "last_sync": "2020-01-01 00:00:00"
        })
        helper.add_instance(classname="test", keyname="recent", fields={
            "last_sync": "2099-12-31 23:59:59"
        })
        helper.add_instance(classname="test", keyname="nosync", fields={})

        aaa = {'perms': ['p_data_admin', 'p_pipeline_run']}
        count_ok, count_discarded, errors = helper.run_pipeline("bulk_disable_out_of_sync", ["test"], aaa=aaa)

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 1)
        self.assertEqual(count_discarded, 2)

        self.assertFalse(Instance.from_keyname(classname="test", keyname="stale").is_enabled)
        self.assertTrue(Instance.from_keyname(classname="test", keyname="recent").is_enabled)
        self.assertTrue(Instance.from_keyname(classname="test", keyname="nosync").is_enabled)


class PipelineBuiltinDeleteOutOfSyncTest(TestCase):

    fixtures = ["init"]

    def setUp(self):
        helper.add_admin_user(login="unittest")
        cache.clear()
        cache_django.clear()

        helper.add_schema(
            classname="test",
            field_definition={
                "last_sync": {"dataformat": "datetime", "displayname": "Last Sync"}
            }
        )

    def test_bulk_delete_disabled_stale_asset(self):

        helper.add_instance(classname="test", keyname="old_disabled", fields={
            "last_sync": "2020-01-01 00:00:00",
            "is_enabled": False,
        })

        aaa = {'perms': ['p_data_admin', 'p_pipeline_run']}
        count_ok, count_discarded, errors = helper.run_pipeline("bulk_delete_out_of_sync", ["test"], aaa=aaa)

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 1)
        self.assertEqual(count_discarded, 0)

        inst = Instance.from_keyname(classname="test", keyname="old_disabled")
        self.assertIsNone(inst)


    def test_bulk_keep_enabled_stale_asset(self):

        helper.add_instance(classname="test", keyname="stale_enabled", fields={
            "last_sync": "2020-01-01 00:00:00",
            "is_enabled": True,
        })

        aaa = {'perms': ['p_data_admin', 'p_pipeline_run']}
        count_ok, count_discarded, errors = helper.run_pipeline("bulk_delete_out_of_sync", ["test"], aaa=aaa)

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 0)
        self.assertEqual(count_discarded, 1)

        inst = Instance.from_keyname(classname="test", keyname="stale_enabled")
        self.assertIsNotNone(inst)


    def test_bulk_keep_disabled_recent_asset(self):

        helper.add_instance(classname="test", keyname="disabled_recent", fields={
            "last_sync": "2099-12-31 23:59:59",
            "is_enabled": False,
        })

        aaa = {'perms': ['p_data_admin', 'p_pipeline_run']}
        count_ok, count_discarded, errors = helper.run_pipeline("bulk_delete_out_of_sync", ["test"], aaa=aaa)

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 0)
        self.assertEqual(count_discarded, 1)

        inst = Instance.from_keyname(classname="test", keyname="disabled_recent")
        self.assertIsNotNone(inst)


    def test_bulk_skip_asset_without_last_sync(self):

        helper.add_instance(classname="test", keyname="nosync", fields={
            "is_enabled": False,
        })

        aaa = {'perms': ['p_data_admin', 'p_pipeline_run']}
        count_ok, count_discarded, errors = helper.run_pipeline("bulk_delete_out_of_sync", ["test"], aaa=aaa)

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 0)
        self.assertEqual(count_discarded, 1)

        inst = Instance.from_keyname(classname="test", keyname="nosync")
        self.assertIsNotNone(inst)


    def test_bulk_delete_mixed_assets(self):

        helper.add_instance(classname="test", keyname="old_disabled", fields={
            "last_sync": "2020-01-01 00:00:00",
            "is_enabled": False,
        })
        helper.add_instance(classname="test", keyname="stale_enabled", fields={
            "last_sync": "2020-01-01 00:00:00",
            "is_enabled": True,
        })
        helper.add_instance(classname="test", keyname="disabled_recent", fields={
            "last_sync": "2099-12-31 23:59:59",
            "is_enabled": False,
        })
        helper.add_instance(classname="test", keyname="nosync", fields={
            "is_enabled": False,
        })

        aaa = {'perms': ['p_data_admin', 'p_pipeline_run']}
        count_ok, count_discarded, errors = helper.run_pipeline("bulk_delete_out_of_sync", ["test"], aaa=aaa)

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 1)
        self.assertEqual(count_discarded, 3)

        self.assertIsNone(Instance.from_keyname(classname="test", keyname="old_disabled"))
        self.assertIsNotNone(Instance.from_keyname(classname="test", keyname="stale_enabled"))
        self.assertIsNotNone(Instance.from_keyname(classname="test", keyname="disabled_recent"))
        self.assertIsNotNone(Instance.from_keyname(classname="test", keyname="nosync"))


class PipelineBuiltinDeleteAllTest(TestCase):

    fixtures = ["init"]

    def setUp(self):
        helper.add_admin_user(login="unittest")
        cache.clear()
        cache_django.clear()

        helper.add_schema(classname="test")

    def test_bulk_delete_all_removes_all(self):

        helper.add_instance(classname="test", keyname="inst01", fields={})
        helper.add_instance(classname="test", keyname="inst02", fields={})
        helper.add_instance(classname="test", keyname="inst03", fields={})

        aaa = {'perms': ['p_data_admin', 'p_pipeline_run']}
        count_ok, count_discarded, errors = helper.run_pipeline("bulk_delete_all", ["test"], aaa=aaa)

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 3)
        self.assertEqual(count_discarded, 0)

        self.assertIsNone(Instance.from_keyname(classname="test", keyname="inst01"))
        self.assertIsNone(Instance.from_keyname(classname="test", keyname="inst02"))
        self.assertIsNone(Instance.from_keyname(classname="test", keyname="inst03"))


    def test_bulk_delete_all_empty_schema(self):

        aaa = {'perms': ['p_data_admin', 'p_pipeline_run']}
        count_ok, count_discarded, errors = helper.run_pipeline("bulk_delete_all", ["test"], aaa=aaa)

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 0)
        self.assertEqual(count_discarded, 0)


class PipelineBuiltinRefreshTest(TestCase):

    fixtures = ["init"]

    def setUp(self):
        helper.add_admin_user(login="unittest")
        cache.clear()
        cache_django.clear()

        helper.add_schema(
            classname="test",
            field_definition={
                "mystring": {"dataformat": "string", "displayname": "MyString"}
            }
        )

    def test_bulk_refresh_all_instances(self):

        helper.add_instance(classname="test", keyname="inst01", fields={"mystring": "hello"})
        helper.add_instance(classname="test", keyname="inst02", fields={"mystring": "world"})

        aaa = {'perms': ['p_data_admin', 'p_pipeline_run']}
        count_ok, count_discarded, errors = helper.run_pipeline("bulk_refresh", ["test"], aaa=aaa)

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 2)
        self.assertEqual(count_discarded, 0)

        self.assertIsNotNone(Instance.from_keyname(classname="test", keyname="inst01"))
        self.assertIsNotNone(Instance.from_keyname(classname="test", keyname="inst02"))


    def test_bulk_refresh_empty_schema(self):

        aaa = {'perms': ['p_data_admin', 'p_pipeline_run']}
        count_ok, count_discarded, errors = helper.run_pipeline("bulk_refresh", ["test"], aaa=aaa)

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 0)
        self.assertEqual(count_discarded, 0)


    def test_bulk_noop(self):

        aaa = {'perms': ['p_data_admin', 'p_pipeline_run']}
        count_ok, count_discarded, errors = helper.run_pipeline("bulk_noop", ["test"], aaa=aaa)

        self.assertEqual(errors, [])
        self.assertEqual(count_ok, 0)
        self.assertEqual(count_discarded, 0)
