Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/kyua/utils/fs/operations_test.cpp
48081 views
1
// Copyright 2010 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 "utils/fs/operations.hpp"
30
31
extern "C" {
32
#include <sys/types.h>
33
#include <sys/stat.h>
34
#include <sys/wait.h>
35
36
#include <dirent.h>
37
#include <signal.h>
38
#include <unistd.h>
39
}
40
41
#include <cerrno>
42
#include <cstdlib>
43
#include <cstring>
44
#include <iostream>
45
#include <stdexcept>
46
#include <string>
47
#include <vector>
48
49
#include <atf-c++.hpp>
50
51
#include "utils/env.hpp"
52
#include "utils/format/containers.ipp"
53
#include "utils/format/macros.hpp"
54
#include "utils/fs/directory.hpp"
55
#include "utils/fs/exceptions.hpp"
56
#include "utils/fs/path.hpp"
57
#include "utils/optional.ipp"
58
#include "utils/passwd.hpp"
59
#include "utils/stream.hpp"
60
#include "utils/units.hpp"
61
62
namespace fs = utils::fs;
63
namespace passwd = utils::passwd;
64
namespace units = utils::units;
65
66
using utils::optional;
67
68
69
namespace {
70
71
72
/// Checks if a directory entry exists and matches a specific type.
73
///
74
/// \param dir The directory in which to look for the entry.
75
/// \param name The name of the entry to look up.
76
/// \param expected_type The expected type of the file as given by dir(5).
77
///
78
/// \return True if the entry exists and matches the given type; false
79
/// otherwise.
80
static bool
81
lookup(const char* dir, const char* name, const unsigned int expected_type)
82
{
83
DIR* dirp = ::opendir(dir);
84
ATF_REQUIRE(dirp != NULL);
85
86
bool found = false;
87
struct dirent* dp;
88
while (!found && (dp = readdir(dirp)) != NULL) {
89
if (std::strcmp(dp->d_name, name) == 0) {
90
struct ::stat s;
91
const fs::path lookup_path = fs::path(dir) / name;
92
ATF_REQUIRE(::stat(lookup_path.c_str(), &s) != -1);
93
if ((s.st_mode & S_IFMT) == expected_type) {
94
found = true;
95
}
96
}
97
}
98
::closedir(dirp);
99
return found;
100
}
101
102
103
} // anonymous namespace
104
105
106
ATF_TEST_CASE_WITHOUT_HEAD(copy__ok);
107
ATF_TEST_CASE_BODY(copy__ok)
108
{
109
const fs::path source("f1.txt");
110
const fs::path target("f2.txt");
111
112
atf::utils::create_file(source.str(), "This is the input");
113
fs::copy(source, target);
114
ATF_REQUIRE(atf::utils::compare_file(target.str(), "This is the input"));
115
}
116
117
118
ATF_TEST_CASE_WITHOUT_HEAD(copy__fail_open);
119
ATF_TEST_CASE_BODY(copy__fail_open)
120
{
121
const fs::path source("f1.txt");
122
const fs::path target("f2.txt");
123
124
ATF_REQUIRE_THROW_RE(fs::error, "Cannot open copy source f1.txt",
125
fs::copy(source, target));
126
}
127
128
129
ATF_TEST_CASE(copy__fail_create);
130
ATF_TEST_CASE_HEAD(copy__fail_create)
131
{
132
set_md_var("require.user", "unprivileged");
133
}
134
ATF_TEST_CASE_BODY(copy__fail_create)
135
{
136
const fs::path source("f1.txt");
137
const fs::path target("f2.txt");
138
139
atf::utils::create_file(target.str(), "Do not override");
140
ATF_REQUIRE(::chmod(target.c_str(), 0444) != -1);
141
142
atf::utils::create_file(source.str(), "This is the input");
143
ATF_REQUIRE_THROW_RE(fs::error, "Cannot create copy target f2.txt",
144
fs::copy(source, target));
145
}
146
147
148
ATF_TEST_CASE_WITHOUT_HEAD(current_path__ok);
149
ATF_TEST_CASE_BODY(current_path__ok)
150
{
151
const fs::path previous = fs::current_path();
152
fs::mkdir(fs::path("root"), 0755);
153
ATF_REQUIRE(::chdir("root") != -1);
154
const fs::path cwd = fs::current_path();
155
ATF_REQUIRE_EQ(cwd.str().length() - 5, cwd.str().find("/root"));
156
ATF_REQUIRE_EQ(previous / "root", cwd);
157
}
158
159
160
ATF_TEST_CASE_WITHOUT_HEAD(current_path__enoent);
161
ATF_TEST_CASE_BODY(current_path__enoent)
162
{
163
const fs::path previous = fs::current_path();
164
fs::mkdir(fs::path("root"), 0755);
165
ATF_REQUIRE(::chdir("root") != -1);
166
ATF_REQUIRE(::rmdir("../root") != -1);
167
try {
168
(void)fs::current_path();
169
fail("system_errpr not raised");
170
} catch (const fs::system_error& e) {
171
ATF_REQUIRE_EQ(ENOENT, e.original_errno());
172
}
173
}
174
175
176
ATF_TEST_CASE_WITHOUT_HEAD(exists);
177
ATF_TEST_CASE_BODY(exists)
178
{
179
const fs::path dir("dir");
180
ATF_REQUIRE(!fs::exists(dir));
181
fs::mkdir(dir, 0755);
182
ATF_REQUIRE(fs::exists(dir));
183
}
184
185
186
ATF_TEST_CASE_WITHOUT_HEAD(find_in_path__no_path);
187
ATF_TEST_CASE_BODY(find_in_path__no_path)
188
{
189
utils::unsetenv("PATH");
190
ATF_REQUIRE(!fs::find_in_path("ls"));
191
atf::utils::create_file("ls", "");
192
ATF_REQUIRE(!fs::find_in_path("ls"));
193
}
194
195
196
ATF_TEST_CASE_WITHOUT_HEAD(find_in_path__empty_path);
197
ATF_TEST_CASE_BODY(find_in_path__empty_path)
198
{
199
utils::setenv("PATH", "");
200
ATF_REQUIRE(!fs::find_in_path("ls"));
201
atf::utils::create_file("ls", "");
202
ATF_REQUIRE(!fs::find_in_path("ls"));
203
}
204
205
206
ATF_TEST_CASE_WITHOUT_HEAD(find_in_path__one_component);
207
ATF_TEST_CASE_BODY(find_in_path__one_component)
208
{
209
const fs::path dir = fs::current_path() / "bin";
210
fs::mkdir(dir, 0755);
211
utils::setenv("PATH", dir.str());
212
213
ATF_REQUIRE(!fs::find_in_path("ls"));
214
atf::utils::create_file((dir / "ls").str(), "");
215
ATF_REQUIRE_EQ(dir / "ls", fs::find_in_path("ls").get());
216
}
217
218
219
ATF_TEST_CASE_WITHOUT_HEAD(find_in_path__many_components);
220
ATF_TEST_CASE_BODY(find_in_path__many_components)
221
{
222
const fs::path dir1 = fs::current_path() / "dir1";
223
const fs::path dir2 = fs::current_path() / "dir2";
224
fs::mkdir(dir1, 0755);
225
fs::mkdir(dir2, 0755);
226
utils::setenv("PATH", dir1.str() + ":" + dir2.str());
227
228
ATF_REQUIRE(!fs::find_in_path("ls"));
229
atf::utils::create_file((dir2 / "ls").str(), "");
230
ATF_REQUIRE_EQ(dir2 / "ls", fs::find_in_path("ls").get());
231
atf::utils::create_file((dir1 / "ls").str(), "");
232
ATF_REQUIRE_EQ(dir1 / "ls", fs::find_in_path("ls").get());
233
}
234
235
236
ATF_TEST_CASE_WITHOUT_HEAD(find_in_path__current_directory);
237
ATF_TEST_CASE_BODY(find_in_path__current_directory)
238
{
239
utils::setenv("PATH", "bin:");
240
241
ATF_REQUIRE(!fs::find_in_path("foo-bar"));
242
atf::utils::create_file("foo-bar", "");
243
ATF_REQUIRE_EQ(fs::path("foo-bar").to_absolute(),
244
fs::find_in_path("foo-bar").get());
245
}
246
247
248
ATF_TEST_CASE_WITHOUT_HEAD(find_in_path__always_absolute);
249
ATF_TEST_CASE_BODY(find_in_path__always_absolute)
250
{
251
fs::mkdir(fs::path("my-bin"), 0755);
252
utils::setenv("PATH", "my-bin");
253
254
ATF_REQUIRE(!fs::find_in_path("abcd"));
255
atf::utils::create_file("my-bin/abcd", "");
256
ATF_REQUIRE_EQ(fs::path("my-bin/abcd").to_absolute(),
257
fs::find_in_path("abcd").get());
258
}
259
260
261
ATF_TEST_CASE_WITHOUT_HEAD(free_disk_space__ok__smoke);
262
ATF_TEST_CASE_BODY(free_disk_space__ok__smoke)
263
{
264
const units::bytes space = fs::free_disk_space(fs::path("."));
265
ATF_REQUIRE(space > units::MB); // Simple test that should always pass.
266
}
267
268
269
/// Unmounts a directory without raising errors.
270
///
271
/// \param cookie Name of a file that exists while the mount point is still
272
/// mounted. Used to prevent a double-unmount, which would print a
273
/// misleading error message.
274
/// \param mount_point Path to the mount point to unmount.
275
static void
276
cleanup_mount_point(const fs::path& cookie, const fs::path& mount_point)
277
{
278
try {
279
if (fs::exists(cookie)) {
280
fs::unmount(mount_point);
281
}
282
} catch (const std::runtime_error& e) {
283
std::cerr << "Failed trying to unmount " + mount_point.str() +
284
" during cleanup: " << e.what() << '\n';
285
}
286
}
287
288
289
ATF_TEST_CASE_WITH_CLEANUP(free_disk_space__ok__real);
290
ATF_TEST_CASE_HEAD(free_disk_space__ok__real)
291
{
292
set_md_var("require.user", "root");
293
}
294
ATF_TEST_CASE_BODY(free_disk_space__ok__real)
295
{
296
try {
297
const fs::path mount_point("mount_point");
298
fs::mkdir(mount_point, 0755);
299
fs::mount_tmpfs(mount_point, units::bytes(32 * units::MB));
300
atf::utils::create_file("mounted", "");
301
const units::bytes space = fs::free_disk_space(fs::path(mount_point));
302
fs::unmount(mount_point);
303
fs::unlink(fs::path("mounted"));
304
ATF_REQUIRE(space < 35 * units::MB);
305
ATF_REQUIRE(space > 28 * units::MB);
306
} catch (const fs::unsupported_operation_error& e) {
307
ATF_SKIP(e.what());
308
}
309
}
310
ATF_TEST_CASE_CLEANUP(free_disk_space__ok__real)
311
{
312
cleanup_mount_point(fs::path("mounted"), fs::path("mount_point"));
313
}
314
315
316
ATF_TEST_CASE_WITHOUT_HEAD(free_disk_space__fail);
317
ATF_TEST_CASE_BODY(free_disk_space__fail)
318
{
319
ATF_REQUIRE_THROW_RE(fs::error, "Failed to stat file system for missing",
320
fs::free_disk_space(fs::path("missing")));
321
}
322
323
324
ATF_TEST_CASE_WITHOUT_HEAD(is_directory__ok);
325
ATF_TEST_CASE_BODY(is_directory__ok)
326
{
327
const fs::path file("file");
328
atf::utils::create_file(file.str(), "");
329
ATF_REQUIRE(!fs::is_directory(file));
330
331
const fs::path dir("dir");
332
fs::mkdir(dir, 0755);
333
ATF_REQUIRE(fs::is_directory(dir));
334
}
335
336
337
ATF_TEST_CASE_WITH_CLEANUP(is_directory__fail);
338
ATF_TEST_CASE_HEAD(is_directory__fail)
339
{
340
set_md_var("require.user", "unprivileged");
341
}
342
ATF_TEST_CASE_BODY(is_directory__fail)
343
{
344
fs::mkdir(fs::path("dir"), 0000);
345
ATF_REQUIRE_THROW(fs::error, fs::is_directory(fs::path("dir/foo")));
346
}
347
ATF_TEST_CASE_CLEANUP(is_directory__fail)
348
{
349
if (::chmod("dir", 0755) == -1) {
350
// If we cannot restore the original permissions, we cannot do much
351
// more. However, leaving an unwritable directory behind will cause the
352
// runtime engine to report us as broken.
353
}
354
}
355
356
357
ATF_TEST_CASE_WITHOUT_HEAD(mkdir__ok);
358
ATF_TEST_CASE_BODY(mkdir__ok)
359
{
360
fs::mkdir(fs::path("dir"), 0755);
361
ATF_REQUIRE(lookup(".", "dir", S_IFDIR));
362
}
363
364
365
ATF_TEST_CASE_WITHOUT_HEAD(mkdir__enoent);
366
ATF_TEST_CASE_BODY(mkdir__enoent)
367
{
368
try {
369
fs::mkdir(fs::path("dir1/dir2"), 0755);
370
fail("system_error not raised");
371
} catch (const fs::system_error& e) {
372
ATF_REQUIRE_EQ(ENOENT, e.original_errno());
373
}
374
ATF_REQUIRE(!lookup(".", "dir1", S_IFDIR));
375
ATF_REQUIRE(!lookup(".", "dir2", S_IFDIR));
376
}
377
378
379
ATF_TEST_CASE_WITHOUT_HEAD(mkdir_p__one_component);
380
ATF_TEST_CASE_BODY(mkdir_p__one_component)
381
{
382
ATF_REQUIRE(!lookup(".", "new-dir", S_IFDIR));
383
fs::mkdir_p(fs::path("new-dir"), 0755);
384
ATF_REQUIRE(lookup(".", "new-dir", S_IFDIR));
385
}
386
387
388
ATF_TEST_CASE_WITHOUT_HEAD(mkdir_p__many_components);
389
ATF_TEST_CASE_BODY(mkdir_p__many_components)
390
{
391
ATF_REQUIRE(!lookup(".", "a", S_IFDIR));
392
fs::mkdir_p(fs::path("a/b/c"), 0755);
393
ATF_REQUIRE(lookup(".", "a", S_IFDIR));
394
ATF_REQUIRE(lookup("a", "b", S_IFDIR));
395
ATF_REQUIRE(lookup("a/b", "c", S_IFDIR));
396
}
397
398
399
ATF_TEST_CASE_WITHOUT_HEAD(mkdir_p__already_exists);
400
ATF_TEST_CASE_BODY(mkdir_p__already_exists)
401
{
402
fs::mkdir(fs::path("a"), 0755);
403
fs::mkdir(fs::path("a/b"), 0755);
404
fs::mkdir_p(fs::path("a/b"), 0755);
405
}
406
407
408
ATF_TEST_CASE(mkdir_p__eacces)
409
ATF_TEST_CASE_HEAD(mkdir_p__eacces)
410
{
411
set_md_var("require.user", "unprivileged");
412
}
413
ATF_TEST_CASE_BODY(mkdir_p__eacces)
414
{
415
fs::mkdir(fs::path("a"), 0755);
416
fs::mkdir(fs::path("a/b"), 0755);
417
ATF_REQUIRE(::chmod("a/b", 0555) != -1);
418
try {
419
fs::mkdir_p(fs::path("a/b/c/d"), 0755);
420
fail("system_error not raised");
421
} catch (const fs::system_error& e) {
422
ATF_REQUIRE_EQ(EACCES, e.original_errno());
423
}
424
ATF_REQUIRE(lookup(".", "a", S_IFDIR));
425
ATF_REQUIRE(lookup("a", "b", S_IFDIR));
426
ATF_REQUIRE(!lookup(".", "c", S_IFDIR));
427
ATF_REQUIRE(!lookup("a", "c", S_IFDIR));
428
ATF_REQUIRE(!lookup("a/b", "c", S_IFDIR));
429
}
430
431
432
ATF_TEST_CASE_WITHOUT_HEAD(mkdtemp_public)
433
ATF_TEST_CASE_BODY(mkdtemp_public)
434
{
435
const fs::path tmpdir = fs::current_path() / "tmp";
436
utils::setenv("TMPDIR", tmpdir.str());
437
fs::mkdir(tmpdir, 0755);
438
439
const std::string dir_template("tempdir.XXXXXX");
440
const fs::path tempdir = fs::mkdtemp_public(dir_template);
441
ATF_REQUIRE(!lookup("tmp", dir_template.c_str(), S_IFDIR));
442
ATF_REQUIRE(lookup("tmp", tempdir.leaf_name().c_str(), S_IFDIR));
443
}
444
445
446
ATF_TEST_CASE(mkdtemp_public__getcwd_as_non_root)
447
ATF_TEST_CASE_HEAD(mkdtemp_public__getcwd_as_non_root)
448
{
449
set_md_var("require.config", "unprivileged-user");
450
set_md_var("require.user", "root");
451
}
452
ATF_TEST_CASE_BODY(mkdtemp_public__getcwd_as_non_root)
453
{
454
const std::string dir_template("dir.XXXXXX");
455
const fs::path dir = fs::mkdtemp_public(dir_template);
456
const fs::path subdir = dir / "subdir";
457
fs::mkdir(subdir, 0755);
458
459
const uid_t old_euid = ::geteuid();
460
const gid_t old_egid = ::getegid();
461
462
const passwd::user unprivileged_user = passwd::find_user_by_name(
463
get_config_var("unprivileged-user"));
464
ATF_REQUIRE(::setegid(unprivileged_user.gid) != -1);
465
ATF_REQUIRE(::seteuid(unprivileged_user.uid) != -1);
466
467
// The next code block runs as non-root. We cannot use any ATF macros nor
468
// functions in it because a failure would cause the test to attempt to
469
// write to the ATF result file which may not be writable as non-root.
470
bool failed = false;
471
{
472
try {
473
if (::chdir(subdir.c_str()) == -1) {
474
std::cerr << "Cannot enter directory\n";
475
failed |= true;
476
} else {
477
fs::current_path();
478
}
479
} catch (const fs::error& e) {
480
failed |= true;
481
std::cerr << "Failed to query current path in: " << subdir << '\n';
482
}
483
484
if (::seteuid(old_euid) == -1) {
485
std::cerr << "Failed to restore euid; cannot continue\n";
486
std::abort();
487
}
488
if (::setegid(old_egid) == -1) {
489
std::cerr << "Failed to restore egid; cannot continue\n";
490
std::abort();
491
}
492
}
493
494
if (failed)
495
fail("Test failed; see stdout for details");
496
}
497
498
499
ATF_TEST_CASE(mkdtemp_public__search_permissions_as_non_root)
500
ATF_TEST_CASE_HEAD(mkdtemp_public__search_permissions_as_non_root)
501
{
502
set_md_var("require.config", "unprivileged-user");
503
set_md_var("require.user", "root");
504
}
505
ATF_TEST_CASE_BODY(mkdtemp_public__search_permissions_as_non_root)
506
{
507
const std::string dir_template("dir.XXXXXX");
508
const fs::path dir = fs::mkdtemp_public(dir_template);
509
const fs::path cookie = dir / "not-secret";
510
atf::utils::create_file(cookie.str(), "this is readable");
511
512
// We are running as root so there is no reason to assume that our current
513
// work directory is accessible by non-root. Weaken the permissions so that
514
// our code below works.
515
ATF_REQUIRE(::chmod(".", 0755) != -1);
516
517
const uid_t old_euid = ::geteuid();
518
const gid_t old_egid = ::getegid();
519
520
const passwd::user unprivileged_user = passwd::find_user_by_name(
521
get_config_var("unprivileged-user"));
522
ATF_REQUIRE(::setegid(unprivileged_user.gid) != -1);
523
ATF_REQUIRE(::seteuid(unprivileged_user.uid) != -1);
524
525
// The next code block runs as non-root. We cannot use any ATF macros nor
526
// functions in it because a failure would cause the test to attempt to
527
// write to the ATF result file which may not be writable as non-root.
528
bool failed = false;
529
{
530
try {
531
const std::string contents = utils::read_file(cookie);
532
std::cerr << "Read contents: " << contents << '\n';
533
failed |= (contents != "this is readable");
534
} catch (const std::runtime_error& e) {
535
failed |= true;
536
std::cerr << "Failed to read " << cookie << '\n';
537
}
538
539
if (::seteuid(old_euid) == -1) {
540
std::cerr << "Failed to restore euid; cannot continue\n";
541
std::abort();
542
}
543
if (::setegid(old_egid) == -1) {
544
std::cerr << "Failed to restore egid; cannot continue\n";
545
std::abort();
546
}
547
}
548
549
if (failed)
550
fail("Test failed; see stdout for details");
551
}
552
553
554
ATF_TEST_CASE_WITHOUT_HEAD(mkstemp)
555
ATF_TEST_CASE_BODY(mkstemp)
556
{
557
const fs::path tmpdir = fs::current_path() / "tmp";
558
utils::setenv("TMPDIR", tmpdir.str());
559
fs::mkdir(tmpdir, 0755);
560
561
const std::string file_template("tempfile.XXXXXX");
562
const fs::path tempfile = fs::mkstemp(file_template);
563
ATF_REQUIRE(!lookup("tmp", file_template.c_str(), S_IFREG));
564
ATF_REQUIRE(lookup("tmp", tempfile.leaf_name().c_str(), S_IFREG));
565
}
566
567
568
static void
569
test_mount_tmpfs_ok(const units::bytes& size)
570
{
571
const fs::path mount_point("mount_point");
572
fs::mkdir(mount_point, 0755);
573
574
try {
575
atf::utils::create_file("outside", "");
576
fs::mount_tmpfs(mount_point, size);
577
atf::utils::create_file("mounted", "");
578
atf::utils::create_file((mount_point / "inside").str(), "");
579
580
struct ::stat outside, inside;
581
ATF_REQUIRE(::stat("outside", &outside) != -1);
582
ATF_REQUIRE(::stat((mount_point / "inside").c_str(), &inside) != -1);
583
ATF_REQUIRE(outside.st_dev != inside.st_dev);
584
fs::unmount(mount_point);
585
} catch (const fs::unsupported_operation_error& e) {
586
ATF_SKIP(e.what());
587
}
588
}
589
590
591
ATF_TEST_CASE_WITH_CLEANUP(mount_tmpfs__ok__default_size)
592
ATF_TEST_CASE_HEAD(mount_tmpfs__ok__default_size)
593
{
594
set_md_var("require.user", "root");
595
}
596
ATF_TEST_CASE_BODY(mount_tmpfs__ok__default_size)
597
{
598
test_mount_tmpfs_ok(units::bytes());
599
}
600
ATF_TEST_CASE_CLEANUP(mount_tmpfs__ok__default_size)
601
{
602
cleanup_mount_point(fs::path("mounted"), fs::path("mount_point"));
603
}
604
605
606
ATF_TEST_CASE_WITH_CLEANUP(mount_tmpfs__ok__explicit_size)
607
ATF_TEST_CASE_HEAD(mount_tmpfs__ok__explicit_size)
608
{
609
set_md_var("require.user", "root");
610
}
611
ATF_TEST_CASE_BODY(mount_tmpfs__ok__explicit_size)
612
{
613
test_mount_tmpfs_ok(units::bytes(10 * units::MB));
614
}
615
ATF_TEST_CASE_CLEANUP(mount_tmpfs__ok__explicit_size)
616
{
617
cleanup_mount_point(fs::path("mounted"), fs::path("mount_point"));
618
}
619
620
621
ATF_TEST_CASE(mount_tmpfs__fail)
622
ATF_TEST_CASE_HEAD(mount_tmpfs__fail)
623
{
624
set_md_var("require.user", "root");
625
}
626
ATF_TEST_CASE_BODY(mount_tmpfs__fail)
627
{
628
try {
629
fs::mount_tmpfs(fs::path("non-existent"));
630
} catch (const fs::unsupported_operation_error& e) {
631
ATF_SKIP(e.what());
632
} catch (const fs::error& e) {
633
// Expected.
634
}
635
}
636
637
638
ATF_TEST_CASE_WITHOUT_HEAD(rm_r__empty);
639
ATF_TEST_CASE_BODY(rm_r__empty)
640
{
641
fs::mkdir(fs::path("root"), 0755);
642
ATF_REQUIRE(lookup(".", "root", S_IFDIR));
643
fs::rm_r(fs::path("root"));
644
ATF_REQUIRE(!lookup(".", "root", S_IFDIR));
645
}
646
647
648
ATF_TEST_CASE_WITHOUT_HEAD(rm_r__files_and_directories);
649
ATF_TEST_CASE_BODY(rm_r__files_and_directories)
650
{
651
fs::mkdir(fs::path("root"), 0755);
652
atf::utils::create_file("root/.hidden_file", "");
653
fs::mkdir(fs::path("root/.hidden_dir"), 0755);
654
atf::utils::create_file("root/.hidden_dir/a", "");
655
atf::utils::create_file("root/file", "");
656
atf::utils::create_file("root/with spaces", "");
657
fs::mkdir(fs::path("root/dir1"), 0755);
658
fs::mkdir(fs::path("root/dir1/dir2"), 0755);
659
atf::utils::create_file("root/dir1/dir2/file", "");
660
fs::mkdir(fs::path("root/dir1/dir3"), 0755);
661
ATF_REQUIRE(lookup(".", "root", S_IFDIR));
662
fs::rm_r(fs::path("root"));
663
ATF_REQUIRE(!lookup(".", "root", S_IFDIR));
664
}
665
666
667
ATF_TEST_CASE_WITHOUT_HEAD(rm_r__bad_perms);
668
ATF_TEST_CASE_BODY(rm_r__bad_perms)
669
{
670
fs::mkdir(fs::path("root"), 0755);
671
fs::mkdir(fs::path("root/dir"), 0755);
672
atf::utils::create_file("root/dir/file", "");
673
::chmod(fs::path("root/dir").c_str(), 0000);
674
ATF_REQUIRE(lookup(".", "root", S_IFDIR));
675
fs::rm_r(fs::path("root"));
676
ATF_REQUIRE(!lookup(".", "root", S_IFDIR));
677
}
678
679
680
ATF_TEST_CASE_WITHOUT_HEAD(rmdir__ok)
681
ATF_TEST_CASE_BODY(rmdir__ok)
682
{
683
ATF_REQUIRE(::mkdir("foo", 0755) != -1);
684
ATF_REQUIRE(::access("foo", X_OK) == 0);
685
fs::rmdir(fs::path("foo"));
686
ATF_REQUIRE(::access("foo", X_OK) == -1);
687
}
688
689
690
ATF_TEST_CASE_WITHOUT_HEAD(rmdir__fail)
691
ATF_TEST_CASE_BODY(rmdir__fail)
692
{
693
ATF_REQUIRE_THROW_RE(fs::system_error, "Removal of foo failed",
694
fs::rmdir(fs::path("foo")));
695
}
696
697
698
ATF_TEST_CASE_WITHOUT_HEAD(scan_directory__ok)
699
ATF_TEST_CASE_BODY(scan_directory__ok)
700
{
701
fs::mkdir(fs::path("dir"), 0755);
702
atf::utils::create_file("dir/foo", "");
703
atf::utils::create_file("dir/.hidden", "");
704
705
const std::set< fs::directory_entry > contents = fs::scan_directory(
706
fs::path("dir"));
707
708
std::set< fs::directory_entry > exp_contents;
709
exp_contents.insert(fs::directory_entry("."));
710
exp_contents.insert(fs::directory_entry(".."));
711
exp_contents.insert(fs::directory_entry(".hidden"));
712
exp_contents.insert(fs::directory_entry("foo"));
713
714
ATF_REQUIRE_EQ(exp_contents, contents);
715
}
716
717
718
ATF_TEST_CASE_WITHOUT_HEAD(scan_directory__fail)
719
ATF_TEST_CASE_BODY(scan_directory__fail)
720
{
721
ATF_REQUIRE_THROW_RE(fs::system_error, "opendir(.*missing.*) failed",
722
fs::scan_directory(fs::path("missing")));
723
}
724
725
726
ATF_TEST_CASE_WITHOUT_HEAD(unlink__ok)
727
ATF_TEST_CASE_BODY(unlink__ok)
728
{
729
atf::utils::create_file("foo", "");
730
ATF_REQUIRE(::access("foo", R_OK) == 0);
731
fs::unlink(fs::path("foo"));
732
ATF_REQUIRE(::access("foo", R_OK) == -1);
733
}
734
735
736
ATF_TEST_CASE_WITHOUT_HEAD(unlink__fail)
737
ATF_TEST_CASE_BODY(unlink__fail)
738
{
739
ATF_REQUIRE_THROW_RE(fs::system_error, "Removal of foo failed",
740
fs::unlink(fs::path("foo")));
741
}
742
743
744
ATF_TEST_CASE(unmount__ok)
745
ATF_TEST_CASE_HEAD(unmount__ok)
746
{
747
set_md_var("require.user", "root");
748
}
749
ATF_TEST_CASE_BODY(unmount__ok)
750
{
751
const fs::path mount_point("mount_point");
752
fs::mkdir(mount_point, 0755);
753
754
atf::utils::create_file((mount_point / "test1").str(), "");
755
try {
756
fs::mount_tmpfs(mount_point);
757
} catch (const fs::unsupported_operation_error& e) {
758
ATF_SKIP(e.what());
759
}
760
761
atf::utils::create_file((mount_point / "test2").str(), "");
762
763
ATF_REQUIRE(!fs::exists(mount_point / "test1"));
764
ATF_REQUIRE( fs::exists(mount_point / "test2"));
765
fs::unmount(mount_point);
766
ATF_REQUIRE( fs::exists(mount_point / "test1"));
767
ATF_REQUIRE(!fs::exists(mount_point / "test2"));
768
}
769
770
771
ATF_TEST_CASE(unmount__fail)
772
ATF_TEST_CASE_HEAD(unmount__fail)
773
{
774
set_md_var("require.user", "root");
775
}
776
ATF_TEST_CASE_BODY(unmount__fail)
777
{
778
ATF_REQUIRE_THROW(fs::error, fs::unmount(fs::path("non-existent")));
779
}
780
781
782
ATF_INIT_TEST_CASES(tcs)
783
{
784
ATF_ADD_TEST_CASE(tcs, copy__ok);
785
ATF_ADD_TEST_CASE(tcs, copy__fail_open);
786
ATF_ADD_TEST_CASE(tcs, copy__fail_create);
787
788
ATF_ADD_TEST_CASE(tcs, current_path__ok);
789
ATF_ADD_TEST_CASE(tcs, current_path__enoent);
790
791
ATF_ADD_TEST_CASE(tcs, exists);
792
793
ATF_ADD_TEST_CASE(tcs, find_in_path__no_path);
794
ATF_ADD_TEST_CASE(tcs, find_in_path__empty_path);
795
ATF_ADD_TEST_CASE(tcs, find_in_path__one_component);
796
ATF_ADD_TEST_CASE(tcs, find_in_path__many_components);
797
ATF_ADD_TEST_CASE(tcs, find_in_path__current_directory);
798
ATF_ADD_TEST_CASE(tcs, find_in_path__always_absolute);
799
800
ATF_ADD_TEST_CASE(tcs, free_disk_space__ok__smoke);
801
ATF_ADD_TEST_CASE(tcs, free_disk_space__ok__real);
802
ATF_ADD_TEST_CASE(tcs, free_disk_space__fail);
803
804
ATF_ADD_TEST_CASE(tcs, is_directory__ok);
805
ATF_ADD_TEST_CASE(tcs, is_directory__fail);
806
807
ATF_ADD_TEST_CASE(tcs, mkdir__ok);
808
ATF_ADD_TEST_CASE(tcs, mkdir__enoent);
809
810
ATF_ADD_TEST_CASE(tcs, mkdir_p__one_component);
811
ATF_ADD_TEST_CASE(tcs, mkdir_p__many_components);
812
ATF_ADD_TEST_CASE(tcs, mkdir_p__already_exists);
813
ATF_ADD_TEST_CASE(tcs, mkdir_p__eacces);
814
815
ATF_ADD_TEST_CASE(tcs, mkdtemp_public);
816
ATF_ADD_TEST_CASE(tcs, mkdtemp_public__getcwd_as_non_root);
817
ATF_ADD_TEST_CASE(tcs, mkdtemp_public__search_permissions_as_non_root);
818
819
ATF_ADD_TEST_CASE(tcs, mkstemp);
820
821
ATF_ADD_TEST_CASE(tcs, mount_tmpfs__ok__default_size);
822
ATF_ADD_TEST_CASE(tcs, mount_tmpfs__ok__explicit_size);
823
ATF_ADD_TEST_CASE(tcs, mount_tmpfs__fail);
824
825
ATF_ADD_TEST_CASE(tcs, rm_r__empty);
826
ATF_ADD_TEST_CASE(tcs, rm_r__files_and_directories);
827
ATF_ADD_TEST_CASE(tcs, rm_r__bad_perms);
828
829
ATF_ADD_TEST_CASE(tcs, rmdir__ok);
830
ATF_ADD_TEST_CASE(tcs, rmdir__fail);
831
832
ATF_ADD_TEST_CASE(tcs, scan_directory__ok);
833
ATF_ADD_TEST_CASE(tcs, scan_directory__fail);
834
835
ATF_ADD_TEST_CASE(tcs, unlink__ok);
836
ATF_ADD_TEST_CASE(tcs, unlink__fail);
837
838
ATF_ADD_TEST_CASE(tcs, unmount__ok);
839
ATF_ADD_TEST_CASE(tcs, unmount__fail);
840
}
841
842