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("Makefile");
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 bool res= I2n::get_dir(".",names);
156 BOOST_CHECK_EQUAL( true, res );
157 BOOST_CHECK( ! names.empty() );
159 StringVector::iterator it = std::find( names.begin(), names.end(), "Makefile");
160 BOOST_CHECK( it != names.end() );
162 it = std::find( names.begin(), names.end(), "." );
163 BOOST_CHECK( it == names.end() );
165 names= get_dir(".",true);
166 BOOST_CHECK( ! names.empty() );
168 for (it= names.begin(); it!=names.end(); ++it)
170 DOUT(" \"" << *it << "\"");
171 BOOST_CHECK_EQUAL( false, it->empty() );
174 it = std::find( names.begin(), names.end(), "." );
175 BOOST_CHECK( it != names.end() );
180 BOOST_AUTO_TEST_CASE(PathCuts1)
182 std::string path1("/an/absolute/path");
184 BOOST_CHECK_EQUAL( std::string("/an/absolute"), dirname(path1) );
185 BOOST_CHECK_EQUAL( std::string("path"), basename(path1) );
187 std::string path2("just.a.name");
188 BOOST_CHECK_EQUAL( std::string("just.a.name"), basename(path2) );
189 BOOST_CHECK_EQUAL( std::string("."), dirname(path2) );
194 BOOST_AUTO_TEST_CASE(NormalizePath1)
198 path= normalize_path("/a/simple/path/");
199 BOOST_CHECK_EQUAL( std::string("/a/simple/path"), path );
201 path= normalize_path("//another///simple/.//path//");
202 BOOST_CHECK_EQUAL( std::string("/another/simple/path"), path );
204 path= normalize_path("//..//..//a/dummy///../././simple/././/path//");
205 BOOST_CHECK_EQUAL( std::string("/a/simple/path"), path );
207 path= normalize_path("../a/dummy//././..//simple//nice//absolute//.././..//relative/path//");
208 BOOST_CHECK_EQUAL( std::string("../a/simple/relative/path"), path );
210 path= normalize_path("../../a/dummy//././..//simple/../nice//absolute//../.x/..//relative/path//");
211 BOOST_CHECK_EQUAL( std::string("../../a/nice/relative/path"), path );
213 } // eo NormalizePath1
215 BOOST_AUTO_TEST_CASE(NormalizePath2)
219 path= normalize_path("/");
220 BOOST_CHECK_EQUAL( std::string("/"), path );
222 path= normalize_path("//");
223 BOOST_CHECK_EQUAL( std::string("/"), path );
225 path= normalize_path("/.//");
226 BOOST_CHECK_EQUAL( std::string("/"), path );
228 path= normalize_path(".");
229 BOOST_CHECK_EQUAL( std::string(""), path );
231 path= normalize_path("./");
232 BOOST_CHECK_EQUAL( std::string(""), path );
234 path= normalize_path(".///");
235 BOOST_CHECK_EQUAL( std::string(""), path );
237 path= normalize_path("/./data/files");
238 BOOST_CHECK_EQUAL( std::string("/data/files"), path );
240 path= normalize_path("./data/files/");
241 BOOST_CHECK_EQUAL( std::string("data/files"), path );
242 } // eo NormalizePath2
244 BOOST_AUTO_TEST_CASE(TestUserAndGroupStuff1)
246 User user_root((uid_t)0);
247 BOOST_CHECK_EQUAL( true, user_root.is_valid() );
248 BOOST_CHECK_EQUAL( true, (bool)user_root );
250 BOOST_CHECK_EQUAL( std::string("root"), user_root.Name );
251 BOOST_CHECK_EQUAL( (uid_t)0, user_root.Uid );
252 BOOST_CHECK_EQUAL( (gid_t)0, user_root.Gid );
254 User user_root2("root");
255 BOOST_CHECK_EQUAL( true, user_root2.is_valid() );
256 BOOST_CHECK_EQUAL( true, (bool)user_root2 );
258 BOOST_CHECK_EQUAL( std::string("root"), user_root2.Name );
259 BOOST_CHECK_EQUAL( (uid_t)0, user_root2.Uid );
260 BOOST_CHECK_EQUAL( (gid_t)0, user_root2.Gid );
262 Group group_root("root");
263 BOOST_CHECK_EQUAL( true, group_root.is_valid() );
264 BOOST_CHECK_EQUAL( true, (bool)group_root );
266 BOOST_CHECK_EQUAL( std::string("root"), group_root.Name );
267 BOOST_CHECK_EQUAL( (gid_t)0, group_root.Gid );
269 } // TestUserAndGroupStuff1()
271 BOOST_AUTO_TEST_CASE(TestUserAndGroupStuff2)
273 // Test if is_valid() works correctly
275 BOOST_CHECK_EQUAL( false, user_root.is_valid() );
278 BOOST_CHECK_EQUAL( false, group_root.is_valid() );
281 BOOST_AUTO_TEST_CASE(TestFileModes1)
283 std::string path= get_check_file_path("FileModes1");
285 write_file(path,"42");
287 Stat stat(path, false);
288 BOOST_CHECK_EQUAL( true, stat.is_valid() );
290 User user( stat.uid() );
291 Group group( stat.gid() );
293 BOOST_CHECK_EQUAL( true, user.is_valid() );
294 BOOST_CHECK_EQUAL( true, group.is_valid() );
296 bool res=chown( path, user.Name.c_str(), group.Gid );
298 BOOST_CHECK_EQUAL( true, res );
299 } // eo TestFileModes1()
303 BOOST_AUTO_TEST_CASE(TestPidOf1)
305 using I2n::Daemon::pid_of;
307 std::vector< pid_t > pid_list;
309 bool res= pid_of("init", pid_list);
310 BOOST_CHECK_EQUAL( true, res);
312 if (pid_list.empty())
314 res= pid_of("systemd", pid_list);
315 BOOST_CHECK_EQUAL( true, res);
318 BOOST_CHECK_EQUAL( false, pid_list.empty() );
320 std::vector< pid_t >::const_iterator pos1 =
321 std::find( pid_list.begin(), pid_list.end(), 1);
323 BOOST_CHECK( pos1 != pid_list.end() );
326 BOOST_AUTO_TEST_CASE(TestCopyFileSourceFail)
328 bool res = copy_file("does not exist", "destination");
329 BOOST_CHECK_EQUAL( false, res );
332 BOOST_AUTO_TEST_CASE(TestCopyFileDestFail)
334 bool res = copy_file("/etc/HOSTNAME", "/proc/not/writable");
335 BOOST_CHECK_EQUAL( false, res );
338 BOOST_AUTO_TEST_CASE(TestCopyFileOk)
340 string input = "copy_source";
341 string data = "test";
344 ofstream finput(input.c_str());
349 input_size = file_size(input);
352 string output = "copy_dest";
353 long output_size = 0;
354 bool res = copy_file(input, output);
357 output_size = file_size(output);
362 bool size_is_zero = output_size == 0 ? true : false;
364 BOOST_CHECK_EQUAL( true, res );
365 BOOST_CHECK_EQUAL( input_size, output_size );
366 BOOST_CHECK_EQUAL( false, size_is_zero );
369 BOOST_AUTO_TEST_CASE(TestMkdtemp)
371 // Create unique directory
372 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
373 BOOST_REQUIRE(unique_dir.size() > 0);
375 // Test if it's really a directory
376 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
379 BOOST_CHECK_EQUAL(true, rmdir(unique_dir));
382 BOOST_AUTO_TEST_CASE(TestRecursiveDelete)
384 // Create unique directory
385 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
386 BOOST_REQUIRE(unique_dir.size() > 0);
388 // Test if it's really a directory
389 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
391 // Create dirs and files below it
392 const std::string sub_dir = unique_dir + "/" + "some_subdir";
393 const std::string some_file = sub_dir + "/" + "some_file";
394 BOOST_CHECK_EQUAL(true, I2n::mkdir(sub_dir));
395 BOOST_CHECK_EQUAL(true, write_file(some_file, "foobar"));
398 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(unique_dir));
399 BOOST_CHECK_EQUAL(false, Stat(unique_dir).is_directory());
402 BOOST_AUTO_TEST_CASE(TestRecursiveDeleteKeepParentDir)
404 // Create unique directory
405 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
406 BOOST_REQUIRE(unique_dir.size() > 0);
408 // Test if it's really a directory
409 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
411 // Create dirs and files below it
412 const std::string sub_dir = unique_dir + "/" + "some_subdir";
413 const std::string some_file = sub_dir + "/" + "some_file";
414 const std::string other_file = unique_dir + "/" + "other_file";
416 BOOST_CHECK_EQUAL(true, I2n::mkdir(sub_dir));
417 BOOST_CHECK_EQUAL(true, write_file(some_file, "foobar"));
418 BOOST_CHECK_EQUAL(true, write_file(other_file, "foobar"));
421 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(unique_dir, true));
424 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
425 BOOST_CHECK_EQUAL(false, Stat(sub_dir).is_directory());
426 BOOST_CHECK_EQUAL(false, Stat(other_file).is_regular_file());
428 BOOST_CHECK_EQUAL(true, I2n::rmdir(unique_dir));
431 BOOST_AUTO_TEST_CASE(TestRecursiveDeleteSymlinkedDirs1)
433 // Create unique directory
434 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
435 BOOST_REQUIRE(unique_dir.size() > 0);
437 // Test if it's really a directory
438 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
440 // Create dirs and files below it
441 const std::string sub_dir = unique_dir + "/" + "some_subdir";
442 const std::string some_file = sub_dir + "/" + "some_file";
443 const std::string dir_symlink_within_unique_dir = unique_dir + "/" + "dir_symlink_within_unique_dir";
444 BOOST_CHECK_EQUAL(true, I2n::mkdir(sub_dir));
445 BOOST_CHECK_EQUAL(true, write_file(some_file, "foobar"));
446 BOOST_CHECK_EQUAL(true, symlink(sub_dir, dir_symlink_within_unique_dir));
449 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(unique_dir));
450 BOOST_CHECK_EQUAL(false, Stat(unique_dir).is_directory());
453 BOOST_AUTO_TEST_CASE(TestRecursiveDeleteSymlinkedDirs2)
455 // Create unique directory
456 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
457 BOOST_REQUIRE(unique_dir.size() > 0);
459 // Test if it's really a directory
460 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
462 // Create another unique directory
463 string other_unique_dir = I2n::mkdtemp("foobar_other.XXXXXX");
464 BOOST_REQUIRE(other_unique_dir.size() > 0);
466 // Test if it's really a directory
467 BOOST_CHECK_EQUAL(true, Stat(other_unique_dir).is_directory());
469 const std::string other_file = other_unique_dir + "/" + "other_file";
470 BOOST_CHECK_EQUAL(true, write_file(other_file, "foobar"));
472 // Create dirs and files below it
473 const std::string sub_dir = unique_dir + "/" + "some_subdir";
474 const std::string some_file = sub_dir + "/" + "some_file";
475 const std::string dir_symlink_to_outside_unique_dir = unique_dir + "/" + "dir_symlink_to_outside_unique_dir";
476 BOOST_CHECK_EQUAL(true, I2n::mkdir(sub_dir));
477 BOOST_CHECK_EQUAL(true, write_file(some_file, "foobar"));
478 BOOST_CHECK_EQUAL(true, symlink(other_unique_dir, dir_symlink_to_outside_unique_dir));
481 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(unique_dir));
482 BOOST_CHECK_EQUAL(false, Stat(unique_dir).is_directory());
484 // other unique dir must still be there
485 BOOST_CHECK_EQUAL(true, Stat(other_unique_dir).is_directory());
486 BOOST_CHECK_EQUAL(true, Stat(other_file).is_regular_file());
488 // finally delete the other unique dir
489 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(other_unique_dir));
490 BOOST_CHECK_EQUAL(false, Stat(other_unique_dir).is_directory());
493 BOOST_AUTO_TEST_CASE(TestMkdtempBrokenTemplate)
495 // Broken directory template -> fail
496 string unique_dir = I2n::mkdtemp("foobar.XXX");
497 BOOST_CHECK_EQUAL("", unique_dir);
500 BOOST_AUTO_TEST_CASE(DirectoryCreation)
502 string dirname = "test_directory";
504 I2n::rmdir (dirname);
506 BOOST_CHECK_EQUAL(true, I2n::mkdir(dirname));
507 BOOST_CHECK_EQUAL(true, Stat(dirname).is_directory());
508 // Verify default permissions
509 BOOST_CHECK_EQUAL(0700, Stat(dirname).mode());
511 BOOST_CHECK_EQUAL(true, I2n::rmdir(dirname));
513 // Second call must fail: Directory already deleted
514 BOOST_CHECK_EQUAL(false, I2n::rmdir(dirname));
517 BOOST_AUTO_TEST_CASE(DirectoryCreatePermission)
519 string dirname = "test_directory";
521 // Save and fix umask
522 mode_t previous_mask = I2n::umask(0);
524 I2n::rmdir (dirname);
525 BOOST_CHECK_EQUAL(true, I2n::mkdir(dirname, 0770));
526 BOOST_CHECK_EQUAL(0770, Stat(dirname).mode());
527 I2n::rmdir (dirname);
530 I2n::umask(previous_mask);
533 BOOST_AUTO_TEST_CASE(ChangeDirectory)
535 string current_directory = I2n::getcwd();
536 BOOST_REQUIRE(!current_directory.empty());
538 BOOST_CHECK_EQUAL(true, I2n::chdir("/"));
539 BOOST_CHECK_EQUAL("/", I2n::getcwd());
541 BOOST_CHECK_EQUAL(true, I2n::chdir(current_directory));
542 BOOST_REQUIRE_EQUAL(current_directory, I2n::getcwd());
545 BOOST_AUTO_TEST_CASE(WriteFileEmptyData)
550 I2n::Stat stat(".foobar");
551 BOOST_CHECK_EQUAL( false, (bool)stat );
553 // Call write_file() with empty data. Should still create the file.
554 write_file(".foobar","");
558 BOOST_CHECK_EQUAL( true, (bool)stat );
559 BOOST_CHECK_EQUAL( true, stat.size() == 0 );
564 BOOST_AUTO_TEST_CASE(FileContentDiffersIsIdentical)
566 BOOST_CHECK_EQUAL( false, file_content_differs("/etc/passwd", "/etc/passwd") );
569 BOOST_AUTO_TEST_CASE(FileContentDiffersNonExistent)
571 BOOST_CHECK_EQUAL( true, file_content_differs("/etc/passwd", "abc") );
572 BOOST_CHECK_EQUAL( true, file_content_differs("abc", "/etc/passwd") );
575 BOOST_AUTO_TEST_CASE(FileContentDiffersEqualSize)
577 const string name1 = "file1", name2 = "file2";
579 ofstream out1(name1.c_str());
582 ofstream out2(name2.c_str());
586 bool res = file_content_differs(name1, name2);
590 BOOST_CHECK_EQUAL( true, res );
593 BOOST_AUTO_TEST_CASE(FreeDiskSpace1)
596 long long get_free_diskspace_tmp;
598 // we need a partition to do this test. we can't create our own because that would require root
599 // so we use /tmp and retry it a few times in case of an error
603 string dfstr=capture_exec("df -P -B 1 /tmp | tail -n 1 | sed \"s/ \\+/\\\\n/g\" | sed -n 4,4p");
606 string_to<long long>(dfstr,dfout);
608 get_free_diskspace_tmp=get_free_diskspace("/tmp");
610 if ( dfout == get_free_diskspace_tmp )
616 // do the check again with BOOST_CHECK_EQUAL to show it in the unit test output
617 BOOST_CHECK_EQUAL( dfout, get_free_diskspace_tmp );
620 BOOST_AUTO_TEST_CASE(FreeDiskSpace2)
622 BOOST_CHECK_EQUAL( -1, get_free_diskspace("/this/path/is/really/bogus") );
625 BOOST_AUTO_TEST_CASE(TestDu)
627 // Create unique directory
628 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
629 BOOST_REQUIRE(unique_dir.size() > 0);
631 // Test if it's really a directory
632 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
634 // Create dirs and files below it
635 const std::string sub_dir = unique_dir + "/" + "some_subdir";
636 const std::string some_file = sub_dir + "/" + "some_file";
637 BOOST_CHECK_EQUAL(true, I2n::mkdir(sub_dir));
638 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"));
640 string dustr=capture_exec(string("du --block-size=1 --sum ")+unique_dir+" | cut -f 1");
642 string_to<long long>(dustr,duout);
644 long long first_du=du(unique_dir);
646 BOOST_CHECK_EQUAL( duout, first_du );
650 cmd=string("ln ")+some_file+" hardlink1";
653 cmd=string("ln ")+some_file+" hardlink2";
656 cmd=string("ln ")+some_file+" hardlink3";
659 long long du_with_hardlinks=du(unique_dir);
661 BOOST_CHECK_EQUAL( first_du , du_with_hardlinks );
664 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(unique_dir));
665 BOOST_CHECK_EQUAL(false, Stat(unique_dir).is_directory());
675 BOOST_AUTO_TEST_SUITE_END()