Home | History | Annotate | Line # | Download | only in cli
config_test.cpp revision 1.1
      1 // Copyright 2011 Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 // * Redistributions of source code must retain the above copyright
      9 //   notice, this list of conditions and the following disclaimer.
     10 // * Redistributions in binary form must reproduce the above copyright
     11 //   notice, this list of conditions and the following disclaimer in the
     12 //   documentation and/or other materials provided with the distribution.
     13 // * Neither the name of Google Inc. nor the names of its contributors
     14 //   may be used to endorse or promote products derived from this software
     15 //   without specific prior written permission.
     16 //
     17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 
     29 #include "cli/config.hpp"
     30 
     31 #include <atf-c++.hpp>
     32 
     33 #include "engine/config.hpp"
     34 #include "engine/exceptions.hpp"
     35 #include "utils/env.hpp"
     36 #include "utils/format/macros.hpp"
     37 #include "utils/fs/operations.hpp"
     38 #include "utils/fs/path.hpp"
     39 
     40 namespace cmdline = utils::cmdline;
     41 namespace config = utils::config;
     42 namespace fs = utils::fs;
     43 
     44 
     45 namespace {
     46 
     47 
     48 /// Creates a configuration file for testing purposes.
     49 ///
     50 /// To ensure that the loaded file is the one created by this function, use
     51 /// validate_mock_config().
     52 ///
     53 /// \param name The name of the configuration file to create.
     54 /// \param cookie The magic value to set in the configuration file, or NULL if a
     55 ///     broken configuration file is desired.
     56 static void
     57 create_mock_config(const char* name, const char* cookie)
     58 {
     59     if (cookie != NULL) {
     60         atf::utils::create_file(
     61             name,
     62             F("syntax(2)\n"
     63               "test_suites.suite.magic_value = '%s'\n") % cookie);
     64     } else {
     65         atf::utils::create_file(name, "syntax(200)\n");
     66     }
     67 }
     68 
     69 
     70 /// Creates an invalid system configuration.
     71 ///
     72 /// \param cookie The magic value to set in the configuration file, or NULL if a
     73 ///     broken configuration file is desired.
     74 static void
     75 mock_system_config(const char* cookie)
     76 {
     77     fs::mkdir(fs::path("system-dir"), 0755);
     78     utils::setenv("KYUA_CONFDIR", (fs::current_path() / "system-dir").str());
     79     create_mock_config("system-dir/kyua.conf", cookie);
     80 }
     81 
     82 
     83 /// Creates an invalid user configuration.
     84 ///
     85 /// \param cookie The magic value to set in the configuration file, or NULL if a
     86 ///     broken configuration file is desired.
     87 static void
     88 mock_user_config(const char* cookie)
     89 {
     90     fs::mkdir(fs::path("user-dir"), 0755);
     91     fs::mkdir(fs::path("user-dir/.kyua"), 0755);
     92     utils::setenv("HOME", (fs::current_path() / "user-dir").str());
     93     create_mock_config("user-dir/.kyua/kyua.conf", cookie);
     94 }
     95 
     96 
     97 /// Ensures that a loaded configuration was created with create_mock_config().
     98 ///
     99 /// \param user_config The configuration to validate.
    100 /// \param cookie The magic value to expect in the configuration file.
    101 static void
    102 validate_mock_config(const config::tree& user_config, const char* cookie)
    103 {
    104     const config::properties_map& properties = user_config.all_properties(
    105         "test_suites.suite", true);
    106     const config::properties_map::const_iterator iter =
    107         properties.find("magic_value");
    108     ATF_REQUIRE(iter != properties.end());
    109     ATF_REQUIRE_EQ(cookie, (*iter).second);
    110 }
    111 
    112 
    113 /// Ensures that two configuration trees are equal.
    114 ///
    115 /// \param exp_tree The expected configuration tree.
    116 /// \param actual_tree The configuration tree being validated against exp_tree.
    117 static void
    118 require_eq(const config::tree& exp_tree, const config::tree& actual_tree)
    119 {
    120     ATF_REQUIRE(exp_tree.all_properties() == actual_tree.all_properties());
    121 }
    122 
    123 
    124 }  // anonymous namespace
    125 
    126 
    127 ATF_TEST_CASE_WITHOUT_HEAD(load_config__none);
    128 ATF_TEST_CASE_BODY(load_config__none)
    129 {
    130     utils::setenv("KYUA_CONFDIR", "/the/system/does/not/exist");
    131     utils::setenv("HOME", "/the/user/does/not/exist");
    132 
    133     std::map< std::string, std::vector< std::string > > options;
    134     options["config"].push_back(cli::config_option.default_value());
    135     const cmdline::parsed_cmdline mock_cmdline(options, cmdline::args_vector());
    136 
    137     require_eq(engine::default_config(),
    138                cli::load_config(mock_cmdline, true));
    139 }
    140 
    141 
    142 ATF_TEST_CASE_WITHOUT_HEAD(load_config__explicit__ok);
    143 ATF_TEST_CASE_BODY(load_config__explicit__ok)
    144 {
    145     mock_system_config(NULL);
    146     mock_user_config(NULL);
    147 
    148     create_mock_config("test-file", "hello");
    149 
    150     std::map< std::string, std::vector< std::string > > options;
    151     options["config"].push_back("test-file");
    152     const cmdline::parsed_cmdline mock_cmdline(options, cmdline::args_vector());
    153 
    154     const config::tree user_config = cli::load_config(mock_cmdline, true);
    155     validate_mock_config(user_config, "hello");
    156 }
    157 
    158 
    159 ATF_TEST_CASE_WITHOUT_HEAD(load_config__explicit__disable);
    160 ATF_TEST_CASE_BODY(load_config__explicit__disable)
    161 {
    162     mock_system_config(NULL);
    163     mock_user_config(NULL);
    164 
    165     std::map< std::string, std::vector< std::string > > options;
    166     options["config"].push_back("none");
    167     const cmdline::parsed_cmdline mock_cmdline(options, cmdline::args_vector());
    168 
    169     require_eq(engine::default_config(),
    170                cli::load_config(mock_cmdline, true));
    171 }
    172 
    173 
    174 ATF_TEST_CASE_WITHOUT_HEAD(load_config__explicit__fail);
    175 ATF_TEST_CASE_BODY(load_config__explicit__fail)
    176 {
    177     mock_system_config("ok1");
    178     mock_user_config("ok2");
    179 
    180     create_mock_config("test-file", NULL);
    181 
    182     std::map< std::string, std::vector< std::string > > options;
    183     options["config"].push_back("test-file");
    184     const cmdline::parsed_cmdline mock_cmdline(options, cmdline::args_vector());
    185 
    186     ATF_REQUIRE_THROW_RE(engine::error, "200",
    187                          cli::load_config(mock_cmdline, true));
    188 
    189     const config::tree config = cli::load_config(mock_cmdline, false);
    190     require_eq(engine::default_config(), config);
    191 }
    192 
    193 
    194 ATF_TEST_CASE_WITHOUT_HEAD(load_config__user__ok);
    195 ATF_TEST_CASE_BODY(load_config__user__ok)
    196 {
    197     mock_system_config(NULL);
    198     mock_user_config("I am the user config");
    199 
    200     std::map< std::string, std::vector< std::string > > options;
    201     options["config"].push_back(cli::config_option.default_value());
    202     const cmdline::parsed_cmdline mock_cmdline(options, cmdline::args_vector());
    203 
    204     const config::tree user_config = cli::load_config(mock_cmdline, true);
    205     validate_mock_config(user_config, "I am the user config");
    206 }
    207 
    208 
    209 ATF_TEST_CASE_WITHOUT_HEAD(load_config__user__fail);
    210 ATF_TEST_CASE_BODY(load_config__user__fail)
    211 {
    212     mock_system_config("valid");
    213     mock_user_config(NULL);
    214 
    215     std::map< std::string, std::vector< std::string > > options;
    216     options["config"].push_back(cli::config_option.default_value());
    217     const cmdline::parsed_cmdline mock_cmdline(options, cmdline::args_vector());
    218 
    219     ATF_REQUIRE_THROW_RE(engine::error, "200",
    220                          cli::load_config(mock_cmdline, true));
    221 
    222     const config::tree config = cli::load_config(mock_cmdline, false);
    223     require_eq(engine::default_config(), config);
    224 }
    225 
    226 
    227 ATF_TEST_CASE_WITHOUT_HEAD(load_config__user__bad_home);
    228 ATF_TEST_CASE_BODY(load_config__user__bad_home)
    229 {
    230     mock_system_config("Fallback system config");
    231     utils::setenv("HOME", "");
    232 
    233     std::map< std::string, std::vector< std::string > > options;
    234     options["config"].push_back(cli::config_option.default_value());
    235     const cmdline::parsed_cmdline mock_cmdline(options, cmdline::args_vector());
    236 
    237     const config::tree user_config = cli::load_config(mock_cmdline, true);
    238     validate_mock_config(user_config, "Fallback system config");
    239 }
    240 
    241 
    242 ATF_TEST_CASE_WITHOUT_HEAD(load_config__system__ok);
    243 ATF_TEST_CASE_BODY(load_config__system__ok)
    244 {
    245     mock_system_config("I am the system config");
    246     utils::setenv("HOME", "/the/user/does/not/exist");
    247 
    248     std::map< std::string, std::vector< std::string > > options;
    249     options["config"].push_back(cli::config_option.default_value());
    250     const cmdline::parsed_cmdline mock_cmdline(options, cmdline::args_vector());
    251 
    252     const config::tree user_config = cli::load_config(mock_cmdline, true);
    253     validate_mock_config(user_config, "I am the system config");
    254 }
    255 
    256 
    257 ATF_TEST_CASE_WITHOUT_HEAD(load_config__system__fail);
    258 ATF_TEST_CASE_BODY(load_config__system__fail)
    259 {
    260     mock_system_config(NULL);
    261     utils::setenv("HOME", "/the/user/does/not/exist");
    262 
    263     std::map< std::string, std::vector< std::string > > options;
    264     options["config"].push_back(cli::config_option.default_value());
    265     const cmdline::parsed_cmdline mock_cmdline(options, cmdline::args_vector());
    266 
    267     ATF_REQUIRE_THROW_RE(engine::error, "200",
    268                          cli::load_config(mock_cmdline, true));
    269 
    270     const config::tree config = cli::load_config(mock_cmdline, false);
    271     require_eq(engine::default_config(), config);
    272 }
    273 
    274 
    275 ATF_TEST_CASE_WITHOUT_HEAD(load_config__overrides__no);
    276 ATF_TEST_CASE_BODY(load_config__overrides__no)
    277 {
    278     utils::setenv("KYUA_CONFDIR", fs::current_path().str());
    279 
    280     std::map< std::string, std::vector< std::string > > options;
    281     options["config"].push_back(cli::config_option.default_value());
    282     options["variable"].push_back("architecture=1");
    283     options["variable"].push_back("platform=2");
    284     const cmdline::parsed_cmdline mock_cmdline(options, cmdline::args_vector());
    285 
    286     const config::tree user_config = cli::load_config(mock_cmdline, true);
    287     ATF_REQUIRE_EQ("1",
    288                    user_config.lookup< config::string_node >("architecture"));
    289     ATF_REQUIRE_EQ("2",
    290                    user_config.lookup< config::string_node >("platform"));
    291 }
    292 
    293 
    294 ATF_TEST_CASE_WITHOUT_HEAD(load_config__overrides__yes);
    295 ATF_TEST_CASE_BODY(load_config__overrides__yes)
    296 {
    297     atf::utils::create_file(
    298         "config",
    299         "syntax(2)\n"
    300         "architecture = 'do not see me'\n"
    301         "platform = 'see me'\n");
    302 
    303     std::map< std::string, std::vector< std::string > > options;
    304     options["config"].push_back("config");
    305     options["variable"].push_back("architecture=overriden");
    306     const cmdline::parsed_cmdline mock_cmdline(options, cmdline::args_vector());
    307 
    308     const config::tree user_config = cli::load_config(mock_cmdline, true);
    309     ATF_REQUIRE_EQ("overriden",
    310                    user_config.lookup< config::string_node >("architecture"));
    311     ATF_REQUIRE_EQ("see me",
    312                    user_config.lookup< config::string_node >("platform"));
    313 }
    314 
    315 
    316 ATF_TEST_CASE_WITHOUT_HEAD(load_config__overrides__fail);
    317 ATF_TEST_CASE_BODY(load_config__overrides__fail)
    318 {
    319     utils::setenv("KYUA_CONFDIR", fs::current_path().str());
    320 
    321     std::map< std::string, std::vector< std::string > > options;
    322     options["config"].push_back(cli::config_option.default_value());
    323     options["variable"].push_back(".a=d");
    324     const cmdline::parsed_cmdline mock_cmdline(options, cmdline::args_vector());
    325 
    326     ATF_REQUIRE_THROW_RE(engine::error, "Empty component in key.*'\\.a'",
    327                          cli::load_config(mock_cmdline, true));
    328 
    329     const config::tree config = cli::load_config(mock_cmdline, false);
    330     require_eq(engine::default_config(), config);
    331 }
    332 
    333 
    334 ATF_INIT_TEST_CASES(tcs)
    335 {
    336     ATF_ADD_TEST_CASE(tcs, load_config__none);
    337     ATF_ADD_TEST_CASE(tcs, load_config__explicit__ok);
    338     ATF_ADD_TEST_CASE(tcs, load_config__explicit__disable);
    339     ATF_ADD_TEST_CASE(tcs, load_config__explicit__fail);
    340     ATF_ADD_TEST_CASE(tcs, load_config__user__ok);
    341     ATF_ADD_TEST_CASE(tcs, load_config__user__fail);
    342     ATF_ADD_TEST_CASE(tcs, load_config__user__bad_home);
    343     ATF_ADD_TEST_CASE(tcs, load_config__system__ok);
    344     ATF_ADD_TEST_CASE(tcs, load_config__system__fail);
    345     ATF_ADD_TEST_CASE(tcs, load_config__overrides__no);
    346     ATF_ADD_TEST_CASE(tcs, load_config__overrides__yes);
    347     ATF_ADD_TEST_CASE(tcs, load_config__overrides__fail);
    348 }
    349