Coverage for tests/test_packages.py: 17%

Shortcuts on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

92 statements  

1#!/usr/bin/env python 

2# 

3# LSST Data Management System 

4# Copyright 2016 AURA/LSST. 

5# 

6# This product includes software developed by the 

7# LSST Project (http://www.lsst.org/). 

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 LSST License Statement and 

20# the GNU General Public License along with this program. If not, 

21# see <https://www.lsstcorp.org/LegalNotices/>. 

22# 

23import os 

24import unittest 

25import tempfile 

26 

27from collections.abc import Mapping 

28 

29import lsst.base 

30 

31TESTDIR = os.path.abspath(os.path.dirname(__file__)) 

32 

33 

34class PackagesTestCase(unittest.TestCase): 

35 """Tests for package version collection 

36 

37 Unfortunately, we're somewhat limited in what we can test because 

38 we only get the versions of things being used at runtime, and this 

39 package sits rather low in the dependency chain so there's not 

40 usually a lot of other packages available when this test gets run. 

41 Therefore some of the tests are only checking that things don't 

42 explode, since they are incapable of testing much more than that. 

43 """ 

44 

45 def testPython(self): 

46 """Test that we get the right version for this python package""" 

47 versions = lsst.base.getPythonPackages() 

48 expected = (lsst.base.version.__version__) 

49 self.assertEqual(versions["base"], expected) 

50 

51 def testEnvironment(self): 

52 """Test getting versions from the environment 

53 

54 Unfortunately, none of the products that need their versions divined 

55 from the environment are dependencies of this package, and so all we 

56 can do is test that this doesn't fall over. 

57 """ 

58 lsst.base.getEnvironmentPackages() 

59 

60 def testRuntime(self): 

61 """Test getting versions from runtime libraries 

62 

63 Unfortunately, none of the products that we get runtime versions from 

64 are dependencies of this package, and so all we can do is test that 

65 this doesn't fall over. 

66 """ 

67 lsst.base.getRuntimeVersions() 

68 

69 def testConda(self): 

70 """Test getting versions from conda environement 

71 

72 We do not rely on being run in a conda environment so all we can do is 

73 test that this doesn't fall over. 

74 """ 

75 lsst.base.getCondaPackages() 

76 

77 def _writeTempFile(self, packages, suffix): 

78 """Write packages to a temp file using the supplied suffix and read 

79 back. 

80 """ 

81 # Can't use lsst.utils.tests.getTempFilePath because we're its 

82 # dependency 

83 temp = tempfile.NamedTemporaryFile(prefix="packages.", suffix=suffix, delete=False) 

84 tempName = temp.name 

85 temp.close() # We don't use the fd, just want a filename 

86 try: 

87 packages.write(tempName) 

88 new = lsst.base.Packages.read(tempName) 

89 finally: 

90 os.unlink(tempName) 

91 return new 

92 

93 def testPackages(self): 

94 """Test the Packages class""" 

95 packages = lsst.base.Packages.fromSystem() 

96 self.assertIsInstance(packages, Mapping) 

97 

98 # Check that stringification is not crashing. 

99 self.assertTrue(str(packages).startswith("Packages({")) 

100 self.assertTrue(repr(packages).startswith("Packages({")) 

101 

102 # Test pickling and YAML 

103 new = self._writeTempFile(packages, ".pickle") 

104 new_pkl = self._writeTempFile(packages, ".pkl") 

105 new_yaml = self._writeTempFile(packages, ".yaml") 

106 

107 self.assertIsInstance(new, lsst.base.Packages, 

108 f"Checking type ({type(new)}) from pickle") 

109 self.assertIsInstance(new_yaml, lsst.base.Packages, 

110 f"Checking type ({type(new_yaml)}) from YAML") 

111 self.assertEqual(new, packages) 

112 self.assertEqual(new_pkl, new) 

113 self.assertEqual(new, new_yaml) 

114 

115 # Dict compatibility. 

116 for k, v in new.items(): 

117 self.assertEqual(new[k], v) 

118 

119 with self.assertRaises(ValueError): 

120 self._writeTempFile(packages, ".txt") 

121 

122 with self.assertRaises(ValueError): 

123 # .txt extension is not recognized 

124 lsst.base.Packages.read("something.txt") 

125 

126 # 'packages' and 'new' should have identical content 

127 self.assertDictEqual(packages.difference(new), {}) 

128 self.assertDictEqual(packages.missing(new), {}) 

129 self.assertDictEqual(packages.extra(new), {}) 

130 self.assertEqual(len(packages), len(new)) 

131 

132 # Check inverted comparisons 

133 self.assertDictEqual(new.difference(packages), {}) 

134 self.assertDictEqual(new.missing(packages), {}) 

135 self.assertDictEqual(new.extra(packages), {}) 

136 

137 # Now load an obscure python package and the list of packages should 

138 # change 

139 # Shouldn't be used by anything we've previously imported 

140 import smtpd # noqa: F401 

141 new = lsst.base.Packages.fromSystem() 

142 self.assertDictEqual(packages.difference(new), {}) # No inconsistencies 

143 self.assertDictEqual(packages.extra(new), {}) # Nothing in 'packages' that's not in 'new' 

144 missing = packages.missing(new) 

145 self.assertGreater(len(missing), 0) # 'packages' should be missing some stuff in 'new' 

146 self.assertIn("smtpd", missing) 

147 

148 # Inverted comparisons 

149 self.assertDictEqual(new.difference(packages), {}) 

150 self.assertDictEqual(new.missing(packages), {}) # Nothing in 'new' that's not in 'packages' 

151 extra = new.extra(packages) 

152 self.assertGreater(len(extra), 0) # 'new' has extra stuff compared to 'packages' 

153 self.assertIn("smtpd", extra) 

154 self.assertIn("smtpd", new) 

155 

156 # Run with both a Packages and a dict 

157 for new_pkg in (new, dict(new)): 

158 packages.update(new_pkg) # Should now be identical 

159 self.assertDictEqual(packages.difference(new_pkg), {}) 

160 self.assertDictEqual(packages.missing(new_pkg), {}) 

161 self.assertDictEqual(packages.extra(new_pkg), {}) 

162 self.assertEqual(len(packages), len(new_pkg)) 

163 

164 # Loop over keys to check iterator. 

165 keys = {k for k in new} 

166 self.assertEqual(keys, set(dict(new).keys())) 

167 

168 # Loop over values to check that we do get them all. 

169 values = {v for v in new.values()} 

170 self.assertEqual(values, set(dict(new).values())) 

171 

172 # Serialize via bytes 

173 for format in ("pickle", "yaml"): 

174 asbytes = new.toBytes(format) 

175 from_bytes = lsst.base.Packages.fromBytes(asbytes, format) 

176 self.assertEqual(from_bytes, new) 

177 

178 with self.assertRaises(ValueError): 

179 new.toBytes("unknown_format") 

180 

181 with self.assertRaises(ValueError): 

182 lsst.base.Packages.fromBytes(from_bytes, "unknown_format") 

183 

184 with self.assertRaises(TypeError): 

185 some_yaml = b"list: [1, 2]" 

186 lsst.base.Packages.fromBytes(some_yaml, "yaml") 

187 

188 def testBackwardsCompatibility(self): 

189 """Test if we can read old data files.""" 

190 

191 # Pickle contents changed when moving to dict base class. 

192 packages_p = lsst.base.Packages.read(os.path.join(TESTDIR, "data", "v1.pickle")) 

193 

194 # YAML format is unchanged when moving from special class to dict 

195 # but test anyway. 

196 packages_y = lsst.base.Packages.read(os.path.join(TESTDIR, "data", "v1.yaml")) 

197 

198 self.assertEqual(packages_p, packages_y) 

199 

200 

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

202 unittest.main()