def setUp(self, *args):
     mock, = args
     self.check_data = deepcopy(CHECK_TEST_DATA)
     self.check = CheckInstance(self.check_data)
     self.trigger = self.check.triggers[0]
     self.notification = Mock()
     self.alerter = AlamoAlerter(mock, self.notification, StatsClient())
class AlerterTest(unittest.TestCase):
    @patch("alamo_alerter.backend.cassandra.CassandraDriver")
    def setUp(self, *args):
        mock, = args
        self.check_data = deepcopy(CHECK_TEST_DATA)
        self.check = CheckInstance(self.check_data)
        self.trigger = self.check.triggers[0]
        self.notification = Mock()
        self.alerter = AlamoAlerter(mock, self.notification, StatsClient())

    def test_retrieve_cached_result_by_rebuilding_cache(self):
        self.alerter.driver.get_result = MagicMock(return_value=[])
        result = self.alerter.get_cached_result(self.check.uuid, self.trigger.uuid, 1)
        self.assertEqual(len(result), 0)

    def test_retrieve_cached_result(self):
        self.alerter.driver.get_result = MagicMock(return_value=[1, 1, 0])

        result = self.alerter.get_cached_result(self.check.uuid, self.trigger.uuid, 3)
        self.assertEqual(len(result), 3)

    @unpack
    @data(
        ([3, 0], 1, "resolve"),
        ([1, 0], 1, "resolve"),
        ([1, 3, 0], 2, "resolve"),
        ([1, 1, 0], 2, "resolve"),
        ([0, 0, 0, 0], 3, None),
        ([0, 0, 0, 1], 3, None),
        ([0, 0, 1, 1], 3, None),
        ([1, 1, 1], 3, "trigger"),
        ([0, 1, 1, 1], 3, "trigger"),
        ([2, 1, 1, 1], 3, "trigger"),
        ([2, 1, 3, 1], 3, "trigger"),
        ([2, 1, 3, 3], 3, "trigger"),
        ([1, 1, 1, 1], 3, None),
        ([1, 1, 1, 0], 3, "resolve"),
        ([1, 1, 3, 0], 3, "resolve"),
        ([3, 1, 3, 0], 3, "resolve"),
        ([0, 0, 1, 0], 3, None),
        ([2, 2, 2, 2], 3, None),
        ([0, 1, 0, 0], 3, None),
        ([1, 0, 0, 0], 3, None),
        ([1, 1, 2, 0], 3, None),
        ([0, 2, 0, 2], 3, None),
        ([1, 2, 1, 1], 3, None),
        ([0, 0, 2, 2], 3, None),
        ([1, 1, 1, 2], 3, None),
        ([0, 1, 1], 5, None),
        ([0, 1, 1, 1], 5, None),
        ([0, 1, 1, 1, 1], 5, None),
        ([1, 1, 1, 1, 1], 5, "trigger"),
    )
    def test_analyze_result(self, results, debounce, expected):
        results = [CachedResult(r, 0, False, "") for r in results]
        repeat = 0
        _, event_type = self.alerter.analyze_result(deque(results, debounce + 1), debounce, repeat)

        self.assertEqual(event_type, expected)

    @patch(
        "alamo_alerter.alerter.AlamoAlerter.get_cached_result",
        MagicMock(
            return_value=deque(
                [CachedResult(0, 0, False, ""), CachedResult(0, 0, False, ""), CachedResult(1, 1, False, "")], 3
            )
        ),
    )
    @patch("alamo_alerter.alerter.AlamoAlerter.send_alert")
    def test_execution_process(self, send_alert_mock):
        self.check_data["triggers"][0]["result"]["status"] = 1
        self.alerter.execute(self.check_data)

        self.assertTrue(send_alert_mock.called)

    @unpack
    @data(
        ([(0, False)], 2, 2),
        ([(1, False)], 2, 3),
        ([(3, False)], 2, 3),
        ([], 2, 2),
        # ok and failed status are skipped
        ([], 1, 1),
        ([], 0, 0),
        ([(1, False)], 1, 1),
        ([(1, False)], 0, 0),
    )
    def test_unknown_status_transformation(self, results, status, expected):
        results = [CachedResult(r[0], 0, r[1], "") for r in results]
        self.trigger.result.status = status
        self.alerter.translate_unknown_status(results, self.trigger)

        self.assertEqual(self.trigger.result.status, expected)

    @unpack
    @data(
        ([(0, False)], 2, False),  # OK -> Unknown, should not copy
        ([(1, False)], 2, True),  # FAIL -> Unknown, should copy
        ([(2, False)], 2, False),  # UNK_OK -> Unknown, should not copy
        ([(3, False)], 2, True),  # UNK_FAIL -> Unknown, should copy
        ([(3, False), (3, False)], 2, True),  # chaining test
    )
    def test_message_copying_for_unknown(self, results, status, should_copy):
        results = [CachedResult(r[0], 0, r[1], "message") for r in results]
        self.trigger.result.status = status
        self.alerter.translate_unknown_status(results, self.trigger)

        is_equal = self.trigger.result.message == "message"
        self.assertEqual(is_equal, should_copy)

    @unpack
    @data(
        ([(0, False)], 1, 0, None),
        ([(1, False)], 1, 0, "trigger"),
        ([(1, False)], 1, 1, "trigger"),
        ([(1, False)], 1, 3, "trigger"),
        ([(0, False), (0, False)], 1, 0, None),
        ([(1, False), (0, False)], 1, 0, "resolve"),
        ([(1, True), (0, False)], 1, 1, "resolve"),
        ([(0, False), (1, False)], 1, 0, "trigger"),
        ([(1, True), (1, False)], 1, 1, "trigger"),
        ([(1, True), (1, False)], 1, 0, None),
        ([(1, False), (1, True)], 1, 2, None),
        ([(1, True), (1, False), (1, True)], 1, 2, "trigger"),
        ([(1, True), (1, False), (1, False)], 1, 2, "trigger"),
        ([(0, False), (1, False), (1, False)], 2, 1, "trigger"),
        ([(1, False), (1, True), (1, False)], 1, 2, None),
        ([(1, True), (0, False), (0, False)], 1, 2, None),
        ([(1, False), (0, False), (1, False), (1, False)], 2, 3, "trigger"),
        ([(1, False), (1, True), (0, False), (0, False)], 2, 3, None),
        ([(1, True), (1, False), (0, False), (0, False)], 2, 3, None),
        ([(1, False), (1, True), (0, False), (1, False)], 2, 3, None),
    )
    def test_repeat_trigger(self, results, debounce, repeat, expected):
        # trigger status is the same as hysteresis status
        results = [(v[0], v[0], v[1], "") for v in results]
        results = [CachedResult(*r) for r in results]
        _, event_type = self.alerter.analyze_result(deque(results, max(debounce, repeat) + 1), debounce, repeat)
        self.assertEqual(event_type, expected)

    @unpack
    @data(
        # [cached_result(status, alert sent)],
        # new_check(status, hysteresis), analyze_result, debounce
        ([(0, False)], (0, 0), (0, None), 1),
        ([(0, True)], (0, 0), (0, None), 1),
        ([(0, False)], (0, 1), (0, None), 1),
        ([(0, True)], (0, 1), (0, None), 1),
        ([(0, False)], (1, 1), (1, "trigger"), 1),
        ([(1, False)], (1, 1), (1, None), 1),
        ([(1, True)], (1, 1), (1, None), 1),
        ([(1, False)], (0, 1), (1, None), 1),
        ([(1, True)], (0, 0), (0, "resolve"), 1),
        ([(0, False), (0, False)], (0, 0), (0, None), 2),
        ([(0, False), (0, False)], (0, 1), (0, None), 2),
        ([(0, False), (0, False)], (1, 1), (1, None), 2),
        ([(0, False), (1, False)], (1, 1), (1, "trigger"), 2),
        ([(0, False), (1, False)], (0, 1), (0, None), 2),
        ([(1, False), (1, False)], (0, 1), (1, None), 2),
        ([(1, False), (1, True)], (0, 1), (1, None), 2),
        ([(1, False), (1, False)], (0, 0), (0, "resolve"), 2),
        ([(1, False), (0, False)], (0, 1), (0, None), 2),
        ([(1, False), (0, False)], (1, 1), (1, None), 2),
    )
    @patch("alamo_alerter.alerter.AlamoAlerter.send_alert")
    @patch("alamo_alerter.alerter.AlamoAlerter.get_cached_result")
    def test_hysteresis_overrides_status(
        self, cached_result, new_check, analyze_result, debounce, mock_get_cached_result, mock_send_alert
    ):

        mock_get_cached_result.return_value = deque(
            [CachedResult(r[0], 0, r[1], "") for r in cached_result], (debounce + 1)
        )
        self.check_data["triggers"][0]["result"]["status"] = new_check[0]
        self.check_data["triggers"][0]["result"]["hysteresis"] = new_check[1]
        self.check_data["fields"]["debounce"] = debounce
        should_send_alert = True if analyze_result[1] else False
        returned_values = self.alerter.execute(self.check_data)

        self.assertTupleEqual(returned_values, analyze_result)
        self.assertTrue(self.alerter.driver.save_result.called)

        status = self.alerter.driver.save_result.call_args[0][1].result.status
        self.assertEqual(status, returned_values[0])
        self.assertEqual(mock_send_alert.called, should_send_alert)