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
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
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/>.
22"""Unit tests for daf_butler CLI config-dump command.
23"""
25import os
26import os.path
27import unittest
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
37TESTDIR = os.path.abspath(os.path.dirname(__file__))
40class ConfigDumpTest(CliCmdTestBase, unittest.TestCase):
42 mockFuncName = "lsst.daf.butler.cli.cmd.commands.script.configDump"
44 @staticmethod
45 def defaultExpected():
46 return dict()
48 @staticmethod
49 def command():
50 return config_dump
53class ConfigDumpUseTest(unittest.TestCase):
54 """Test executing the command."""
56 def setUp(self):
57 self.runner = LogCliRunner()
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))
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)
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)
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)
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,))
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")
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)
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)
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)
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))
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))
171 def test_presetsDashedName(self):
172 """Test file overrides when the option has a dash in its name."""
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)
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)
193if __name__ == "__main__": 193 ↛ 194line 193 didn't jump to line 194, because the condition on line 193 was never true
194 unittest.main()