Coverage for tests/test_apdbMetricTask.py: 33%
94 statements
« prev ^ index » next coverage.py v6.4.4, created at 2022-08-30 02:50 -0700
« prev ^ index » next coverage.py v6.4.4, created at 2022-08-30 02:50 -0700
1# This file is part of verify.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://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 <https://www.gnu.org/licenses/>.
22import shutil
23import tempfile
24import unittest.mock
26import astropy.units as u
28import lsst.utils.tests
29from lsst.pex.config import Config
30import lsst.daf.butler.tests as butlerTests
31from lsst.pipe.base import Task, Struct, testUtils
33from lsst.verify import Measurement
34from lsst.verify.tasks import ApdbMetricTask, MetricComputationError
35from lsst.verify.tasks.testUtils import ApdbMetricTestCase
38class DummyTask(ApdbMetricTask):
39 _DefaultName = "NotARealTask"
41 def makeMeasurement(self, _dbHandle, outputDataId):
42 if outputDataId:
43 nChars = len(outputDataId["instrument"])
44 return Measurement(self.config.metricName,
45 nChars * u.dimensionless_unscaled)
46 else:
47 return Measurement(self.config.metricName,
48 0 * u.dimensionless_unscaled)
51class Gen3ApdbTestSuite(ApdbMetricTestCase):
52 @classmethod
53 def makeTask(cls):
54 class MockDbLoader(Task):
55 ConfigClass = Config
57 def run(self, _):
58 return Struct(apdb=unittest.mock.Mock())
60 config = DummyTask.ConfigClass()
61 config.dbLoader.retarget(MockDbLoader)
62 config.connections.package = "verify"
63 config.connections.metric = "DummyApdb"
64 return DummyTask(config=config)
66 @classmethod
67 def setUpClass(cls):
68 super().setUpClass()
70 cls.CAMERA_ID = "NotACam"
71 cls.VISIT_ID = 42
72 cls.CHIP_ID = 5
74 # makeTestRepo called in setUpClass because it's *very* slow
75 cls.root = tempfile.mkdtemp()
76 cls.repo = butlerTests.makeTestRepo(cls.root, {
77 "instrument": [cls.CAMERA_ID],
78 "visit": [cls.VISIT_ID],
79 "detector": [cls.CHIP_ID],
80 })
82 # self.task not visible at class level
83 task = cls.makeTask()
84 connections = task.config.ConnectionsClass(config=task.config)
86 butlerTests.addDatasetType(
87 cls.repo,
88 connections.measurement.name,
89 connections.measurement.dimensions,
90 connections.measurement.storageClass)
91 butlerTests.addDatasetType(
92 cls.repo,
93 connections.dbInfo.name,
94 connections.dbInfo.dimensions,
95 connections.dbInfo.storageClass)
97 @classmethod
98 def tearDownClass(cls):
99 shutil.rmtree(cls.root, ignore_errors=True)
100 super().tearDownClass()
102 def setUp(self):
103 super().setUp()
105 self.connections = self.task.config.ConnectionsClass(
106 config=self.task.config)
108 def _prepareQuantum(self, task):
109 globalId = {
110 "instrument": self.CAMERA_ID,
111 }
112 detectorId = {
113 "instrument": self.CAMERA_ID,
114 "visit": self.VISIT_ID,
115 "detector": self.CHIP_ID,
116 }
118 butler = butlerTests.makeTestCollection(self.repo)
119 # task.config not persistable if it refers to a local class
120 # We don't actually use the persisted config, so just make a new one
121 info = task.ConfigClass()
122 butler.put(info, "apdb_marker", detectorId)
124 quantum = testUtils.makeQuantum(
125 task, butler, globalId,
126 {"dbInfo": [detectorId], "measurement": globalId})
128 return (butler, quantum, info)
130 def testRunQuantum(self):
131 butler, quantum, input = self._prepareQuantum(self.task)
133 run = testUtils.runTestQuantum(self.task, butler, quantum)
135 # Did output data ID get passed to DummyTask.run?
136 expectedId = lsst.daf.butler.DataCoordinate.standardize(
137 {"instrument": self.CAMERA_ID},
138 universe=butler.registry.dimensions)
139 run.assert_called_once_with(
140 dbInfo=[input],
141 outputDataId=expectedId)
143 def testRunQuantumNone(self):
144 class NoneTask(DummyTask):
145 def run(self, *args, **kwargs):
146 return Struct(measurement=None)
148 config = NoneTask.ConfigClass()
149 config.connections.package = "verify"
150 config.connections.metric = "DummyApdb"
151 task = NoneTask(config=config)
152 butler, quantum, input = self._prepareQuantum(task)
154 with unittest.mock.patch.object(
155 lsst.pipe.base.ButlerQuantumContext, "put") as put:
156 testUtils.runTestQuantum(task, butler, quantum, mockRun=False)
157 # Should not attempt to write nonexistent data
158 put.assert_not_called()
160 def testRunQuantumException(self):
161 class ExceptionalTask(DummyTask):
162 def run(self, *args, **kwargs):
163 raise MetricComputationError()
165 config = ExceptionalTask.ConfigClass()
166 config.connections.package = "verify"
167 config.connections.metric = "DummyApdb"
168 task = ExceptionalTask(config=config)
169 butler, quantum, input = self._prepareQuantum(task)
171 with unittest.mock.patch.object(
172 lsst.pipe.base.ButlerQuantumContext, "put") as put:
173 testUtils.runTestQuantum(task, butler, quantum, mockRun=False)
174 # Should not propagate MetricComputationError
175 # Should not attempt to write data that was never returned
176 put.assert_not_called()
179# Hack around unittest's hacky test setup system
180del ApdbMetricTestCase
183class MemoryTester(lsst.utils.tests.MemoryTestCase):
184 pass
187def setup_module(module):
188 lsst.utils.tests.init()
191if __name__ == "__main__": 191 ↛ 192line 191 didn't jump to line 192, because the condition on line 191 was never true
192 lsst.utils.tests.init()
193 unittest.main()