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
43namespace config = utils::config;
44namespace fs = utils::fs;
45namespace passwd = utils::passwd;
46namespace units = utils::units;
47
48
49ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__none);
50ATF_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
58ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_architectures__one_ok);
59ATF_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
72ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_architectures__one_fail);
73ATF_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
87ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_architectures__many_ok);
88ATF_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
103ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_architectures__many_fail);
104ATF_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
120ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_platforms__one_ok);
121ATF_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
134ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_platforms__one_fail);
135ATF_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
149ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_platforms__many_ok);
150ATF_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
165ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__allowed_platforms__many_fail);
166ATF_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
182ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_configs__one_ok);
183ATF_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
198ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_configs__one_fail);
199ATF_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
216ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_configs__many_ok);
217ATF_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
236ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_configs__many_fail);
237ATF_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
255ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_configs__special);
256ATF_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
273ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_user__root__ok);
274ATF_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
288ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_user__root__fail);
289ATF_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
302ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_user__unprivileged__same);
303ATF_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
317ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_user__unprivileged__ok);
318ATF_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
333ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_user__unprivileged__fail);
334ATF_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
349ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_disk_space__ok);
350ATF_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
361ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_disk_space__fail);
362ATF_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
374ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_files__ok);
375ATF_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
388ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_files__fail);
389ATF_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
401ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_memory__ok);
402ATF_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
413ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_memory__fail);
414ATF_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
428ATF_TEST_CASE(check_reqs__required_programs__ok);
429ATF_TEST_CASE_HEAD(check_reqs__required_programs__ok)
430{
431    set_md_var("require.progs", "/bin/ls /bin/mv");
432}
433ATF_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
450ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_programs__fail_absolute);
451ATF_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
463ATF_TEST_CASE_WITHOUT_HEAD(check_reqs__required_programs__fail_relative);
464ATF_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
481ATF_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