Coverage for tests/test_nightReport.py: 25%

120 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-03-03 03:15 -0800

1# This file is part of summit_extras. 

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 unittest 

23import tempfile 

24import itertools 

25import os 

26from unittest import mock 

27from numpy.random import shuffle 

28from astro_metadata_translator import ObservationInfo 

29 

30import lsst.utils.tests 

31 

32import matplotlib as mpl 

33mpl.use('Agg') 

34 

35from lsst.summit.utils.nightReport import NightReport, ColorAndMarker # noqa: E402 

36import lsst.summit.utils.butlerUtils as butlerUtils # noqa: E402 

37 

38 

39class NightReportTestCase(lsst.utils.tests.TestCase): 

40 

41 @classmethod 

42 def setUpClass(cls): 

43 try: 

44 cls.butler = butlerUtils.makeDefaultLatissButler() 

45 except FileNotFoundError: 

46 raise unittest.SkipTest("Skipping tests that require the LATISS butler repo.") 

47 

48 cls.dayObs = 20200314 # has 377 images and data also exists on the TTS & summit 

49 

50 # Do the init in setUpClass because this takes about 35s for 20200314 

51 cls.report = NightReport(cls.butler, cls.dayObs) 

52 # number of images isn't necessarily the same as the number for the 

53 # the dayObs in the registry becacuse of the test stands/summit 

54 # having partial data, so get the number of images from the length 

55 # of the scraped data. Not ideal, but best that can be done due to 

56 # only having partial days in the test datasets. 

57 cls.nImages = len(cls.report.data.keys()) 

58 cls.seqNums = list(cls.report.data.keys()) 

59 

60 def test_saveAndLoad(self): 

61 """Test that a NightReport can save itself, and be loaded back. 

62 """ 

63 writeDir = tempfile.mkdtemp() 

64 saveFile = os.path.join(writeDir, f'testNightReport_{self.dayObs}.pickle') 

65 self.report.save(saveFile) 

66 self.assertTrue(os.path.exists(saveFile)) 

67 

68 loaded = NightReport(self.butler, self.dayObs, saveFile) 

69 self.assertIsInstance(loaded, lsst.summit.utils.nightReport.NightReport) 

70 self.assertGreaterEqual(len(loaded.data), 1) 

71 self.assertEqual(loaded.dayObs, self.dayObs) 

72 

73 # TODO: add a self.assertRaises on a mismatched dayObs 

74 

75 def test_getSortedData(self): 

76 """Test the _getSortedData returns the seqNums in order. 

77 """ 

78 shuffledKeys = list(self.report.data.keys()) 

79 shuffle(shuffledKeys) 

80 shuffledData = {k: self.report.data[k] for k in shuffledKeys} 

81 

82 sortedData = self.report._getSortedData(shuffledData) 

83 sortedKeys = sorted(list(sortedData.keys())) 

84 self.assertEqual(sortedKeys, list(self.report.data.keys())) 

85 return 

86 

87 def test_getExpRecordDictForDayObs(self): 

88 """Test getExpRecordDictForDayObs. 

89 

90 Test it returns a dict of dicts, keyed by integer seqNums. 

91 """ 

92 expRecDict = self.report.getExpRecordDictForDayObs(self.dayObs) 

93 self.assertIsInstance(expRecDict, dict) 

94 self.assertGreaterEqual(len(expRecDict), 1) 

95 

96 # check all the keys are ints 

97 seqNums = list(expRecDict.keys()) 

98 self.assertTrue(all(isinstance(s, int) for s in seqNums)) 

99 

100 # check all the values are dicts 

101 self.assertTrue(all(isinstance(expRecDict[s], dict) for s in seqNums)) 

102 return 

103 

104 def test_getObsInfoAndMetadataForSeqNum(self): 

105 """Test that getObsInfoAndMetadataForSeqNum returns the correct types. 

106 """ 

107 seqNum = self.seqNums[0] 

108 obsInfo, md = self.report.getObsInfoAndMetadataForSeqNum(seqNum) 

109 self.assertIsInstance(obsInfo, ObservationInfo) 

110 self.assertIsInstance(md, dict) 

111 return 

112 

113 def test_rebuild(self): 

114 """Test that rebuild does nothing, as no data will be being added. 

115 

116 NB Do not call full=True on this, as it will double the length of the 

117 tests and they're already extremely slow. 

118 """ 

119 lenBefore = len(self.report.data) 

120 self.report.rebuild() 

121 self.assertEqual(len(self.report.data), lenBefore) 

122 return 

123 

124 def test_getExposureMidpoint(self): 

125 """Test the exposure midpoint calculation 

126 """ 

127 midPoint = self.report.getExposureMidpoint(self.seqNums[0]) 

128 record = self.report.data[self.seqNums[0]] 

129 self.assertGreater(midPoint, record['datetime_begin'].mjd) 

130 self.assertLess(midPoint, record['datetime_end'].mjd) 

131 return 

132 

133 def test_getTimeDeltas(self): 

134 """Test the time delta calculation returns a dict. 

135 """ 

136 dts = self.report.getTimeDeltas() 

137 self.assertIsInstance(dts, dict) 

138 return 

139 

140 def test_makeStarColorAndMarkerMap(self): 

141 """Test the color map maker returns a dict of ColorAndMarker objects. 

142 """ 

143 cMap = self.report.makeStarColorAndMarkerMap(self.report.stars) 

144 self.assertEqual(len(cMap), len(self.report.stars)) 

145 self.assertIsInstance(cMap, dict) 

146 values = list(cMap.values()) 

147 self.assertTrue(all(isinstance(value, ColorAndMarker) for value in values)) 

148 return 

149 

150 def test_printObsTable(self): 

151 """Test that a the printObsTable() method prints out the correct 

152 number of lines. 

153 """ 

154 with mock.patch('sys.stdout') as fake_stdout: 

155 self.report.printObsTable() 

156 

157 # newline for each row plus header line, plus the line with dashes 

158 self.assertEqual(len(fake_stdout.mock_calls), 2*(self.nImages + 2)) 

159 

160 def test_plotPerObjectAirMass(self): 

161 """Test that a the per-object airmass plots runs. 

162 """ 

163 # We assume matplotlib is making plots, so just check that these 

164 # don't crash. 

165 

166 # Default plotting: 

167 self.report.plotPerObjectAirMass() 

168 # plot with only one object as a str not a list of str 

169 self.report.plotPerObjectAirMass(objects=self.report.stars[0]) 

170 # plot with first two objects as a list 

171 self.report.plotPerObjectAirMass(objects=self.report.stars[0:2]) 

172 # flip y axis option 

173 self.report.plotPerObjectAirMass(airmassOneAtTop=True) 

174 # flip and select stars 

175 self.report.plotPerObjectAirMass(objects=self.report.stars[0], airmassOneAtTop=True) # both 

176 

177 def test_makeAltAzCoveragePlot(self): 

178 """Test that a the polar coverage plotting code runs. 

179 """ 

180 # We assume matplotlib is making plots, so just check that these 

181 # don't crash. 

182 

183 # test the default case 

184 self.report.makeAltAzCoveragePlot() 

185 # plot with only one object as a str not a list of str 

186 self.report.makeAltAzCoveragePlot(objects=self.report.stars[0]) 

187 # plot with first two objects as a list 

188 self.report.makeAltAzCoveragePlot(objects=self.report.stars[0:2]) 

189 # test turning lines off 

190 self.report.makeAltAzCoveragePlot(objects=self.report.stars[0:2], withLines=False) 

191 

192 def test_calcShutterTimes(self): 

193 timings = self.report.calcShutterTimes() 

194 efficiency = 100*(timings['scienceTimeTotal']/timings['nightLength']) 

195 self.assertGreater(efficiency, 0) 

196 self.assertLessEqual(efficiency, 100) 

197 

198 def test_doesNotRaise(self): 

199 """Tests for things which are hard to test, so just make sure they run. 

200 """ 

201 self.report.printShutterTimes() 

202 for sample, includeRaw in itertools.product((True, False), (True, False)): 

203 self.report.printAvailableKeys(sample=sample, includeRaw=includeRaw) 

204 self.report.printObsTable() 

205 for threshold, includeCalibs in itertools.product((0, 1, 10), (True, False)): 

206 self.report.printObsGaps(threshold=threshold, includeCalibs=includeCalibs) 

207 

208 def test_internals(self): 

209 startNum = self.report.getObservingStartSeqNum() 

210 self.assertIsInstance(startNum, int) 

211 self.assertGreater(startNum, 0) # the day starts at 1, so zero would be an error of some sort 

212 

213 starsFromGetter = self.report.getObservedObjects() 

214 self.assertIsInstance(starsFromGetter, list) 

215 self.assertSetEqual(set(starsFromGetter), set(self.report.stars)) 

216 

217 starsFromGetter = self.report.getObservedObjects(ignoreTileNum=True) 

218 self.assertLessEqual(len(starsFromGetter), len(self.report.stars)) 

219 

220 # check the internal color map has the right number of items 

221 self.assertEqual(len(self.report.cMap), len(starsFromGetter)) 

222 

223 

224class TestMemory(lsst.utils.tests.MemoryTestCase): 

225 pass 

226 

227 

228def setup_module(module): 

229 lsst.utils.tests.init() 

230 

231 

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

233 lsst.utils.tests.init() 

234 unittest.main()