Coverage for tests/test_apdbMetricTask.py: 33%

95 statements  

« prev     ^ index     » next       coverage.py v6.4.2, created at 2022-07-13 02:58 -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/>. 

21 

22import shutil 

23import tempfile 

24import unittest.mock 

25 

26import astropy.units as u 

27 

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 

32 

33from lsst.verify import Measurement 

34from lsst.verify.tasks import ApdbMetricTask, MetricComputationError 

35from lsst.verify.tasks.testUtils import ApdbMetricTestCase 

36 

37 

38class DummyTask(ApdbMetricTask): 

39 _DefaultName = "NotARealTask" 

40 

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) 

49 

50 

51class Gen3ApdbTestSuite(ApdbMetricTestCase): 

52 @classmethod 

53 def makeTask(cls): 

54 class MockDbLoader(Task): 

55 ConfigClass = Config 

56 

57 def run(self, _): 

58 return Struct(apdb=unittest.mock.Mock()) 

59 

60 config = DummyTask.ConfigClass() 

61 config.dbLoader.retarget(MockDbLoader) 

62 config.connections.package = "verify" 

63 config.connections.metric = "DummyApdb" 

64 config.validate() 

65 return DummyTask(config=config) 

66 

67 @classmethod 

68 def setUpClass(cls): 

69 super().setUpClass() 

70 

71 cls.CAMERA_ID = "NotACam" 

72 cls.VISIT_ID = 42 

73 cls.CHIP_ID = 5 

74 

75 # makeTestRepo called in setUpClass because it's *very* slow 

76 cls.root = tempfile.mkdtemp() 

77 cls.repo = butlerTests.makeTestRepo(cls.root, { 

78 "instrument": [cls.CAMERA_ID], 

79 "visit": [cls.VISIT_ID], 

80 "detector": [cls.CHIP_ID], 

81 }) 

82 

83 # self.task not visible at class level 

84 task = cls.makeTask() 

85 connections = task.config.ConnectionsClass(config=task.config) 

86 

87 butlerTests.addDatasetType( 

88 cls.repo, 

89 connections.measurement.name, 

90 connections.measurement.dimensions, 

91 connections.measurement.storageClass) 

92 butlerTests.addDatasetType( 

93 cls.repo, 

94 connections.dbInfo.name, 

95 connections.dbInfo.dimensions, 

96 connections.dbInfo.storageClass) 

97 

98 @classmethod 

99 def tearDownClass(cls): 

100 shutil.rmtree(cls.root, ignore_errors=True) 

101 super().tearDownClass() 

102 

103 def setUp(self): 

104 super().setUp() 

105 

106 self.connections = self.task.config.ConnectionsClass( 

107 config=self.task.config) 

108 

109 def _prepareQuantum(self, task): 

110 globalId = { 

111 "instrument": self.CAMERA_ID, 

112 } 

113 detectorId = { 

114 "instrument": self.CAMERA_ID, 

115 "visit": self.VISIT_ID, 

116 "detector": self.CHIP_ID, 

117 } 

118 

119 butler = butlerTests.makeTestCollection(self.repo) 

120 # task.config not persistable if it refers to a local class 

121 # We don't actually use the persisted config, so just make a new one 

122 info = task.ConfigClass() 

123 butler.put(info, "apdb_marker", detectorId) 

124 

125 quantum = testUtils.makeQuantum( 

126 task, butler, globalId, 

127 {"dbInfo": [detectorId], "measurement": globalId}) 

128 

129 return (butler, quantum, info) 

130 

131 def testRunQuantum(self): 

132 butler, quantum, input = self._prepareQuantum(self.task) 

133 

134 run = testUtils.runTestQuantum(self.task, butler, quantum) 

135 

136 # Did output data ID get passed to DummyTask.run? 

137 expectedId = lsst.daf.butler.DataCoordinate.standardize( 

138 {"instrument": self.CAMERA_ID}, 

139 universe=butler.registry.dimensions) 

140 run.assert_called_once_with( 

141 dbInfo=[input], 

142 outputDataId=expectedId) 

143 

144 def testRunQuantumNone(self): 

145 class NoneTask(DummyTask): 

146 def run(self, *args, **kwargs): 

147 return Struct(measurement=None) 

148 

149 config = NoneTask.ConfigClass() 

150 config.connections.package = "verify" 

151 config.connections.metric = "DummyApdb" 

152 task = NoneTask(config=config) 

153 butler, quantum, input = self._prepareQuantum(task) 

154 

155 with unittest.mock.patch.object( 

156 lsst.pipe.base.ButlerQuantumContext, "put") as put: 

157 testUtils.runTestQuantum(task, butler, quantum, mockRun=False) 

158 # Should not attempt to write nonexistent data 

159 put.assert_not_called() 

160 

161 def testRunQuantumException(self): 

162 class ExceptionalTask(DummyTask): 

163 def run(self, *args, **kwargs): 

164 raise MetricComputationError() 

165 

166 config = ExceptionalTask.ConfigClass() 

167 config.connections.package = "verify" 

168 config.connections.metric = "DummyApdb" 

169 task = ExceptionalTask(config=config) 

170 butler, quantum, input = self._prepareQuantum(task) 

171 

172 with unittest.mock.patch.object( 

173 lsst.pipe.base.ButlerQuantumContext, "put") as put: 

174 testUtils.runTestQuantum(task, butler, quantum, mockRun=False) 

175 # Should not propagate MetricComputationError 

176 # Should not attempt to write data that was never returned 

177 put.assert_not_called() 

178 

179 

180# Hack around unittest's hacky test setup system 

181del ApdbMetricTestCase 

182 

183 

184class MemoryTester(lsst.utils.tests.MemoryTestCase): 

185 pass 

186 

187 

188def setup_module(module): 

189 lsst.utils.tests.init() 

190 

191 

192if __name__ == "__main__": 192 ↛ 193line 192 didn't jump to line 193, because the condition on line 192 was never true

193 lsst.utils.tests.init() 

194 unittest.main()