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