1// Copyright 2012 Google Inc.
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/metadata.hpp"
30
31#include <sstream>
32
33#include <atf-c++.hpp>
34
35#include "engine/config.hpp"
36#include "utils/config/tree.ipp"
37#include "utils/datetime.hpp"
38#include "utils/env.hpp"
39#include "utils/fs/operations.hpp"
40#include "utils/fs/path.hpp"
41#include "utils/memory.hpp"
42#include "utils/passwd.hpp"
43#include "utils/units.hpp"
44
45namespace config = utils::config;
46namespace datetime = utils::datetime;
47namespace fs = utils::fs;
48namespace passwd = utils::passwd;
49namespace units = utils::units;
50
51
52ATF_TEST_CASE_WITHOUT_HEAD(defaults);
53ATF_TEST_CASE_BODY(defaults)
54{
55    const engine::metadata md = engine::metadata_builder().build();
56    ATF_REQUIRE(md.allowed_architectures().empty());
57    ATF_REQUIRE(md.allowed_platforms().empty());
58    ATF_REQUIRE(md.allowed_platforms().empty());
59    ATF_REQUIRE(md.custom().empty());
60    ATF_REQUIRE(md.description().empty());
61    ATF_REQUIRE(!md.has_cleanup());
62    ATF_REQUIRE(md.required_configs().empty());
63    ATF_REQUIRE(md.required_files().empty());
64    ATF_REQUIRE_EQ(units::bytes(0), md.required_memory());
65    ATF_REQUIRE(md.required_programs().empty());
66    ATF_REQUIRE(md.required_user().empty());
67    ATF_REQUIRE(engine::default_timeout == md.timeout());
68}
69
70
71ATF_TEST_CASE_WITHOUT_HEAD(add);
72ATF_TEST_CASE_BODY(add)
73{
74    engine::strings_set architectures;
75    architectures.insert("1-architecture");
76    architectures.insert("2-architecture");
77
78    engine::strings_set platforms;
79    platforms.insert("1-platform");
80    platforms.insert("2-platform");
81
82    engine::properties_map custom;
83    custom["1-custom"] = "first";
84    custom["2-custom"] = "second";
85
86    engine::strings_set configs;
87    configs.insert("1-config");
88    configs.insert("2-config");
89
90    engine::paths_set files;
91    files.insert(fs::path("1-file"));
92    files.insert(fs::path("2-file"));
93
94    engine::paths_set programs;
95    programs.insert(fs::path("1-program"));
96    programs.insert(fs::path("2-program"));
97
98    const engine::metadata md = engine::metadata_builder()
99        .add_allowed_architecture("1-architecture")
100        .add_allowed_platform("1-platform")
101        .add_custom("1-custom", "first")
102        .add_custom("2-custom", "second")
103        .add_required_config("1-config")
104        .add_required_file(fs::path("1-file"))
105        .add_required_program(fs::path("1-program"))
106        .add_allowed_architecture("2-architecture")
107        .add_allowed_platform("2-platform")
108        .add_required_config("2-config")
109        .add_required_file(fs::path("2-file"))
110        .add_required_program(fs::path("2-program"))
111        .build();
112
113    ATF_REQUIRE(architectures == md.allowed_architectures());
114    ATF_REQUIRE(platforms == md.allowed_platforms());
115    ATF_REQUIRE(custom == md.custom());
116    ATF_REQUIRE(configs == md.required_configs());
117    ATF_REQUIRE(files == md.required_files());
118    ATF_REQUIRE(programs == md.required_programs());
119}
120
121
122ATF_TEST_CASE_WITHOUT_HEAD(copy);
123ATF_TEST_CASE_BODY(copy)
124{
125    const engine::metadata md1 = engine::metadata_builder()
126        .add_allowed_architecture("1-architecture")
127        .add_allowed_platform("1-platform")
128        .build();
129
130    const engine::metadata md2 = engine::metadata_builder(md1)
131        .add_allowed_architecture("2-architecture")
132        .build();
133
134    ATF_REQUIRE_EQ(1, md1.allowed_architectures().size());
135    ATF_REQUIRE_EQ(2, md2.allowed_architectures().size());
136    ATF_REQUIRE_EQ(1, md1.allowed_platforms().size());
137    ATF_REQUIRE_EQ(1, md2.allowed_platforms().size());
138}
139
140
141ATF_TEST_CASE_WITHOUT_HEAD(override_all_with_setters);
142ATF_TEST_CASE_BODY(override_all_with_setters)
143{
144    engine::strings_set architectures;
145    architectures.insert("the-architecture");
146
147    engine::strings_set platforms;
148    platforms.insert("the-platforms");
149
150    engine::properties_map custom;
151    custom["first"] = "hello";
152    custom["second"] = "bye";
153
154    const std::string description = "Some long text";
155
156    engine::strings_set configs;
157    configs.insert("the-configs");
158
159    engine::paths_set files;
160    files.insert(fs::path("the-files"));
161
162    const units::bytes memory(12345);
163
164    engine::paths_set programs;
165    programs.insert(fs::path("the-programs"));
166
167    const std::string user = "root";
168
169    const datetime::delta timeout(123, 0);
170
171    const engine::metadata md = engine::metadata_builder()
172        .set_allowed_architectures(architectures)
173        .set_allowed_platforms(platforms)
174        .set_custom(custom)
175        .set_description(description)
176        .set_has_cleanup(true)
177        .set_required_configs(configs)
178        .set_required_files(files)
179        .set_required_memory(memory)
180        .set_required_programs(programs)
181        .set_required_user(user)
182        .set_timeout(timeout)
183        .build();
184
185    ATF_REQUIRE(architectures == md.allowed_architectures());
186    ATF_REQUIRE(platforms == md.allowed_platforms());
187    ATF_REQUIRE(custom == md.custom());
188    ATF_REQUIRE_EQ(description, md.description());
189    ATF_REQUIRE(md.has_cleanup());
190    ATF_REQUIRE(configs == md.required_configs());
191    ATF_REQUIRE(files == md.required_files());
192    ATF_REQUIRE_EQ(memory, md.required_memory());
193    ATF_REQUIRE(programs == md.required_programs());
194    ATF_REQUIRE_EQ(user, md.required_user());
195    ATF_REQUIRE(timeout == md.timeout());
196}
197
198
199ATF_TEST_CASE_WITHOUT_HEAD(override_all_with_set_string);
200ATF_TEST_CASE_BODY(override_all_with_set_string)
201{
202    engine::strings_set architectures;
203    architectures.insert("a1");
204    architectures.insert("a2");
205
206    engine::strings_set platforms;
207    platforms.insert("p1");
208    platforms.insert("p2");
209
210    engine::properties_map custom;
211    custom["user-defined"] = "the-value";
212
213    const std::string description = "Another long text";
214
215    engine::strings_set configs;
216    configs.insert("config-var");
217
218    engine::paths_set files;
219    files.insert(fs::path("plain"));
220    files.insert(fs::path("/absolute/path"));
221
222    const units::bytes memory(1024 * 1024);
223
224    engine::paths_set programs;
225    programs.insert(fs::path("program"));
226    programs.insert(fs::path("/absolute/prog"));
227
228    const std::string user = "unprivileged";
229
230    const datetime::delta timeout(45, 0);
231
232    const engine::metadata md = engine::metadata_builder()
233        .set_string("allowed_architectures", "a1 a2")
234        .set_string("allowed_platforms", "p1 p2")
235        .set_string("custom.user-defined", "the-value")
236        .set_string("description", "Another long text")
237        .set_string("has_cleanup", "true")
238        .set_string("required_configs", "config-var")
239        .set_string("required_files", "plain /absolute/path")
240        .set_string("required_memory", "1M")
241        .set_string("required_programs", "program /absolute/prog")
242        .set_string("required_user", "unprivileged")
243        .set_string("timeout", "45")
244        .build();
245
246    ATF_REQUIRE(architectures == md.allowed_architectures());
247    ATF_REQUIRE(platforms == md.allowed_platforms());
248    ATF_REQUIRE(custom == md.custom());
249    ATF_REQUIRE_EQ(description, md.description());
250    ATF_REQUIRE(md.has_cleanup());
251    ATF_REQUIRE(configs == md.required_configs());
252    ATF_REQUIRE(files == md.required_files());
253    ATF_REQUIRE_EQ(memory, md.required_memory());
254    ATF_REQUIRE(programs == md.required_programs());
255    ATF_REQUIRE_EQ(user, md.required_user());
256    ATF_REQUIRE(timeout == md.timeout());
257}
258
259
260ATF_TEST_CASE_WITHOUT_HEAD(operators_eq_and_ne__empty);
261ATF_TEST_CASE_BODY(operators_eq_and_ne__empty)
262{
263    const engine::metadata md1 = engine::metadata_builder().build();
264    const engine::metadata md2 = engine::metadata_builder().build();
265    ATF_REQUIRE(  md1 == md2);
266    ATF_REQUIRE(!(md1 != md2));
267}
268
269
270ATF_TEST_CASE_WITHOUT_HEAD(operators_eq_and_ne__copy);
271ATF_TEST_CASE_BODY(operators_eq_and_ne__copy)
272{
273    const engine::metadata md1 = engine::metadata_builder()
274        .add_custom("X-foo", "bar")
275        .build();
276    const engine::metadata md2 = md1;
277    ATF_REQUIRE(  md1 == md2);
278    ATF_REQUIRE(!(md1 != md2));
279}
280
281
282ATF_TEST_CASE_WITHOUT_HEAD(operators_eq_and_ne__equal);
283ATF_TEST_CASE_BODY(operators_eq_and_ne__equal)
284{
285    const engine::metadata md1 = engine::metadata_builder()
286        .add_allowed_architecture("a")
287        .add_allowed_architecture("b")
288        .add_custom("X-foo", "bar")
289        .build();
290    const engine::metadata md2 = engine::metadata_builder()
291        .add_allowed_architecture("b")
292        .add_allowed_architecture("a")
293        .add_custom("X-foo", "bar")
294        .build();
295    ATF_REQUIRE(  md1 == md2);
296    ATF_REQUIRE(!(md1 != md2));
297}
298
299
300ATF_TEST_CASE_WITHOUT_HEAD(operators_eq_and_ne__different);
301ATF_TEST_CASE_BODY(operators_eq_and_ne__different)
302{
303    const engine::metadata md1 = engine::metadata_builder()
304        .add_custom("X-foo", "bar")
305        .build();
306    const engine::metadata md2 = engine::metadata_builder()
307        .add_custom("X-foo", "bar")
308        .add_custom("X-baz", "foo bar")
309        .build();
310    ATF_REQUIRE(!(md1 == md2));
311    ATF_REQUIRE(  md1 != md2);
312}
313
314
315ATF_TEST_CASE_WITHOUT_HEAD(output__defaults);
316ATF_TEST_CASE_BODY(output__defaults)
317{
318    std::ostringstream str;
319    str << engine::metadata_builder().build();
320    ATF_REQUIRE_EQ("metadata{allowed_architectures='', allowed_platforms='', "
321                   "description='', has_cleanup='false', required_configs='', "
322                   "required_files='', required_memory='0', "
323                   "required_programs='', required_user='', timeout='300'}",
324                   str.str());
325}
326
327
328ATF_TEST_CASE_WITHOUT_HEAD(output__some_values);
329ATF_TEST_CASE_BODY(output__some_values)
330{
331    std::ostringstream str;
332    str << engine::metadata_builder()
333        .add_allowed_architecture("abc")
334        .add_required_file(fs::path("foo"))
335        .add_required_file(fs::path("bar"))
336        .set_required_memory(units::bytes(1024))
337        .build();
338    ATF_REQUIRE_EQ(
339        "metadata{allowed_architectures='abc', allowed_platforms='', "
340        "description='', has_cleanup='false', required_configs='', "
341        "required_files='bar foo', required_memory='1.00K', "
342        "required_programs='', required_user='', timeout='300'}",
343        str.str());
344}
345
346
347ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__none);
348ATF_TEST_CASE_BODY(check_reqs__none)
349{
350    const engine::metadata md = engine::metadata_builder().build();
351    ATF_REQUIRE(engine::check_reqs(md, engine::empty_config(), "").empty());
352}
353
354
355ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_architectures__one_ok);
356ATF_TEST_CASE_BODY(check_reqs__allowed_architectures__one_ok)
357{
358    const engine::metadata md = engine::metadata_builder()
359        .add_allowed_architecture("x86_64")
360        .build();
361
362    config::tree user_config = engine::default_config();
363    user_config.set_string("architecture", "x86_64");
364    user_config.set_string("platform", "");
365    ATF_REQUIRE(engine::check_reqs(md, user_config, "").empty());
366}
367
368
369ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_architectures__one_fail);
370ATF_TEST_CASE_BODY(check_reqs__allowed_architectures__one_fail)
371{
372    const engine::metadata md = engine::metadata_builder()
373        .add_allowed_architecture("x86_64")
374        .build();
375
376    config::tree user_config = engine::default_config();
377    user_config.set_string("architecture", "i386");
378    user_config.set_string("platform", "");
379    ATF_REQUIRE_MATCH("Current architecture 'i386' not supported",
380                      engine::check_reqs(md, user_config, ""));
381}
382
383
384ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_architectures__many_ok);
385ATF_TEST_CASE_BODY(check_reqs__allowed_architectures__many_ok)
386{
387    const engine::metadata md = engine::metadata_builder()
388        .add_allowed_architecture("x86_64")
389        .add_allowed_architecture("i386")
390        .add_allowed_architecture("powerpc")
391        .build();
392
393    config::tree user_config = engine::default_config();
394    user_config.set_string("architecture", "i386");
395    user_config.set_string("platform", "");
396    ATF_REQUIRE(engine::check_reqs(md, user_config, "").empty());
397}
398
399
400ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_architectures__many_fail);
401ATF_TEST_CASE_BODY(check_reqs__allowed_architectures__many_fail)
402{
403    const engine::metadata md = engine::metadata_builder()
404        .add_allowed_architecture("x86_64")
405        .add_allowed_architecture("i386")
406        .add_allowed_architecture("powerpc")
407        .build();
408
409    config::tree user_config = engine::default_config();
410    user_config.set_string("architecture", "arm");
411    user_config.set_string("platform", "");
412    ATF_REQUIRE_MATCH("Current architecture 'arm' not supported",
413                      engine::check_reqs(md, user_config, ""));
414}
415
416
417ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_platforms__one_ok);
418ATF_TEST_CASE_BODY(check_reqs__allowed_platforms__one_ok)
419{
420    const engine::metadata md = engine::metadata_builder()
421        .add_allowed_platform("amd64")
422        .build();
423
424    config::tree user_config = engine::default_config();
425    user_config.set_string("architecture", "");
426    user_config.set_string("platform", "amd64");
427    ATF_REQUIRE(engine::check_reqs(md, user_config, "").empty());
428}
429
430
431ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_platforms__one_fail);
432ATF_TEST_CASE_BODY(check_reqs__allowed_platforms__one_fail)
433{
434    const engine::metadata md = engine::metadata_builder()
435        .add_allowed_platform("amd64")
436        .build();
437
438    config::tree user_config = engine::default_config();
439    user_config.set_string("architecture", "");
440    user_config.set_string("platform", "i386");
441    ATF_REQUIRE_MATCH("Current platform 'i386' not supported",
442                      engine::check_reqs(md, user_config, ""));
443}
444
445
446ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_platforms__many_ok);
447ATF_TEST_CASE_BODY(check_reqs__allowed_platforms__many_ok)
448{
449    const engine::metadata md = engine::metadata_builder()
450        .add_allowed_platform("amd64")
451        .add_allowed_platform("i386")
452        .add_allowed_platform("macppc")
453        .build();
454
455    config::tree user_config = engine::default_config();
456    user_config.set_string("architecture", "");
457    user_config.set_string("platform", "i386");
458    ATF_REQUIRE(engine::check_reqs(md, user_config, "").empty());
459}
460
461
462ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_platforms__many_fail);
463ATF_TEST_CASE_BODY(check_reqs__allowed_platforms__many_fail)
464{
465    const engine::metadata md = engine::metadata_builder()
466        .add_allowed_platform("amd64")
467        .add_allowed_platform("i386")
468        .add_allowed_platform("macppc")
469        .build();
470
471    config::tree user_config = engine::default_config();
472    user_config.set_string("architecture", "");
473    user_config.set_string("platform", "shark");
474    ATF_REQUIRE_MATCH("Current platform 'shark' not supported",
475                      engine::check_reqs(md, user_config, ""));
476}
477
478
479ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_configs__one_ok);
480ATF_TEST_CASE_BODY(check_reqs__required_configs__one_ok)
481{
482    const engine::metadata md = engine::metadata_builder()
483        .add_required_config("my-var")
484        .build();
485
486    config::tree user_config = engine::default_config();
487    user_config.set_string("test_suites.suite.aaa", "value1");
488    user_config.set_string("test_suites.suite.my-var", "value2");
489    user_config.set_string("test_suites.suite.zzz", "value3");
490    ATF_REQUIRE(engine::check_reqs(md, user_config, "suite").empty());
491}
492
493
494ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_configs__one_fail);
495ATF_TEST_CASE_BODY(check_reqs__required_configs__one_fail)
496{
497    const engine::metadata md = engine::metadata_builder()
498        .add_required_config("unprivileged_user")
499        .build();
500
501    config::tree user_config = engine::default_config();
502    user_config.set_string("test_suites.suite.aaa", "value1");
503    user_config.set_string("test_suites.suite.my-var", "value2");
504    user_config.set_string("test_suites.suite.zzz", "value3");
505    ATF_REQUIRE_MATCH("Required configuration property 'unprivileged_user' not "
506                      "defined",
507                      engine::check_reqs(md, user_config, "suite"));
508}
509
510
511ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_configs__many_ok);
512ATF_TEST_CASE_BODY(check_reqs__required_configs__many_ok)
513{
514    const engine::metadata md = engine::metadata_builder()
515        .add_required_config("foo")
516        .add_required_config("bar")
517        .add_required_config("baz")
518        .build();
519
520    config::tree user_config = engine::default_config();
521    user_config.set_string("test_suites.suite.aaa", "value1");
522    user_config.set_string("test_suites.suite.foo", "value2");
523    user_config.set_string("test_suites.suite.bar", "value3");
524    user_config.set_string("test_suites.suite.baz", "value4");
525    user_config.set_string("test_suites.suite.zzz", "value5");
526    ATF_REQUIRE(engine::check_reqs(md, user_config, "suite").empty());
527}
528
529
530ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_configs__many_fail);
531ATF_TEST_CASE_BODY(check_reqs__required_configs__many_fail)
532{
533    const engine::metadata md = engine::metadata_builder()
534        .add_required_config("foo")
535        .add_required_config("bar")
536        .add_required_config("baz")
537        .build();
538
539    config::tree user_config = engine::default_config();
540    user_config.set_string("test_suites.suite.aaa", "value1");
541    user_config.set_string("test_suites.suite.foo", "value2");
542    user_config.set_string("test_suites.suite.zzz", "value3");
543    ATF_REQUIRE_MATCH("Required configuration property 'bar' not defined",
544                      engine::check_reqs(md, user_config, "suite"));
545}
546
547
548ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_configs__special);
549ATF_TEST_CASE_BODY(check_reqs__required_configs__special)
550{
551    const engine::metadata md = engine::metadata_builder()
552        .add_required_config("unprivileged-user")
553        .build();
554
555    config::tree user_config = engine::default_config();
556    ATF_REQUIRE_MATCH("Required configuration property 'unprivileged-user' "
557                      "not defined",
558                      engine::check_reqs(md, user_config, ""));
559    user_config.set< engine::user_node >(
560        "unprivileged_user", passwd::user("foo", 1, 2));
561    ATF_REQUIRE(engine::check_reqs(md, user_config, "foo").empty());
562}
563
564
565ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_user__root__ok);
566ATF_TEST_CASE_BODY(check_reqs__required_user__root__ok)
567{
568    const engine::metadata md = engine::metadata_builder()
569        .set_required_user("root")
570        .build();
571
572    config::tree user_config = engine::default_config();
573    ATF_REQUIRE(!user_config.is_set("unprivileged_user"));
574
575    passwd::set_current_user_for_testing(passwd::user("", 0, 1));
576    ATF_REQUIRE(engine::check_reqs(md, user_config, "").empty());
577}
578
579
580ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_user__root__fail);
581ATF_TEST_CASE_BODY(check_reqs__required_user__root__fail)
582{
583    const engine::metadata md = engine::metadata_builder()
584        .set_required_user("root")
585        .build();
586
587    passwd::set_current_user_for_testing(passwd::user("", 123, 1));
588    ATF_REQUIRE_MATCH("Requires root privileges",
589                      engine::check_reqs(md, engine::empty_config(), ""));
590}
591
592
593ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_user__unprivileged__same);
594ATF_TEST_CASE_BODY(check_reqs__required_user__unprivileged__same)
595{
596    const engine::metadata md = engine::metadata_builder()
597        .set_required_user("unprivileged")
598        .build();
599
600    config::tree user_config = engine::default_config();
601    ATF_REQUIRE(!user_config.is_set("unprivileged_user"));
602
603    passwd::set_current_user_for_testing(passwd::user("", 123, 1));
604    ATF_REQUIRE(engine::check_reqs(md, user_config, "").empty());
605}
606
607
608ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_user__unprivileged__ok);
609ATF_TEST_CASE_BODY(check_reqs__required_user__unprivileged__ok)
610{
611    const engine::metadata md = engine::metadata_builder()
612        .set_required_user("unprivileged")
613        .build();
614
615    config::tree user_config = engine::default_config();
616    user_config.set< engine::user_node >(
617        "unprivileged_user", passwd::user("", 123, 1));
618
619    passwd::set_current_user_for_testing(passwd::user("", 0, 1));
620    ATF_REQUIRE(engine::check_reqs(md, user_config, "").empty());
621}
622
623
624ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_user__unprivileged__fail);
625ATF_TEST_CASE_BODY(check_reqs__required_user__unprivileged__fail)
626{
627    const engine::metadata md = engine::metadata_builder()
628        .set_required_user("unprivileged")
629        .build();
630
631    config::tree user_config = engine::default_config();
632    ATF_REQUIRE(!user_config.is_set("unprivileged_user"));
633
634    passwd::set_current_user_for_testing(passwd::user("", 0, 1));
635    ATF_REQUIRE_MATCH("Requires.*unprivileged.*unprivileged-user",
636                      engine::check_reqs(md, user_config, ""));
637}
638
639
640ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_files__ok);
641ATF_TEST_CASE_BODY(check_reqs__required_files__ok)
642{
643    const engine::metadata md = engine::metadata_builder()
644        .add_required_file(fs::current_path() / "test-file")
645        .build();
646
647    atf::utils::create_file("test-file", "");
648
649    ATF_REQUIRE(engine::check_reqs(md, engine::empty_config(), "").empty());
650}
651
652
653ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_files__fail);
654ATF_TEST_CASE_BODY(check_reqs__required_files__fail)
655{
656    const engine::metadata md = engine::metadata_builder()
657        .add_required_file(fs::path("/non-existent/file"))
658        .build();
659
660    ATF_REQUIRE_MATCH("'/non-existent/file' not found$",
661                      engine::check_reqs(md, engine::empty_config(), ""));
662}
663
664
665ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_memory__ok);
666ATF_TEST_CASE_BODY(check_reqs__required_memory__ok)
667{
668    const engine::metadata md = engine::metadata_builder()
669        .set_required_memory(units::bytes::parse("1m"))
670        .build();
671
672    ATF_REQUIRE(engine::check_reqs(md, engine::empty_config(), "").empty());
673}
674
675
676ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_memory__fail);
677ATF_TEST_CASE_BODY(check_reqs__required_memory__fail)
678{
679    const engine::metadata md = engine::metadata_builder()
680        .set_required_memory(units::bytes::parse("100t"))
681        .build();
682
683    if (utils::physical_memory() == 0)
684        skip("Don't know how to query the amount of physical memory");
685    ATF_REQUIRE_MATCH("Requires 100.00T .*memory",
686                      engine::check_reqs(md, engine::empty_config(), ""));
687}
688
689
690ATF_TEST_CASE(check_reqs__required_programs__ok);
691ATF_TEST_CASE_HEAD(check_reqs__required_programs__ok)
692{
693    set_md_var("require.progs", "/bin/ls /bin/mv");
694}
695ATF_TEST_CASE_BODY(check_reqs__required_programs__ok)
696{
697    const engine::metadata md = engine::metadata_builder()
698        .add_required_program(fs::path("/bin/ls"))
699        .add_required_program(fs::path("foo"))
700        .add_required_program(fs::path("/bin/mv"))
701        .build();
702
703    fs::mkdir(fs::path("bin"), 0755);
704    atf::utils::create_file("bin/foo", "");
705    utils::setenv("PATH", (fs::current_path() / "bin").str());
706
707    ATF_REQUIRE(engine::check_reqs(md, engine::empty_config(), "").empty());
708}
709
710
711ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_programs__fail_absolute);
712ATF_TEST_CASE_BODY(check_reqs__required_programs__fail_absolute)
713{
714    const engine::metadata md = engine::metadata_builder()
715        .add_required_program(fs::path("/non-existent/program"))
716        .build();
717
718    ATF_REQUIRE_MATCH("'/non-existent/program' not found$",
719                      engine::check_reqs(md, engine::empty_config(), ""));
720}
721
722
723ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_programs__fail_relative);
724ATF_TEST_CASE_BODY(check_reqs__required_programs__fail_relative)
725{
726    const engine::metadata md = engine::metadata_builder()
727        .add_required_program(fs::path("foo"))
728        .add_required_program(fs::path("bar"))
729        .build();
730
731    fs::mkdir(fs::path("bin"), 0755);
732    atf::utils::create_file("bin/foo", "");
733    utils::setenv("PATH", (fs::current_path() / "bin").str());
734
735    ATF_REQUIRE_MATCH("'bar' not found in PATH$",
736                      engine::check_reqs(md, engine::empty_config(), ""));
737}
738
739
740ATF_INIT_TEST_CASES(tcs)
741{
742    ATF_ADD_TEST_CASE(tcs, defaults);
743    ATF_ADD_TEST_CASE(tcs, add);
744    ATF_ADD_TEST_CASE(tcs, copy);
745    ATF_ADD_TEST_CASE(tcs, override_all_with_setters);
746    ATF_ADD_TEST_CASE(tcs, override_all_with_set_string);
747
748    ATF_ADD_TEST_CASE(tcs, operators_eq_and_ne__empty);
749    ATF_ADD_TEST_CASE(tcs, operators_eq_and_ne__copy);
750    ATF_ADD_TEST_CASE(tcs, operators_eq_and_ne__equal);
751    ATF_ADD_TEST_CASE(tcs, operators_eq_and_ne__different);
752
753    ATF_ADD_TEST_CASE(tcs, output__defaults);
754    ATF_ADD_TEST_CASE(tcs, output__some_values);
755
756    // TODO(jmmv): Add tests for error conditions (invalid keys and invalid
757    // values).
758
759    ATF_ADD_TEST_CASE(tcs, check_reqs__none);
760    ATF_ADD_TEST_CASE(tcs, check_reqs__allowed_architectures__one_ok);
761    ATF_ADD_TEST_CASE(tcs, check_reqs__allowed_architectures__one_fail);
762    ATF_ADD_TEST_CASE(tcs, check_reqs__allowed_architectures__many_ok);
763    ATF_ADD_TEST_CASE(tcs, check_reqs__allowed_architectures__many_fail);
764    ATF_ADD_TEST_CASE(tcs, check_reqs__allowed_platforms__one_ok);
765    ATF_ADD_TEST_CASE(tcs, check_reqs__allowed_platforms__one_fail);
766    ATF_ADD_TEST_CASE(tcs, check_reqs__allowed_platforms__many_ok);
767    ATF_ADD_TEST_CASE(tcs, check_reqs__allowed_platforms__many_fail);
768    ATF_ADD_TEST_CASE(tcs, check_reqs__required_configs__one_ok);
769    ATF_ADD_TEST_CASE(tcs, check_reqs__required_configs__one_fail);
770    ATF_ADD_TEST_CASE(tcs, check_reqs__required_configs__many_ok);
771    ATF_ADD_TEST_CASE(tcs, check_reqs__required_configs__many_fail);
772    ATF_ADD_TEST_CASE(tcs, check_reqs__required_configs__special);
773    ATF_ADD_TEST_CASE(tcs, check_reqs__required_user__root__ok);
774    ATF_ADD_TEST_CASE(tcs, check_reqs__required_user__root__fail);
775    ATF_ADD_TEST_CASE(tcs, check_reqs__required_user__unprivileged__same);
776    ATF_ADD_TEST_CASE(tcs, check_reqs__required_user__unprivileged__ok);
777    ATF_ADD_TEST_CASE(tcs, check_reqs__required_user__unprivileged__fail);
778    ATF_ADD_TEST_CASE(tcs, check_reqs__required_files__ok);
779    ATF_ADD_TEST_CASE(tcs, check_reqs__required_files__fail);
780    ATF_ADD_TEST_CASE(tcs, check_reqs__required_memory__ok);
781    ATF_ADD_TEST_CASE(tcs, check_reqs__required_memory__fail);
782    ATF_ADD_TEST_CASE(tcs, check_reqs__required_programs__ok);
783    ATF_ADD_TEST_CASE(tcs, check_reqs__required_programs__fail_absolute);
784    ATF_ADD_TEST_CASE(tcs, check_reqs__required_programs__fail_relative);
785}
786