xref: /freebsd/contrib/kyua/engine/requirements_test.cpp (revision ce6a89e27cd190313be39bb479880aeda4778436)
1 // Copyright 2012 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 "model/metadata.hpp"
30 
31 #include <atf-c++.hpp>
32 
33 #include "engine/config.hpp"
34 #include "engine/requirements.hpp"
35 #include "utils/config/tree.ipp"
36 #include "utils/env.hpp"
37 #include "utils/fs/operations.hpp"
38 #include "utils/fs/path.hpp"
39 #include "utils/memory.hpp"
40 #include "utils/passwd.hpp"
41 #include "utils/units.hpp"
42 
43 namespace config = utils::config;
44 namespace fs = utils::fs;
45 namespace passwd = utils::passwd;
46 namespace units = utils::units;
47 
48 
49 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__none);
50 ATF_TEST_CASE_BODY(check_reqs__none)
51 {
52     const model::metadata md = model::metadata_builder().build();
53     ATF_REQUIRE(engine::check_reqs(md, engine::empty_config(), "",
54                                    fs::path(".")).empty());
55 }
56 
57 
58 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_architectures__one_ok);
59 ATF_TEST_CASE_BODY(check_reqs__allowed_architectures__one_ok)
60 {
61     const model::metadata md = model::metadata_builder()
62         .add_allowed_architecture("x86_64")
63         .build();
64 
65     config::tree user_config = engine::default_config();
66     user_config.set_string("architecture", "x86_64");
67     user_config.set_string("platform", "");
68     ATF_REQUIRE(engine::check_reqs(md, user_config, "", fs::path(".")).empty());
69 }
70 
71 
72 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_architectures__one_fail);
73 ATF_TEST_CASE_BODY(check_reqs__allowed_architectures__one_fail)
74 {
75     const model::metadata md = model::metadata_builder()
76         .add_allowed_architecture("x86_64")
77         .build();
78 
79     config::tree user_config = engine::default_config();
80     user_config.set_string("architecture", "i386");
81     user_config.set_string("platform", "");
82     ATF_REQUIRE_MATCH("Current architecture 'i386' not supported",
83                       engine::check_reqs(md, user_config, "", fs::path(".")));
84 }
85 
86 
87 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_architectures__many_ok);
88 ATF_TEST_CASE_BODY(check_reqs__allowed_architectures__many_ok)
89 {
90     const model::metadata md = model::metadata_builder()
91         .add_allowed_architecture("x86_64")
92         .add_allowed_architecture("i386")
93         .add_allowed_architecture("powerpc")
94         .build();
95 
96     config::tree user_config = engine::default_config();
97     user_config.set_string("architecture", "i386");
98     user_config.set_string("platform", "");
99     ATF_REQUIRE(engine::check_reqs(md, user_config, "", fs::path(".")).empty());
100 }
101 
102 
103 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_architectures__many_fail);
104 ATF_TEST_CASE_BODY(check_reqs__allowed_architectures__many_fail)
105 {
106     const model::metadata md = model::metadata_builder()
107         .add_allowed_architecture("x86_64")
108         .add_allowed_architecture("i386")
109         .add_allowed_architecture("powerpc")
110         .build();
111 
112     config::tree user_config = engine::default_config();
113     user_config.set_string("architecture", "arm");
114     user_config.set_string("platform", "");
115     ATF_REQUIRE_MATCH("Current architecture 'arm' not supported",
116                       engine::check_reqs(md, user_config, "", fs::path(".")));
117 }
118 
119 
120 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_platforms__one_ok);
121 ATF_TEST_CASE_BODY(check_reqs__allowed_platforms__one_ok)
122 {
123     const model::metadata md = model::metadata_builder()
124         .add_allowed_platform("amd64")
125         .build();
126 
127     config::tree user_config = engine::default_config();
128     user_config.set_string("architecture", "");
129     user_config.set_string("platform", "amd64");
130     ATF_REQUIRE(engine::check_reqs(md, user_config, "", fs::path(".")).empty());
131 }
132 
133 
134 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_platforms__one_fail);
135 ATF_TEST_CASE_BODY(check_reqs__allowed_platforms__one_fail)
136 {
137     const model::metadata md = model::metadata_builder()
138         .add_allowed_platform("amd64")
139         .build();
140 
141     config::tree user_config = engine::default_config();
142     user_config.set_string("architecture", "");
143     user_config.set_string("platform", "i386");
144     ATF_REQUIRE_MATCH("Current platform 'i386' not supported",
145                       engine::check_reqs(md, user_config, "", fs::path(".")));
146 }
147 
148 
149 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_platforms__many_ok);
150 ATF_TEST_CASE_BODY(check_reqs__allowed_platforms__many_ok)
151 {
152     const model::metadata md = model::metadata_builder()
153         .add_allowed_platform("amd64")
154         .add_allowed_platform("i386")
155         .add_allowed_platform("macppc")
156         .build();
157 
158     config::tree user_config = engine::default_config();
159     user_config.set_string("architecture", "");
160     user_config.set_string("platform", "i386");
161     ATF_REQUIRE(engine::check_reqs(md, user_config, "", fs::path(".")).empty());
162 }
163 
164 
165 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_platforms__many_fail);
166 ATF_TEST_CASE_BODY(check_reqs__allowed_platforms__many_fail)
167 {
168     const model::metadata md = model::metadata_builder()
169         .add_allowed_platform("amd64")
170         .add_allowed_platform("i386")
171         .add_allowed_platform("macppc")
172         .build();
173 
174     config::tree user_config = engine::default_config();
175     user_config.set_string("architecture", "");
176     user_config.set_string("platform", "shark");
177     ATF_REQUIRE_MATCH("Current platform 'shark' not supported",
178                       engine::check_reqs(md, user_config, "", fs::path(".")));
179 }
180 
181 
182 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_configs__one_ok);
183 ATF_TEST_CASE_BODY(check_reqs__required_configs__one_ok)
184 {
185     const model::metadata md = model::metadata_builder()
186         .add_required_config("my-var")
187         .build();
188 
189     config::tree user_config = engine::default_config();
190     user_config.set_string("test_suites.suite.aaa", "value1");
191     user_config.set_string("test_suites.suite.my-var", "value2");
192     user_config.set_string("test_suites.suite.zzz", "value3");
193     ATF_REQUIRE(engine::check_reqs(md, user_config, "suite",
194                                    fs::path(".")).empty());
195 }
196 
197 
198 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_configs__one_fail);
199 ATF_TEST_CASE_BODY(check_reqs__required_configs__one_fail)
200 {
201     const model::metadata md = model::metadata_builder()
202         .add_required_config("unprivileged_user")
203         .build();
204 
205     config::tree user_config = engine::default_config();
206     user_config.set_string("test_suites.suite.aaa", "value1");
207     user_config.set_string("test_suites.suite.my-var", "value2");
208     user_config.set_string("test_suites.suite.zzz", "value3");
209     ATF_REQUIRE_MATCH("Required configuration property 'unprivileged_user' not "
210                       "defined",
211                       engine::check_reqs(md, user_config, "suite",
212                                          fs::path(".")));
213 }
214 
215 
216 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_configs__many_ok);
217 ATF_TEST_CASE_BODY(check_reqs__required_configs__many_ok)
218 {
219     const model::metadata md = model::metadata_builder()
220         .add_required_config("foo")
221         .add_required_config("bar")
222         .add_required_config("baz")
223         .build();
224 
225     config::tree user_config = engine::default_config();
226     user_config.set_string("test_suites.suite.aaa", "value1");
227     user_config.set_string("test_suites.suite.foo", "value2");
228     user_config.set_string("test_suites.suite.bar", "value3");
229     user_config.set_string("test_suites.suite.baz", "value4");
230     user_config.set_string("test_suites.suite.zzz", "value5");
231     ATF_REQUIRE(engine::check_reqs(md, user_config, "suite",
232                                    fs::path(".")).empty());
233 }
234 
235 
236 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_configs__many_fail);
237 ATF_TEST_CASE_BODY(check_reqs__required_configs__many_fail)
238 {
239     const model::metadata md = model::metadata_builder()
240         .add_required_config("foo")
241         .add_required_config("bar")
242         .add_required_config("baz")
243         .build();
244 
245     config::tree user_config = engine::default_config();
246     user_config.set_string("test_suites.suite.aaa", "value1");
247     user_config.set_string("test_suites.suite.foo", "value2");
248     user_config.set_string("test_suites.suite.zzz", "value3");
249     ATF_REQUIRE_MATCH("Required configuration property 'bar' not defined",
250                       engine::check_reqs(md, user_config, "suite",
251                                          fs::path(".")));
252 }
253 
254 
255 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_configs__special);
256 ATF_TEST_CASE_BODY(check_reqs__required_configs__special)
257 {
258     const model::metadata md = model::metadata_builder()
259         .add_required_config("unprivileged-user")
260         .build();
261 
262     config::tree user_config = engine::default_config();
263     ATF_REQUIRE_MATCH("Required configuration property 'unprivileged-user' "
264                       "not defined",
265                       engine::check_reqs(md, user_config, "", fs::path(".")));
266     user_config.set< engine::user_node >(
267         "unprivileged_user", passwd::user("foo", 1, 2));
268     ATF_REQUIRE(engine::check_reqs(md, user_config, "foo",
269                                    fs::path(".")).empty());
270 }
271 
272 
273 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_user__root__ok);
274 ATF_TEST_CASE_BODY(check_reqs__required_user__root__ok)
275 {
276     const model::metadata md = model::metadata_builder()
277         .set_required_user("root")
278         .build();
279 
280     config::tree user_config = engine::default_config();
281     ATF_REQUIRE(!user_config.is_set("unprivileged_user"));
282 
283     passwd::set_current_user_for_testing(passwd::user("", 0, 1));
284     ATF_REQUIRE(engine::check_reqs(md, user_config, "", fs::path(".")).empty());
285 }
286 
287 
288 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_user__root__fail);
289 ATF_TEST_CASE_BODY(check_reqs__required_user__root__fail)
290 {
291     const model::metadata md = model::metadata_builder()
292         .set_required_user("root")
293         .build();
294 
295     passwd::set_current_user_for_testing(passwd::user("", 123, 1));
296     ATF_REQUIRE_MATCH("Requires root privileges",
297                       engine::check_reqs(md, engine::empty_config(), "",
298                                          fs::path(".")));
299 }
300 
301 
302 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_user__unprivileged__same);
303 ATF_TEST_CASE_BODY(check_reqs__required_user__unprivileged__same)
304 {
305     const model::metadata md = model::metadata_builder()
306         .set_required_user("unprivileged")
307         .build();
308 
309     config::tree user_config = engine::default_config();
310     ATF_REQUIRE(!user_config.is_set("unprivileged_user"));
311 
312     passwd::set_current_user_for_testing(passwd::user("", 123, 1));
313     ATF_REQUIRE(engine::check_reqs(md, user_config, "", fs::path(".")).empty());
314 }
315 
316 
317 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_user__unprivileged__ok);
318 ATF_TEST_CASE_BODY(check_reqs__required_user__unprivileged__ok)
319 {
320     const model::metadata md = model::metadata_builder()
321         .set_required_user("unprivileged")
322         .build();
323 
324     config::tree user_config = engine::default_config();
325     user_config.set< engine::user_node >(
326         "unprivileged_user", passwd::user("", 123, 1));
327 
328     passwd::set_current_user_for_testing(passwd::user("", 0, 1));
329     ATF_REQUIRE(engine::check_reqs(md, user_config, "", fs::path(".")).empty());
330 }
331 
332 
333 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_user__unprivileged__fail);
334 ATF_TEST_CASE_BODY(check_reqs__required_user__unprivileged__fail)
335 {
336     const model::metadata md = model::metadata_builder()
337         .set_required_user("unprivileged")
338         .build();
339 
340     config::tree user_config = engine::default_config();
341     ATF_REQUIRE(!user_config.is_set("unprivileged_user"));
342 
343     passwd::set_current_user_for_testing(passwd::user("", 0, 1));
344     ATF_REQUIRE_MATCH("Requires.*unprivileged.*unprivileged-user",
345                       engine::check_reqs(md, user_config, "", fs::path(".")));
346 }
347 
348 
349 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_disk_space__ok);
350 ATF_TEST_CASE_BODY(check_reqs__required_disk_space__ok)
351 {
352     const model::metadata md = model::metadata_builder()
353         .set_required_disk_space(units::bytes::parse("1m"))
354         .build();
355 
356     ATF_REQUIRE(engine::check_reqs(md, engine::empty_config(), "",
357                                    fs::path(".")).empty());
358 }
359 
360 
361 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_disk_space__fail);
362 ATF_TEST_CASE_BODY(check_reqs__required_disk_space__fail)
363 {
364     const model::metadata md = model::metadata_builder()
365         .set_required_disk_space(units::bytes::parse("1000t"))
366         .build();
367 
368     ATF_REQUIRE_MATCH("Requires 1000.00T .*disk space",
369                       engine::check_reqs(md, engine::empty_config(), "",
370                                          fs::path(".")));
371 }
372 
373 
374 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_files__ok);
375 ATF_TEST_CASE_BODY(check_reqs__required_files__ok)
376 {
377     const model::metadata md = model::metadata_builder()
378         .add_required_file(fs::current_path() / "test-file")
379         .build();
380 
381     atf::utils::create_file("test-file", "");
382 
383     ATF_REQUIRE(engine::check_reqs(md, engine::empty_config(), "",
384                                    fs::path(".")).empty());
385 }
386 
387 
388 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_files__fail);
389 ATF_TEST_CASE_BODY(check_reqs__required_files__fail)
390 {
391     const model::metadata md = model::metadata_builder()
392         .add_required_file(fs::path("/non-existent/file"))
393         .build();
394 
395     ATF_REQUIRE_MATCH("'/non-existent/file' not found$",
396                       engine::check_reqs(md, engine::empty_config(), "",
397                                          fs::path(".")));
398 }
399 
400 
401 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_memory__ok);
402 ATF_TEST_CASE_BODY(check_reqs__required_memory__ok)
403 {
404     const model::metadata md = model::metadata_builder()
405         .set_required_memory(units::bytes::parse("1m"))
406         .build();
407 
408     ATF_REQUIRE(engine::check_reqs(md, engine::empty_config(), "",
409                                    fs::path(".")).empty());
410 }
411 
412 
413 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_memory__fail);
414 ATF_TEST_CASE_BODY(check_reqs__required_memory__fail)
415 {
416     const model::metadata md = model::metadata_builder()
417         .set_required_memory(units::bytes::parse("100t"))
418         .build();
419 
420     if (utils::physical_memory() == 0)
421         skip("Don't know how to query the amount of physical memory");
422     ATF_REQUIRE_MATCH("Requires 100.00T .*memory",
423                       engine::check_reqs(md, engine::empty_config(), "",
424                                          fs::path(".")));
425 }
426 
427 
428 ATF_TEST_CASE(check_reqs__required_programs__ok);
429 ATF_TEST_CASE_HEAD(check_reqs__required_programs__ok)
430 {
431     set_md_var("require.progs", "/bin/ls /bin/mv");
432 }
433 ATF_TEST_CASE_BODY(check_reqs__required_programs__ok)
434 {
435     const model::metadata md = model::metadata_builder()
436         .add_required_program(fs::path("/bin/ls"))
437         .add_required_program(fs::path("foo"))
438         .add_required_program(fs::path("/bin/mv"))
439         .build();
440 
441     fs::mkdir(fs::path("bin"), 0755);
442     atf::utils::create_file("bin/foo", "");
443     utils::setenv("PATH", (fs::current_path() / "bin").str());
444 
445     ATF_REQUIRE(engine::check_reqs(md, engine::empty_config(), "",
446                                    fs::path(".")).empty());
447 }
448 
449 
450 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_programs__fail_absolute);
451 ATF_TEST_CASE_BODY(check_reqs__required_programs__fail_absolute)
452 {
453     const model::metadata md = model::metadata_builder()
454         .add_required_program(fs::path("/non-existent/program"))
455         .build();
456 
457     ATF_REQUIRE_MATCH("'/non-existent/program' not found$",
458                       engine::check_reqs(md, engine::empty_config(), "",
459                                          fs::path(".")));
460 }
461 
462 
463 ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_programs__fail_relative);
464 ATF_TEST_CASE_BODY(check_reqs__required_programs__fail_relative)
465 {
466     const model::metadata md = model::metadata_builder()
467         .add_required_program(fs::path("foo"))
468         .add_required_program(fs::path("bar"))
469         .build();
470 
471     fs::mkdir(fs::path("bin"), 0755);
472     atf::utils::create_file("bin/foo", "");
473     utils::setenv("PATH", (fs::current_path() / "bin").str());
474 
475     ATF_REQUIRE_MATCH("'bar' not found in PATH$",
476                       engine::check_reqs(md, engine::empty_config(), "",
477                                          fs::path(".")));
478 }
479 
480 
481 ATF_INIT_TEST_CASES(tcs)
482 {
483     ATF_ADD_TEST_CASE(tcs, check_reqs__none);
484     ATF_ADD_TEST_CASE(tcs, check_reqs__allowed_architectures__one_ok);
485     ATF_ADD_TEST_CASE(tcs, check_reqs__allowed_architectures__one_fail);
486     ATF_ADD_TEST_CASE(tcs, check_reqs__allowed_architectures__many_ok);
487     ATF_ADD_TEST_CASE(tcs, check_reqs__allowed_architectures__many_fail);
488     ATF_ADD_TEST_CASE(tcs, check_reqs__allowed_platforms__one_ok);
489     ATF_ADD_TEST_CASE(tcs, check_reqs__allowed_platforms__one_fail);
490     ATF_ADD_TEST_CASE(tcs, check_reqs__allowed_platforms__many_ok);
491     ATF_ADD_TEST_CASE(tcs, check_reqs__allowed_platforms__many_fail);
492     ATF_ADD_TEST_CASE(tcs, check_reqs__required_configs__one_ok);
493     ATF_ADD_TEST_CASE(tcs, check_reqs__required_configs__one_fail);
494     ATF_ADD_TEST_CASE(tcs, check_reqs__required_configs__many_ok);
495     ATF_ADD_TEST_CASE(tcs, check_reqs__required_configs__many_fail);
496     ATF_ADD_TEST_CASE(tcs, check_reqs__required_configs__special);
497     ATF_ADD_TEST_CASE(tcs, check_reqs__required_user__root__ok);
498     ATF_ADD_TEST_CASE(tcs, check_reqs__required_user__root__fail);
499     ATF_ADD_TEST_CASE(tcs, check_reqs__required_user__unprivileged__same);
500     ATF_ADD_TEST_CASE(tcs, check_reqs__required_user__unprivileged__ok);
501     ATF_ADD_TEST_CASE(tcs, check_reqs__required_user__unprivileged__fail);
502     ATF_ADD_TEST_CASE(tcs, check_reqs__required_disk_space__ok);
503     ATF_ADD_TEST_CASE(tcs, check_reqs__required_disk_space__fail);
504     ATF_ADD_TEST_CASE(tcs, check_reqs__required_files__ok);
505     ATF_ADD_TEST_CASE(tcs, check_reqs__required_files__fail);
506     ATF_ADD_TEST_CASE(tcs, check_reqs__required_memory__ok);
507     ATF_ADD_TEST_CASE(tcs, check_reqs__required_memory__fail);
508     ATF_ADD_TEST_CASE(tcs, check_reqs__required_programs__ok);
509     ATF_ADD_TEST_CASE(tcs, check_reqs__required_programs__fail_absolute);
510     ATF_ADD_TEST_CASE(tcs, check_reqs__required_programs__fail_relative);
511 }
512