1 // Copyright 2010 The Kyua Authors. 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 "engine/config.hpp" 30 31 #if defined(HAVE_CONFIG_H) 32 # include "config.h" 33 #endif 34 35 #include <stdexcept> 36 #include <vector> 37 38 #include <atf-c++.hpp> 39 40 #include "engine/exceptions.hpp" 41 #include "utils/cmdline/exceptions.hpp" 42 #include "utils/cmdline/parser.hpp" 43 #include "utils/config/tree.ipp" 44 #include "utils/passwd.hpp" 45 46 namespace config = utils::config; 47 namespace fs = utils::fs; 48 namespace passwd = utils::passwd; 49 50 using utils::none; 51 using utils::optional; 52 53 54 namespace { 55 56 57 /// Replaces the system user database with a fake one for testing purposes. 58 static void 59 set_mock_users(void) 60 { 61 std::vector< passwd::user > users; 62 users.push_back(passwd::user("user1", 100, 150)); 63 users.push_back(passwd::user("user2", 200, 250)); 64 passwd::set_mock_users_for_testing(users); 65 } 66 67 68 /// Checks that the default values of a config object match our expectations. 69 /// 70 /// This fails the test case if any field of the input config object is not 71 /// what we expect. 72 /// 73 /// \param config The configuration to validate. 74 static void 75 validate_defaults(const config::tree& config) 76 { 77 ATF_REQUIRE_EQ( 78 KYUA_ARCHITECTURE, 79 config.lookup< config::string_node >("architecture")); 80 81 ATF_REQUIRE_EQ( 82 1, 83 config.lookup< config::positive_int_node >("parallelism")); 84 85 ATF_REQUIRE_EQ( 86 KYUA_PLATFORM, 87 config.lookup< config::string_node >("platform")); 88 89 ATF_REQUIRE(!config.is_set("unprivileged_user")); 90 91 ATF_REQUIRE(config.all_properties("test_suites").empty()); 92 } 93 94 95 } // anonymous namespace 96 97 98 ATF_TEST_CASE_WITHOUT_HEAD(config__defaults); 99 ATF_TEST_CASE_BODY(config__defaults) 100 { 101 const config::tree user_config = engine::default_config(); 102 validate_defaults(user_config); 103 } 104 105 106 ATF_TEST_CASE_WITHOUT_HEAD(config__set__parallelism); 107 ATF_TEST_CASE_BODY(config__set__parallelism) 108 { 109 config::tree user_config = engine::default_config(); 110 user_config.set_string("parallelism", "8"); 111 ATF_REQUIRE_THROW_RE( 112 config::error, "parallelism.*Must be a positive integer", 113 user_config.set_string("parallelism", "0")); 114 ATF_REQUIRE_THROW_RE( 115 config::error, "parallelism.*Must be a positive integer", 116 user_config.set_string("parallelism", "-1")); 117 } 118 119 120 ATF_TEST_CASE_WITHOUT_HEAD(config__load__defaults); 121 ATF_TEST_CASE_BODY(config__load__defaults) 122 { 123 atf::utils::create_file("config", "syntax(2)\n"); 124 125 const config::tree user_config = engine::load_config(fs::path("config")); 126 validate_defaults(user_config); 127 } 128 129 130 ATF_TEST_CASE_WITHOUT_HEAD(config__load__overrides); 131 ATF_TEST_CASE_BODY(config__load__overrides) 132 { 133 set_mock_users(); 134 135 atf::utils::create_file( 136 "config", 137 "syntax(2)\n" 138 "architecture = 'test-architecture'\n" 139 "parallelism = 16\n" 140 "platform = 'test-platform'\n" 141 "unprivileged_user = 'user2'\n" 142 "test_suites.mysuite.myvar = 'myvalue'\n"); 143 144 const config::tree user_config = engine::load_config(fs::path("config")); 145 146 ATF_REQUIRE_EQ("test-architecture", 147 user_config.lookup_string("architecture")); 148 ATF_REQUIRE_EQ("16", 149 user_config.lookup_string("parallelism")); 150 ATF_REQUIRE_EQ("test-platform", 151 user_config.lookup_string("platform")); 152 153 const passwd::user& user = user_config.lookup< engine::user_node >( 154 "unprivileged_user"); 155 ATF_REQUIRE_EQ("user2", user.name); 156 ATF_REQUIRE_EQ(200, user.uid); 157 158 config::properties_map exp_test_suites; 159 exp_test_suites["test_suites.mysuite.myvar"] = "myvalue"; 160 161 ATF_REQUIRE(exp_test_suites == user_config.all_properties("test_suites")); 162 } 163 164 165 ATF_TEST_CASE_WITHOUT_HEAD(config__load__lua_error); 166 ATF_TEST_CASE_BODY(config__load__lua_error) 167 { 168 atf::utils::create_file("config", "this syntax is invalid\n"); 169 170 ATF_REQUIRE_THROW(engine::load_error, engine::load_config( 171 fs::path("config"))); 172 } 173 174 175 ATF_TEST_CASE_WITHOUT_HEAD(config__load__bad_syntax__version); 176 ATF_TEST_CASE_BODY(config__load__bad_syntax__version) 177 { 178 atf::utils::create_file("config", "syntax(123)\n"); 179 180 ATF_REQUIRE_THROW_RE(engine::load_error, 181 "Unsupported config version 123", 182 engine::load_config(fs::path("config"))); 183 } 184 185 186 ATF_TEST_CASE_WITHOUT_HEAD(config__load__missing_file); 187 ATF_TEST_CASE_BODY(config__load__missing_file) 188 { 189 ATF_REQUIRE_THROW_RE(engine::load_error, "Load of 'missing' failed", 190 engine::load_config(fs::path("missing"))); 191 } 192 193 194 ATF_INIT_TEST_CASES(tcs) 195 { 196 ATF_ADD_TEST_CASE(tcs, config__defaults); 197 ATF_ADD_TEST_CASE(tcs, config__set__parallelism); 198 ATF_ADD_TEST_CASE(tcs, config__load__defaults); 199 ATF_ADD_TEST_CASE(tcs, config__load__overrides); 200 ATF_ADD_TEST_CASE(tcs, config__load__lua_error); 201 ATF_ADD_TEST_CASE(tcs, config__load__bad_syntax__version); 202 ATF_ADD_TEST_CASE(tcs, config__load__missing_file); 203 } 204