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() );
159 BOOST_CHECK_EQUAL(I2n::get_dir_size(test_dir), names.size());
161 BOOST_MESSAGE("Looking for " << basename(__FILE__) << " in " << test_dir);
162 StringVector::iterator it = std::find( names.begin(), names.end(), basename(__FILE__));
163 BOOST_CHECK( it != names.end() );
165 it = std::find( names.begin(), names.end(), "." );
166 BOOST_CHECK( it == names.end() );
168 names= get_dir(test_dir,true);
169 BOOST_CHECK( ! names.empty() );
170 BOOST_CHECK_EQUAL(I2n::get_dir_size(test_dir, true), names.size());
172 for (it= names.begin(); it!=names.end(); ++it)
174 DOUT(" \"" << *it << "\"");
175 BOOST_CHECK_EQUAL( false, it->empty() );
178 it = std::find( names.begin(), names.end(), "." );
179 BOOST_CHECK( it != names.end() );
184 BOOST_AUTO_TEST_CASE(PathCuts1)
186 std::string path1("/an/absolute/path");
188 BOOST_CHECK_EQUAL( std::string("/an/absolute"), dirname(path1) );
189 BOOST_CHECK_EQUAL( std::string("path"), basename(path1) );
191 std::string path2("just.a.name");
192 BOOST_CHECK_EQUAL( std::string("just.a.name"), basename(path2) );
193 BOOST_CHECK_EQUAL( std::string("."), dirname(path2) );
198 BOOST_AUTO_TEST_CASE(NormalizePath1)
202 path= normalize_path("/a/simple/path/");
203 BOOST_CHECK_EQUAL( std::string("/a/simple/path"), path );
205 path= normalize_path("//another///simple/.//path//");
206 BOOST_CHECK_EQUAL( std::string("/another/simple/path"), path );
208 path= normalize_path("//..//..//a/dummy///../././simple/././/path//");
209 BOOST_CHECK_EQUAL( std::string("/a/simple/path"), path );
211 path= normalize_path("../a/dummy//././..//simple//nice//absolute//.././..//relative/path//");
212 BOOST_CHECK_EQUAL( std::string("../a/simple/relative/path"), path );
214 path= normalize_path("../../a/dummy//././..//simple/../nice//absolute//../.x/..//relative/path//");
215 BOOST_CHECK_EQUAL( std::string("../../a/nice/relative/path"), path );
217 } // eo NormalizePath1
219 BOOST_AUTO_TEST_CASE(NormalizePath2)
223 path= normalize_path("/");
224 BOOST_CHECK_EQUAL( std::string("/"), path );
226 path= normalize_path("//");
227 BOOST_CHECK_EQUAL( std::string("/"), path );
229 path= normalize_path("/.//");
230 BOOST_CHECK_EQUAL( std::string("/"), path );
232 path= normalize_path(".");
233 BOOST_CHECK_EQUAL( std::string(""), path );
235 path= normalize_path("./");
236 BOOST_CHECK_EQUAL( std::string(""), path );
238 path= normalize_path(".///");
239 BOOST_CHECK_EQUAL( std::string(""), path );
241 path= normalize_path("/./data/files");
242 BOOST_CHECK_EQUAL( std::string("/data/files"), path );
244 path= normalize_path("./data/files/");
245 BOOST_CHECK_EQUAL( std::string("data/files"), path );
246 } // eo NormalizePath2
248 BOOST_AUTO_TEST_CASE(TestUserAndGroupStuff1)
250 User user_root((uid_t)0);
251 BOOST_CHECK_EQUAL( true, user_root.is_valid() );
252 BOOST_CHECK_EQUAL( true, (bool)user_root );
254 BOOST_CHECK_EQUAL( std::string("root"), user_root.Name );
255 BOOST_CHECK_EQUAL( (uid_t)0, user_root.Uid );
256 BOOST_CHECK_EQUAL( (gid_t)0, user_root.Gid );
258 User user_root2("root");
259 BOOST_CHECK_EQUAL( true, user_root2.is_valid() );
260 BOOST_CHECK_EQUAL( true, (bool)user_root2 );
262 BOOST_CHECK_EQUAL( std::string("root"), user_root2.Name );
263 BOOST_CHECK_EQUAL( (uid_t)0, user_root2.Uid );
264 BOOST_CHECK_EQUAL( (gid_t)0, user_root2.Gid );
266 Group group_root("root");
267 BOOST_CHECK_EQUAL( true, group_root.is_valid() );
268 BOOST_CHECK_EQUAL( true, (bool)group_root );
270 BOOST_CHECK_EQUAL( std::string("root"), group_root.Name );
271 BOOST_CHECK_EQUAL( (gid_t)0, group_root.Gid );
273 } // TestUserAndGroupStuff1()
275 BOOST_AUTO_TEST_CASE(TestUserAndGroupStuff2)
277 // Test if is_valid() works correctly
279 BOOST_CHECK_EQUAL( false, user_root.is_valid() );
282 BOOST_CHECK_EQUAL( false, group_root.is_valid() );
285 BOOST_AUTO_TEST_CASE(TestFileModes1)
287 std::string path= get_check_file_path("FileModes1");
289 write_file(path,"42");
291 Stat stat(path, false);
292 BOOST_CHECK_EQUAL( true, stat.is_valid() );
294 User user( stat.uid() );
295 Group group( stat.gid() );
297 BOOST_CHECK_EQUAL( true, user.is_valid() );
298 BOOST_CHECK_EQUAL( true, group.is_valid() );
300 bool res=chown( path, user.Name.c_str(), group.Gid );
302 BOOST_CHECK_EQUAL( true, res );
303 } // eo TestFileModes1()
307 BOOST_AUTO_TEST_CASE(TestPidOf1)
309 using I2n::Daemon::pid_of;
311 std::vector< pid_t > pid_list;
313 bool res= pid_of("init", pid_list);
314 BOOST_CHECK_EQUAL( true, res);
316 if (pid_list.empty())
318 res= pid_of("systemd", pid_list);
319 BOOST_CHECK_EQUAL( true, res);
322 BOOST_CHECK_EQUAL( false, pid_list.empty() );
324 std::vector< pid_t >::const_iterator pos1 =
325 std::find( pid_list.begin(), pid_list.end(), 1);
327 BOOST_CHECK( pos1 != pid_list.end() );
330 BOOST_AUTO_TEST_CASE(TestCopyFileSourceFail)
332 bool res = copy_file("does not exist", "destination");
333 BOOST_CHECK_EQUAL( false, res );
336 BOOST_AUTO_TEST_CASE(TestCopyFileDestFail)
338 bool res = copy_file("/etc/HOSTNAME", "/proc/not/writable");
339 BOOST_CHECK_EQUAL( false, res );
342 BOOST_AUTO_TEST_CASE(TestCopyFileOk)
344 string input = "copy_source";
345 string data = "test";
348 ofstream finput(input.c_str());
353 input_size = file_size(input);
356 string output = "copy_dest";
357 long output_size = 0;
358 bool res = copy_file(input, output);
361 output_size = file_size(output);
366 bool size_is_zero = output_size == 0 ? true : false;
368 BOOST_CHECK_EQUAL( true, res );
369 BOOST_CHECK_EQUAL( input_size, output_size );
370 BOOST_CHECK_EQUAL( false, size_is_zero );
373 BOOST_AUTO_TEST_CASE(TestMkdtemp)
375 // Create unique directory
376 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
377 BOOST_REQUIRE(unique_dir.size() > 0);
379 // Test if it's really a directory
380 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
383 BOOST_CHECK_EQUAL(true, rmdir(unique_dir));
386 BOOST_AUTO_TEST_CASE(TestRecursiveDelete)
388 // Create unique directory
389 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
390 BOOST_REQUIRE(unique_dir.size() > 0);
392 // Test if it's really a directory
393 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
395 // Create dirs and files below it
396 const std::string sub_dir = unique_dir + "/" + "some_subdir";
397 const std::string some_file = sub_dir + "/" + "some_file";
398 BOOST_CHECK_EQUAL(true, I2n::mkdir(sub_dir));
399 BOOST_CHECK_EQUAL(true, write_file(some_file, "foobar"));
402 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(unique_dir));
403 BOOST_CHECK_EQUAL(false, Stat(unique_dir).is_directory());
406 BOOST_AUTO_TEST_CASE(TestRecursiveDeleteKeepParentDir)
408 // Create unique directory
409 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
410 BOOST_REQUIRE(unique_dir.size() > 0);
412 // Test if it's really a directory
413 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
415 // Create dirs and files below it
416 const std::string sub_dir = unique_dir + "/" + "some_subdir";
417 const std::string some_file = sub_dir + "/" + "some_file";
418 const std::string other_file = unique_dir + "/" + "other_file";
420 BOOST_CHECK_EQUAL(true, I2n::mkdir(sub_dir));
421 BOOST_CHECK_EQUAL(true, write_file(some_file, "foobar"));
422 BOOST_CHECK_EQUAL(true, write_file(other_file, "foobar"));
425 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(unique_dir, true));
428 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
429 BOOST_CHECK_EQUAL(false, Stat(sub_dir).is_directory());
430 BOOST_CHECK_EQUAL(false, Stat(other_file).is_regular_file());
432 BOOST_CHECK_EQUAL(true, I2n::rmdir(unique_dir));
435 BOOST_AUTO_TEST_CASE(TestRecursiveDeleteSymlinkedDirs1)
437 // Create unique directory
438 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
439 BOOST_REQUIRE(unique_dir.size() > 0);
441 // Test if it's really a directory
442 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
444 // Create dirs and files below it
445 const std::string sub_dir = unique_dir + "/" + "some_subdir";
446 const std::string some_file = sub_dir + "/" + "some_file";
447 const std::string dir_symlink_within_unique_dir = unique_dir + "/" + "dir_symlink_within_unique_dir";
448 BOOST_CHECK_EQUAL(true, I2n::mkdir(sub_dir));
449 BOOST_CHECK_EQUAL(true, write_file(some_file, "foobar"));
450 BOOST_CHECK_EQUAL(true, symlink(sub_dir, dir_symlink_within_unique_dir));
453 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(unique_dir));
454 BOOST_CHECK_EQUAL(false, Stat(unique_dir).is_directory());
457 BOOST_AUTO_TEST_CASE(TestRecursiveDeleteSymlinkedDirs2)
459 // Create unique directory
460 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
461 BOOST_REQUIRE(unique_dir.size() > 0);
463 // Test if it's really a directory
464 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
466 // Create another unique directory
467 string other_unique_dir = I2n::mkdtemp("foobar_other.XXXXXX");
468 BOOST_REQUIRE(other_unique_dir.size() > 0);
470 // Test if it's really a directory
471 BOOST_CHECK_EQUAL(true, Stat(other_unique_dir).is_directory());
473 const std::string other_file = other_unique_dir + "/" + "other_file";
474 BOOST_CHECK_EQUAL(true, write_file(other_file, "foobar"));
476 // Create dirs and files below it
477 const std::string sub_dir = unique_dir + "/" + "some_subdir";
478 const std::string some_file = sub_dir + "/" + "some_file";
479 const std::string dir_symlink_to_outside_unique_dir = unique_dir + "/" + "dir_symlink_to_outside_unique_dir";
480 BOOST_CHECK_EQUAL(true, I2n::mkdir(sub_dir));
481 BOOST_CHECK_EQUAL(true, write_file(some_file, "foobar"));
482 BOOST_CHECK_EQUAL(true, symlink(other_unique_dir, dir_symlink_to_outside_unique_dir));
485 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(unique_dir));
486 BOOST_CHECK_EQUAL(false, Stat(unique_dir).is_directory());
488 // other unique dir must still be there
489 BOOST_CHECK_EQUAL(true, Stat(other_unique_dir).is_directory());
490 BOOST_CHECK_EQUAL(true, Stat(other_file).is_regular_file());
492 // finally delete the other unique dir
493 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(other_unique_dir));
494 BOOST_CHECK_EQUAL(false, Stat(other_unique_dir).is_directory());
497 BOOST_AUTO_TEST_CASE(TestMkdtempBrokenTemplate)
499 // Broken directory template -> fail
500 string unique_dir = I2n::mkdtemp("foobar.XXX");
501 BOOST_CHECK_EQUAL("", unique_dir);
504 BOOST_AUTO_TEST_CASE(DirectoryCreation)
506 string dirname = "test_directory";
508 I2n::rmdir (dirname);
510 BOOST_CHECK_EQUAL(true, I2n::mkdir(dirname));
511 BOOST_CHECK_EQUAL(true, Stat(dirname).is_directory());
512 // Verify default permissions
513 BOOST_CHECK_EQUAL(0700, Stat(dirname).mode());
515 BOOST_CHECK_EQUAL(true, I2n::rmdir(dirname));
517 // Second call must fail: Directory already deleted
518 BOOST_CHECK_EQUAL(false, I2n::rmdir(dirname));
521 BOOST_AUTO_TEST_CASE(DirectoryCreatePermission)
523 string dirname = "test_directory";
525 // Save and fix umask
526 mode_t previous_mask = I2n::umask(0);
528 I2n::rmdir (dirname);
529 BOOST_CHECK_EQUAL(true, I2n::mkdir(dirname, 0770));
530 BOOST_CHECK_EQUAL(0770, Stat(dirname).mode());
531 I2n::rmdir (dirname);
534 I2n::umask(previous_mask);
537 BOOST_AUTO_TEST_CASE(ChangeDirectory)
539 string current_directory = I2n::getcwd();
540 BOOST_REQUIRE(!current_directory.empty());
542 BOOST_CHECK_EQUAL(true, I2n::chdir("/"));
543 BOOST_CHECK_EQUAL("/", I2n::getcwd());
545 BOOST_CHECK_EQUAL(true, I2n::chdir(current_directory));
546 BOOST_REQUIRE_EQUAL(current_directory, I2n::getcwd());
549 BOOST_AUTO_TEST_CASE(WriteFileEmptyData)
554 I2n::Stat stat(".foobar");
555 BOOST_CHECK_EQUAL( false, (bool)stat );
557 // Call write_file() with empty data. Should still create the file.
558 write_file(".foobar","");
562 BOOST_CHECK_EQUAL( true, (bool)stat );
563 BOOST_CHECK_EQUAL( true, stat.size() == 0 );
568 BOOST_AUTO_TEST_CASE(FileContentDiffersIsIdentical)
570 BOOST_CHECK_EQUAL( false, file_content_differs("/etc/passwd", "/etc/passwd") );
573 BOOST_AUTO_TEST_CASE(FileContentDiffersNonExistent)
575 BOOST_CHECK_EQUAL( true, file_content_differs("/etc/passwd", "abc") );
576 BOOST_CHECK_EQUAL( true, file_content_differs("abc", "/etc/passwd") );
579 BOOST_AUTO_TEST_CASE(FileContentDiffersEqualSize)
581 const string name1 = "file1", name2 = "file2";
583 ofstream out1(name1.c_str());
586 ofstream out2(name2.c_str());
590 bool res = file_content_differs(name1, name2);
594 BOOST_CHECK_EQUAL( true, res );
597 BOOST_AUTO_TEST_CASE(FreeDiskSpace1)
600 long long get_free_diskspace_tmp;
602 // we need a partition to do this test. we can't create our own because that would require root
603 // so we use /tmp and retry it a few times in case of an error
607 string dfstr=capture_exec("df -P -B 1 /tmp | tail -n 1 | sed \"s/ \\+/\\\\n/g\" | sed -n 4,4p");
610 string_to<long long>(dfstr,dfout);
612 get_free_diskspace_tmp=get_free_diskspace("/tmp");
614 if ( dfout == get_free_diskspace_tmp )
620 // do the check again with BOOST_CHECK_EQUAL to show it in the unit test output
621 BOOST_CHECK_EQUAL( dfout, get_free_diskspace_tmp );
624 BOOST_AUTO_TEST_CASE(FreeDiskSpace2)
626 BOOST_CHECK_EQUAL( -1, get_free_diskspace("/this/path/is/really/bogus") );
629 BOOST_AUTO_TEST_CASE(TestDu)
631 // Create unique directory
632 string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
633 BOOST_REQUIRE(unique_dir.size() > 0);
635 // Test if it's really a directory
636 BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
638 // Create dirs and files below it
639 const std::string sub_dir = unique_dir + "/" + "some_subdir";
640 const std::string some_file = sub_dir + "/" + "some_file";
641 BOOST_CHECK_EQUAL(true, I2n::mkdir(sub_dir));
642 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"));
644 string dustr=capture_exec(string("du --block-size=1 --sum ")+unique_dir+" | cut -f 1");
646 string_to<long long>(dustr,duout);
648 long long first_du=du(unique_dir);
650 BOOST_CHECK_EQUAL( duout, first_du );
654 cmd=string("ln ")+some_file+" hardlink1";
657 cmd=string("ln ")+some_file+" hardlink2";
660 cmd=string("ln ")+some_file+" hardlink3";
663 long long du_with_hardlinks=du(unique_dir);
665 BOOST_CHECK_EQUAL( first_du , du_with_hardlinks );
668 BOOST_CHECK_EQUAL(true, I2n::recursive_delete(unique_dir));
669 BOOST_CHECK_EQUAL(false, Stat(unique_dir).is_directory());
679 BOOST_AUTO_TEST_SUITE_END()