1# Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2#  This source code is licensed under both the GPLv2 (found in the
3#  COPYING file in the root directory) and Apache 2.0 License
4#  (found in the LICENSE.Apache file in the root directory).
5
6from advisor.db_log_parser import DatabaseLogs, Log, NO_COL_FAMILY
7from advisor.rule_parser import Condition, LogCondition
8import os
9import unittest
10
11
12class TestLog(unittest.TestCase):
13    def setUp(self):
14        self.column_families = ['default', 'col_fam_A']
15
16    def test_get_column_family(self):
17        test_log = (
18            "2018/05/25-14:34:21.047233 7f82ba72e700 [db/flush_job.cc:371] " +
19            "[col_fam_A] [JOB 44] Level-0 flush table #84: 1890780 bytes OK"
20        )
21        db_log = Log(test_log, self.column_families)
22        self.assertEqual('col_fam_A', db_log.get_column_family())
23
24        test_log = (
25            "2018/05/25-14:34:21.047233 7f82ba72e700 [db/flush_job.cc:371] " +
26            "[JOB 44] Level-0 flush table #84: 1890780 bytes OK"
27        )
28        db_log = Log(test_log, self.column_families)
29        db_log.append_message('[default] some remaining part of log')
30        self.assertEqual(NO_COL_FAMILY, db_log.get_column_family())
31
32    def test_get_methods(self):
33        hr_time = "2018/05/25-14:30:25.491635"
34        context = "7f82ba72e700"
35        message = (
36            "[db/flush_job.cc:331] [default] [JOB 10] Level-0 flush table " +
37            "#23: started"
38        )
39        test_log = hr_time + " " + context + " " + message
40        db_log = Log(test_log, self.column_families)
41        self.assertEqual(db_log.get_message(), message)
42        remaining_message = "[col_fam_A] some more logs"
43        db_log.append_message(remaining_message)
44        self.assertEqual(
45            db_log.get_human_readable_time(), "2018/05/25-14:30:25.491635"
46        )
47        self.assertEqual(db_log.get_context(), "7f82ba72e700")
48        self.assertEqual(db_log.get_timestamp(), 1527258625)
49        self.assertEqual(
50            db_log.get_message(), str(message + '\n' + remaining_message)
51        )
52
53    def test_is_new_log(self):
54        new_log = "2018/05/25-14:34:21.047233 context random new log"
55        remaining_log = "2018/05/25 not really a new log"
56        self.assertTrue(Log.is_new_log(new_log))
57        self.assertFalse(Log.is_new_log(remaining_log))
58
59
60class TestDatabaseLogs(unittest.TestCase):
61    def test_check_and_trigger_conditions(self):
62        this_path = os.path.abspath(os.path.dirname(__file__))
63        logs_path_prefix = os.path.join(this_path, 'input_files/LOG-0')
64        column_families = ['default', 'col-fam-A', 'col-fam-B']
65        db_logs = DatabaseLogs(logs_path_prefix, column_families)
66        # matches, has 2 col_fams
67        condition1 = LogCondition.create(Condition('cond-A'))
68        condition1.set_parameter('regex', 'random log message')
69        # matches, multiple lines message
70        condition2 = LogCondition.create(Condition('cond-B'))
71        condition2.set_parameter('regex', 'continuing on next line')
72        # does not match
73        condition3 = LogCondition.create(Condition('cond-C'))
74        condition3.set_parameter('regex', 'this should match no log')
75        db_logs.check_and_trigger_conditions(
76            [condition1, condition2, condition3]
77        )
78        cond1_trigger = condition1.get_trigger()
79        self.assertEqual(2, len(cond1_trigger.keys()))
80        self.assertSetEqual(
81            {'col-fam-A', NO_COL_FAMILY}, set(cond1_trigger.keys())
82        )
83        self.assertEqual(2, len(cond1_trigger['col-fam-A']))
84        messages = [
85            "[db/db_impl.cc:563] [col-fam-A] random log message for testing",
86            "[db/db_impl.cc:653] [col-fam-A] another random log message"
87        ]
88        self.assertIn(cond1_trigger['col-fam-A'][0].get_message(), messages)
89        self.assertIn(cond1_trigger['col-fam-A'][1].get_message(), messages)
90        self.assertEqual(1, len(cond1_trigger[NO_COL_FAMILY]))
91        self.assertEqual(
92            cond1_trigger[NO_COL_FAMILY][0].get_message(),
93            "[db/db_impl.cc:331] [unknown] random log message no column family"
94        )
95        cond2_trigger = condition2.get_trigger()
96        self.assertEqual(['col-fam-B'], list(cond2_trigger.keys()))
97        self.assertEqual(1, len(cond2_trigger['col-fam-B']))
98        self.assertEqual(
99            cond2_trigger['col-fam-B'][0].get_message(),
100            "[db/db_impl.cc:234] [col-fam-B] log continuing on next line\n" +
101            "remaining part of the log"
102        )
103        self.assertIsNone(condition3.get_trigger())
104