Coverage for tests/test_monitor.py: 14%
118 statements
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-16 03:20 -0700
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-16 03:20 -0700
1# This file is part of dax_apdb.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (http://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <http://www.gnu.org/licenses/>.
22import unittest
23from collections.abc import Mapping
24from typing import Any
26from lsst.dax.apdb import monitor, timer
29class _TestHandler(monitor.MonHandler):
30 """Implementation of monitoring handler used in unit tests."""
32 name: str
33 tags: Mapping
34 values: Mapping
35 agent_name: str
37 def handle(
38 self, name: str, timestamp: float, tags: monitor._TagsType, values: Mapping[str, Any], agent_name: str
39 ) -> None:
40 self.name = name
41 self.tags = tags
42 self.values = values
43 self.agent_name = agent_name
46class MonitorTestCase(unittest.TestCase):
47 """Unit tests for monitoring classes."""
49 def setUp(self) -> None:
50 # MonService is a singleton wit global/shared test, need to reset it
51 # for each new test.
52 monsvc = monitor.MonService()
53 monsvc._handlers = []
54 monsvc._context_tags = None
55 monsvc._filters = []
57 def test_simple(self) -> None:
58 """Test few simple calls."""
59 handler = _TestHandler()
60 monitor.MonService().add_handler(handler)
62 agent = monitor.MonAgent("007")
63 agent.add_record("mon", values={"quantity": 1})
65 self.assertEqual(handler.name, "mon")
66 self.assertEqual(handler.tags, {})
67 self.assertEqual(handler.values, {"quantity": 1})
68 self.assertEqual(handler.agent_name, "007")
70 def test_two_handlers(self) -> None:
71 """Test few simple calls with two handlers."""
72 handler1 = _TestHandler()
73 monitor.MonService().add_handler(handler1)
74 handler2 = _TestHandler()
75 monitor.MonService().add_handler(handler2)
77 agent = monitor.MonAgent("007")
78 agent.add_record("mon", values={"quantity": 1}, tags={"tag1": "atag"})
80 self.assertEqual(handler1.name, "mon")
81 self.assertEqual(handler1.tags, {"tag1": "atag"})
82 self.assertEqual(handler1.values, {"quantity": 1})
83 self.assertEqual(handler1.agent_name, "007")
84 self.assertEqual(handler2.name, "mon")
85 self.assertEqual(handler2.tags, {"tag1": "atag"})
86 self.assertEqual(handler2.values, {"quantity": 1})
87 self.assertEqual(handler2.agent_name, "007")
89 def test_tag_context(self) -> None:
90 """Test tag context."""
91 handler = _TestHandler()
92 monitor.MonService().add_handler(handler)
94 agent = monitor.MonAgent("007")
96 with agent.context_tags({"tag1": "atag"}):
97 agent.add_record("mon", values={"quantity": 1})
99 self.assertEqual(handler.name, "mon")
100 self.assertEqual(handler.tags, {"tag1": "atag"})
101 self.assertEqual(handler.values, {"quantity": 1})
102 self.assertEqual(handler.agent_name, "007")
104 def test_logging_handler(self) -> None:
105 """Test logging handler."""
106 handler = monitor.LoggingMonHandler("logger")
107 monitor.MonService().add_handler(handler)
109 agent = monitor.MonAgent("007")
111 with self.assertLogs("logger", level="INFO") as cm:
112 # Need to use fixed timestamps here to be able to compare strings.
113 agent.add_record("mon", values={"quantity": 1}, tags={"tag1": "atag1"}, timestamp=100.0)
114 agent.add_record("mon", values={"quantity": 2}, tags={"tag1": "atag2"}, timestamp=101.0)
115 self.assertEqual(
116 cm.output,
117 [
118 'INFO:logger:{"name": "mon", "timestamp": 100.0, '
119 '"tags": {"tag1": "atag1"}, "values": {"quantity": 1}, "source": "007"}',
120 'INFO:logger:{"name": "mon", "timestamp": 101.0, '
121 '"tags": {"tag1": "atag2"}, "values": {"quantity": 2}, "source": "007"}',
122 ],
123 )
125 def test_timer(self) -> None:
126 """Test monitoring output via Timer."""
127 handler = _TestHandler()
128 monitor.MonService().add_handler(handler)
130 agent = monitor.MonAgent("007")
131 with agent.context_tags({"tag1": "atag"}):
132 with timer.Timer("timer", agent):
133 pass
134 self.assertEqual(handler.name, "timer")
135 self.assertEqual(handler.tags, {"tag1": "atag"})
136 self.assertEqual(set(handler.values), {"real", "user", "sys"})
137 self.assertEqual(handler.agent_name, "007")
139 def test_filters(self) -> None:
140 """Test agent filtering."""
141 handler = _TestHandler()
142 monitor.MonService().add_handler(handler)
144 # Note that unlike in the `logging` there is no parent/child relation
145 # between agent, disabling "lsst" will not disable two others.
146 agent1 = monitor.MonAgent("lsst.agent1")
147 agent2 = monitor.MonAgent("lsst.agent2")
148 agent3 = monitor.MonAgent("lsst")
150 # By default nothing is filtered
151 agent1.add_record("mon1", values={"quantity": 1})
152 self.assertEqual(handler.name, "mon1")
153 self.assertEqual(handler.values["quantity"], 1)
154 agent2.add_record("mon2", values={"quantity": 2})
155 self.assertEqual(handler.name, "mon2")
156 self.assertEqual(handler.values["quantity"], 2)
157 agent3.add_record("mon3", values={"quantity": 3})
158 self.assertEqual(handler.name, "mon3")
159 self.assertEqual(handler.values["quantity"], 3)
161 # Disable one of them.
162 monitor.MonService().set_filters(["-lsst"])
163 agent1.add_record("mon1", values={"quantity": 1})
164 self.assertEqual(handler.name, "mon1")
165 self.assertEqual(handler.values["quantity"], 1)
166 agent2.add_record("mon2", values={"quantity": 2})
167 self.assertEqual(handler.name, "mon2")
168 self.assertEqual(handler.values["quantity"], 2)
169 agent3.add_record("mon3", values={"quantity": 3})
170 self.assertEqual(handler.name, "mon2")
171 self.assertEqual(handler.values["quantity"], 2)
173 # Disable all except one.
174 monitor.MonService().set_filters(["+lsst.agent1", "-any"])
175 agent1.add_record("mon1", values={"quantity": 1})
176 self.assertEqual(handler.name, "mon1")
177 self.assertEqual(handler.values["quantity"], 1)
178 agent2.add_record("mon2", values={"quantity": 2})
179 self.assertEqual(handler.name, "mon1")
180 self.assertEqual(handler.values["quantity"], 1)
181 agent3.add_record("mon3", values={"quantity": 3})
182 self.assertEqual(handler.name, "mon1")
183 self.assertEqual(handler.values["quantity"], 1)
185 # Plus sign is optional in the rule.
186 monitor.MonService().set_filters(["+lsst.agent1", "lsst.agent2", "-lsst"])
187 agent1.add_record("mon1", values={"quantity": 1})
188 self.assertEqual(handler.name, "mon1")
189 self.assertEqual(handler.values["quantity"], 1)
190 agent2.add_record("mon2", values={"quantity": 2})
191 self.assertEqual(handler.name, "mon2")
192 self.assertEqual(handler.values["quantity"], 2)
193 agent3.add_record("mon3", values={"quantity": 3})
194 self.assertEqual(handler.name, "mon2")
195 self.assertEqual(handler.values["quantity"], 2)
198if __name__ == "__main__":
199 unittest.main()