Coverage for tests/test_cliCmdConfigDump.py: 27%

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

112 statements  

1# This file is part of daf_butler. 

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/>. 

21 

22"""Unit tests for daf_butler CLI config-dump command. 

23""" 

24 

25import os 

26import os.path 

27import unittest 

28 

29import click 

30import yaml 

31from lsst.daf.butler.cli import butler 

32from lsst.daf.butler.cli.cmd import config_dump 

33from lsst.daf.butler.cli.opt import options_file_option 

34from lsst.daf.butler.cli.utils import LogCliRunner, clickResultMsg 

35from lsst.daf.butler.tests import CliCmdTestBase 

36 

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

38 

39 

40class ConfigDumpTest(CliCmdTestBase, unittest.TestCase): 

41 

42 mockFuncName = "lsst.daf.butler.cli.cmd.commands.script.configDump" 

43 

44 @staticmethod 

45 def defaultExpected(): 

46 return dict() 

47 

48 @staticmethod 

49 def command(): 

50 return config_dump 

51 

52 

53class ConfigDumpUseTest(unittest.TestCase): 

54 """Test executing the command.""" 

55 

56 def setUp(self): 

57 self.runner = LogCliRunner() 

58 

59 def test_stdout(self): 

60 """Test dumping the config to stdout.""" 

61 with self.runner.isolated_filesystem(): 

62 result = self.runner.invoke(butler.cli, ["create", "here"]) 

63 self.assertEqual(result.exit_code, 0, clickResultMsg(result)) 

64 

65 # test dumping to stdout: 

66 result = self.runner.invoke(butler.cli, ["config-dump", "here"]) 

67 self.assertEqual(result.exit_code, 0, clickResultMsg(result)) 

68 # check for some expected keywords: 

69 cfg = yaml.safe_load(result.stdout) 

70 self.assertIn("datastore", cfg) 

71 self.assertIn("composites", cfg["datastore"]) 

72 self.assertIn("storageClasses", cfg) 

73 

74 def test_file(self): 

75 """test dumping the config to a file.""" 

76 with self.runner.isolated_filesystem(): 

77 result = self.runner.invoke(butler.cli, ["create", "here"]) 

78 self.assertEqual(result.exit_code, 0, clickResultMsg(result)) 

79 result = self.runner.invoke(butler.cli, ["config-dump", "here", "--file=there"]) 

80 self.assertEqual(result.exit_code, 0, clickResultMsg(result)) 

81 # check for some expected keywords: 

82 with open("there", "r") as f: 

83 cfg = yaml.safe_load(f) 

84 self.assertIn("datastore", cfg) 

85 self.assertIn("composites", cfg["datastore"]) 

86 self.assertIn("storageClasses", cfg) 

87 

88 def test_subset(self): 

89 """Test selecting a subset of the config.""" 

90 with self.runner.isolated_filesystem(): 

91 result = self.runner.invoke(butler.cli, ["create", "here"]) 

92 self.assertEqual(result.exit_code, 0, clickResultMsg(result)) 

93 result = self.runner.invoke(butler.cli, ["config-dump", "here", "--subset", "datastore"]) 

94 self.assertEqual(result.exit_code, 0, clickResultMsg(result)) 

95 cfg = yaml.safe_load(result.stdout) 

96 # count the keys in the datastore config 

97 self.assertEqual(len(cfg), 8) 

98 self.assertIn("cls", cfg) 

99 self.assertIn("create", cfg) 

100 self.assertIn("formatters", cfg) 

101 self.assertIn("records", cfg) 

102 self.assertIn("root", cfg) 

103 self.assertIn("templates", cfg) 

104 

105 def test_invalidSubset(self): 

106 """Test selecting a subset key that does not exist in the config.""" 

107 with self.runner.isolated_filesystem(): 

108 result = self.runner.invoke(butler.cli, ["create", "here"]) 

109 self.assertEqual(result.exit_code, 0, clickResultMsg(result)) 

110 # test dumping to stdout: 

111 result = self.runner.invoke(butler.cli, ["config-dump", "here", "--subset", "foo"]) 

112 self.assertEqual(result.exit_code, 1) 

113 # exception type is click.Exit, and its argument is a return code 

114 self.assertEqual(result.exception.args, (1,)) 

115 

116 def test_presets(self): 

117 """Test that file overrides can set command line options in bulk.""" 

118 with self.runner.isolated_filesystem(): 

119 result = self.runner.invoke(butler.cli, ["create", "here"]) 

120 self.assertEqual(result.exit_code, 0, clickResultMsg(result)) 

121 overrides_path = os.path.join(TESTDIR, "data", "config-overrides.yaml") 

122 

123 # Run with a presets file 

124 result = self.runner.invoke(butler.cli, ["config-dump", "here", "--options-file", overrides_path]) 

125 self.assertEqual(result.exit_code, 0, clickResultMsg(result)) 

126 cfg = yaml.safe_load(result.stdout) 

127 # Look for datastore information 

128 self.assertIn("formatters", cfg) 

129 self.assertIn("root", cfg) 

130 

131 # Now run with an explicit subset and presets 

132 result = self.runner.invoke( 

133 butler.cli, ["config-dump", "here", f"-@{overrides_path}", "--subset", ".registry"] 

134 ) 

135 self.assertEqual(result.exit_code, 0, clickResultMsg(result)) 

136 cfg = yaml.safe_load(result.stdout) 

137 # Look for datastore information 

138 self.assertNotIn("formatters", cfg) 

139 self.assertIn("managers", cfg) 

140 

141 # Now with subset before presets -- explicit always trumps 

142 # presets. 

143 result = self.runner.invoke( 

144 butler.cli, ["config-dump", "here", "--subset", ".registry", "--options-file", overrides_path] 

145 ) 

146 self.assertEqual(result.exit_code, 0, clickResultMsg(result)) 

147 cfg = yaml.safe_load(result.stdout) 

148 # Look for datastore information 

149 self.assertNotIn("formatters", cfg) 

150 self.assertIn("managers", cfg) 

151 

152 configfile = "overrides.yaml" 

153 outfile = "repodef.yaml" 

154 # Check that a misspelled command option causes an error: 

155 with open(configfile, "w") as f: 

156 f.write(yaml.dump({"config-dump": {"fil": outfile}})) 

157 result = self.runner.invoke(butler.cli, ["config-dump", "here", f"-@{configfile}"]) 

158 self.assertNotEqual(result.exit_code, 0, clickResultMsg(result)) 

159 

160 # Check that an option that declares a different command argument 

161 # name is mapped correctly. 

162 # Note that the option `config-dump --file` 

163 # becomes the `outfile` argument in `def config_dump(..., outfile)` 

164 # and we use the option name "file" in the presets file. 

165 with open(configfile, "w") as f: 

166 f.write(yaml.dump({"config-dump": {"file": outfile}})) 

167 result = self.runner.invoke(butler.cli, ["config-dump", "here", f"-@{configfile}"]) 

168 self.assertEqual(result.exit_code, 0, clickResultMsg(result)) 

169 self.assertTrue(os.path.exists(outfile)) 

170 

171 def test_presetsDashedName(self): 

172 """Test file overrides when the option has a dash in its name.""" 

173 

174 # Instead of using `butler config-dump` as we do in other tests, 

175 # create a small command for testing, because config-dump does 

176 # not have any options with dashes in the name. 

177 @click.command() 

178 @click.option("--test-option") 

179 @options_file_option() 

180 def cmd(test_option): 

181 print(test_option) 

182 

183 configfile = "overrides.yaml" 

184 val = "foo" 

185 with self.runner.isolated_filesystem(): 

186 with open(configfile, "w") as f: 

187 f.write(yaml.dump({"cmd": {"test-option": val}})) 

188 result = self.runner.invoke(cmd, ["-@", configfile]) 

189 self.assertEqual(result.exit_code, 0, clickResultMsg(result)) 

190 self.assertTrue(val in result.output) 

191 

192 

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

194 unittest.main()