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