xref: /freebsd/contrib/kyua/engine/atf_list_test.cpp (revision 6befd3511105a17decdafbf9d3f55324c83aaea1)
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