1//
2// Automated Testing Framework (atf)
3//
4// Copyright (c) 2010 The NetBSD Foundation, Inc.
5// All rights reserved.
6//
7// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions
9// are met:
10// 1. Redistributions of source code must retain the above copyright
11//    notice, this list of conditions and the following disclaimer.
12// 2. Redistributions in binary form must reproduce the above copyright
13//    notice, this list of conditions and the following disclaimer in the
14//    documentation and/or other materials provided with the distribution.
15//
16// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28//
29
30#include <atf-c++.hpp>
31
32#include "config.hpp"
33#include "requirements.hpp"
34#include "text.hpp"
35#include "user.hpp"
36
37namespace impl = tools;
38
39// -------------------------------------------------------------------------
40// Auxiliary functions.
41// -------------------------------------------------------------------------
42
43namespace {
44
45typedef std::map< std::string, std::string > vars_map;
46
47const vars_map no_config;
48
49void
50do_check(const std::string& expected, const vars_map& metadata,
51         const vars_map& config = no_config)
52{
53    const std::string actual = impl::check_requirements(metadata, config);
54    if (!tools::text::match(actual, expected))
55        ATF_FAIL("Requirements failure reason \"" + actual + "\" does not "
56                 "match \"" + expected + "\"");
57}
58
59} // anonymous namespace
60
61// -------------------------------------------------------------------------
62// Tests for the require.arch metadata property.
63// -------------------------------------------------------------------------
64
65ATF_TEST_CASE(require_arch_one_ok);
66ATF_TEST_CASE_HEAD(require_arch_one_ok) {}
67ATF_TEST_CASE_BODY(require_arch_one_ok) {
68    vars_map metadata;
69    metadata["require.arch"] = tools::config::get("atf_arch");
70    do_check("", metadata);
71}
72
73ATF_TEST_CASE(require_arch_one_fail);
74ATF_TEST_CASE_HEAD(require_arch_one_fail) {}
75ATF_TEST_CASE_BODY(require_arch_one_fail) {
76    vars_map metadata;
77    metadata["require.arch"] = "__fake_arch__";
78    do_check("Requires the '__fake_arch__' architecture", metadata);
79}
80
81ATF_TEST_CASE(require_arch_many_ok);
82ATF_TEST_CASE_HEAD(require_arch_many_ok) {}
83ATF_TEST_CASE_BODY(require_arch_many_ok) {
84    vars_map metadata;
85    metadata["require.arch"] = "__foo__ " + tools::config::get("atf_arch") +
86        " __bar__";
87    do_check("", metadata);
88}
89
90ATF_TEST_CASE(require_arch_many_fail);
91ATF_TEST_CASE_HEAD(require_arch_many_fail) {}
92ATF_TEST_CASE_BODY(require_arch_many_fail) {
93    vars_map metadata;
94    metadata["require.arch"] = "__foo__ __bar__ __baz__";
95    do_check("Requires one of the '__foo__ __bar__ __baz__' architectures",
96             metadata);
97}
98
99// -------------------------------------------------------------------------
100// Tests for the require.config metadata property.
101// -------------------------------------------------------------------------
102
103ATF_TEST_CASE(require_config_one_ok);
104ATF_TEST_CASE_HEAD(require_config_one_ok) {}
105ATF_TEST_CASE_BODY(require_config_one_ok) {
106    vars_map metadata, config;
107    metadata["require.config"] = "var1";
108    config["var1"] = "some-value";
109    do_check("", metadata, config);
110}
111
112ATF_TEST_CASE(require_config_one_fail);
113ATF_TEST_CASE_HEAD(require_config_one_fail) {}
114ATF_TEST_CASE_BODY(require_config_one_fail) {
115    vars_map metadata, config;
116    metadata["require.config"] = "var1";
117    do_check("Required configuration variable 'var1' not defined", metadata,
118             config);
119}
120
121ATF_TEST_CASE(require_config_many_ok);
122ATF_TEST_CASE_HEAD(require_config_many_ok) {}
123ATF_TEST_CASE_BODY(require_config_many_ok) {
124    vars_map metadata, config;
125    metadata["require.config"] = "var1 var2 var3";
126    config["var1"] = "first-value";
127    config["var2"] = "second-value";
128    config["var3"] = "third-value";
129    do_check("", metadata, config);
130}
131
132ATF_TEST_CASE(require_config_many_fail);
133ATF_TEST_CASE_HEAD(require_config_many_fail) {}
134ATF_TEST_CASE_BODY(require_config_many_fail) {
135    vars_map metadata, config;
136    metadata["require.config"] = "var1 var2 var3";
137    config["var1"] = "first-value";
138    config["var3"] = "third-value";
139    do_check("Required configuration variable 'var2' not defined", metadata,
140             config);
141}
142
143// -------------------------------------------------------------------------
144// Tests for the require.files metadata property.
145// -------------------------------------------------------------------------
146
147ATF_TEST_CASE_WITHOUT_HEAD(require_files_one_ok);
148ATF_TEST_CASE_BODY(require_files_one_ok) {
149    vars_map metadata;
150    metadata["require.files"] = "/bin/ls";
151    do_check("", metadata);
152}
153
154ATF_TEST_CASE_WITHOUT_HEAD(require_files_one_missing);
155ATF_TEST_CASE_BODY(require_files_one_missing) {
156    vars_map metadata;
157    metadata["require.files"] = "/non-existent/foo";
158    do_check("Required file '/non-existent/foo' not found", metadata);
159}
160
161ATF_TEST_CASE_WITHOUT_HEAD(require_files_one_fail);
162ATF_TEST_CASE_BODY(require_files_one_fail) {
163    vars_map metadata;
164    metadata["require.files"] = "/bin/cp this-is-relative";
165    ATF_REQUIRE_THROW_RE(std::runtime_error, "Relative.*(this-is-relative)",
166                         impl::check_requirements(metadata, no_config));
167}
168
169ATF_TEST_CASE_WITHOUT_HEAD(require_files_many_ok);
170ATF_TEST_CASE_BODY(require_files_many_ok) {
171    vars_map metadata;
172    metadata["require.files"] = "/bin/ls /bin/cp";
173    do_check("", metadata);
174}
175
176ATF_TEST_CASE_WITHOUT_HEAD(require_files_many_missing);
177ATF_TEST_CASE_BODY(require_files_many_missing) {
178    vars_map metadata;
179    metadata["require.files"] = "/bin/ls /non-existent/bar /bin/cp";
180    do_check("Required file '/non-existent/bar' not found", metadata);
181}
182
183ATF_TEST_CASE_WITHOUT_HEAD(require_files_many_fail);
184ATF_TEST_CASE_BODY(require_files_many_fail) {
185    vars_map metadata;
186    metadata["require.files"] = "/bin/cp also-relative";
187    ATF_REQUIRE_THROW_RE(std::runtime_error, "Relative.*(also-relative)",
188                         impl::check_requirements(metadata, no_config));
189}
190
191// -------------------------------------------------------------------------
192// Tests for the require.machine metadata property.
193// -------------------------------------------------------------------------
194
195ATF_TEST_CASE(require_machine_one_ok);
196ATF_TEST_CASE_HEAD(require_machine_one_ok) {}
197ATF_TEST_CASE_BODY(require_machine_one_ok) {
198    vars_map metadata;
199    metadata["require.machine"] = tools::config::get("atf_machine");
200    do_check("", metadata);
201}
202
203ATF_TEST_CASE(require_machine_one_fail);
204ATF_TEST_CASE_HEAD(require_machine_one_fail) {}
205ATF_TEST_CASE_BODY(require_machine_one_fail) {
206    vars_map metadata;
207    metadata["require.machine"] = "__fake_machine__";
208    do_check("Requires the '__fake_machine__' machine type", metadata);
209}
210
211ATF_TEST_CASE(require_machine_many_ok);
212ATF_TEST_CASE_HEAD(require_machine_many_ok) {}
213ATF_TEST_CASE_BODY(require_machine_many_ok) {
214    vars_map metadata;
215    metadata["require.machine"] = "__foo__ " +
216        tools::config::get("atf_machine") + " __bar__";
217    do_check("", metadata);
218}
219
220ATF_TEST_CASE(require_machine_many_fail);
221ATF_TEST_CASE_HEAD(require_machine_many_fail) {}
222ATF_TEST_CASE_BODY(require_machine_many_fail) {
223    vars_map metadata;
224    metadata["require.machine"] = "__foo__ __bar__ __baz__";
225    do_check("Requires one of the '__foo__ __bar__ __baz__' machine types",
226             metadata);
227}
228
229// -------------------------------------------------------------------------
230// Tests for the require.memory metadata property.
231// -------------------------------------------------------------------------
232
233ATF_TEST_CASE_WITHOUT_HEAD(require_memory_ok);
234ATF_TEST_CASE_BODY(require_memory_ok) {
235    vars_map metadata;
236    metadata["require.memory"] = "1m";
237    do_check("", metadata);
238}
239
240ATF_TEST_CASE_WITHOUT_HEAD(require_memory_not_enough);
241ATF_TEST_CASE_BODY(require_memory_not_enough) {
242    vars_map metadata;
243    metadata["require.memory"] = "128t";
244    do_check("Not enough memory; needed 140737488355328, available [0-9]*",
245             metadata);
246}
247
248ATF_TEST_CASE_WITHOUT_HEAD(require_memory_fail);
249ATF_TEST_CASE_BODY(require_memory_fail) {
250    vars_map metadata;
251    metadata["require.memory"] = "foo";
252    ATF_REQUIRE_THROW(std::runtime_error,
253                      impl::check_requirements(metadata, no_config));
254}
255
256// -------------------------------------------------------------------------
257// Tests for the require.progs metadata property.
258// -------------------------------------------------------------------------
259
260ATF_TEST_CASE(require_progs_one_ok);
261ATF_TEST_CASE_HEAD(require_progs_one_ok) {}
262ATF_TEST_CASE_BODY(require_progs_one_ok) {
263    vars_map metadata;
264    metadata["require.progs"] = "cp";
265    do_check("", metadata);
266}
267
268ATF_TEST_CASE(require_progs_one_missing);
269ATF_TEST_CASE_HEAD(require_progs_one_missing) {}
270ATF_TEST_CASE_BODY(require_progs_one_missing) {
271    vars_map metadata;
272    metadata["require.progs"] = "cp __non-existent__";
273    do_check("Required program '__non-existent__' not found in the PATH",
274             metadata);
275}
276
277ATF_TEST_CASE(require_progs_one_fail);
278ATF_TEST_CASE_HEAD(require_progs_one_fail) {}
279ATF_TEST_CASE_BODY(require_progs_one_fail) {
280    vars_map metadata;
281    metadata["require.progs"] = "bin/cp";
282    ATF_REQUIRE_THROW(std::runtime_error,
283                    impl::check_requirements(metadata, no_config));
284}
285
286ATF_TEST_CASE(require_progs_many_ok);
287ATF_TEST_CASE_HEAD(require_progs_many_ok) {}
288ATF_TEST_CASE_BODY(require_progs_many_ok) {
289    vars_map metadata;
290    metadata["require.progs"] = "cp ls mv";
291    do_check("", metadata);
292}
293
294ATF_TEST_CASE(require_progs_many_missing);
295ATF_TEST_CASE_HEAD(require_progs_many_missing) {}
296ATF_TEST_CASE_BODY(require_progs_many_missing) {
297    vars_map metadata;
298    metadata["require.progs"] = "mv ls __foo__ cp";
299    do_check("Required program '__foo__' not found in the PATH", metadata);
300}
301
302ATF_TEST_CASE(require_progs_many_fail);
303ATF_TEST_CASE_HEAD(require_progs_many_fail) {}
304ATF_TEST_CASE_BODY(require_progs_many_fail) {
305    vars_map metadata;
306    metadata["require.progs"] = "ls cp ../bin/cp";
307    ATF_REQUIRE_THROW(std::runtime_error,
308                    impl::check_requirements(metadata, no_config));
309}
310
311// -------------------------------------------------------------------------
312// Tests for the require.user metadata property.
313// -------------------------------------------------------------------------
314
315ATF_TEST_CASE(require_user_root);
316ATF_TEST_CASE_HEAD(require_user_root) {}
317ATF_TEST_CASE_BODY(require_user_root) {
318    vars_map metadata;
319    metadata["require.user"] = "root";
320    if (tools::user::is_root())
321        do_check("", metadata);
322    else
323        do_check("Requires root privileges", metadata);
324}
325
326ATF_TEST_CASE(require_user_unprivileged);
327ATF_TEST_CASE_HEAD(require_user_unprivileged) {}
328ATF_TEST_CASE_BODY(require_user_unprivileged) {
329    vars_map metadata;
330    metadata["require.user"] = "unprivileged";
331    if (tools::user::is_root())
332        do_check("Requires an unprivileged user and the 'unprivileged-user' "
333                 "configuration variable is not set", metadata);
334    else
335        do_check("", metadata);
336}
337
338ATF_TEST_CASE(require_user_fail);
339ATF_TEST_CASE_HEAD(require_user_fail) {}
340ATF_TEST_CASE_BODY(require_user_fail) {
341    vars_map metadata;
342    metadata["require.user"] = "nobody";
343    ATF_REQUIRE_THROW(std::runtime_error,
344                    impl::check_requirements(metadata, no_config));
345}
346
347// -------------------------------------------------------------------------
348// Main.
349// -------------------------------------------------------------------------
350
351ATF_INIT_TEST_CASES(tcs)
352{
353    // Add test cases for require.arch.
354    ATF_ADD_TEST_CASE(tcs, require_arch_one_ok);
355    ATF_ADD_TEST_CASE(tcs, require_arch_one_fail);
356    ATF_ADD_TEST_CASE(tcs, require_arch_many_ok);
357    ATF_ADD_TEST_CASE(tcs, require_arch_many_fail);
358
359    // Add test cases for require.config.
360    ATF_ADD_TEST_CASE(tcs, require_config_one_ok);
361    ATF_ADD_TEST_CASE(tcs, require_config_one_fail);
362    ATF_ADD_TEST_CASE(tcs, require_config_many_ok);
363    ATF_ADD_TEST_CASE(tcs, require_config_many_fail);
364
365    // Add test cases for require.files.
366    ATF_ADD_TEST_CASE(tcs, require_files_one_ok);
367    ATF_ADD_TEST_CASE(tcs, require_files_one_missing);
368    ATF_ADD_TEST_CASE(tcs, require_files_one_fail);
369    ATF_ADD_TEST_CASE(tcs, require_files_many_ok);
370    ATF_ADD_TEST_CASE(tcs, require_files_many_missing);
371    ATF_ADD_TEST_CASE(tcs, require_files_many_fail);
372
373    // Add test cases for require.machine.
374    ATF_ADD_TEST_CASE(tcs, require_machine_one_ok);
375    ATF_ADD_TEST_CASE(tcs, require_machine_one_fail);
376    ATF_ADD_TEST_CASE(tcs, require_machine_many_ok);
377    ATF_ADD_TEST_CASE(tcs, require_machine_many_fail);
378
379    // Add test cases for require.memory.
380    ATF_ADD_TEST_CASE(tcs, require_memory_ok);
381    ATF_ADD_TEST_CASE(tcs, require_memory_not_enough);
382    ATF_ADD_TEST_CASE(tcs, require_memory_fail);
383
384    // Add test cases for require.progs.
385    ATF_ADD_TEST_CASE(tcs, require_progs_one_ok);
386    ATF_ADD_TEST_CASE(tcs, require_progs_one_missing);
387    ATF_ADD_TEST_CASE(tcs, require_progs_one_fail);
388    ATF_ADD_TEST_CASE(tcs, require_progs_many_ok);
389    ATF_ADD_TEST_CASE(tcs, require_progs_many_missing);
390    ATF_ADD_TEST_CASE(tcs, require_progs_many_fail);
391
392    // Add test cases for require.user.
393    ATF_ADD_TEST_CASE(tcs, require_user_root);
394    ATF_ADD_TEST_CASE(tcs, require_user_unprivileged);
395    ATF_ADD_TEST_CASE(tcs, require_user_fail);
396}
397