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)
ATF_TEST_CASE_BODY(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)
ATF_TEST_CASE_BODY(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)
ATF_TEST_CASE_BODY(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);
ATF_TEST_CASE_BODY(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);
ATF_TEST_CASE_BODY(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);
ATF_TEST_CASE_BODY(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);
ATF_TEST_CASE_BODY(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);
ATF_TEST_CASE_BODY(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);
ATF_TEST_CASE_BODY(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);
ATF_TEST_CASE_BODY(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);
ATF_TEST_CASE_BODY(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);
ATF_TEST_CASE_BODY(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);
ATF_TEST_CASE_BODY(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
ATF_INIT_TEST_CASES(tcs)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