2 The software in this package is distributed under the GNU General
3 Public License version 2 (with a special exception described below).
5 A copy of GNU General Public License (GPL) is included in this distribution,
6 in the file COPYING.GPL.
8 As a special exception, if other files instantiate templates or use macros
9 or inline functions from this file, or you compile this file and link it
10 with other works to produce a work based on this file, this file
11 does not by itself cause the resulting work to be covered
12 by the GNU General Public License.
14 However the source code for this file must still be made available
15 in accordance with section (3) of the GNU General Public License.
17 This exception does not invalidate any other reasons why a work based
18 on this file might be covered by the GNU General Public License.
22 * tests for the modules "filefunc", "daemonfunc"
24 * (c) Copyright 2007-2008 by Intra2net AG
39 #define BOOST_TEST_DYN_LINK
40 #include <boost/test/unit_test.hpp>
42 #include <filefunc.hxx>
43 #include <daemonfunc.hpp>
44 #include <pipestream.hxx>
45 #include <stringfunc.hxx>
48 #define DOUT(msg) std::cout << msg << std::endl
50 #define DOUT(msg) do {} while (0)
56 class TestFileFuncFixture
59 typedef std::list< std::string > StringList;
60 std::set<std::string> used_check_files;
62 std::string get_check_file_path(std::string tag)
65 result= "__unittest__" + tag + ".dat";
66 used_check_files.insert(result);
68 } // eo get_check_file_path
70 void remove_check_files()
72 for (std::set<std::string>::iterator it= used_check_files.begin();
73 it != used_check_files.end();
76 std::string filepath(*it);
77 if (path_exists(filepath))
83 used_check_files.clear();
84 } // eo remove_check_files
91 ~TestFileFuncFixture()
97 BOOST_FIXTURE_TEST_SUITE(TestFileFunc, TestFileFuncFixture)
99 BOOST_AUTO_TEST_CASE(StatTest1)
101 I2n::Stat stat(__FILE__);
103 BOOST_CHECK_EQUAL( true, (bool)stat );
104 BOOST_CHECK_EQUAL( true, stat.is_regular_file() );
105 BOOST_CHECK_EQUAL( false, stat.is_directory() );
107 stat= Stat("/dev/null");
109 BOOST_CHECK_EQUAL( true, (bool)stat );
110 BOOST_CHECK_EQUAL( false, stat.is_regular_file() );
111 BOOST_CHECK_EQUAL( false, stat.is_directory() );
112 BOOST_CHECK_EQUAL( true, stat.is_device() );
113 BOOST_CHECK_EQUAL( true, stat.is_character_device() );
114 BOOST_CHECK_EQUAL( false, stat.is_block_device() );
117 BOOST_AUTO_TEST_CASE(StatSize)
119 write_file("/tmp/test","some nice content to make sure the file system optimizations don't inline this into the inode block");
121 I2n::Stat stat("/tmp/test");
123 BOOST_CHECK_EQUAL( true, (bool)stat );
124 BOOST_CHECK_EQUAL( true, stat.is_regular_file() );
126 BOOST_CHECK_EQUAL( true, ( stat.bytes_on_disk() >= 512 ) );
131 BOOST_AUTO_TEST_CASE(StatRecheck)
136 I2n::Stat stat(".foobar");
137 BOOST_CHECK_EQUAL( false, (bool)stat );
139 write_file(".foobar","hello world");
143 BOOST_CHECK_EQUAL( true, (bool)stat );
144 BOOST_CHECK_EQUAL( true, stat.size() > 0 );
149 BOOST_AUTO_TEST_CASE(DirTest1)
151 typedef std::vector< std::string > StringVector;
154 string test_dir = dirname(__FILE__);
155 bool res= I2n::get_dir(test_dir,names);
157 BOOST_CHECK_EQUAL( true, res );
158 BOOST_CHECK( ! names.empty() );
160 BOOST_MESSAGE("Looking for " << basename(__FILE__) << " in " << test_dir);
161 StringVector::iterator it = std::find( names.begin(), names.end(), basename(__FILE__));
162 BOOST_CHECK( it != names.end() );
164 it = std::find( names.begin(), names.end(), "." );
165 BOOST_CHECK( it == names.end() );
167 names= get_dir(test_dir,true);
168 BOOST_CHECK( ! names.empty() );
170 for (it= names.begin(); it!=names.end(); ++it)
172 DOUT(" \"" << *it << "\"");
173 BOOST_CHECK_EQUAL( false, it->empty() );
176 it = std::find( names.begin(), names.end(), "." );
177 BOOST_CHECK( it != names.end() );
182 BOOST_AUTO_TEST_CASE(PathCuts1)
184 std::string path1("/an/absolute/path");
186 BOOST_CHECK_EQUAL( std::string("/an/absolute"), dirname(path1) );
187 BOOST_CHECK_EQUAL( std::string("path"), basename(path1) );
189 std::string path2("just.a.name");
190 BOOST_CHECK_EQUAL( std::string("just.a.name"), basename(path2) );
191 BOOST_CHECK_EQUAL( std::string("."), dirname(path2) );
196 BOOST_AUTO_TEST_CASE(NormalizePath1)
200 path= normalize_path("/a/simple/path/");
201 BOOST_CHECK_EQUAL( std::string("/a/simple/path"), path );
203 path= normalize_path("//another///simple/.//path//");
204 BOOST_CHECK_EQUAL( std::string("/another/simple/path"), path );
206 path= normalize_path("//..//..//a/dummy///../././simple/././/path//");
207 BOOST_CHECK_EQUAL( std::string("/a/simple/path"), path );
209 path= normalize_path("../a/dummy//././..//simple//nice//absolute//.././..//relative/path//");
210 BOOST_CHECK_EQUAL( std::string("../a/simple/relative/path"), path );
212 path= normalize_path("../../a/dummy//././..//simple/../nice//absolute//../.x/..//relative/path//");
213 BOOST_CHECK_EQUAL( std::string("../../a/nice/relative/path"), path );
215 } // eo NormalizePath1
217 BOOST_AUTO_TEST_CASE(NormalizePath2)
221 path= normalize_path("/");
222 BOOST_CHECK_EQUAL( std::string("/"), path );
224 path= normalize_path("//");
225 BOOST_CHECK_EQUAL( std::string("/"), path );
227 path= normalize_path("/.//");
228 BOOST_CHECK_EQUAL( std::string("/"), path );
230 path= normalize_path(".");
231 BOOST_CHECK_EQUAL( std::string(""), path );
233 path= normalize_path("./");
234 BOOST_CHECK_EQUAL( std::string(""), path );
236 path= normalize_path(".///");
237 BOOST_CHECK_EQUAL( std::string(""), path );
239 path= normalize_path("/./data/files");
240 BOOST_CHECK_EQUAL( std::string("/data/files"), path );
242 path= normalize_path("./data/files/");
243 BOOST_CHECK_EQUAL( std::string("data/files"), path );
244 } // eo NormalizePath2
246 BOOST_AUTO_TEST_CASE(TestUserAndGroupStuff1)
248 User user_root((uid_t)0);
249 BOOST_CHECK_EQUAL( true, user_root.is_valid() );
250 BOOST_CHECK_EQUAL( true, (bool)user_root );
252 BOOST_CHECK_EQUAL( std::string("root"), user_root.Name );
253 BOOST_CHECK_EQUAL( (uid_t)0, user_root.Uid );
254 BOOST_CHECK_EQUAL( (gid_t)0, user_root.Gid );
256 User user_root2("root");
257 BOOST_CHECK_EQUAL( true, user_root2.is_valid() );
258 BOOST_CHECK_EQUAL( true, (bool)user_root2 );
260 BOOST_CHECK_EQUAL( std::string("root"), user_root2.Name );
261 BOOST_CHECK_EQUAL( (uid_t)0, user_root2.Uid );
262 BOOST_CHECK_EQUAL( (gid_t)0, user_root2.Gid );
264 Group group_root("root");
265 BOOST_CHECK_EQUAL( true, group_root.is_valid() );
266 BOOST_CHECK_EQUAL( true, (bool)group_root );
268 BOOST_CHECK_EQUAL( std::string("root"), group_root.Name );
269 BOOST_CHECK_EQUAL( (gid_t)0, group_root.Gid );
271 } // TestUserAndGroupStuff1()
273 BOOST_AUTO_TEST_CASE(TestUserAndGroupStuff2)
275 // Test if is_valid() works correctly
277 BOOST_CHECK_EQUAL( false, user_root.is_valid() );
280 BOOST_CHECK_EQUAL( false, group_root.is_valid() );
283 BOOST_AUTO_TEST_CASE(TestFileModes1)
285 std::string path= get_check_file_path("FileModes1");
287 write_file(path,"42");
289 Stat stat(path, false);
290 BOOST_CHECK_EQUAL( true, stat.is_valid() );
292 User user( stat.uid() );
293 Group group( stat.gid() );
295 BOOST_CHECK_EQUAL( true, user.is_valid() );
296 BOOST_CHECK_EQUAL( true, group.is_valid() );
298 bool res=chown( path, user.Name.c_str(), group.Gid );
300 BOOST_CHECK_EQUAL( true, res );
301 } // eo TestFileModes1()
305 BOOST_AUTO_TEST_CASE(TestPidOf1)
307 using I2n::Daemon::pid_of;
309 std::vector< pid_t > pid_list;
311 bool res= pid_of("init", pid_list);
312 BOOST_CHECK_EQUAL( true, res);
314 if (pid_list.empty())
316 res= pid_of("systemd", pid_list);
317 BOOST_CHECK_EQUAL( true, res);
320 BOOST_CHECK_EQUAL( false, pid_list.empty() );
322 std::vector< pid_t >::const_iterator pos1 =
323 std::find( pid_list.begin(), pid_list.end(), 1);
325 BOOST_CHECK( pos1 != pid_list.end() );
328 BOOST_AUTO_TEST_CASE(TestCopyFileSourceFail)
330 bool res = copy_file("does not exist", "destination");
331 BOOST_CHECK_EQUAL( false, res );
334 BOOST_AUTO_TEST_CASE(TestCopyFileDestFail)
336 bool res = copy_file("/etc/HOSTNAME", "/proc/not/writable");
337 BOOST_CHECK_EQUAL( false, res );
340 BOOST_AUTO_TEST_CASE(TestCopyFileOk)
342 string input = "copy_source";
343 string data = "test";
346 ofstream finput(input.c_str());
351 input_size = file_size(input);
354 string output = "copy_dest";
355 long output_size = 0;
356 bool res = copy_file(input, output);
359 output_size = file_size(output);
364 bool size_is_zero = output_size == 0 ? true : false;
366 BOOST_CHECK_EQUAL( true, res );
367 BOOST_CHECK_EQUAL( input_size, output_size );
368 BOOST_CHECK_EQUAL( false, size_is_zero );
371 BOOST_AUTO_TEST_CASE(TestMkdtemp)
373 // Create unique directory
374 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
375 BOOST_REQUIRE(unique_dir.size() > 0);
377 // Test if it's really a directory
378 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
381 BOOST_CHECK_EQUAL(true, rmdir(unique_dir));
384 BOOST_AUTO_TEST_CASE(TestRecursiveDelete)
386 // Create unique directory
387 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
388 BOOST_REQUIRE(unique_dir.size() > 0);
390 // Test if it's really a directory
391 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
393 // Create dirs and files below it
394 const std::string sub_dir = unique_dir + "/" + "some_subdir";
395 const std::string some_file = sub_dir + "/" + "some_file";
396 BOOST_CHECK_EQUAL(true, I2n::mkdir(sub_dir));
397 BOOST_CHECK_EQUAL(true, write_file(some_file, "foobar"));
400 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(unique_dir));
401 BOOST_CHECK_EQUAL(false, Stat(unique_dir).is_directory());
404 BOOST_AUTO_TEST_CASE(TestRecursiveDeleteKeepParentDir)
406 // Create unique directory
407 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
408 BOOST_REQUIRE(unique_dir.size() > 0);
410 // Test if it's really a directory
411 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
413 // Create dirs and files below it
414 const std::string sub_dir = unique_dir + "/" + "some_subdir";
415 const std::string some_file = sub_dir + "/" + "some_file";
416 const std::string other_file = unique_dir + "/" + "other_file";
418 BOOST_CHECK_EQUAL(true, I2n::mkdir(sub_dir));
419 BOOST_CHECK_EQUAL(true, write_file(some_file, "foobar"));
420 BOOST_CHECK_EQUAL(true, write_file(other_file, "foobar"));
423 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(unique_dir, true));
426 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
427 BOOST_CHECK_EQUAL(false, Stat(sub_dir).is_directory());
428 BOOST_CHECK_EQUAL(false, Stat(other_file).is_regular_file());
430 BOOST_CHECK_EQUAL(true, I2n::rmdir(unique_dir));
433 BOOST_AUTO_TEST_CASE(TestRecursiveDeleteSymlinkedDirs1)
435 // Create unique directory
436 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
437 BOOST_REQUIRE(unique_dir.size() > 0);
439 // Test if it's really a directory
440 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
442 // Create dirs and files below it
443 const std::string sub_dir = unique_dir + "/" + "some_subdir";
444 const std::string some_file = sub_dir + "/" + "some_file";
445 const std::string dir_symlink_within_unique_dir = unique_dir + "/" + "dir_symlink_within_unique_dir";
446 BOOST_CHECK_EQUAL(true, I2n::mkdir(sub_dir));
447 BOOST_CHECK_EQUAL(true, write_file(some_file, "foobar"));
448 BOOST_CHECK_EQUAL(true, symlink(sub_dir, dir_symlink_within_unique_dir));
451 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(unique_dir));
452 BOOST_CHECK_EQUAL(false, Stat(unique_dir).is_directory());
455 BOOST_AUTO_TEST_CASE(TestRecursiveDeleteSymlinkedDirs2)
457 // Create unique directory
458 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
459 BOOST_REQUIRE(unique_dir.size() > 0);
461 // Test if it's really a directory
462 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
464 // Create another unique directory
465 string other_unique_dir = I2n::mkdtemp("foobar_other.XXXXXX");
466 BOOST_REQUIRE(other_unique_dir.size() > 0);
468 // Test if it's really a directory
469 BOOST_CHECK_EQUAL(true, Stat(other_unique_dir).is_directory());
471 const std::string other_file = other_unique_dir + "/" + "other_file";
472 BOOST_CHECK_EQUAL(true, write_file(other_file, "foobar"));
474 // Create dirs and files below it
475 const std::string sub_dir = unique_dir + "/" + "some_subdir";
476 const std::string some_file = sub_dir + "/" + "some_file";
477 const std::string dir_symlink_to_outside_unique_dir = unique_dir + "/" + "dir_symlink_to_outside_unique_dir";
478 BOOST_CHECK_EQUAL(true, I2n::mkdir(sub_dir));
479 BOOST_CHECK_EQUAL(true, write_file(some_file, "foobar"));
480 BOOST_CHECK_EQUAL(true, symlink(other_unique_dir, dir_symlink_to_outside_unique_dir));
483 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(unique_dir));
484 BOOST_CHECK_EQUAL(false, Stat(unique_dir).is_directory());
486 // other unique dir must still be there
487 BOOST_CHECK_EQUAL(true, Stat(other_unique_dir).is_directory());
488 BOOST_CHECK_EQUAL(true, Stat(other_file).is_regular_file());
490 // finally delete the other unique dir
491 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(other_unique_dir));
492 BOOST_CHECK_EQUAL(false, Stat(other_unique_dir).is_directory());
495 BOOST_AUTO_TEST_CASE(TestMkdtempBrokenTemplate)
497 // Broken directory template -> fail
498 string unique_dir = I2n::mkdtemp("foobar.XXX");
499 BOOST_CHECK_EQUAL("", unique_dir);
502 BOOST_AUTO_TEST_CASE(DirectoryCreation)
504 string dirname = "test_directory";
506 I2n::rmdir (dirname);
508 BOOST_CHECK_EQUAL(true, I2n::mkdir(dirname));
509 BOOST_CHECK_EQUAL(true, Stat(dirname).is_directory());
510 // Verify default permissions
511 BOOST_CHECK_EQUAL(0700, Stat(dirname).mode());
513 BOOST_CHECK_EQUAL(true, I2n::rmdir(dirname));
515 // Second call must fail: Directory already deleted
516 BOOST_CHECK_EQUAL(false, I2n::rmdir(dirname));
519 BOOST_AUTO_TEST_CASE(DirectoryCreatePermission)
521 string dirname = "test_directory";
523 // Save and fix umask
524 mode_t previous_mask = I2n::umask(0);
526 I2n::rmdir (dirname);
527 BOOST_CHECK_EQUAL(true, I2n::mkdir(dirname, 0770));
528 BOOST_CHECK_EQUAL(0770, Stat(dirname).mode());
529 I2n::rmdir (dirname);
532 I2n::umask(previous_mask);
535 BOOST_AUTO_TEST_CASE(ChangeDirectory)
537 string current_directory = I2n::getcwd();
538 BOOST_REQUIRE(!current_directory.empty());
540 BOOST_CHECK_EQUAL(true, I2n::chdir("/"));
541 BOOST_CHECK_EQUAL("/", I2n::getcwd());
543 BOOST_CHECK_EQUAL(true, I2n::chdir(current_directory));
544 BOOST_REQUIRE_EQUAL(current_directory, I2n::getcwd());
547 BOOST_AUTO_TEST_CASE(WriteFileEmptyData)
552 I2n::Stat stat(".foobar");
553 BOOST_CHECK_EQUAL( false, (bool)stat );
555 // Call write_file() with empty data. Should still create the file.
556 write_file(".foobar","");
560 BOOST_CHECK_EQUAL( true, (bool)stat );
561 BOOST_CHECK_EQUAL( true, stat.size() == 0 );
566 BOOST_AUTO_TEST_CASE(FileContentDiffersIsIdentical)
568 BOOST_CHECK_EQUAL( false, file_content_differs("/etc/passwd", "/etc/passwd") );
571 BOOST_AUTO_TEST_CASE(FileContentDiffersNonExistent)
573 BOOST_CHECK_EQUAL( true, file_content_differs("/etc/passwd", "abc") );
574 BOOST_CHECK_EQUAL( true, file_content_differs("abc", "/etc/passwd") );
577 BOOST_AUTO_TEST_CASE(FileContentDiffersEqualSize)
579 const string name1 = "file1", name2 = "file2";
581 ofstream out1(name1.c_str());
584 ofstream out2(name2.c_str());
588 bool res = file_content_differs(name1, name2);
592 BOOST_CHECK_EQUAL( true, res );
595 BOOST_AUTO_TEST_CASE(FreeDiskSpace1)
598 long long get_free_diskspace_tmp;
600 // we need a partition to do this test. we can't create our own because that would require root
601 // so we use /tmp and retry it a few times in case of an error
605 string dfstr=capture_exec("df -P -B 1 /tmp | tail -n 1 | sed \"s/ \\+/\\\\n/g\" | sed -n 4,4p");
608 string_to<long long>(dfstr,dfout);
610 get_free_diskspace_tmp=get_free_diskspace("/tmp");
612 if ( dfout == get_free_diskspace_tmp )
618 // do the check again with BOOST_CHECK_EQUAL to show it in the unit test output
619 BOOST_CHECK_EQUAL( dfout, get_free_diskspace_tmp );
622 BOOST_AUTO_TEST_CASE(FreeDiskSpace2)
624 BOOST_CHECK_EQUAL( -1, get_free_diskspace("/this/path/is/really/bogus") );
627 BOOST_AUTO_TEST_CASE(TestDu)
629 // Create unique directory
630 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
631 BOOST_REQUIRE(unique_dir.size() > 0);
633 // Test if it's really a directory
634 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
636 // Create dirs and files below it
637 const std::string sub_dir = unique_dir + "/" + "some_subdir";
638 const std::string some_file = sub_dir + "/" + "some_file";
639 BOOST_CHECK_EQUAL(true, I2n::mkdir(sub_dir));
640 BOOST_CHECK_EQUAL(true, write_file(some_file, "foobar and some more data, even more that Tom would like to see in one line without linebreak but I still want to have it all here"));
642 string dustr=capture_exec(string("du --block-size=1 --sum ")+unique_dir+" | cut -f 1");
644 string_to<long long>(dustr,duout);
646 long long first_du=du(unique_dir);
648 BOOST_CHECK_EQUAL( duout, first_du );
652 cmd=string("ln ")+some_file+" hardlink1";
655 cmd=string("ln ")+some_file+" hardlink2";
658 cmd=string("ln ")+some_file+" hardlink3";
661 long long du_with_hardlinks=du(unique_dir);
663 BOOST_CHECK_EQUAL( first_du , du_with_hardlinks );
666 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(unique_dir));
667 BOOST_CHECK_EQUAL(false, Stat(unique_dir).is_directory());
677 BOOST_AUTO_TEST_SUITE_END()