1 // Copyright 2015 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/atf_list.hpp" 30 31 #include <sstream> 32 #include <string> 33 34 #include <atf-c++.hpp> 35 36 #include "engine/exceptions.hpp" 37 #include "model/metadata.hpp" 38 #include "model/test_case.hpp" 39 #include "model/types.hpp" 40 #include "utils/datetime.hpp" 41 #include "utils/format/containers.ipp" 42 #include "utils/fs/path.hpp" 43 #include "utils/units.hpp" 44 45 namespace datetime = utils::datetime; 46 namespace fs = utils::fs; 47 namespace units = utils::units; 48 49 50 ATF_TEST_CASE_WITHOUT_HEAD(parse_atf_metadata__defaults) 51 ATF_TEST_CASE_BODY(parse_atf_metadata__defaults) 52 { 53 const model::properties_map properties; 54 const model::metadata md = engine::parse_atf_metadata(properties); 55 56 const model::metadata exp_md = model::metadata_builder().build(); 57 ATF_REQUIRE_EQ(exp_md, md); 58 } 59 60 61 ATF_TEST_CASE_WITHOUT_HEAD(parse_atf_metadata__override_all) 62 ATF_TEST_CASE_BODY(parse_atf_metadata__override_all) 63 { 64 model::properties_map properties; 65 properties["descr"] = "Some text"; 66 properties["has.cleanup"] = "true"; 67 properties["is.exclusive"] = "true"; 68 properties["require.arch"] = "i386 x86_64"; 69 properties["require.config"] = "var1 var2 var3"; 70 properties["require.diskspace"] = "10g"; 71 properties["require.files"] = "/file1 /dir/file2"; 72 properties["require.machine"] = "amd64"; 73 properties["require.memory"] = "1m"; 74 properties["require.progs"] = "/bin/ls svn"; 75 properties["require.user"] = "root"; 76 properties["timeout"] = "123"; 77 properties["X-foo"] = "value1"; 78 properties["X-bar"] = "value2"; 79 properties["X-baz-www"] = "value3"; 80 const model::metadata md = engine::parse_atf_metadata(properties); 81 82 const model::metadata exp_md = model::metadata_builder() 83 .add_allowed_architecture("i386") 84 .add_allowed_architecture("x86_64") 85 .add_allowed_platform("amd64") 86 .add_custom("foo", "value1") 87 .add_custom("bar", "value2") 88 .add_custom("baz-www", "value3") 89 .add_required_config("var1") 90 .add_required_config("var2") 91 .add_required_config("var3") 92 .add_required_file(fs::path("/file1")) 93 .add_required_file(fs::path("/dir/file2")) 94 .add_required_program(fs::path("/bin/ls")) 95 .add_required_program(fs::path("svn")) 96 .set_description("Some text") 97 .set_has_cleanup(true) 98 .set_is_exclusive(true) 99 .set_required_disk_space(units::bytes::parse("10g")) 100 .set_required_memory(units::bytes::parse("1m")) 101 .set_required_user("root") 102 .set_timeout(datetime::delta(123, 0)) 103 .build(); 104 ATF_REQUIRE_EQ(exp_md, md); 105 } 106 107 108 ATF_TEST_CASE_WITHOUT_HEAD(parse_atf_metadata__unknown) 109 ATF_TEST_CASE_BODY(parse_atf_metadata__unknown) 110 { 111 model::properties_map properties; 112 properties["foobar"] = "Some text"; 113 114 ATF_REQUIRE_THROW_RE(engine::format_error, "Unknown.*property.*'foobar'", 115 engine::parse_atf_metadata(properties)); 116 } 117 118 119 ATF_TEST_CASE_WITHOUT_HEAD(parse_atf_list__empty); 120 ATF_TEST_CASE_BODY(parse_atf_list__empty) 121 { 122 const std::string text = ""; 123 std::istringstream input(text); 124 ATF_REQUIRE_THROW_RE(engine::format_error, "expecting Content-Type", 125 engine::parse_atf_list(input)); 126 } 127 128 129 ATF_TEST_CASE_WITHOUT_HEAD(parse_atf_list__invalid_header); 130 ATF_TEST_CASE_BODY(parse_atf_list__invalid_header) 131 { 132 { 133 const std::string text = 134 "Content-Type: application/X-atf-tp; version=\"1\"\n"; 135 std::istringstream input(text); 136 ATF_REQUIRE_THROW_RE(engine::format_error, "expecting.*blank line", 137 engine::parse_atf_list(input)); 138 } 139 140 { 141 const std::string text = 142 "Content-Type: application/X-atf-tp; version=\"1\"\nfoo\n"; 143 std::istringstream input(text); 144 ATF_REQUIRE_THROW_RE(engine::format_error, "expecting.*blank line", 145 engine::parse_atf_list(input)); 146 } 147 148 { 149 const std::string text = 150 "Content-Type: application/X-atf-tp; version=\"2\"\n\n"; 151 std::istringstream input(text); 152 ATF_REQUIRE_THROW_RE(engine::format_error, "expecting Content-Type", 153 engine::parse_atf_list(input)); 154 } 155 } 156 157 158 ATF_TEST_CASE_WITHOUT_HEAD(parse_atf_list__no_test_cases); 159 ATF_TEST_CASE_BODY(parse_atf_list__no_test_cases) 160 { 161 const std::string text = 162 "Content-Type: application/X-atf-tp; version=\"1\"\n\n"; 163 std::istringstream input(text); 164 ATF_REQUIRE_THROW_RE(engine::format_error, "No test cases", 165 engine::parse_atf_list(input)); 166 } 167 168 169 ATF_TEST_CASE_WITHOUT_HEAD(parse_atf_list__one_test_case_simple); 170 ATF_TEST_CASE_BODY(parse_atf_list__one_test_case_simple) 171 { 172 const std::string text = 173 "Content-Type: application/X-atf-tp; version=\"1\"\n" 174 "\n" 175 "ident: test-case\n"; 176 std::istringstream input(text); 177 const model::test_cases_map tests = engine::parse_atf_list(input); 178 179 const model::test_cases_map exp_tests = model::test_cases_map_builder() 180 .add("test-case").build(); 181 ATF_REQUIRE_EQ(exp_tests, tests); 182 } 183 184 185 ATF_TEST_CASE_WITHOUT_HEAD(parse_atf_list__one_test_case_complex); 186 ATF_TEST_CASE_BODY(parse_atf_list__one_test_case_complex) 187 { 188 const std::string text = 189 "Content-Type: application/X-atf-tp; version=\"1\"\n" 190 "\n" 191 "ident: first\n" 192 "descr: This is the description\n" 193 "timeout: 500\n"; 194 std::istringstream input(text); 195 const model::test_cases_map tests = engine::parse_atf_list(input); 196 197 const model::test_cases_map exp_tests = model::test_cases_map_builder() 198 .add("first", model::metadata_builder() 199 .set_description("This is the description") 200 .set_timeout(datetime::delta(500, 0)) 201 .build()) 202 .build(); 203 ATF_REQUIRE_EQ(exp_tests, tests); 204 } 205 206 207 ATF_TEST_CASE_WITHOUT_HEAD(parse_atf_list__one_test_case_invalid_syntax); 208 ATF_TEST_CASE_BODY(parse_atf_list__one_test_case_invalid_syntax) 209 { 210 const std::string text = 211 "Content-Type: application/X-atf-tp; version=\"1\"\n\n" 212 "descr: This is the description\n" 213 "ident: first\n"; 214 std::istringstream input(text); 215 ATF_REQUIRE_THROW_RE(engine::format_error, "preceeded.*identifier", 216 engine::parse_atf_list(input)); 217 } 218 219 220 ATF_TEST_CASE_WITHOUT_HEAD(parse_atf_list__one_test_case_invalid_properties); 221 ATF_TEST_CASE_BODY(parse_atf_list__one_test_case_invalid_properties) 222 { 223 // Inject a single invalid property that makes test_case::from_properties() 224 // raise a particular error message so that we can validate that such 225 // function was called. We do intensive testing separately, so it is not 226 // necessary to redo it here. 227 const std::string text = 228 "Content-Type: application/X-atf-tp; version=\"1\"\n\n" 229 "ident: first\n" 230 "require.progs: bin/ls\n"; 231 std::istringstream input(text); 232 ATF_REQUIRE_THROW_RE(engine::format_error, "Relative path 'bin/ls'", 233 engine::parse_atf_list(input)); 234 } 235 236 237 ATF_TEST_CASE_WITHOUT_HEAD(parse_atf_list__many_test_cases); 238 ATF_TEST_CASE_BODY(parse_atf_list__many_test_cases) 239 { 240 const std::string text = 241 "Content-Type: application/X-atf-tp; version=\"1\"\n" 242 "\n" 243 "ident: first\n" 244 "descr: This is the description\n" 245 "\n" 246 "ident: second\n" 247 "timeout: 500\n" 248 "descr: Some text\n" 249 "\n" 250 "ident: third\n"; 251 std::istringstream input(text); 252 const model::test_cases_map tests = engine::parse_atf_list(input); 253 254 const model::test_cases_map exp_tests = model::test_cases_map_builder() 255 .add("first", model::metadata_builder() 256 .set_description("This is the description") 257 .build()) 258 .add("second", model::metadata_builder() 259 .set_description("Some text") 260 .set_timeout(datetime::delta(500, 0)) 261 .build()) 262 .add("third") 263 .build(); 264 ATF_REQUIRE_EQ(exp_tests, tests); 265 } 266 267 268 ATF_TEST_CASE_WITHOUT_HEAD(parse_atf_list__is_exclusive_support); 269 ATF_TEST_CASE_BODY(parse_atf_list__is_exclusive_support) 270 { 271 const std::string text = 272 "Content-Type: application/X-atf-tp; version=\"1\"\n" 273 "\n" 274 "ident: first\n" 275 "is.exclusive: false\n" 276 "descr: This is the descr\n" 277 "\n" 278 "ident: second\n" 279 "is.exclusive: true\n" 280 "\n" 281 "ident: third\n"; 282 std::istringstream input(text); 283 const model::test_cases_map tests = engine::parse_atf_list(input); 284 285 const model::test_cases_map exp_tests = model::test_cases_map_builder() 286 .add("first", model::metadata_builder() 287 .set_description("This is the descr") 288 .build()) 289 .add("second", model::metadata_builder() 290 .set_is_exclusive(true) 291 .build()) 292 .add("third") 293 .build(); 294 ATF_REQUIRE_EQ(exp_tests, tests); 295 } 296 297 298 ATF_TEST_CASE_WITHOUT_HEAD(parse_atf_list__disk_space_support); 299 ATF_TEST_CASE_BODY(parse_atf_list__disk_space_support) 300 { 301 const std::string text = 302 "Content-Type: application/X-atf-tp; version=\"1\"\n" 303 "\n" 304 "ident: first\n" 305 "require.diskspace: 123M\n"; 306 std::istringstream input(text); 307 const model::test_cases_map tests = engine::parse_atf_list(input); 308 309 const model::test_cases_map exp_tests = model::test_cases_map_builder() 310 .add("first", model::metadata_builder() 311 .set_required_disk_space(units::bytes::parse("123M")) 312 .build()) 313 .build(); 314 ATF_REQUIRE_EQ(exp_tests, tests); 315 } 316 317 318 ATF_INIT_TEST_CASES(tcs) 319 { 320 ATF_ADD_TEST_CASE(tcs, parse_atf_metadata__defaults); 321 ATF_ADD_TEST_CASE(tcs, parse_atf_metadata__override_all); 322 ATF_ADD_TEST_CASE(tcs, parse_atf_metadata__unknown); 323 324 ATF_ADD_TEST_CASE(tcs, parse_atf_list__empty); 325 ATF_ADD_TEST_CASE(tcs, parse_atf_list__invalid_header); 326 ATF_ADD_TEST_CASE(tcs, parse_atf_list__no_test_cases); 327 ATF_ADD_TEST_CASE(tcs, parse_atf_list__one_test_case_simple); 328 ATF_ADD_TEST_CASE(tcs, parse_atf_list__one_test_case_complex); 329 ATF_ADD_TEST_CASE(tcs, parse_atf_list__one_test_case_invalid_syntax); 330 ATF_ADD_TEST_CASE(tcs, parse_atf_list__one_test_case_invalid_properties); 331 ATF_ADD_TEST_CASE(tcs, parse_atf_list__many_test_cases); 332 ATF_ADD_TEST_CASE(tcs, parse_atf_list__is_exclusive_support); 333 ATF_ADD_TEST_CASE(tcs, parse_atf_list__disk_space_support); 334 } 335