source: box/trunk/test/bbackupd/testbbackupd.cpp @ 3086

Revision 3086, 112.4 KB checked in by chris, 2 months ago (diff)

Add support for SyncAllowScript? to set maximum upload bandwidth dynamically.

  • Property svn:eol-style set to native
Line 
1// --------------------------------------------------------------------------
2//
3// File
4//              Name:    testbbackupd.cpp
5//              Purpose: test backup daemon (and associated client bits)
6//              Created: 2003/10/07
7//
8// --------------------------------------------------------------------------
9
10#include "Box.h"
11
12// do not include MinGW's dirent.h on Win32,
13// as we override some of it in lib/win32.
14
15#ifndef WIN32
16        #include <dirent.h>
17#endif
18
19#include <stdio.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <limits.h>
23#include <string.h>
24#include <unistd.h>
25
26#ifdef HAVE_SYS_WAIT_H
27        #include <sys/wait.h>
28#endif
29
30#ifdef HAVE_SYS_XATTR_H
31        #include <cerrno>
32        #include <sys/xattr.h>
33#endif
34
35#ifdef HAVE_SIGNAL_H
36        #include <signal.h>
37#endif
38
39#include <map>
40
41#ifdef HAVE_SYSCALL
42        #include <sys/syscall.h>
43#endif
44
45#include "autogen_BackupProtocol.h"
46#include "BackupClientCryptoKeys.h"
47#include "BackupClientFileAttributes.h"
48#include "BackupClientRestore.h"
49#include "BackupDaemon.h"
50#include "BackupDaemonConfigVerify.h"
51#include "BackupQueries.h"
52#include "BackupStoreConstants.h"
53#include "BackupStoreContext.h"
54#include "BackupStoreDaemon.h"
55#include "BackupStoreDirectory.h"
56#include "BackupStoreException.h"
57#include "BoxPortsAndFiles.h"
58#include "BoxTime.h"
59#include "BoxTimeToUnix.h"
60#include "CollectInBufferStream.h"
61#include "CommonException.h"
62#include "Configuration.h"
63#include "FileModificationTime.h"
64#include "FileStream.h"
65#include "intercept.h"
66#include "IOStreamGetLine.h"
67#include "LocalProcessStream.h"
68#include "SSLLib.h"
69#include "ServerControl.h"
70#include "Socket.h"
71#include "SocketStreamTLS.h"
72#include "TLSContext.h"
73#include "Test.h"
74#include "Timer.h"
75#include "Utils.h"
76
77#include "MemLeakFindOn.h"
78
79// ENOATTR may be defined in a separate header file which we may not have
80#ifndef ENOATTR
81#define ENOATTR ENODATA
82#endif
83
84// two cycles and a bit
85#define TIME_TO_WAIT_FOR_BACKUP_OPERATION       12
86
87void wait_for_backup_operation(const char* message)
88{
89        wait_for_operation(TIME_TO_WAIT_FOR_BACKUP_OPERATION, message);
90}
91
92int bbstored_pid = 0;
93int bbackupd_pid = 0;
94
95#ifdef HAVE_SYS_XATTR_H
96bool readxattr_into_map(const char *filename, std::map<std::string,std::string> &rOutput)
97{
98        rOutput.clear();
99       
100        ssize_t xattrNamesBufferSize = llistxattr(filename, NULL, 0);
101        if(xattrNamesBufferSize < 0)
102        {
103                return false;
104        }
105        else if(xattrNamesBufferSize > 0)
106        {
107                // There is some data there to look at
108                char *xattrNamesBuffer = (char*)malloc(xattrNamesBufferSize + 4);
109                if(xattrNamesBuffer == NULL) return false;
110                char *xattrDataBuffer = 0;
111                int xattrDataBufferSize = 0;
112                // note: will leak these buffers if a read error occurs. (test code, so doesn't matter)
113               
114                ssize_t ns = llistxattr(filename, xattrNamesBuffer, xattrNamesBufferSize);
115                if(ns < 0)
116                {
117                        return false;
118                }
119                else if(ns > 0)
120                {
121                        // Read all the attribute values
122                        const char *xattrName = xattrNamesBuffer;
123                        while(xattrName < (xattrNamesBuffer + ns))
124                        {
125                                // Store size of name
126                                int xattrNameSize = strlen(xattrName);
127                               
128                                bool ok = true;
129                                       
130                                ssize_t dataSize = lgetxattr(filename, xattrName, NULL, 0);
131                                if(dataSize < 0)
132                                {
133                                        if(errno == ENOATTR)
134                                        {
135                                                // Deleted from under us
136                                                ok = false;
137                                        }
138                                        else
139                                        {
140                                                return false;
141                                        }
142                                }
143                                else if(dataSize == 0)
144                                {
145                                        // something must have removed all the data from under us
146                                        ok = false;
147                                }
148                                else
149                                {
150                                        // Make sure there's enough space in the buffer to get the attribute
151                                        if(xattrDataBuffer == 0)
152                                        {
153                                                xattrDataBuffer = (char*)malloc(dataSize + 4);
154                                                xattrDataBufferSize = dataSize + 4;
155                                        }
156                                        else if(xattrDataBufferSize < (dataSize + 4))
157                                        {
158                                                char *resized = (char*)realloc(xattrDataBuffer, dataSize + 4);
159                                                if(resized == NULL) return false;
160                                                xattrDataBuffer = resized;
161                                                xattrDataBufferSize = dataSize + 4;
162                                        }
163                                }
164
165                                // Read the data!
166                                dataSize = 0;
167                                if(ok)
168                                {
169                                        dataSize = lgetxattr(filename, xattrName, xattrDataBuffer,
170                                                xattrDataBufferSize - 1 /*for terminator*/);
171                                        if(dataSize < 0)
172                                        {
173                                                if(errno == ENOATTR)
174                                                {
175                                                        // Deleted from under us
176                                                        ok = false;
177                                                }
178                                                else
179                                                {
180                                                        return false;
181                                                }
182                                        }
183                                        else if(dataSize == 0)
184                                        {
185                                                // something must have deleted this from under us
186                                                ok = false;
187                                        }
188                                        else
189                                        {
190                                                // Terminate the data
191                                                xattrDataBuffer[dataSize] = '\0';
192                                        }
193                                        // Got the data in the buffer
194                                }
195                               
196                                // Store in map
197                                if(ok)
198                                {
199                                        rOutput[std::string(xattrName)] = std::string(xattrDataBuffer, dataSize);
200                                }
201
202                                // Next attribute
203                                xattrName += xattrNameSize + 1;
204                        }
205                }
206               
207                if(xattrNamesBuffer != 0) ::free(xattrNamesBuffer);
208                if(xattrDataBuffer != 0) ::free(xattrDataBuffer);
209        }
210
211        return true;
212}
213
214static FILE *xattrTestDataHandle = 0;
215bool write_xattr_test(const char *filename, const char *attrName, unsigned int length, bool *pNotSupported = 0)
216{
217        if(xattrTestDataHandle == 0)
218        {
219                xattrTestDataHandle = ::fopen("testfiles/test3.tgz", "rb");     // largest test file
220        }
221        if(xattrTestDataHandle == 0)
222        {
223                return false;
224        }
225        else
226        {
227                char data[1024];
228                if(length > sizeof(data)) length = sizeof(data);
229               
230                if(::fread(data, length, 1, xattrTestDataHandle) != 1)
231                {
232                        return false;
233                }
234               
235                if(::lsetxattr(filename, attrName, data, length, 0) != 0)
236                {
237                        if(pNotSupported != 0)
238                        {
239                                *pNotSupported = (errno == ENOTSUP);
240                        }
241                        return false;
242                }
243        }
244
245        return true;
246}
247void finish_with_write_xattr_test()
248{
249        if(xattrTestDataHandle != 0)
250        {
251                ::fclose(xattrTestDataHandle);
252        }
253}
254#endif // HAVE_SYS_XATTR_H
255
256bool attrmatch(const char *f1, const char *f2)
257{
258        EMU_STRUCT_STAT s1, s2;
259        TEST_THAT(EMU_LSTAT(f1, &s1) == 0);
260        TEST_THAT(EMU_LSTAT(f2, &s2) == 0);
261
262#ifdef HAVE_SYS_XATTR_H
263        {
264                std::map<std::string,std::string> xattr1, xattr2;
265                if(!readxattr_into_map(f1, xattr1)
266                        || !readxattr_into_map(f2, xattr2))
267                {
268                        return false;
269                }
270                if(!(xattr1 == xattr2))
271                {
272                        return false;
273                }
274        }
275#endif // HAVE_SYS_XATTR_H
276
277        // if link, just make sure other file is a link too, and that the link to names match
278        if((s1.st_mode & S_IFMT) == S_IFLNK)
279        {
280#ifdef WIN32
281                TEST_FAIL_WITH_MESSAGE("No symlinks on win32!")
282#else
283                if((s2.st_mode & S_IFMT) != S_IFLNK) return false;
284               
285                char p1[PATH_MAX], p2[PATH_MAX];
286                int p1l = ::readlink(f1, p1, PATH_MAX);
287                int p2l = ::readlink(f2, p2, PATH_MAX);
288                TEST_THAT(p1l != -1 && p2l != -1);
289                // terminate strings properly
290                p1[p1l] = '\0';
291                p2[p2l] = '\0';
292                return strcmp(p1, p2) == 0;
293#endif
294        }
295
296        // modification times
297        if(FileModificationTime(s1) != FileModificationTime(s2))
298        {
299                return false;
300        }
301
302        // compare the rest
303        return (s1.st_mode == s2.st_mode && s1.st_uid == s2.st_uid && s1.st_gid == s2.st_gid);
304}
305
306int test_basics()
307{
308        // Read attributes from files
309        BackupClientFileAttributes t1;
310        t1.ReadAttributes("testfiles/test1");
311        TEST_THAT(!t1.IsSymLink());
312
313#ifndef WIN32
314        BackupClientFileAttributes t2;
315        t2.ReadAttributes("testfiles/test2");
316        TEST_THAT(t2.IsSymLink());
317        // Check that it's actually been encrypted (search for symlink name encoded in it)
318        void *te = ::memchr(t2.GetBuffer(), 't', t2.GetSize() - 3);
319        TEST_THAT(te == 0 || ::memcmp(te, "test", 4) != 0);
320#endif
321       
322        BackupClientFileAttributes t3;
323        {
324                Logging::Guard guard(Log::ERROR);
325                TEST_CHECK_THROWS(t3.ReadAttributes("doesn't exist"),
326                        CommonException, OSFileError);
327        }
328
329        // Create some more files
330        FILE *f = fopen("testfiles/test1_n", "w");
331        fclose(f);
332        f = fopen("testfiles/test2_n", "w");
333        fclose(f);
334       
335        // Apply attributes to these new files
336        t1.WriteAttributes("testfiles/test1_n");
337#ifdef WIN32
338        t1.WriteAttributes("testfiles/test2_n");
339#else
340        t2.WriteAttributes("testfiles/test2_n");
341#endif
342
343#ifndef WIN32
344        {
345                Logging::Guard guard(Log::ERROR);
346                TEST_CHECK_THROWS(t1.WriteAttributes("testfiles/test1_nXX"),
347                        CommonException, OSFileError);
348                TEST_CHECK_THROWS(t3.WriteAttributes("doesn't exist"),
349                        BackupStoreException, AttributesNotLoaded);
350        }
351
352        // Test that attributes are vaguely similar
353        TEST_THAT(attrmatch("testfiles/test1", "testfiles/test1_n"));
354        TEST_THAT(attrmatch("testfiles/test2", "testfiles/test2_n"));
355#endif
356       
357        // Check encryption, and recovery from encryption
358        // First, check that two attributes taken from the same thing have different encrypted values (think IV)
359        BackupClientFileAttributes t1b;
360        t1b.ReadAttributes("testfiles/test1");
361        TEST_THAT(::memcmp(t1.GetBuffer(), t1b.GetBuffer(), t1.GetSize()) != 0);
362        // But that comparing them works OK.
363        TEST_THAT(t1 == t1b);
364        // Then store them both to a stream
365        CollectInBufferStream stream;
366        t1.WriteToStream(stream);
367        t1b.WriteToStream(stream);
368        // Read them back again
369        stream.SetForReading();
370        BackupClientFileAttributes t1_r, t1b_r;
371        t1_r.ReadFromStream(stream, 1000);
372        t1b_r.ReadFromStream(stream, 1000);
373        TEST_THAT(::memcmp(t1_r.GetBuffer(), t1b_r.GetBuffer(), t1_r.GetSize()) != 0);
374        TEST_THAT(t1_r == t1b_r);
375        TEST_THAT(t1 == t1_r);
376        TEST_THAT(t1b == t1b_r);
377        TEST_THAT(t1_r == t1b);
378        TEST_THAT(t1b_r == t1);
379
380#ifdef HAVE_SYS_XATTR_H
381        // Write some attributes to the file, checking for ENOTSUP
382        bool xattrNotSupported = false;
383        if(!write_xattr_test("testfiles/test1", "user.attr_1", 1000, &xattrNotSupported) && xattrNotSupported)
384        {
385                ::printf("***********\nYour platform supports xattr, but your filesystem does not.\nSkipping tests.\n***********\n");
386        }
387        else
388        {
389                BackupClientFileAttributes x1, x2, x3, x4;
390
391                // Write more attributes
392                TEST_THAT(write_xattr_test("testfiles/test1", "user.attr_2", 947));
393                TEST_THAT(write_xattr_test("testfiles/test1", "user.sadfohij39998.3hj", 123));
394       
395                // Read file attributes
396                x1.ReadAttributes("testfiles/test1");
397               
398                // Write file attributes
399                FILE *f = fopen("testfiles/test1_nx", "w");
400                fclose(f);
401                x1.WriteAttributes("testfiles/test1_nx");
402               
403                // Compare to see if xattr copied
404                TEST_THAT(attrmatch("testfiles/test1", "testfiles/test1_nx"));
405               
406                // Add more attributes to a file
407                x2.ReadAttributes("testfiles/test1");
408                TEST_THAT(write_xattr_test("testfiles/test1", "user.328989sj..sdf", 23));
409               
410                // Read them again, and check that the Compare() function detects that they're different
411                x3.ReadAttributes("testfiles/test1");
412                TEST_THAT(x1.Compare(x2, true, true));
413                TEST_THAT(!x1.Compare(x3, true, true));
414               
415                // Change the value of one of them, leaving the size the same.
416                TEST_THAT(write_xattr_test("testfiles/test1", "user.328989sj..sdf", 23));
417                x4.ReadAttributes("testfiles/test1");
418                TEST_THAT(!x1.Compare(x4, true, true));
419        }
420        finish_with_write_xattr_test();
421#endif // HAVE_SYS_XATTR_H
422
423        return 0;
424}
425
426int test_setupaccount()
427{
428        TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS " -c "
429                "testfiles/bbstored.conf create 01234567 0 1000B 2000B") == 0);
430        TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
431        return 0;
432}
433
434int test_run_bbstored()
435{
436        std::string cmd = BBSTORED " " + bbstored_args + 
437                " testfiles/bbstored.conf";
438        bbstored_pid = LaunchServer(cmd, "testfiles/bbstored.pid");
439
440        TEST_THAT(bbstored_pid != -1 && bbstored_pid != 0);
441
442        if(bbstored_pid > 0)
443        {
444                ::safe_sleep(1);
445                TEST_THAT(ServerIsAlive(bbstored_pid));
446                return 0;       // success
447        }
448       
449        return 1;
450}
451
452int test_kill_bbstored(bool wait_for_process = false)
453{
454        TEST_THAT(KillServer(bbstored_pid, wait_for_process));
455        ::safe_sleep(1);
456        TEST_THAT(!ServerIsAlive(bbstored_pid));
457        if (!ServerIsAlive(bbstored_pid))
458        {
459                bbstored_pid = 0;
460        }
461
462        #ifdef WIN32
463                TEST_THAT(unlink("testfiles/bbstored.pid") == 0);
464        #else
465                TestRemoteProcessMemLeaks("bbstored.memleaks");
466        #endif
467       
468        return 0;
469}
470
471int64_t GetDirID(BackupProtocolClient &protocol, const char *name, int64_t InDirectory)
472{
473        protocol.QueryListDirectory(
474                        InDirectory,
475                        BackupProtocolListDirectory::Flags_Dir,
476                        BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING,
477                        true /* want attributes */);
478       
479        // Retrieve the directory from the stream following
480        BackupStoreDirectory dir;
481        std::auto_ptr<IOStream> dirstream(protocol.ReceiveStream());
482        dir.ReadFromStream(*dirstream, protocol.GetTimeout());
483       
484        BackupStoreDirectory::Iterator i(dir);
485        BackupStoreDirectory::Entry *en = 0;
486        int64_t dirid = 0;
487        BackupStoreFilenameClear dirname(name);
488        while((en = i.Next()) != 0)
489        {
490                if(en->GetName() == dirname)
491                {
492                        dirid = en->GetObjectID();
493                }
494        }
495        return dirid;
496}
497
498void terminate_on_alarm(int sigraised)
499{
500        abort();
501}
502
503#ifndef WIN32
504void do_interrupted_restore(const TLSContext &context, int64_t restoredirid)
505{
506        int pid = 0;
507        switch((pid = fork()))
508        {
509        case 0:
510                // child process
511                {
512                        // connect and log in
513                        SocketStreamTLS conn;
514                        conn.Open(context, Socket::TypeINET, "localhost",
515                                22011);
516                        BackupProtocolClient protocol(conn);
517                        protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION);
518                        std::auto_ptr<BackupProtocolLoginConfirmed>
519                                loginConf(protocol.QueryLogin(0x01234567,
520                                        BackupProtocolLogin::Flags_ReadOnly));
521                       
522                        // Test the restoration
523                        TEST_THAT(BackupClientRestore(protocol, restoredirid,
524                                "testfiles/restore-interrupt", /* remote */
525                                "testfiles/restore-interrupt", /* local */
526                                true /* print progress dots */,
527                                false /* restore deleted */,
528                                false /* undelete after */,
529                                false /* resume */,
530                                false /* keep going */) == Restore_Complete);
531
532                        // Log out
533                        protocol.QueryFinished();
534                }
535                exit(0);
536                break;
537       
538        case -1:
539                {
540                        printf("Fork failed\n");
541                        exit(1);
542                }
543       
544        default:
545                {
546                        // Wait until a resume file is written, then terminate the child
547                        while(true)
548                        {
549                                // Test for existence of the result file
550                                int64_t resumesize = 0;
551                                if(FileExists("testfiles/restore-interrupt.boxbackupresume", &resumesize) && resumesize > 16)
552                                {
553                                        // It's done something. Terminate it.   
554                                        ::kill(pid, SIGTERM);
555                                        break;
556                                }
557
558                                // Process finished?
559                                int status = 0;
560                                if(waitpid(pid, &status, WNOHANG) != 0)
561                                {
562                                        // child has finished anyway.
563                                        return;
564                                }
565                               
566                                // Give up timeslot so as not to hog the processor
567                                ::sleep(0);
568                        }
569                       
570                        // Just wait until the child has completed
571                        int status = 0;
572                        waitpid(pid, &status, 0);
573                }
574        }
575}
576#endif // !WIN32
577
578#ifdef WIN32
579bool set_file_time(const char* filename, FILETIME creationTime, 
580        FILETIME lastModTime, FILETIME lastAccessTime)
581{
582        HANDLE handle = openfile(filename, O_RDWR, 0);
583        TEST_THAT(handle != INVALID_HANDLE_VALUE);
584        if (handle == INVALID_HANDLE_VALUE) return false;
585               
586        BOOL success = SetFileTime(handle, &creationTime, &lastAccessTime,
587                &lastModTime);
588        TEST_THAT(success);
589
590        TEST_THAT(CloseHandle(handle));
591        return success;
592}
593#endif
594
595void intercept_setup_delay(const char *filename, unsigned int delay_after, 
596        int delay_ms, int syscall_to_delay);
597bool intercept_triggered();
598
599int64_t SearchDir(BackupStoreDirectory& rDir,
600        const std::string& rChildName)
601{
602        BackupStoreDirectory::Iterator i(rDir);
603        BackupStoreFilenameClear child(rChildName.c_str());
604        BackupStoreDirectory::Entry *en = i.FindMatchingClearName(child);
605        if (en == 0) return 0;
606        int64_t id = en->GetObjectID();
607        TEST_THAT(id > 0);
608        TEST_THAT(id != BackupProtocolListDirectory::RootDirectory);
609        return id;
610}
611
612SocketStreamTLS sSocket;
613
614std::auto_ptr<BackupProtocolClient> Connect(TLSContext& rContext)
615{
616        sSocket.Open(rContext, Socket::TypeINET, 
617                "localhost", 22011);
618        std::auto_ptr<BackupProtocolClient> connection;
619        connection.reset(new BackupProtocolClient(sSocket));
620        connection->Handshake();
621        std::auto_ptr<BackupProtocolVersion> 
622                serverVersion(connection->QueryVersion(
623                        BACKUP_STORE_SERVER_VERSION));
624        if(serverVersion->GetVersion() != 
625                BACKUP_STORE_SERVER_VERSION)
626        {
627                THROW_EXCEPTION(BackupStoreException, 
628                        WrongServerVersion);
629        }
630        return connection;
631}
632
633std::auto_ptr<BackupProtocolClient> ConnectAndLogin(TLSContext& rContext,
634        int flags)
635{
636        std::auto_ptr<BackupProtocolClient> connection(Connect(rContext));
637        connection->QueryLogin(0x01234567, flags);
638        return connection;
639}
640       
641std::auto_ptr<BackupStoreDirectory> ReadDirectory
642(
643        BackupProtocolClient& rClient,
644        int64_t id = BackupProtocolListDirectory::RootDirectory
645)
646{
647        std::auto_ptr<BackupProtocolSuccess> dirreply(
648                rClient.QueryListDirectory(id, false, 0, false));
649        std::auto_ptr<IOStream> dirstream(rClient.ReceiveStream());
650        std::auto_ptr<BackupStoreDirectory> apDir(new BackupStoreDirectory());
651        apDir->ReadFromStream(*dirstream, rClient.GetTimeout());
652        return apDir;
653}
654       
655Daemon* spDaemon = NULL;
656
657int start_internal_daemon()
658{
659        // ensure that no child processes end up running tests!
660        int own_pid = getpid();
661        BOX_TRACE("Test PID is " << own_pid);
662               
663        // this is a quick hack to allow passing some options to the daemon
664        const char* argv[] = {
665                "dummy",
666                bbackupd_args.c_str(),
667        };
668
669        BackupDaemon daemon;
670        spDaemon = &daemon; // to propagate into child
671        int result;
672
673        if (bbackupd_args.size() > 0)
674        {
675                result = daemon.Main("testfiles/bbackupd.conf", 2, argv);
676        }
677        else
678        {
679                result = daemon.Main("testfiles/bbackupd.conf", 1, argv);
680        }
681
682        spDaemon = NULL; // to ensure not used by parent
683       
684        TEST_EQUAL_LINE(0, result, "Daemon exit code");
685       
686        // ensure that no child processes end up running tests!
687        if (getpid() != own_pid)
688        {
689                // abort!
690                BOX_INFO("Daemon child finished, exiting now.");
691                _exit(0);
692        }
693
694        TEST_THAT(TestFileExists("testfiles/bbackupd.pid"));
695       
696        printf("Waiting for backup daemon to start: ");
697        int pid = -1;
698       
699        for (int i = 0; i < 30; i++)
700        {
701                printf(".");
702                fflush(stdout);
703                safe_sleep(1);
704
705                if (TestFileExists("testfiles/bbackupd.pid"))
706                {
707                        pid = ReadPidFile("testfiles/bbackupd.pid");
708                }
709
710                if (pid > 0)
711                {
712                        break;
713                }               
714        }
715       
716        printf(" done.\n");
717        fflush(stdout);
718
719        TEST_THAT(pid > 0);
720        spDaemon = &daemon;
721        return pid;
722}
723
724bool stop_internal_daemon(int pid)
725{
726        bool killed_server = KillServer(pid, false);
727        TEST_THAT(killed_server);
728        return killed_server;
729}
730
731static struct dirent readdir_test_dirent;
732static int readdir_test_counter = 0;
733static int readdir_stop_time = 0;
734static char stat_hook_filename[512];
735
736// First test hook, during the directory scanning stage, returns empty.
737// This will not match the directory on the store, so a sync will start.
738// We set up the next intercept for the same directory by passing NULL.
739
740extern "C" struct dirent *readdir_test_hook_2(DIR *dir);
741
742#ifdef LINUX_WEIRD_LSTAT
743extern "C" int lstat_test_hook(int ver, const char *file_name, struct stat *buf);
744#else
745extern "C" int lstat_test_hook(const char *file_name, struct stat *buf);
746#endif
747
748extern "C" struct dirent *readdir_test_hook_1(DIR *dir)
749{
750#ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
751        intercept_setup_readdir_hook(NULL, readdir_test_hook_2);
752#endif
753        return NULL;
754}
755
756// Second test hook, during the directory sync stage, keeps returning
757// new filenames until the timer expires, then disables the intercept.
758
759extern "C" struct dirent *readdir_test_hook_2(DIR *dir)
760{
761        if (spDaemon->IsTerminateWanted())
762        {
763                // force daemon to crash, right now
764                return NULL;
765        }
766
767        time_t time_now = time(NULL);
768
769        if (time_now >= readdir_stop_time)
770        {
771#ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
772                BOX_NOTICE("Cancelling readdir hook at " << time_now);
773                intercept_setup_readdir_hook(NULL, NULL);
774                intercept_setup_lstat_hook  (NULL, NULL);
775                // we will not be called again.
776#else
777                BOX_NOTICE("Failed to cancel readdir hook at " << time_now);
778#endif
779        }
780        else
781        {
782                BOX_TRACE("readdir hook still active at " << time_now << ", "
783                        "waiting for " << readdir_stop_time);
784        }
785
786        // fill in the struct dirent appropriately
787        memset(&readdir_test_dirent, 0, sizeof(readdir_test_dirent));
788
789        #ifdef HAVE_STRUCT_DIRENT_D_INO
790                readdir_test_dirent.d_ino = ++readdir_test_counter;
791        #endif
792
793        snprintf(readdir_test_dirent.d_name, 
794                sizeof(readdir_test_dirent.d_name),
795                "test.%d", readdir_test_counter);
796        BOX_TRACE("readdir hook returning " << readdir_test_dirent.d_name);
797
798        // ensure that when bbackupd stats the file, it gets the
799        // right answer
800        snprintf(stat_hook_filename, sizeof(stat_hook_filename),
801                "testfiles/TestDir1/spacetest/d1/test.%d", 
802                readdir_test_counter);
803
804#ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
805        intercept_setup_lstat_hook(stat_hook_filename, lstat_test_hook);
806#endif
807
808        // sleep a bit to reduce the number of dirents returned
809        ::safe_sleep(1);
810
811        return &readdir_test_dirent;
812}
813
814#ifdef LINUX_WEIRD_LSTAT
815extern "C" int lstat_test_hook(int ver, const char *file_name, struct stat *buf)
816#else
817extern "C" int lstat_test_hook(const char *file_name, struct stat *buf)
818#endif
819{
820        // TRACE1("lstat hook triggered for %s", file_name);
821        memset(buf, 0, sizeof(*buf));
822        buf->st_mode = S_IFREG;
823        return 0;
824}
825
826// Simulate a symlink that is on a different device than the file
827// that it points to.
828int lstat_test_post_hook(int old_ret, const char *file_name, struct stat *buf)
829{
830        BOX_TRACE("lstat post hook triggered for " << file_name);
831        if (old_ret == 0 &&
832                strcmp(file_name, "testfiles/symlink-to-TestDir1") == 0)
833        {
834                buf->st_dev ^= 0xFFFF;
835        }
836        return old_ret;
837}
838
839bool test_entry_deleted(BackupStoreDirectory& rDir, 
840        const std::string& rName)
841{
842        BackupStoreDirectory::Iterator i(rDir);
843
844        BackupStoreDirectory::Entry *en = i.FindMatchingClearName(
845                BackupStoreFilenameClear(rName));
846        TEST_THAT(en != 0);
847        if (en == 0) return false;
848
849        int16_t flags = en->GetFlags();
850        TEST_THAT(flags && BackupStoreDirectory::Entry::Flags_Deleted);
851        return flags && BackupStoreDirectory::Entry::Flags_Deleted;
852}
853
854bool compare_all(BackupQueries::ReturnCode::Type expected_status,
855        std::string config_file = "testfiles/bbackupd.conf")
856{
857        std::string cmd = BBACKUPQUERY;
858        cmd += " ";
859        cmd += (expected_status == BackupQueries::ReturnCode::Compare_Same)
860                ? "-Werror" : "-Wwarning";
861        cmd += " -c ";
862        cmd += config_file;
863        cmd += " \"compare -acQ\" quit";
864
865        int returnValue = ::system(cmd.c_str());
866
867        int expected_system_result = (int) expected_status;
868
869        #ifndef WIN32
870                expected_system_result <<= 8;
871        #endif
872
873        TEST_EQUAL_LINE(expected_system_result, returnValue, "compare return value");
874        TestRemoteProcessMemLeaks("bbackupquery.memleaks");
875        return (returnValue == expected_system_result);
876}
877
878#define TEST_COMPARE(...) \
879        TEST_THAT(compare_all(BackupQueries::ReturnCode::__VA_ARGS__));
880
881int test_bbackupd()
882{
883        // First, wait for a normal period to make sure the last changes
884        // attributes are within a normal backup timeframe.
885        // wait_for_backup_operation();
886
887        // Connection gubbins
888        TLSContext context;
889        context.Initialise(false /* client */,
890                        "testfiles/clientCerts.pem",
891                        "testfiles/clientPrivKey.pem",
892                        "testfiles/clientTrustedCAs.pem");
893
894        printf("\n==== Testing that ReadDirectory on nonexistent directory "
895                "does not crash\n");
896        {
897                std::auto_ptr<BackupProtocolClient> client = ConnectAndLogin(
898                        context, 0 /* read-write */);
899               
900                {
901                        Logging::Guard guard(Log::ERROR);
902                        TEST_CHECK_THROWS(ReadDirectory(*client, 0x12345678),
903                                ConnectionException,
904                                Conn_Protocol_UnexpectedReply);
905                }
906
907                client->QueryFinished();
908                sSocket.Close();
909        }
910
911        // unpack the files for the initial test
912        TEST_THAT(::system("rm -rf testfiles/TestDir1") == 0);
913        TEST_THAT(::mkdir("testfiles/TestDir1", 0777) == 0);
914
915        #ifdef WIN32
916                TEST_THAT(::system("tar xzvf testfiles/spacetest1.tgz "
917                        "-C testfiles/TestDir1") == 0);
918        #else
919                TEST_THAT(::system("gzip -d < testfiles/spacetest1.tgz "
920                        "| ( cd testfiles/TestDir1 && tar xf - )") == 0);
921        #endif
922
923#ifdef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
924        printf("\n==== Skipping intercept-based KeepAlive tests "
925                "on this platform.\n");
926#else
927        printf("\n==== Testing SSL KeepAlive messages\n");
928
929        {
930                #ifdef WIN32
931                #error TODO: implement threads on Win32, or this test \
932                        will not finish properly
933                #endif
934
935                // bbackupd daemon will try to initialise timers itself
936                Timers::Cleanup();
937               
938                // something to diff against (empty file doesn't work)
939                int fd = open("testfiles/TestDir1/spacetest/f1", O_WRONLY);
940                TEST_THAT(fd > 0);
941
942                char buffer[10000];
943                memset(buffer, 0, sizeof(buffer));
944
945                TEST_EQUAL_LINE(sizeof(buffer),
946                        write(fd, buffer, sizeof(buffer)),
947                        "Buffer write");
948                TEST_THAT(close(fd) == 0);
949               
950                int pid = start_internal_daemon();
951                wait_for_backup_operation("internal daemon to run a sync");
952                TEST_THAT(stop_internal_daemon(pid));
953
954                // two-second delay on the first read() of f1
955                // should mean that a single keepalive is sent,
956                // and diff does not abort.
957                intercept_setup_delay("testfiles/TestDir1/spacetest/f1", 
958                        0, 2000, SYS_read, 1);
959                TEST_THAT(unlink("testfiles/bbackupd.log") == 0);
960
961                pid = start_internal_daemon();
962                intercept_clear_setup();
963               
964                fd = open("testfiles/TestDir1/spacetest/f1", O_WRONLY);
965                TEST_THAT(fd > 0);
966                // write again, to update the file's timestamp
967                TEST_EQUAL_LINE(sizeof(buffer),
968                        write(fd, buffer, sizeof(buffer)),
969                        "Buffer write");
970                TEST_THAT(close(fd) == 0);     
971
972                wait_for_backup_operation("internal daemon to sync "
973                        "spacetest/f1");
974                // can't test whether intercept was triggered, because
975                // it's in a different process.
976                // TEST_THAT(intercept_triggered());
977                TEST_THAT(stop_internal_daemon(pid));
978
979                // check that keepalive was written to logs, and
980                // diff was not aborted, i.e. upload was a diff
981                FileStream fs("testfiles/bbackupd.log", O_RDONLY);
982                IOStreamGetLine reader(fs);
983                bool found1 = false;
984
985                while (!reader.IsEOF())
986                {
987                        std::string line;
988                        TEST_THAT(reader.GetLine(line));
989                        if (line == "Send GetBlockIndexByName(0x3,\"f1\")")
990                        {
991                                found1 = true;
992                                break;
993                        }
994                }
995
996                TEST_THAT(found1);
997                if (found1)
998                {
999                        std::string line;
1000                        TEST_THAT(reader.GetLine(line));
1001                        std::string comp = "Receive Success(0x";
1002                        TEST_EQUAL_LINE(comp, line.substr(0, comp.size()),
1003                                line);
1004                        TEST_THAT(reader.GetLine(line));
1005                        TEST_EQUAL("Receiving stream, size 124", line);
1006                        TEST_THAT(reader.GetLine(line));
1007                        TEST_EQUAL("Send GetIsAlive()", line);
1008                        TEST_THAT(reader.GetLine(line));
1009                        TEST_EQUAL("Receive IsAlive()", line);
1010
1011                        TEST_THAT(reader.GetLine(line));
1012                        comp = "Send StoreFile(0x3,";
1013                        TEST_EQUAL_LINE(comp, line.substr(0, comp.size()),
1014                                line);
1015                        comp = ",\"f1\")";
1016                        std::string sub = line.substr(line.size() - comp.size());
1017                        TEST_EQUAL_LINE(comp, sub, line);
1018                        std::string comp2 = ",0x0,";
1019                        sub = line.substr(line.size() - comp.size() -
1020                                comp2.size() + 1, comp2.size());
1021                        TEST_LINE(comp2 != sub, line);
1022                }
1023
1024                Timers::Init();
1025               
1026                if (failures > 0)
1027                {
1028                        // stop early to make debugging easier
1029                        return 1;
1030                }
1031
1032                // four-second delay on first read() of f1
1033                // should mean that no keepalives were sent,
1034                // because diff was immediately aborted
1035                // before any matching blocks could be found.
1036                intercept_setup_delay("testfiles/TestDir1/spacetest/f1", 
1037                        0, 4000, SYS_read, 1);
1038               
1039                {
1040                        BackupDaemon bbackupd;
1041                        bbackupd.Configure("testfiles/bbackupd.conf");
1042                        bbackupd.InitCrypto();
1043               
1044                        fd = open("testfiles/TestDir1/spacetest/f1", O_WRONLY);
1045                        TEST_THAT(fd > 0);
1046                        // write again, to update the file's timestamp
1047                        TEST_EQUAL_LINE(1, write(fd, "z", 1), "Buffer write");
1048                        TEST_THAT(close(fd) == 0);
1049
1050                        // wait long enough to put file into sync window
1051                        wait_for_operation(5, "locally modified file to "
1052                                "mature for sync");
1053
1054                        bbackupd.RunSyncNow();
1055                        TEST_THAT(intercept_triggered());
1056                        intercept_clear_setup();
1057                        Timers::Cleanup();
1058                }
1059
1060                // check that the diff was aborted, i.e. upload was not a diff
1061                found1 = false;
1062
1063                while (!reader.IsEOF())
1064                {
1065                        std::string line;
1066                        TEST_THAT(reader.GetLine(line));
1067                        if (line == "Send GetBlockIndexByName(0x3,\"f1\")")
1068                        {
1069                                found1 = true;
1070                                break;
1071                        }
1072                }
1073
1074                TEST_THAT(found1);
1075                if (found1)
1076                {
1077                        std::string line;
1078                        TEST_THAT(reader.GetLine(line));
1079                        std::string comp = "Receive Success(0x";
1080                        TEST_EQUAL_LINE(comp, line.substr(0, comp.size()),
1081                                line);
1082                        TEST_THAT(reader.GetLine(line));
1083                        TEST_EQUAL("Receiving stream, size 124", line);
1084
1085                        // delaying for 4 seconds in one step means that
1086                        // the diff timer and the keepalive timer will
1087                        // both expire, and the diff timer is honoured first,
1088                        // so there will be no keepalives.
1089
1090                        TEST_THAT(reader.GetLine(line));
1091                        comp = "Send StoreFile(0x3,";
1092                        TEST_EQUAL_LINE(comp, line.substr(0, comp.size()),
1093                                line);
1094                        comp = ",0x0,\"f1\")";
1095                        std::string sub = line.substr(line.size() - comp.size());
1096                        TEST_EQUAL_LINE(comp, sub, line);
1097                }
1098
1099                if (failures > 0)
1100                {
1101                        // stop early to make debugging easier
1102                        Timers::Init();
1103                        return 1;
1104                }
1105
1106                intercept_setup_delay("testfiles/TestDir1/spacetest/f1", 
1107                        0, 1000, SYS_read, 3);
1108                pid = start_internal_daemon();
1109                intercept_clear_setup();
1110               
1111                fd = open("testfiles/TestDir1/spacetest/f1", O_WRONLY);
1112                TEST_THAT(fd > 0);
1113                // write again, to update the file's timestamp
1114                TEST_EQUAL_LINE(sizeof(buffer),
1115                        write(fd, buffer, sizeof(buffer)),
1116                        "Buffer write");
1117                TEST_THAT(close(fd) == 0);     
1118
1119                wait_for_backup_operation("internal daemon to sync "
1120                        "spacetest/f1 again");
1121                // can't test whether intercept was triggered, because
1122                // it's in a different process.
1123                // TEST_THAT(intercept_triggered());
1124                TEST_THAT(stop_internal_daemon(pid));
1125
1126                // check that the diff was aborted, i.e. upload was not a diff
1127                found1 = false;
1128
1129                while (!reader.IsEOF())
1130                {
1131                        std::string line;
1132                        TEST_THAT(reader.GetLine(line));
1133                        if (line == "Send GetBlockIndexByName(0x3,\"f1\")")
1134                        {
1135                                found1 = true;
1136                                break;
1137                        }
1138                }
1139
1140                TEST_THAT(found1);
1141                if (found1)
1142                {
1143                        std::string line;
1144                        TEST_THAT(reader.GetLine(line));
1145                        std::string comp = "Receive Success(0x";
1146                        TEST_EQUAL_LINE(comp, line.substr(0, comp.size()),
1147                                line);
1148                        TEST_THAT(reader.GetLine(line));
1149                        TEST_EQUAL("Receiving stream, size 124", line);
1150
1151                        // delaying for 3 seconds in steps of 1 second
1152                        // means that the keepalive timer will expire 3 times,
1153                        // and on the 3rd time the diff timer will expire too.
1154                        // The diff timer is honoured first, so there will be
1155                        // only two keepalives.
1156                       
1157                        TEST_THAT(reader.GetLine(line));
1158                        TEST_EQUAL("Send GetIsAlive()", line);
1159                        TEST_THAT(reader.GetLine(line));
1160                        TEST_EQUAL("Receive IsAlive()", line);
1161                        TEST_THAT(reader.GetLine(line));
1162                        TEST_EQUAL("Send GetIsAlive()", line);
1163                        TEST_THAT(reader.GetLine(line));
1164                        TEST_EQUAL("Receive IsAlive()", line);
1165
1166                        // but two matching blocks should have been found
1167                        // already, so the upload should be a diff.
1168
1169                        TEST_THAT(reader.GetLine(line));
1170                        comp = "Send StoreFile(0x3,";
1171                        TEST_EQUAL_LINE(comp, line.substr(0, comp.size()),
1172                                line);
1173                        comp = ",\"f1\")";
1174                        std::string sub = line.substr(line.size() - comp.size());
1175                        TEST_EQUAL_LINE(comp, sub, line);
1176                        std::string comp2 = ",0x0,";
1177                        sub = line.substr(line.size() - comp.size() -
1178                                comp2.size() + 1, comp2.size());
1179                        TEST_LINE(comp2 != sub, line);
1180                }
1181
1182                // Check that no read error has been reported yet
1183                TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1"));
1184
1185                if (failures > 0)
1186                {
1187                        // stop early to make debugging easier
1188                        Timers::Init();
1189                        return 1;
1190                }
1191
1192                intercept_setup_readdir_hook("testfiles/TestDir1/spacetest/d1", 
1193                        readdir_test_hook_1);
1194               
1195                // time for at least two keepalives
1196                readdir_stop_time = time(NULL) + 12 + 2;
1197
1198                pid = start_internal_daemon();
1199                intercept_clear_setup();
1200               
1201                std::string touchfile = 
1202                        "testfiles/TestDir1/spacetest/d1/touch-me";
1203
1204                fd = open(touchfile.c_str(), O_CREAT | O_WRONLY);
1205                TEST_THAT(fd > 0);
1206                // write again, to update the file's timestamp
1207                TEST_EQUAL_LINE(sizeof(buffer),
1208                        write(fd, buffer, sizeof(buffer)),
1209                        "Buffer write");
1210                TEST_THAT(close(fd) == 0);     
1211
1212                wait_for_backup_operation("internal daemon to scan "
1213                        "spacetest/d1");
1214                // can't test whether intercept was triggered, because
1215                // it's in a different process.
1216                // TEST_THAT(intercept_triggered());
1217                TEST_THAT(stop_internal_daemon(pid));
1218
1219                // check that keepalives were sent during the dir search
1220                found1 = false;
1221
1222                // skip to next login
1223                while (!reader.IsEOF())
1224                {
1225                        std::string line;
1226                        TEST_THAT(reader.GetLine(line));
1227                        if (line == "Send ListDirectory(0x3,0xffff,0xc,true)")
1228                        {
1229                                found1 = true;
1230                                break;
1231                        }
1232                }
1233
1234                TEST_THAT(found1);
1235                if (found1)
1236                {
1237                        found1 = false;
1238
1239                        while (!reader.IsEOF())
1240                        {
1241                                std::string line;
1242                                TEST_THAT(reader.GetLine(line));
1243                                if (line == "Send ListDirectory(0x3,0xffffffff,0xc,true)")
1244                                {
1245                                        found1 = true;
1246                                        break;
1247                                }
1248                        }
1249                }
1250
1251                if (found1)
1252                {
1253                        std::string line;
1254                        TEST_THAT(reader.GetLine(line));
1255                        TEST_EQUAL("Receive Success(0x3)", line);
1256                        TEST_THAT(reader.GetLine(line));
1257                        TEST_EQUAL("Receiving stream, size 425", line);
1258                        TEST_THAT(reader.GetLine(line));
1259                        TEST_EQUAL("Send GetIsAlive()", line);
1260                        TEST_THAT(reader.GetLine(line));
1261                        TEST_EQUAL("Receive IsAlive()", line);
1262                        TEST_THAT(reader.GetLine(line));
1263                        TEST_EQUAL("Send GetIsAlive()", line);
1264                        TEST_THAT(reader.GetLine(line));
1265                        TEST_EQUAL("Receive IsAlive()", line);
1266                }
1267
1268                if (failures > 0)
1269                {
1270                        // stop early to make debugging easier
1271                        Timers::Init();
1272                        return 1;
1273                }
1274
1275                TEST_THAT(unlink(touchfile.c_str()) == 0);
1276
1277                // restore timers for rest of tests
1278                Timers::Init();
1279        }
1280#endif // PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
1281
1282        // Check that no read error has been reported yet
1283        TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1"));
1284
1285        std::string cmd = BBACKUPD " " + bbackupd_args + 
1286                " testfiles/bbackupd.conf";
1287
1288        bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid");
1289        TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0);
1290        ::safe_sleep(1);
1291
1292        TEST_THAT(ServerIsAlive(bbackupd_pid));
1293        TEST_THAT(ServerIsAlive(bbstored_pid));
1294        if (!ServerIsAlive(bbackupd_pid)) return 1;
1295        if (!ServerIsAlive(bbstored_pid)) return 1;
1296
1297        if(bbackupd_pid > 0)
1298        {
1299                printf("\n==== Testing that backup pauses when "
1300                        "store is full\n");
1301
1302                // wait for files to be uploaded
1303                BOX_TRACE("Waiting for all outstanding files to be uploaded")
1304                wait_for_sync_end();
1305                BOX_TRACE("done.")
1306
1307                // Set limit to something very small
1308                // 26 blocks will be used at this point.
1309                // (12 files + location * 2 for raidfile)
1310                // 20 is what we'll need in a minute
1311                // set soft limit to 0 to ensure that all deleted files
1312                // are deleted immediately by housekeeping
1313                TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS " -c "
1314                        "testfiles/bbstored.conf setlimit 01234567 0B 20B") 
1315                        == 0);
1316                TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
1317
1318                // Unpack some more files
1319                #ifdef WIN32
1320                        TEST_THAT(::system("tar xzvf testfiles/spacetest2.tgz "
1321                                "-C testfiles/TestDir1") == 0);
1322                #else
1323                        TEST_THAT(::system("gzip -d < testfiles/spacetest2.tgz "
1324                                "| ( cd testfiles/TestDir1 && tar xf - )") == 0);
1325                #endif
1326
1327                // Delete a file and a directory
1328                TEST_THAT(::unlink("testfiles/TestDir1/spacetest/f1") == 0);
1329                TEST_THAT(::system("rm -rf testfiles/TestDir1/spacetest/d7") == 0);
1330
1331                // The following files should be on the server:
1332                // 00000001 -d---- 00002 (root)
1333                // 00000002 -d---- 00002 Test1
1334                // 00000003 -d---- 00002 Test1/spacetest
1335                // 00000004 f-X--- 00002 Test1/spacetest/f1
1336                // 00000005 f----- 00002 Test1/spacetest/f2
1337                // 00000006 -d---- 00002 Test1/spacetest/d1
1338                // 00000007 f----- 00002 Test1/spacetest/d1/f3
1339                // 00000008 f----- 00002 Test1/spacetest/d1/f4
1340                // 00000009 -d---- 00002 Test1/spacetest/d2
1341                // 0000000a -d---- 00002 Test1/spacetest/d3
1342                // 0000000b -d---- 00002 Test1/spacetest/d3/d4
1343                // 0000000c f----- 00002 Test1/spacetest/d3/d4/f5
1344                // 0000000d -d---- 00002 Test1/spacetest/d6
1345                // 0000000e -dX--- 00002 Test1/spacetest/d7
1346                // This is 28 blocks total, of which 2 in deleted files
1347                // and 18 in directories. Note that f1 and d7 may or may
1348                // not be deleted yet.
1349                //
1350                // spacetest1 + spacetest2 = 16 files = 32 blocks with raidfile
1351                // minus one file and one dir is 28 blocks
1352                //
1353                // d2/f6, d6/d8 and d6/d8/f7 are new
1354                // even if the client marks f1 and d7 as deleted, and
1355                // housekeeping deleted them, the backup cannot complete
1356                // if the limit is 20 blocks.
1357
1358                BOX_TRACE("Waiting for sync for bbackupd to notice that the "
1359                        "store is full");
1360                wait_for_sync_end();
1361                BOX_TRACE("Sync finished.");
1362
1363                BOX_TRACE("Compare to check that there are differences");
1364                TEST_COMPARE(Compare_Different);
1365                BOX_TRACE("Compare finished.");
1366
1367                // Check that the notify script was run
1368                TEST_THAT(TestFileExists("testfiles/notifyran.store-full.1"));
1369                // But only once!
1370                TEST_THAT(!TestFileExists("testfiles/notifyran.store-full.2"));
1371               
1372                // Kill the daemon
1373                terminate_bbackupd(bbackupd_pid);
1374
1375                wait_for_operation(5, "housekeeping to remove the "
1376                        "deleted files");
1377
1378                // This removes f1 and d7, which were previously marked
1379                // as deleted, so total usage drops by 4 blocks to 24.
1380
1381                // BLOCK
1382                {
1383                        std::auto_ptr<BackupProtocolClient> client =
1384                                ConnectAndLogin(context, 0 /* read-write */);
1385               
1386                        std::auto_ptr<BackupProtocolAccountUsage> usage(
1387                                client->QueryGetAccountUsage());
1388                        TEST_EQUAL_LINE(24, usage->GetBlocksUsed(),
1389                                "blocks used");
1390                        TEST_EQUAL_LINE(0,  usage->GetBlocksInDeletedFiles(),
1391                                "deleted blocks");
1392                        TEST_EQUAL_LINE(16, usage->GetBlocksInDirectories(),
1393                                "directory blocks");
1394
1395                        client->QueryFinished();
1396                        sSocket.Close();
1397                }
1398
1399                if (failures > 0)
1400                {
1401                        // stop early to make debugging easier
1402                        return 1;
1403                }
1404
1405                // ensure time is different to refresh the cache
1406                ::safe_sleep(1);
1407
1408                BOX_TRACE("Restart bbackupd with more exclusions");
1409                // Start again with a new config that excludes d3 and f2,
1410                // and hence also d3/d4 and d3/d4/f5. bbackupd should mark
1411                // them as deleted and housekeeping should clean up,
1412                // making space to upload the new files.
1413                // total required: (13-2-4+3)*2 = 20 blocks
1414                /*
1415                cmd = BBACKUPD " " + bbackupd_args +
1416                        " testfiles/bbackupd-exclude.conf";
1417                bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid");
1418                TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0);
1419                TEST_THAT(ServerIsAlive(bbackupd_pid));
1420                TEST_THAT(ServerIsAlive(bbstored_pid));
1421                if (!ServerIsAlive(bbackupd_pid)) return 1;
1422                if (!ServerIsAlive(bbstored_pid)) return 1;
1423                */
1424
1425                BackupDaemon bbackupd;
1426
1427                {
1428                        const char* argv[] = { "bbackupd",
1429                                bbackupd_args.c_str() };
1430                        TEST_EQUAL_LINE(0, bbackupd.ProcessOptions(2, argv),
1431                                "processing command-line options");
1432                }
1433
1434                bbackupd.Configure("testfiles/bbackupd-exclude.conf");
1435                bbackupd.InitCrypto();
1436                BOX_TRACE("done.");
1437
1438                // Should be marked as deleted by this run
1439                // wait_for_sync_end();
1440                {
1441                        // Logging::Guard guard(Log::ERROR);
1442                        bbackupd.RunSyncNow();
1443                }
1444
1445                TEST_THAT(bbackupd.StorageLimitExceeded());
1446
1447                // Check that the notify script was run
1448                // TEST_THAT(TestFileExists("testfiles/notifyran.store-full.2"));
1449                // But only twice!
1450                // TEST_THAT(!TestFileExists("testfiles/notifyran.store-full.3"));
1451
1452                // All these should be marked as deleted but hopefully
1453                // not removed by housekeeping yet:
1454                // f1           deleted
1455                // f2           excluded
1456                // d1           excluded (why?)
1457                // d1/f3        excluded (why?)
1458                // d3           excluded
1459                // d3/d4        excluded
1460                // d3/d4/f5     excluded
1461                // d7           deleted
1462                // Careful with timing here, these files will be removed by
1463                // housekeeping the next time it runs. On Win32, housekeeping
1464                // runs immediately after disconnect, but only if enough time
1465                // has elapsed since the last housekeeping. Since the
1466                // backup run closely follows the last one, housekeeping
1467                // should not run afterwards. On other platforms, we want to
1468                // get in immediately after the backup and hope that
1469                // housekeeping doesn't beat us to it.
1470
1471                BOX_TRACE("Find out whether bbackupd marked files as deleted");
1472                {
1473                        std::auto_ptr<BackupProtocolClient> client =
1474                                ConnectAndLogin(context, 0 /* read-write */);
1475               
1476                        std::auto_ptr<BackupStoreDirectory> rootDir = 
1477                                ReadDirectory(*client);
1478
1479                        int64_t testDirId = SearchDir(*rootDir, "Test1");
1480                        TEST_THAT(testDirId != 0);
1481
1482                        std::auto_ptr<BackupStoreDirectory> Test1_dir =
1483                                ReadDirectory(*client, testDirId);
1484
1485                        int64_t spacetestDirId = SearchDir(*Test1_dir, 
1486                                "spacetest");
1487                        TEST_THAT(spacetestDirId != 0);
1488
1489                        std::auto_ptr<BackupStoreDirectory> spacetest_dir =
1490                                ReadDirectory(*client, spacetestDirId);
1491
1492                        // these files were deleted before, they should be
1493                        // long gone by now
1494
1495                        TEST_THAT(SearchDir(*spacetest_dir, "f1") == 0);
1496                        TEST_THAT(SearchDir(*spacetest_dir, "d7") == 0);
1497
1498                        // these files have just been deleted, because
1499                        // they are excluded by the new configuration.
1500                        // but housekeeping should not have run yet
1501
1502                        TEST_THAT(test_entry_deleted(*spacetest_dir, "f2"));
1503                        TEST_THAT(test_entry_deleted(*spacetest_dir, "d3"));
1504
1505                        int64_t d3_id = SearchDir(*spacetest_dir, "d3");
1506                        TEST_THAT(d3_id != 0);
1507
1508                        std::auto_ptr<BackupStoreDirectory> d3_dir =
1509                                ReadDirectory(*client, d3_id);
1510                        TEST_THAT(test_entry_deleted(*d3_dir, "d4"));
1511
1512                        int64_t d4_id = SearchDir(*d3_dir, "d4");
1513                        TEST_THAT(d4_id != 0);
1514
1515                        std::auto_ptr<BackupStoreDirectory> d4_dir =
1516                                ReadDirectory(*client, d4_id);
1517                        TEST_THAT(test_entry_deleted(*d4_dir, "f5"));
1518
1519                        std::auto_ptr<BackupProtocolAccountUsage> usage(
1520                                client->QueryGetAccountUsage());
1521                        TEST_EQUAL_LINE(24, usage->GetBlocksUsed(),
1522                                "blocks used");
1523                        TEST_EQUAL_LINE(4, usage->GetBlocksInDeletedFiles(),
1524                                "deleted blocks");
1525                        TEST_EQUAL_LINE(16, usage->GetBlocksInDirectories(),
1526                                "directory blocks");
1527                        // d1/f3 and d1/f4 are the only two files on the
1528                        // server which are not deleted, they use 2 blocks
1529                        // each, the rest is directories and 2 deleted files
1530                        // (f1 and d3/d4/f5)
1531
1532                        // Log out.
1533                        client->QueryFinished();
1534                        sSocket.Close();
1535                }
1536                BOX_TRACE("done.");
1537
1538                if (failures > 0)
1539                {
1540                        // stop early to make debugging easier
1541                        return 1;
1542                }
1543
1544                wait_for_operation(5, "housekeeping to remove the "
1545                        "deleted files");
1546
1547                BOX_TRACE("Check that the files were removed");
1548                {
1549                        std::auto_ptr<BackupProtocolClient> client = 
1550                                ConnectAndLogin(context, 0 /* read-write */);
1551                       
1552                        std::auto_ptr<BackupStoreDirectory> rootDir = 
1553                                ReadDirectory(*client);
1554
1555                        int64_t testDirId = SearchDir(*rootDir, "Test1");
1556                        TEST_THAT(testDirId != 0);
1557
1558                        std::auto_ptr<BackupStoreDirectory> Test1_dir =
1559                                ReadDirectory(*client, testDirId);
1560
1561                        int64_t spacetestDirId = SearchDir(*Test1_dir, 
1562                                "spacetest");
1563                        TEST_THAT(spacetestDirId != 0);
1564
1565                        std::auto_ptr<BackupStoreDirectory> spacetest_dir =
1566                                ReadDirectory(*client, spacetestDirId);
1567
1568                        TEST_THAT(SearchDir(*spacetest_dir, "f1") == 0);
1569                        TEST_THAT(SearchDir(*spacetest_dir, "f2") == 0);
1570                        TEST_THAT(SearchDir(*spacetest_dir, "d3") == 0);
1571                        TEST_THAT(SearchDir(*spacetest_dir, "d7") == 0);
1572
1573                        std::auto_ptr<BackupProtocolAccountUsage> usage(
1574                                client->QueryGetAccountUsage());
1575                        TEST_EQUAL_LINE(16, usage->GetBlocksUsed(),
1576                                "blocks used");
1577                        TEST_EQUAL_LINE(0, usage->GetBlocksInDeletedFiles(),
1578                                "deleted blocks");
1579                        TEST_EQUAL_LINE(12, usage->GetBlocksInDirectories(),
1580                                "directory blocks");
1581                        // d1/f3 and d1/f4 are the only two files on the
1582                        // server, they use 2 blocks each, the rest is
1583                        // directories.
1584
1585                        // Log out.
1586                        client->QueryFinished();
1587                        sSocket.Close();
1588                }
1589
1590                if (failures > 0)
1591                {
1592                        // stop early to make debugging easier
1593                        return 1;
1594                }
1595
1596                // Need 22 blocks free to upload everything
1597                TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS " -c "
1598                        "testfiles/bbstored.conf setlimit 01234567 0B 22B") 
1599                        == 0);
1600                TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
1601
1602                // Run another backup, now there should be enough space
1603                // for everything we want to upload.
1604                bbackupd.RunSyncNow();
1605                TEST_THAT(!bbackupd.StorageLimitExceeded());
1606
1607                // Check that the contents of the store are the same
1608                // as the contents of the disc
1609                TEST_COMPARE(Compare_Same, "testfiles/bbackupd-exclude.conf");
1610                BOX_TRACE("done.");
1611
1612                // BLOCK
1613                {
1614                        std::auto_ptr<BackupProtocolClient> client = 
1615                                ConnectAndLogin(context, 0 /* read-write */);
1616
1617                        std::auto_ptr<BackupProtocolAccountUsage> usage(
1618                                client->QueryGetAccountUsage());
1619                        TEST_EQUAL_LINE(22, usage->GetBlocksUsed(),
1620                                "blocks used");
1621                        TEST_EQUAL_LINE(0, usage->GetBlocksInDeletedFiles(),
1622                                "deleted blocks");
1623                        TEST_EQUAL_LINE(14, usage->GetBlocksInDirectories(),
1624                                "directory blocks");
1625                        // d2/f6, d6/d8 and d6/d8/f7 are new
1626                        // i.e. 2 new files, 1 new directory
1627
1628                        client->QueryFinished();
1629                        sSocket.Close();
1630                }
1631
1632                if (failures > 0)
1633                {
1634                        // stop early to make debugging easier
1635                        return 1;
1636                }
1637
1638                // Put the limit back
1639                TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS " -c "
1640                        "testfiles/bbstored.conf setlimit 01234567 "
1641                        "1000B 2000B") == 0);
1642                TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
1643       
1644                // Start again with the old config
1645                BOX_TRACE("Restart bbackupd with original configuration");
1646                // terminate_bbackupd();
1647                cmd = BBACKUPD " " + bbackupd_args +
1648                        " testfiles/bbackupd.conf";
1649                bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid");
1650                TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0);
1651                ::safe_sleep(1);
1652                TEST_THAT(ServerIsAlive(bbackupd_pid));
1653                TEST_THAT(ServerIsAlive(bbstored_pid));
1654                if (!ServerIsAlive(bbackupd_pid)) return 1;
1655                if (!ServerIsAlive(bbstored_pid)) return 1;
1656                BOX_TRACE("done.");
1657
1658                // unpack the initial files again
1659                #ifdef WIN32
1660                        TEST_THAT(::system("tar xzvf testfiles/test_base.tgz "
1661                                "-C testfiles") == 0);
1662                #else
1663                        TEST_THAT(::system("gzip -d < testfiles/test_base.tgz "
1664                                "| ( cd testfiles && tar xf - )") == 0);
1665                #endif
1666
1667                wait_for_backup_operation("bbackupd to upload more files");
1668               
1669                // Check that the contents of the store are the same
1670                // as the contents of the disc
1671                // (-a = all, -c = give result in return code)
1672                BOX_TRACE("Check that all files were uploaded successfully");
1673                TEST_COMPARE(Compare_Same);
1674                BOX_TRACE("done.");
1675
1676                TEST_THAT(ServerIsAlive(bbackupd_pid));
1677                TEST_THAT(ServerIsAlive(bbstored_pid));
1678                if (!ServerIsAlive(bbackupd_pid)) return 1;
1679                if (!ServerIsAlive(bbstored_pid)) return 1;
1680
1681                if (failures > 0)
1682                {
1683                        // stop early to make debugging easier
1684                        return 1;
1685                }
1686        }
1687
1688        // Check that no read error has been reported yet
1689        TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1"));
1690
1691        #ifndef WIN32 // requires fork
1692        printf("\n==== Testing that bbackupd responds correctly to "
1693                "connection failure\n");
1694
1695        {
1696                // Kill the daemons
1697                terminate_bbackupd(bbackupd_pid);
1698                test_kill_bbstored();
1699
1700                // create a new file to force an upload
1701
1702                const char* new_file = "testfiles/TestDir1/force-upload-2";
1703                int fd = open(new_file, 
1704                        O_CREAT | O_EXCL | O_WRONLY, 0700);
1705                if (fd <= 0)
1706                {
1707                        perror(new_file);
1708                }
1709                TEST_THAT(fd > 0);
1710       
1711                const char* control_string = "whee!\n";
1712                TEST_THAT(write(fd, control_string, 
1713                        strlen(control_string)) ==
1714                        (int)strlen(control_string));
1715                close(fd);
1716
1717                // sleep to make it old enough to upload
1718                safe_sleep(4);
1719
1720                class MyHook : public BackupStoreContext::TestHook
1721                {
1722                        virtual std::auto_ptr<BackupProtocolMessage> StartCommand(
1723                                const BackupProtocolMessage& rCommand)
1724                        {
1725                                if (rCommand.GetType() ==
1726                                        BackupProtocolStoreFile::TypeID)
1727                                {
1728                                        // terminate badly
1729                                        THROW_EXCEPTION(CommonException,
1730                                                Internal);
1731                                }
1732                                return std::auto_ptr<BackupProtocolMessage>();
1733                        }
1734                };
1735                MyHook hook;
1736
1737                bbstored_pid = fork();
1738
1739                if (bbstored_pid < 0)
1740                {
1741                        BOX_LOG_SYS_ERROR("failed to fork()");
1742                        return 1;
1743                }
1744
1745                if (bbstored_pid == 0)
1746                {
1747                        // in fork child
1748                        TEST_THAT(setsid() != -1);
1749
1750                        if (!Logging::IsEnabled(Log::TRACE))
1751                        {
1752                                Logging::SetGlobalLevel(Log::NOTHING);
1753                        }
1754
1755                        // BackupStoreDaemon must be destroyed before exit(),
1756                        // to avoid memory leaks being reported.
1757                        {
1758                                BackupStoreDaemon bbstored;
1759                                bbstored.SetTestHook(hook);
1760                                bbstored.SetRunInForeground(true);
1761                                bbstored.Main("testfiles/bbstored.conf");
1762                        }
1763
1764                        Timers::Cleanup(); // avoid memory leaks
1765                        exit(0);
1766                }
1767
1768                // in fork parent
1769                bbstored_pid = WaitForServerStartup("testfiles/bbstored.pid",
1770                        bbstored_pid);
1771
1772                TEST_THAT(::system("rm -f testfiles/notifyran.store-full.*") == 0);
1773
1774                // Ignore SIGPIPE so that when the connection is broken,
1775                // the daemon doesn't terminate.
1776                ::signal(SIGPIPE, SIG_IGN);
1777
1778                {
1779                        Log::Level newLevel = Logging::GetGlobalLevel();
1780
1781                        if (!Logging::IsEnabled(Log::TRACE))
1782                        {
1783                                newLevel = Log::NOTHING;
1784                        }
1785
1786                        Logging::Guard guard(newLevel);
1787
1788                        BackupDaemon bbackupd;
1789                        bbackupd.Configure("testfiles/bbackupd.conf");
1790                        bbackupd.InitCrypto();
1791                        bbackupd.RunSyncNowWithExceptionHandling();
1792                }
1793
1794                ::signal(SIGPIPE, SIG_DFL);
1795
1796                TEST_THAT(TestFileExists("testfiles/notifyran.backup-error.1"));
1797                TEST_THAT(!TestFileExists("testfiles/notifyran.backup-error.2"));
1798                TEST_THAT(!TestFileExists("testfiles/notifyran.store-full.1"));
1799
1800                test_kill_bbstored(true);
1801
1802                if (failures > 0)
1803                {
1804                        // stop early to make debugging easier
1805                        return 1;
1806                }
1807
1808                TEST_THAT(test_run_bbstored() == 0);
1809
1810                cmd = BBACKUPD " " + bbackupd_args +
1811                        " testfiles/bbackupd.conf";
1812                bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid");
1813                TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0);
1814                ::safe_sleep(1);
1815                TEST_THAT(ServerIsAlive(bbackupd_pid));
1816                TEST_THAT(ServerIsAlive(bbstored_pid));
1817                if (!ServerIsAlive(bbackupd_pid)) return 1;
1818                if (!ServerIsAlive(bbstored_pid)) return 1;
1819        }
1820        #endif // !WIN32
1821
1822        #ifndef WIN32
1823        printf("\n==== Testing that absolute symlinks are not followed "
1824                "during restore\n");
1825
1826        {
1827                #define SYM_DIR "testfiles" DIRECTORY_SEPARATOR "TestDir1" \
1828                        DIRECTORY_SEPARATOR "symlink_test"
1829
1830                TEST_THAT(::mkdir(SYM_DIR, 0777) == 0);
1831                TEST_THAT(::mkdir(SYM_DIR DIRECTORY_SEPARATOR "a", 0777) == 0);
1832                TEST_THAT(::mkdir(SYM_DIR DIRECTORY_SEPARATOR "a"
1833                        DIRECTORY_SEPARATOR "subdir", 0777) == 0);
1834                TEST_THAT(::mkdir(SYM_DIR DIRECTORY_SEPARATOR "b", 0777) == 0);
1835
1836                FILE* fp = fopen(SYM_DIR DIRECTORY_SEPARATOR "a"
1837                        DIRECTORY_SEPARATOR "subdir"
1838                        DIRECTORY_SEPARATOR "content", "w");
1839                TEST_THAT(fp != NULL);
1840                fputs("before\n", fp);
1841                fclose(fp);
1842
1843                char buf[PATH_MAX];
1844                TEST_THAT(getcwd(buf, sizeof(buf)) == buf);
1845                std::string path = buf;
1846                path += DIRECTORY_SEPARATOR SYM_DIR
1847                        DIRECTORY_SEPARATOR "a"
1848                        DIRECTORY_SEPARATOR "subdir";
1849                TEST_THAT(symlink(path.c_str(), SYM_DIR
1850                        DIRECTORY_SEPARATOR "b"
1851                        DIRECTORY_SEPARATOR "link") == 0);
1852
1853                // also test symlink-to-self loop does not break restore
1854                TEST_THAT(symlink("self", SYM_DIR "/self") == 0);
1855
1856                wait_for_operation(4, "symlinks to be old enough");
1857                sync_and_wait();
1858
1859                // Check that the backup was successful, i.e. no differences
1860                TEST_COMPARE(Compare_Same);
1861
1862                // now stop bbackupd and update the test file,
1863                // make the original directory unreadable
1864                terminate_bbackupd(bbackupd_pid);
1865
1866                fp = fopen(SYM_DIR DIRECTORY_SEPARATOR "a"
1867                        DIRECTORY_SEPARATOR "subdir"
1868                        DIRECTORY_SEPARATOR "content", "w");
1869                TEST_THAT(fp != NULL);
1870                fputs("after\n", fp);
1871                fclose(fp);
1872
1873                TEST_THAT(chmod(SYM_DIR, 0) == 0);
1874
1875                // check that we can restore it
1876                {
1877                        int returnValue = ::system(BBACKUPQUERY " "
1878                                "-c testfiles/bbackupd.conf "
1879                                "-Wwarning \"restore Test1 testfiles/restore-symlink\" "
1880                                "quit");
1881                        TEST_RETURN(returnValue,
1882                                BackupQueries::ReturnCode::Command_OK);
1883                }
1884
1885                // make it accessible again
1886                TEST_THAT(chmod(SYM_DIR, 0755) == 0);
1887
1888                // check that the original file was not overwritten
1889                FileStream fs(SYM_DIR "/a/subdir/content");
1890                IOStreamGetLine gl(fs);
1891                std::string line;
1892                TEST_THAT(gl.GetLine(line));
1893                TEST_THAT(line != "before");
1894                TEST_EQUAL("after", line);
1895
1896                #undef SYM_DIR
1897
1898                /*
1899                // This is not worth testing or fixing.
1900                //
1901                #ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
1902                printf("\n==== Testing that symlinks to other filesystems "
1903                        "can be backed up as roots\n");
1904
1905                intercept_setup_lstat_post_hook(lstat_test_post_hook);
1906                TEST_THAT(symlink("TestDir1", "testfiles/symlink-to-TestDir1")
1907                        == 0);
1908
1909                struct stat stat_st, lstat_st;
1910                TEST_THAT(stat("testfiles/symlink-to-TestDir1", &stat_st) == 0);
1911                TEST_THAT(lstat("testfiles/symlink-to-TestDir1", &lstat_st) == 0);
1912                TEST_EQUAL_LINE((stat_st.st_dev ^ 0xFFFF), lstat_st.st_dev,
1913                        "stat vs lstat");
1914
1915                BackupDaemon bbackupd;
1916                bbackupd.Configure("testfiles/bbackupd-symlink.conf");
1917                bbackupd.InitCrypto();
1918                bbackupd.RunSyncNow();
1919                intercept_clear_setup();
1920
1921                compareReturnValue = ::system(BBACKUPQUERY " "
1922                        "-c testfiles/bbackupd.conf "
1923                        "-l testfiles/query0a.log "
1924                        "-Wwarning \"compare -acQ\" quit");
1925                TEST_RETURN(compareReturnValue,
1926                        BackupQueries::ReturnCode::Compare_Same);
1927                TestRemoteProcessMemLeaks("bbackupquery.memleaks");
1928
1929                // and again using the symlink during compare
1930                compareReturnValue = ::system(BBACKUPQUERY " "
1931                        "-c testfiles/bbackupd-symlink.conf "
1932                        "-l testfiles/query0a.log "
1933                        "-Wwarning \"compare -acQ\" quit");
1934                TEST_RETURN(compareReturnValue,
1935                        BackupQueries::ReturnCode::Compare_Same);
1936                TestRemoteProcessMemLeaks("bbackupquery.memleaks");
1937                #endif
1938                */
1939
1940                bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid");
1941                TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0);
1942                ::safe_sleep(1);
1943
1944                TEST_THAT(ServerIsAlive(bbackupd_pid));
1945                TEST_THAT(ServerIsAlive(bbstored_pid));
1946                if (!ServerIsAlive(bbackupd_pid)) return 1;
1947                if (!ServerIsAlive(bbstored_pid)) return 1;
1948        }
1949        #endif // !WIN32
1950
1951        printf("\n==== Testing that nonexistent locations are backed up "
1952                "if they are created later\n");
1953       
1954        // ensure that the directory does not exist at the start
1955        TEST_THAT(::system("rm -rf testfiles/TestDir2") == 0);
1956
1957        // BLOCK
1958        {
1959                // Kill the daemon
1960                terminate_bbackupd(bbackupd_pid);
1961
1962                // Delete any old result marker files
1963                TEST_RETURN(0, system("rm -f testfiles/notifyran.*"));
1964
1965                // Start it with a config that has a temporary location
1966                // whose path does not exist yet
1967                std::string cmd = BBACKUPD " " + bbackupd_args + 
1968                        " testfiles/bbackupd-temploc.conf";
1969
1970                bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid");
1971                TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0);
1972
1973                TEST_THAT(ServerIsAlive(bbackupd_pid));
1974                TEST_THAT(ServerIsAlive(bbstored_pid));
1975                if (!ServerIsAlive(bbackupd_pid)) return 1;
1976                if (!ServerIsAlive(bbstored_pid)) return 1;
1977
1978                TEST_THAT(!TestFileExists("testfiles/notifyran.backup-start.1"));
1979                TEST_THAT(!TestFileExists("testfiles/notifyran.backup-start.2"));
1980                TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1"));
1981                TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.2"));
1982                TEST_THAT(!TestFileExists("testfiles/notifyran.backup-ok.1"));
1983                TEST_THAT(!TestFileExists("testfiles/notifyran.backup-finish.1"));
1984                TEST_THAT(!TestFileExists("testfiles/notifyran.backup-finish.2"));
1985
1986                sync_and_wait();
1987                TEST_COMPARE(Compare_Same);
1988
1989                TEST_THAT( TestFileExists("testfiles/notifyran.backup-start.1"));
1990                TEST_THAT(!TestFileExists("testfiles/notifyran.backup-start.2"));
1991                TEST_THAT( TestFileExists("testfiles/notifyran.read-error.1"));
1992                TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.2"));
1993                TEST_THAT(!TestFileExists("testfiles/notifyran.backup-ok.1"));
1994                TEST_THAT( TestFileExists("testfiles/notifyran.backup-finish.1"));
1995                TEST_THAT(!TestFileExists("testfiles/notifyran.backup-finish.2"));
1996               
1997                // Did it actually get created? Should not have been!
1998                std::auto_ptr<BackupProtocolClient> client =
1999                        ConnectAndLogin(context,
2000                        BackupProtocolLogin::Flags_ReadOnly);
2001               
2002                std::auto_ptr<BackupStoreDirectory> dir = 
2003                        ReadDirectory(*client);
2004                int64_t testDirId = SearchDir(*dir, "Test2");
2005                TEST_THAT(testDirId == 0);
2006                client->QueryFinished();
2007                sSocket.Close();
2008        }
2009
2010        // create the location directory and unpack some files into it
2011        TEST_THAT(::mkdir("testfiles/TestDir2", 0777) == 0);
2012
2013        #ifdef WIN32
2014                TEST_THAT(::system("tar xzvf testfiles/spacetest1.tgz "
2015                        "-C testfiles/TestDir2") == 0);
2016        #else
2017                TEST_THAT(::system("gzip -d < testfiles/spacetest1.tgz "
2018                        "| ( cd testfiles/TestDir2 && tar xf - )") == 0);
2019        #endif
2020
2021        // check that the files are backed up now
2022        sync_and_wait();
2023        TEST_COMPARE(Compare_Same);
2024
2025        TEST_THAT( TestFileExists("testfiles/notifyran.backup-start.2"));
2026        TEST_THAT(!TestFileExists("testfiles/notifyran.backup-start.3"));
2027        TEST_THAT( TestFileExists("testfiles/notifyran.read-error.1"));
2028        TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.2"));
2029        TEST_THAT( TestFileExists("testfiles/notifyran.backup-ok.1"));
2030        TEST_THAT(!TestFileExists("testfiles/notifyran.backup-ok.2"));
2031        TEST_THAT( TestFileExists("testfiles/notifyran.backup-finish.2"));
2032        TEST_THAT(!TestFileExists("testfiles/notifyran.backup-finish.3"));
2033
2034        // BLOCK
2035        {
2036                std::auto_ptr<BackupProtocolClient> client =
2037                        ConnectAndLogin(context,
2038                        BackupProtocolLogin::Flags_ReadOnly);
2039               
2040                std::auto_ptr<BackupStoreDirectory> dir = 
2041                        ReadDirectory(*client,
2042                        BackupProtocolListDirectory::RootDirectory);
2043                int64_t testDirId = SearchDir(*dir, "Test2");
2044                TEST_THAT(testDirId != 0);
2045
2046                client->QueryFinished();
2047                sSocket.Close();
2048        }
2049
2050        printf("\n==== Testing that redundant locations are deleted on time\n");
2051
2052        // BLOCK
2053        {
2054                // Kill the daemon
2055                terminate_bbackupd(bbackupd_pid);
2056
2057                // Start it again with the normal config (no Test2)
2058                cmd = BBACKUPD " " + bbackupd_args + " testfiles/bbackupd.conf";
2059                bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid");
2060
2061                TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0);
2062
2063                ::safe_sleep(1);
2064
2065                TEST_THAT(ServerIsAlive(bbackupd_pid));
2066                TEST_THAT(ServerIsAlive(bbstored_pid));
2067                if (!ServerIsAlive(bbackupd_pid)) return 1;
2068                if (!ServerIsAlive(bbstored_pid)) return 1;
2069
2070                // Test2 should be deleted after 10 seconds (4 runs)
2071                wait_for_sync_end();
2072                wait_for_sync_end();
2073                wait_for_sync_end();
2074
2075                // not yet! should still be there
2076
2077                {
2078                        std::auto_ptr<BackupProtocolClient> client =
2079                                ConnectAndLogin(context,
2080                                BackupProtocolLogin::Flags_ReadOnly);
2081                       
2082                        std::auto_ptr<BackupStoreDirectory> dir = 
2083                                ReadDirectory(*client);
2084                        int64_t testDirId = SearchDir(*dir, "Test2");
2085                        TEST_THAT(testDirId != 0);
2086
2087                        client->QueryFinished();
2088                        sSocket.Close();
2089                }
2090
2091                wait_for_sync_end();
2092
2093                // NOW it should be gone
2094
2095                {
2096                        std::auto_ptr<BackupProtocolClient> client =
2097                                ConnectAndLogin(context,
2098                                BackupProtocolLogin::Flags_ReadOnly);
2099                       
2100                        std::auto_ptr<BackupStoreDirectory> root_dir = 
2101                                ReadDirectory(*client);
2102
2103                        TEST_THAT(test_entry_deleted(*root_dir, "Test2"));
2104
2105                        client->QueryFinished();
2106                        sSocket.Close();
2107                }
2108        }
2109
2110        TEST_THAT(ServerIsAlive(bbackupd_pid));
2111        TEST_THAT(ServerIsAlive(bbstored_pid));
2112        if (!ServerIsAlive(bbackupd_pid)) return 1;
2113        if (!ServerIsAlive(bbstored_pid)) return 1;
2114
2115        if(bbackupd_pid > 0)
2116        {
2117                // Delete any old result marker files
2118                TEST_RETURN(0, system("rm -f testfiles/notifyran.*"));
2119
2120                printf("\n==== Check that read-only directories and "
2121                        "their contents can be restored.\n");
2122
2123                int compareReturnValue;
2124
2125                {
2126                        #ifdef WIN32
2127                                TEST_THAT(::system("chmod 0555 testfiles/"
2128                                        "TestDir1/x1") == 0);
2129                        #else
2130                                TEST_THAT(chmod("testfiles/TestDir1/x1",
2131                                        0555) == 0);
2132                        #endif
2133
2134                        wait_for_sync_end(); // too new
2135                        wait_for_sync_end(); // should be backed up now
2136
2137                        compareReturnValue = ::system(BBACKUPQUERY " "
2138                                "-Wwarning "
2139                                "-c testfiles/bbackupd.conf "
2140                                "\"compare -cEQ Test1 testfiles/TestDir1\" " 
2141                                "quit");
2142                        TEST_RETURN(compareReturnValue,
2143                                BackupQueries::ReturnCode::Compare_Same);
2144                        TestRemoteProcessMemLeaks("bbackupquery.memleaks");
2145
2146                        // check that we can restore it
2147                        compareReturnValue = ::system(BBACKUPQUERY " "
2148                                "-Wwarning "
2149                                "-c testfiles/bbackupd.conf "
2150                                "\"restore Test1 testfiles/restore1\" "
2151                                "quit");
2152                        TEST_RETURN(compareReturnValue,
2153                                BackupQueries::ReturnCode::Command_OK);
2154                        TestRemoteProcessMemLeaks("bbackupquery.memleaks");
2155
2156                        // check that it restored properly
2157                        compareReturnValue = ::system(BBACKUPQUERY " "
2158                                "-Wwarning "
2159                                "-c testfiles/bbackupd.conf "
2160                                "\"compare -cEQ Test1 testfiles/restore1\" " 
2161                                "quit");
2162                        TEST_RETURN(compareReturnValue,
2163                                BackupQueries::ReturnCode::Compare_Same);
2164                        TestRemoteProcessMemLeaks("bbackupquery.memleaks");
2165
2166                        // Try a restore with just the remote directory name,
2167                        // check that it uses the same name in the local
2168                        // directory.
2169                        TEST_THAT(::mkdir("testfiles/restore-test", 0700) == 0);
2170
2171                        compareReturnValue = ::system(BBACKUPQUERY " "
2172                                "-Wwarning "
2173                                "-c testfiles/bbackupd.conf "
2174                                "\"lcd testfiles/restore-test\" "
2175                                "\"restore Test1\" "
2176                                "quit");
2177                        TEST_RETURN(compareReturnValue,
2178                                BackupQueries::ReturnCode::Command_OK);
2179                        TestRemoteProcessMemLeaks("testfiles/restore-test/"
2180                                "bbackupquery.memleaks");
2181
2182                        // check that it restored properly
2183                        compareReturnValue = ::system(BBACKUPQUERY " "
2184                                "-Wwarning "
2185                                "-c testfiles/bbackupd.conf "
2186                                "\"compare -cEQ Test1 testfiles/restore-test/Test1\" " 
2187                                "quit");
2188                        TEST_RETURN(compareReturnValue,
2189                                BackupQueries::ReturnCode::Compare_Same);
2190                        TestRemoteProcessMemLeaks("bbackupquery.memleaks");
2191
2192                        // put the permissions back to sensible values
2193                        #ifdef WIN32
2194                                TEST_THAT(::system("chmod 0755 testfiles/"
2195                                        "TestDir1/x1") == 0);
2196                                TEST_THAT(::system("chmod 0755 testfiles/"
2197                                        "restore1/x1") == 0);
2198                        #else
2199                                TEST_THAT(chmod("testfiles/TestDir1/x1",
2200                                        0755) == 0);
2201                                TEST_THAT(chmod("testfiles/restore1/x1",
2202                                        0755) == 0);
2203                        #endif
2204                }
2205
2206#ifdef WIN32
2207                printf("\n==== Check that filenames in UTF-8 "
2208                        "can be backed up\n");
2209
2210                // We have no guarantee that a random Unicode string can be
2211                // represented in the user's character set, so we go the
2212                // other way, taking three random characters from the
2213                // character set and converting them to Unicode.
2214                //
2215                // We hope that these characters are valid in most
2216                // character sets, but they probably are not in multibyte
2217                // character sets such as Shift-JIS, GB2312, etc. This test
2218                // will probably fail if your system locale is set to
2219                // Chinese, Japanese, etc. where one of these character
2220                // sets is used by default. You can check the character
2221                // set for your system in Control Panel -> Regional
2222                // Options -> General -> Language Settings -> Set Default
2223                // (System Locale). Because bbackupquery converts from
2224                // system locale to UTF-8 via the console code page
2225                // (which you can check from the Command Prompt with "chcp")
2226                // they must also be valid in your code page (850 for
2227                // Western Europe).
2228                //
2229                // In ISO-8859-1 (Danish locale) they are three Danish
2230                // accented characters, which are supported in code page
2231                // 850. Depending on your locale, YYMV (your yak may vomit).
2232
2233                std::string foreignCharsNative("\x91\x9b\x86");
2234                std::string foreignCharsUnicode;
2235                TEST_THAT(ConvertConsoleToUtf8(foreignCharsNative.c_str(),
2236                        foreignCharsUnicode));
2237
2238                std::string basedir("testfiles/TestDir1");
2239                std::string dirname("test" + foreignCharsUnicode + "testdir");
2240                std::string dirpath(basedir + "/" + dirname);
2241                TEST_THAT(mkdir(dirpath.c_str(), 0) == 0);
2242
2243                std::string filename("test" + foreignCharsUnicode + "testfile");
2244                std::string filepath(dirpath + "/" + filename);
2245
2246                char cwdbuf[1024];
2247                TEST_THAT(getcwd(cwdbuf, sizeof(cwdbuf)) == cwdbuf);
2248                std::string cwd = cwdbuf;
2249
2250                // Test that our emulated chdir() works properly
2251                // with relative and absolute paths
2252                TEST_THAT(::chdir(dirpath.c_str()) == 0);
2253                TEST_THAT(::chdir("../../..") == 0);
2254                TEST_THAT(::chdir(cwd.c_str()) == 0);
2255
2256                // Check that it can be converted to the system encoding
2257                // (which is what is needed on the command line)
2258                std::string systemDirName;
2259                TEST_THAT(ConvertEncoding(dirname.c_str(), CP_UTF8,
2260                        systemDirName, CP_ACP));
2261
2262                std::string systemFileName;
2263                TEST_THAT(ConvertEncoding(filename.c_str(), CP_UTF8,
2264                        systemFileName, CP_ACP));
2265
2266                // Check that it can be converted to the console encoding
2267                // (which is what we will see in the output)
2268                std::string consoleDirName;
2269                TEST_THAT(ConvertUtf8ToConsole(dirname.c_str(),
2270                        consoleDirName));
2271
2272                std::string consoleFileName;
2273                TEST_THAT(ConvertUtf8ToConsole(filename.c_str(),
2274                        consoleFileName));
2275
2276                // test that bbackupd will let us lcd into the local
2277                // directory using a relative path
2278                std::string command = BBACKUPQUERY " "
2279                        "-Wwarning "
2280                        "-c testfiles/bbackupd.conf "
2281                        "\"lcd testfiles/TestDir1/" + systemDirName + "\" "
2282                        "quit";
2283                compareReturnValue = ::system(command.c_str());
2284                TEST_RETURN(compareReturnValue,
2285                        BackupQueries::ReturnCode::Command_OK);
2286
2287                // and back out again
2288                command = BBACKUPQUERY " "
2289                        "-Wwarning "
2290                        "-c testfiles/bbackupd.conf "
2291                        "\"lcd testfiles/TestDir1/" + systemDirName + "\" "
2292                        "\"lcd ..\" quit";
2293                compareReturnValue = ::system(command.c_str());
2294                TEST_RETURN(compareReturnValue,
2295                        BackupQueries::ReturnCode::Command_OK);
2296
2297                // and using an absolute path
2298                command = BBACKUPQUERY " "
2299                        "-Wwarning "
2300                        "-c testfiles/bbackupd.conf "
2301                        "\"lcd " + cwd + "/testfiles/TestDir1/" + 
2302                        systemDirName + "\" quit";
2303                compareReturnValue = ::system(command.c_str());
2304                TEST_RETURN(compareReturnValue,
2305                        BackupQueries::ReturnCode::Command_OK);
2306
2307                // and back out again
2308                command = BBACKUPQUERY " "
2309                        "-Wwarning "
2310                        "-c testfiles/bbackupd.conf "
2311                        "\"lcd " + cwd + "/testfiles/TestDir1/" + 
2312                        systemDirName + "\" "
2313                        "\"lcd ..\" quit";
2314                compareReturnValue = ::system(command.c_str());
2315                TEST_RETURN(compareReturnValue,
2316                        BackupQueries::ReturnCode::Command_OK);
2317
2318                {
2319                        FileStream fs(filepath.c_str(), O_CREAT | O_RDWR);
2320
2321                        std::string data("hello world\n");
2322                        fs.Write(data.c_str(), data.size());
2323                        TEST_EQUAL_LINE(12, fs.GetPosition(),
2324                                "FileStream position");
2325                        fs.Close();
2326                }
2327
2328                wait_for_backup_operation("upload of file with unicode name");
2329
2330                // Compare to check that the file was uploaded
2331                TEST_COMPARE(Compare_Same);
2332
2333                // Check that we can find it in directory listing
2334                {
2335                        std::auto_ptr<BackupProtocolClient> client =
2336                                ConnectAndLogin(context, 0);
2337
2338                        std::auto_ptr<BackupStoreDirectory> dir = ReadDirectory(
2339                                *client);
2340
2341                        int64_t baseDirId = SearchDir(*dir, "Test1");
2342                        TEST_THAT(baseDirId != 0);
2343                        dir = ReadDirectory(*client, baseDirId);
2344
2345                        int64_t testDirId = SearchDir(*dir, dirname.c_str());
2346                        TEST_THAT(testDirId != 0);
2347                        dir = ReadDirectory(*client, testDirId);
2348               
2349                        TEST_THAT(SearchDir(*dir, filename.c_str()) != 0);
2350                        // Log out
2351                        client->QueryFinished();
2352                        sSocket.Close();
2353                }
2354
2355                // Check that bbackupquery shows the dir in console encoding
2356                command = BBACKUPQUERY " -Wwarning "
2357                        "-c testfiles/bbackupd.conf "
2358                        "-q \"list Test1\" quit";
2359                pid_t bbackupquery_pid;
2360                std::auto_ptr<IOStream> queryout;
2361                queryout = LocalProcessStream(command.c_str(), 
2362                        bbackupquery_pid);
2363                TEST_THAT(queryout.get() != NULL);
2364                TEST_THAT(bbackupquery_pid != -1);
2365
2366                IOStreamGetLine reader(*queryout);
2367                std::string line;
2368                bool found = false;
2369                while (!reader.IsEOF())
2370                {
2371                        TEST_THAT(reader.GetLine(line));
2372                        if (line.find(consoleDirName) != std::string::npos)
2373                        {
2374                                found = true;
2375                        }
2376                }
2377                TEST_THAT(!(queryout->StreamDataLeft()));
2378                TEST_THAT(reader.IsEOF());
2379                TEST_THAT(found);
2380                queryout->Close();
2381
2382                // Check that bbackupquery can list the dir when given
2383                // on the command line in system encoding, and shows
2384                // the file in console encoding
2385                command = BBACKUPQUERY " -c testfiles/bbackupd.conf "
2386                        "-Wwarning \"list Test1/" + systemDirName + "\" quit";
2387                queryout = LocalProcessStream(command.c_str(), 
2388                        bbackupquery_pid);
2389                TEST_THAT(queryout.get() != NULL);
2390                TEST_THAT(bbackupquery_pid != -1);
2391
2392                IOStreamGetLine reader2(*queryout);
2393                found = false;
2394                while (!reader2.IsEOF())
2395                {
2396                        TEST_THAT(reader2.GetLine(line));
2397                        if (line.find(consoleFileName) != std::string::npos)
2398                        {
2399                                found = true;
2400                        }
2401                }
2402                TEST_THAT(!(queryout->StreamDataLeft()));
2403                TEST_THAT(reader2.IsEOF());
2404                TEST_THAT(found);
2405                queryout->Close();
2406
2407                // Check that bbackupquery can compare the dir when given
2408                // on the command line in system encoding.
2409                command = BBACKUPQUERY " -c testfiles/bbackupd.conf "
2410                        "-Wwarning \"compare -cEQ Test1/" + systemDirName +
2411                        " testfiles/TestDir1/" + systemDirName + "\" quit";
2412
2413                compareReturnValue = ::system(command.c_str());
2414                TestRemoteProcessMemLeaks("bbackupquery.memleaks");
2415                TEST_RETURN(compareReturnValue,
2416                        BackupQueries::ReturnCode::Compare_Same);
2417
2418                // Check that bbackupquery can restore the dir when given
2419                // on the command line in system encoding.
2420                command = BBACKUPQUERY " -c testfiles/bbackupd.conf "
2421                        "-Wwarning \"restore Test1/" + systemDirName +
2422                        " testfiles/restore-" + systemDirName + "\" quit";
2423
2424                compareReturnValue = ::system(command.c_str());
2425                TestRemoteProcessMemLeaks("bbackupquery.memleaks");
2426                TEST_RETURN(compareReturnValue,
2427                        BackupQueries::ReturnCode::Command_OK);
2428
2429                // Compare to make sure it was restored properly.
2430                command = BBACKUPQUERY " -c testfiles/bbackupd.conf "
2431                        "-Wwarning \"compare -cEQ Test1/" + systemDirName +
2432                        " testfiles/restore-" + systemDirName + "\" quit";
2433
2434                compareReturnValue = ::system(command.c_str());
2435                TestRemoteProcessMemLeaks("bbackupquery.memleaks");
2436                TEST_RETURN(compareReturnValue,
2437                        BackupQueries::ReturnCode::Compare_Same);
2438
2439                std::string fileToUnlink = "testfiles/restore-" + 
2440                        dirname + "/" + filename;
2441                TEST_THAT(::unlink(fileToUnlink.c_str()) == 0);
2442
2443                // Check that bbackupquery can get the file when given
2444                // on the command line in system encoding.
2445                command = BBACKUPQUERY " -c testfiles/bbackupd.conf "
2446                        "-Wwarning \"get Test1/" + systemDirName + "/" + 
2447                        systemFileName + " " + "testfiles/restore-" + 
2448                        systemDirName + "/" + systemFileName + "\" quit";
2449
2450                compareReturnValue = ::system(command.c_str());
2451                TEST_RETURN(compareReturnValue,
2452                        BackupQueries::ReturnCode::Command_OK);
2453                TestRemoteProcessMemLeaks("bbackupquery.memleaks");
2454
2455                // And after changing directory to a relative path
2456                command = BBACKUPQUERY " -c testfiles/bbackupd.conf "
2457                        "-Wwarning "
2458                        "\"lcd testfiles\" "
2459                        "\"cd Test1/" + systemDirName + "\" " + 
2460                        "\"get " + systemFileName + "\" quit";
2461
2462                compareReturnValue = ::system(command.c_str());
2463                TEST_RETURN(compareReturnValue,
2464                        BackupQueries::ReturnCode::Command_OK);
2465                TestRemoteProcessMemLeaks("testfiles/bbackupquery.memleaks");
2466
2467                // cannot overwrite a file that exists, so delete it
2468                std::string tmp = "testfiles/" + filename;
2469                TEST_THAT(::unlink(tmp.c_str()) == 0);
2470
2471                // And after changing directory to an absolute path
2472                command = BBACKUPQUERY " -c testfiles/bbackupd.conf -Wwarning "
2473                        "\"lcd " + cwd + "/testfiles\" "
2474                        "\"cd Test1/" + systemDirName + "\" " + 
2475                        "\"get " + systemFileName + "\" quit";
2476
2477                compareReturnValue = ::system(command.c_str());
2478                TEST_RETURN(compareReturnValue,
2479                        BackupQueries::ReturnCode::Command_OK);
2480                TestRemoteProcessMemLeaks("testfiles/bbackupquery.memleaks");
2481
2482                // Compare to make sure it was restored properly.
2483                // The Get command does not restore attributes, so
2484                // we must compare without them (-A) to succeed.
2485                command = BBACKUPQUERY " "
2486                        "-c testfiles/bbackupd.conf "
2487                        "-Wwarning \"compare -cAEQ Test1/" + systemDirName +
2488                        " testfiles/restore-" + systemDirName + "\" quit";
2489
2490                compareReturnValue = ::system(command.c_str());
2491                TestRemoteProcessMemLeaks("bbackupquery.memleaks");
2492                TEST_RETURN(compareReturnValue,
2493                        BackupQueries::ReturnCode::Compare_Same);
2494
2495                // Compare without attributes. This should fail.
2496                command = BBACKUPQUERY " "
2497                        "-c testfiles/bbackupd.conf "
2498                        "-Werror \"compare -cEQ Test1/" + systemDirName +
2499                        " testfiles/restore-" + systemDirName + "\" quit";
2500                compareReturnValue = ::system(command.c_str());
2501                TestRemoteProcessMemLeaks("bbackupquery.memleaks");
2502                TEST_RETURN(compareReturnValue,
2503                        BackupQueries::ReturnCode::Compare_Different);
2504#endif // WIN32
2505
2506                // Check that no read error has been reported yet
2507                TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1"));
2508
2509                TEST_THAT(ServerIsAlive(bbackupd_pid));
2510                TEST_THAT(ServerIsAlive(bbstored_pid));
2511                if (!ServerIsAlive(bbackupd_pid)) return 1;
2512                if (!ServerIsAlive(bbstored_pid)) return 1;
2513
2514                printf("\n==== Check that SyncAllowScript is executed and can "
2515                        "pause backup\n");
2516                fflush(stdout);
2517
2518                {
2519                        wait_for_sync_end();
2520                        // we now have 3 seconds before bbackupd
2521                        // runs the SyncAllowScript again.
2522
2523                        const char* sync_control_file = "testfiles" 
2524                                DIRECTORY_SEPARATOR "syncallowscript.control";
2525                        int fd = open(sync_control_file, 
2526                                O_CREAT | O_EXCL | O_WRONLY, 0700);
2527                        if (fd <= 0)
2528                        {
2529                                perror(sync_control_file);
2530                        }
2531                        TEST_THAT(fd > 0);
2532               
2533                        const char* control_string = "10\n";
2534                        TEST_THAT(write(fd, control_string, 
2535                                strlen(control_string)) ==
2536                                (int)strlen(control_string));
2537                        close(fd);
2538
2539                        // this will pause backups, bbackupd will check
2540                        // every 10 seconds to see if they are allowed again.
2541
2542                        const char* new_test_file = "testfiles"
2543                                DIRECTORY_SEPARATOR "TestDir1"
2544                                DIRECTORY_SEPARATOR "Added_During_Pause";
2545                        fd = open(new_test_file,
2546                                O_CREAT | O_EXCL | O_WRONLY, 0700);
2547                        if (fd <= 0)
2548                        {
2549                                perror(new_test_file);
2550                        }
2551                        TEST_THAT(fd > 0);
2552                        close(fd);
2553
2554                        struct stat st;
2555
2556                        // next poll should happen within the next
2557                        // 5 seconds (normally about 3 seconds)
2558
2559                        wait_for_operation(1, "2 seconds before next run");
2560                        TEST_THAT(stat("testfiles" DIRECTORY_SEPARATOR
2561                                "syncallowscript.notifyran.1", &st) != 0);
2562                        wait_for_operation(4, "2 seconds after run");
2563                        TEST_THAT(stat("testfiles" DIRECTORY_SEPARATOR
2564                                "syncallowscript.notifyran.1", &st) == 0);
2565                        TEST_THAT(stat("testfiles" DIRECTORY_SEPARATOR
2566                                "syncallowscript.notifyran.2", &st) != 0);
2567
2568                        // next poll should happen within the next
2569                        // 10 seconds (normally about 8 seconds)
2570
2571                        wait_for_operation(6, "2 seconds before next run");
2572                        TEST_THAT(stat("testfiles" DIRECTORY_SEPARATOR
2573                                "syncallowscript.notifyran.2", &st) != 0);
2574                        wait_for_operation(4, "2 seconds after run");
2575                        TEST_THAT(stat("testfiles" DIRECTORY_SEPARATOR
2576                                "syncallowscript.notifyran.2", &st) == 0);
2577
2578                        // bbackupquery compare might take a while
2579                        // on slow machines, so start the timer now
2580                        long start_time = time(NULL);
2581
2582                        // check that no backup has run (compare fails)
2583                        TEST_COMPARE(Compare_Different);
2584
2585                        TEST_THAT(unlink(sync_control_file) == 0);
2586                        wait_for_sync_start();
2587                        long end_time = time(NULL);
2588
2589                        long wait_time = end_time - start_time + 2;
2590
2591                        // should be about 10 seconds
2592                        if (wait_time < 8 || wait_time > 12)
2593                        {
2594                                printf("Waited for %ld seconds, should have "
2595                                        "been %s", wait_time, control_string);
2596                        }
2597
2598                        TEST_THAT(wait_time >= 8);
2599                        TEST_THAT(wait_time <= 12);
2600
2601                        wait_for_sync_end();
2602
2603                        // check that backup has run (compare succeeds)
2604                        TEST_COMPARE(Compare_Same);
2605
2606                        if (failures > 0)
2607                        {
2608                                // stop early to make debugging easier
2609                                return 1;
2610                        }
2611                }
2612
2613                // Check that no read error has been reported yet
2614                TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1"));
2615
2616                TEST_THAT(ServerIsAlive(bbackupd_pid));
2617                TEST_THAT(ServerIsAlive(bbstored_pid));
2618                if (!ServerIsAlive(bbackupd_pid)) return 1;
2619                if (!ServerIsAlive(bbstored_pid)) return 1;
2620
2621                printf("\n==== Delete file and update another, "
2622                        "create symlink.\n");
2623               
2624                // Delete a file
2625                TEST_THAT(::unlink("testfiles/TestDir1/x1/dsfdsfs98.fd") == 0);
2626
2627                #ifndef WIN32
2628                        // New symlink
2629                        TEST_THAT(::symlink("does-not-exist", 
2630                                "testfiles/TestDir1/symlink-to-dir") == 0);
2631                #endif         
2632
2633                // Update a file (will be uploaded as a diff)
2634                {
2635                        // Check that the file is over the diffing
2636                        // threshold in the bbackupd.conf file
2637                        TEST_THAT(TestGetFileSize("testfiles/TestDir1/f45.df") 
2638                                > 1024);
2639                       
2640                        // Add a bit to the end
2641                        FILE *f = ::fopen("testfiles/TestDir1/f45.df", "a");
2642                        TEST_THAT(f != 0);
2643                        ::fprintf(f, "EXTRA STUFF");
2644                        ::fclose(f);
2645                        TEST_THAT(TestGetFileSize("testfiles/TestDir1/f45.df") 
2646                                > 1024);
2647                }
2648
2649                // wait long enough for new files to be old enough to backup
2650                wait_for_operation(5, "new files to be old enough");
2651
2652                // wait for backup daemon to do it's stuff
2653                sync_and_wait();
2654
2655                // compare to make sure that it worked
2656                TEST_COMPARE(Compare_Same);
2657
2658                // Try a quick compare, just for fun
2659                compareReturnValue = ::system(BBACKUPQUERY " "
2660                        "-c testfiles/bbackupd.conf "
2661                        "-l testfiles/query2q.log "
2662                        "-Wwarning \"compare -acqQ\" quit");
2663                TEST_RETURN(compareReturnValue,
2664                        BackupQueries::ReturnCode::Compare_Same);
2665                TestRemoteProcessMemLeaks("bbackupquery.memleaks");
2666               
2667                TEST_THAT(ServerIsAlive(bbackupd_pid));
2668                TEST_THAT(ServerIsAlive(bbstored_pid));
2669                if (!ServerIsAlive(bbackupd_pid)) return 1;
2670                if (!ServerIsAlive(bbstored_pid)) return 1;
2671
2672                // Check that store errors are reported neatly
2673                printf("\n==== Create store error\n");
2674                TEST_THAT(system("rm -f testfiles/notifyran.backup-error.*")
2675                        == 0);
2676
2677                // break the store
2678                TEST_THAT(::rename("testfiles/0_0/backup/01234567/info.rf",
2679                        "testfiles/0_0/backup/01234567/info.rf.bak") == 0);
2680                TEST_THAT(::rename("testfiles/0_1/backup/01234567/info.rf",
2681                        "testfiles/0_1/backup/01234567/info.rf.bak") == 0);
2682                TEST_THAT(::rename("testfiles/0_2/backup/01234567/info.rf",
2683                        "testfiles/0_2/backup/01234567/info.rf.bak") == 0);
2684
2685                // Create a file to trigger an upload
2686                {
2687                        int fd1 = open("testfiles/TestDir1/force-upload", 
2688                                O_CREAT | O_EXCL | O_WRONLY, 0700);
2689                        TEST_THAT(fd1 > 0);
2690                        TEST_THAT(write(fd1, "just do it", 10) == 10);
2691                        TEST_THAT(close(fd1) == 0);
2692                }
2693
2694                wait_for_operation(4, "bbackupd to try to access the store");
2695
2696                // Check that an error was reported just once
2697                TEST_THAT(TestFileExists("testfiles/notifyran.backup-error.1"));
2698                TEST_THAT(!TestFileExists("testfiles/notifyran.backup-error.2"));
2699                // Now kill bbackupd and start one that's running in
2700                // snapshot mode, check that it automatically syncs after
2701                // an error, without waiting for another sync command.
2702                terminate_bbackupd(bbackupd_pid);
2703                std::string cmd = BBACKUPD " " + bbackupd_args + 
2704                        " testfiles/bbackupd-snapshot.conf";
2705                bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid");
2706                TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0);
2707                ::safe_sleep(1);
2708                TEST_THAT(ServerIsAlive(bbackupd_pid));
2709                TEST_THAT(ServerIsAlive(bbstored_pid));
2710                if (!ServerIsAlive(bbackupd_pid)) return 1;
2711                if (!ServerIsAlive(bbstored_pid)) return 1;
2712
2713                sync_and_wait();
2714
2715                // Check that the error was reported once more
2716                TEST_THAT(TestFileExists("testfiles/notifyran.backup-error.2"));
2717                TEST_THAT(!TestFileExists("testfiles/notifyran.backup-error.3"));
2718
2719                // Fix the store (so that bbackupquery compare works)
2720                TEST_THAT(::rename("testfiles/0_0/backup/01234567/info.rf.bak",
2721                        "testfiles/0_0/backup/01234567/info.rf") == 0);
2722                TEST_THAT(::rename("testfiles/0_1/backup/01234567/info.rf.bak",
2723                        "testfiles/0_1/backup/01234567/info.rf") == 0);
2724                TEST_THAT(::rename("testfiles/0_2/backup/01234567/info.rf.bak",
2725                        "testfiles/0_2/backup/01234567/info.rf") == 0);
2726
2727                int store_fixed_time = time(NULL);
2728
2729                // Check that we DO get errors on compare (cannot do this
2730                // until after we fix the store, which creates a race)
2731                TEST_COMPARE(Compare_Different);
2732
2733                // Test initial state
2734                TEST_THAT(!TestFileExists("testfiles/"
2735                        "notifyran.backup-start.wait-snapshot.1"));
2736
2737                // Set a tag for the notify script to distinguish from
2738                // previous runs.
2739                {
2740                        int fd1 = open("testfiles/notifyscript.tag", 
2741                                O_CREAT | O_EXCL | O_WRONLY, 0700);
2742                        TEST_THAT(fd1 > 0);
2743                        TEST_THAT(write(fd1, "wait-snapshot", 13) == 13);
2744                        TEST_THAT(close(fd1) == 0);
2745                }
2746
2747                // bbackupd should pause for about 90 seconds from
2748                // store_fixed_time, so check that it hasn't run after
2749                // 85 seconds after store_fixed_time
2750                wait_for_operation(85 - time(NULL) + store_fixed_time,
2751                        "just before bbackupd recovers");
2752                TEST_THAT(!TestFileExists("testfiles/"
2753                        "notifyran.backup-start.wait-snapshot.1"));
2754
2755                // Should not have backed up, should still get errors
2756                TEST_COMPARE(Compare_Different);
2757
2758                // wait another 10 seconds, bbackup should have run
2759                wait_for_operation(10, "bbackupd to recover");
2760                TEST_THAT(TestFileExists("testfiles/"
2761                        "notifyran.backup-start.wait-snapshot.1"));
2762       
2763                // Check that it did get uploaded, and we have no more errors
2764                TEST_COMPARE(Compare_Same);
2765
2766                TEST_THAT(::unlink("testfiles/notifyscript.tag") == 0);
2767
2768                // Stop the snapshot bbackupd
2769                terminate_bbackupd(bbackupd_pid);
2770
2771                // Break the store again
2772                TEST_THAT(::rename("testfiles/0_0/backup/01234567/info.rf",
2773                        "testfiles/0_0/backup/01234567/info.rf.bak") == 0);
2774                TEST_THAT(::rename("testfiles/0_1/backup/01234567/info.rf",
2775                        "testfiles/0_1/backup/01234567/info.rf.bak") == 0);
2776                TEST_THAT(::rename("testfiles/0_2/backup/01234567/info.rf",
2777                        "testfiles/0_2/backup/01234567/info.rf.bak") == 0);
2778
2779                // Modify a file to trigger an upload
2780                {
2781                        int fd1 = open("testfiles/TestDir1/force-upload", 
2782                                O_WRONLY, 0700);
2783                        TEST_THAT(fd1 > 0);
2784                        TEST_THAT(write(fd1, "and again", 9) == 9);
2785                        TEST_THAT(close(fd1) == 0);
2786                }
2787
2788                // Restart the old bbackupd, in automatic mode
2789                cmd = BBACKUPD " " + bbackupd_args + 
2790                        " testfiles/bbackupd.conf";
2791                bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid");
2792                TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0);
2793                ::safe_sleep(1);
2794                TEST_THAT(ServerIsAlive(bbackupd_pid));
2795                TEST_THAT(ServerIsAlive(bbstored_pid));
2796                if (!ServerIsAlive(bbackupd_pid)) return 1;
2797                if (!ServerIsAlive(bbstored_pid)) return 1;
2798
2799                sync_and_wait();
2800
2801                // Fix the store again
2802                TEST_THAT(::rename("testfiles/0_0/backup/01234567/info.rf.bak",
2803                        "testfiles/0_0/backup/01234567/info.rf") == 0);
2804                TEST_THAT(::rename("testfiles/0_1/backup/01234567/info.rf.bak",
2805                        "testfiles/0_1/backup/01234567/info.rf") == 0);
2806                TEST_THAT(::rename("testfiles/0_2/backup/01234567/info.rf.bak",
2807                        "testfiles/0_2/backup/01234567/info.rf") == 0);
2808
2809                store_fixed_time = time(NULL);
2810
2811                // Check that we DO get errors on compare (cannot do this
2812                // until after we fix the store, which creates a race)
2813                TEST_COMPARE(Compare_Different);
2814
2815                // Test initial state
2816                TEST_THAT(!TestFileExists("testfiles/"
2817                        "notifyran.backup-start.wait-automatic.1"));
2818
2819                // Set a tag for the notify script to distinguist from
2820                // previous runs.
2821                {
2822                        int fd1 = open("testfiles/notifyscript.tag", 
2823                                O_CREAT | O_EXCL | O_WRONLY, 0700);
2824                        TEST_THAT(fd1 > 0);
2825                        TEST_THAT(write(fd1, "wait-automatic", 14) == 14);
2826                        TEST_THAT(close(fd1) == 0);
2827                }
2828
2829                // bbackupd should pause for about 90 seconds from
2830                // store_fixed_time, so check that it hasn't run after
2831                // 85 seconds from store_fixed_time
2832                wait_for_operation(85 - time(NULL) + store_fixed_time,
2833                        "just before bbackupd recovers");
2834                TEST_THAT(!TestFileExists("testfiles/"
2835                        "notifyran.backup-start.wait-automatic.1"));
2836
2837                // Should not have backed up, should still get errors
2838                TEST_COMPARE(Compare_Different);
2839
2840                // wait another 10 seconds, bbackup should have run
2841                wait_for_operation(10, "bbackupd to recover");
2842                TEST_THAT(TestFileExists("testfiles/"
2843                        "notifyran.backup-start.wait-automatic.1"));
2844       
2845                // Check that it did get uploaded, and we have no more errors
2846                TEST_COMPARE(Compare_Same);
2847
2848                TEST_THAT(::unlink("testfiles/notifyscript.tag") == 0);
2849
2850                TEST_THAT(ServerIsAlive(bbackupd_pid));
2851                TEST_THAT(ServerIsAlive(bbstored_pid));
2852                if (!ServerIsAlive(bbackupd_pid)) return 1;
2853                if (!ServerIsAlive(bbstored_pid)) return 1;
2854
2855                // Bad case: delete a file/symlink, replace it with a directory
2856                printf("\n==== Replace symlink with directory, "
2857                        "add new directory\n");
2858
2859                #ifndef WIN32
2860                        TEST_THAT(::unlink("testfiles/TestDir1/symlink-to-dir")
2861                                == 0);
2862                #endif
2863
2864                TEST_THAT(::mkdir("testfiles/TestDir1/symlink-to-dir", 0755) 
2865                        == 0);
2866                TEST_THAT(::mkdir("testfiles/TestDir1/x1/dir-to-file", 0755) 
2867                        == 0);
2868
2869                // NOTE: create a file within the directory to
2870                // avoid deletion by the housekeeping process later
2871
2872                #ifndef WIN32
2873                        TEST_THAT(::symlink("does-not-exist", 
2874                                "testfiles/TestDir1/x1/dir-to-file/contents") 
2875                                == 0);
2876                #endif
2877
2878                wait_for_backup_operation("bbackupd to sync the changes");
2879                TEST_COMPARE(Compare_Same);
2880
2881                TEST_THAT(ServerIsAlive(bbackupd_pid));
2882                TEST_THAT(ServerIsAlive(bbstored_pid));
2883                if (!ServerIsAlive(bbackupd_pid)) return 1;
2884                if (!ServerIsAlive(bbstored_pid)) return 1;
2885
2886                // And the inverse, replace a directory with a file/symlink
2887                printf("\n==== Replace directory with symlink\n");
2888
2889                #ifndef WIN32
2890                        TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file"
2891                                "/contents") == 0);
2892                #endif
2893
2894                TEST_THAT(::rmdir("testfiles/TestDir1/x1/dir-to-file") == 0);
2895
2896                #ifndef WIN32
2897                        TEST_THAT(::symlink("does-not-exist", 
2898                                "testfiles/TestDir1/x1/dir-to-file") == 0);
2899                #endif
2900
2901                wait_for_backup_operation("bbackupd to sync the changes");
2902
2903                TEST_COMPARE(Compare_Same);
2904               
2905                TEST_THAT(ServerIsAlive(bbackupd_pid));
2906                TEST_THAT(ServerIsAlive(bbstored_pid));
2907                if (!ServerIsAlive(bbackupd_pid)) return 1;
2908                if (!ServerIsAlive(bbstored_pid)) return 1;
2909
2910                // And then, put it back to how it was before.
2911                printf("\n==== Replace symlink with directory "
2912                        "(which was a symlink)\n");
2913
2914                #ifndef WIN32
2915                        TEST_THAT(::unlink("testfiles/TestDir1/x1"
2916                                "/dir-to-file") == 0);
2917                #endif
2918
2919                TEST_THAT(::mkdir("testfiles/TestDir1/x1/dir-to-file", 
2920                        0755) == 0);
2921
2922                #ifndef WIN32
2923                        TEST_THAT(::symlink("does-not-exist", 
2924                                "testfiles/TestDir1/x1/dir-to-file/contents2")
2925                                == 0);
2926                #endif
2927
2928                wait_for_backup_operation("bbackupd to sync the changes");
2929
2930                TEST_COMPARE(Compare_Same);
2931               
2932                TEST_THAT(ServerIsAlive(bbackupd_pid));
2933                TEST_THAT(ServerIsAlive(bbstored_pid));
2934                if (!ServerIsAlive(bbackupd_pid)) return 1;
2935                if (!ServerIsAlive(bbstored_pid)) return 1;
2936
2937                // And finally, put it back to how it was before
2938                // it was put back to how it was before
2939                // This gets lots of nasty things in the store with
2940                // directories over other old directories.
2941                printf("\n==== Put it all back to how it was\n");
2942
2943                #ifndef WIN32
2944                        TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file"
2945                                "/contents2") == 0);
2946                #endif
2947
2948                TEST_THAT(::rmdir("testfiles/TestDir1/x1/dir-to-file") == 0);
2949
2950                #ifndef WIN32
2951                        TEST_THAT(::symlink("does-not-exist", 
2952                                "testfiles/TestDir1/x1/dir-to-file") == 0);
2953                #endif
2954
2955                wait_for_backup_operation("bbackupd to sync the changes");
2956
2957                TEST_COMPARE(Compare_Same);
2958
2959                TEST_THAT(ServerIsAlive(bbackupd_pid));
2960                TEST_THAT(ServerIsAlive(bbstored_pid));
2961                if (!ServerIsAlive(bbackupd_pid)) return 1;
2962                if (!ServerIsAlive(bbstored_pid)) return 1;
2963
2964                // rename an untracked file over an
2965                // existing untracked file
2966                printf("\n==== Rename over existing untracked file\n");
2967                int fd1 = open("testfiles/TestDir1/untracked-1", 
2968                        O_CREAT | O_EXCL | O_WRONLY, 0700);
2969                int fd2 = open("testfiles/TestDir1/untracked-2",
2970                        O_CREAT | O_EXCL | O_WRONLY, 0700);
2971                TEST_THAT(fd1 > 0);
2972                TEST_THAT(fd2 > 0);
2973                TEST_THAT(write(fd1, "hello", 5) == 5);
2974                TEST_THAT(close(fd1) == 0);
2975                safe_sleep(1);
2976                TEST_THAT(write(fd2, "world", 5) == 5);
2977                TEST_THAT(close(fd2) == 0);
2978                TEST_THAT(TestFileExists("testfiles/TestDir1/untracked-1"));
2979                TEST_THAT(TestFileExists("testfiles/TestDir1/untracked-2"));
2980
2981                // back up both files
2982                wait_for_operation(5, "untracked files to be old enough");
2983                wait_for_backup_operation("bbackupd to sync the "
2984                        "untracked files");
2985
2986                TEST_COMPARE(Compare_Same);
2987
2988                #ifdef WIN32
2989                        TEST_THAT(::unlink("testfiles/TestDir1/untracked-2")
2990                                == 0);
2991                #endif
2992
2993                TEST_THAT(::rename("testfiles/TestDir1/untracked-1", 
2994                        "testfiles/TestDir1/untracked-2") == 0);
2995                TEST_THAT(!TestFileExists("testfiles/TestDir1/untracked-1"));
2996                TEST_THAT( TestFileExists("testfiles/TestDir1/untracked-2"));
2997
2998                wait_for_backup_operation("bbackupd to sync the untracked "
2999                        "files again");
3000
3001                TEST_COMPARE(Compare_Same);
3002
3003                TEST_THAT(ServerIsAlive(bbackupd_pid));
3004                TEST_THAT(ServerIsAlive(bbstored_pid));
3005                if (!ServerIsAlive(bbackupd_pid)) return 1;
3006                if (!ServerIsAlive(bbstored_pid)) return 1;
3007
3008                // case which went wrong: rename a tracked file over an
3009                // existing tracked file
3010                printf("\n==== Rename over existing tracked file\n");
3011                fd1 = open("testfiles/TestDir1/tracked-1", 
3012                        O_CREAT | O_EXCL | O_WRONLY, 0700);
3013                fd2 = open("testfiles/TestDir1/tracked-2",
3014                        O_CREAT | O_EXCL | O_WRONLY, 0700);
3015                TEST_THAT(fd1 > 0);
3016                TEST_THAT(fd2 > 0);
3017                char buffer[1024];
3018                TEST_THAT(write(fd1, "hello", 5) == 5);
3019                TEST_THAT(write(fd1, buffer, sizeof(buffer)) == sizeof(buffer));
3020                TEST_THAT(close(fd1) == 0);
3021                safe_sleep(1);
3022                TEST_THAT(write(fd2, "world", 5) == 5);
3023                TEST_THAT(write(fd2, buffer, sizeof(buffer)) == sizeof(buffer));
3024                TEST_THAT(close(fd2) == 0);
3025                TEST_THAT(TestFileExists("testfiles/TestDir1/tracked-1"));
3026                TEST_THAT(TestFileExists("testfiles/TestDir1/tracked-2"));
3027
3028                // wait for them to be old enough to back up
3029                wait_for_operation(5, "tracked files to be old enough");
3030               
3031                // back up both files
3032                sync_and_wait();
3033
3034                // compare to make sure that it worked
3035                TEST_COMPARE(Compare_Same);
3036
3037                #ifdef WIN32
3038                        TEST_THAT(::unlink("testfiles/TestDir1/tracked-2")
3039                                == 0);
3040                #endif
3041
3042                TEST_THAT(::rename("testfiles/TestDir1/tracked-1", 
3043                        "testfiles/TestDir1/tracked-2") == 0);
3044                TEST_THAT(!TestFileExists("testfiles/TestDir1/tracked-1"));
3045                TEST_THAT( TestFileExists("testfiles/TestDir1/tracked-2"));
3046
3047                wait_for_backup_operation("bbackupd to sync the tracked "
3048                        "files again");
3049
3050                TEST_COMPARE(Compare_Same);
3051       
3052                TEST_THAT(ServerIsAlive(bbackupd_pid));
3053                TEST_THAT(ServerIsAlive(bbstored_pid));
3054                if (!ServerIsAlive(bbackupd_pid)) return 1;
3055                if (!ServerIsAlive(bbstored_pid)) return 1;
3056
3057                // case which went wrong: rename a tracked file
3058                // over a deleted file
3059                printf("\n==== Rename an existing file over a deleted file\n");
3060                TEST_THAT(!TestFileExists("testfiles/TestDir1/x1/dsfdsfs98.fd"));
3061                TEST_THAT(::rename("testfiles/TestDir1/df9834.dsf", 
3062                        "testfiles/TestDir1/x1/dsfdsfs98.fd") == 0);
3063               
3064                wait_for_backup_operation("bbackupd to sync");
3065
3066                TEST_COMPARE(Compare_Same);
3067               
3068                // Check that no read error has been reported yet
3069                TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1"));
3070
3071                TEST_THAT(ServerIsAlive(bbackupd_pid));
3072                TEST_THAT(ServerIsAlive(bbstored_pid));
3073                if (!ServerIsAlive(bbackupd_pid)) return 1;
3074                if (!ServerIsAlive(bbstored_pid)) return 1;
3075
3076                printf("\n==== Add files with old times, update "
3077                        "attributes of one to latest time\n");
3078
3079                // Move that file back
3080                TEST_THAT(::rename("testfiles/TestDir1/x1/dsfdsfs98.fd", 
3081                        "testfiles/TestDir1/df9834.dsf") == 0);
3082               
3083                // Add some more files
3084                // Because the 'm' option is not used, these files will
3085                // look very old to the daemon.
3086                // Lucky it'll upload them then!
3087                #ifdef WIN32
3088                        TEST_THAT(::system("tar xzvf testfiles/test2.tgz "
3089                                "-C testfiles") == 0);
3090                #else
3091                        TEST_THAT(::system("gzip -d < testfiles/test2.tgz "
3092                                "| ( cd  testfiles && tar xf - )") == 0);
3093                        ::chmod("testfiles/TestDir1/sub23/dhsfdss/blf.h", 0415);
3094                #endif
3095               
3096                // Wait and test
3097                wait_for_backup_operation("bbackupd to sync old files");
3098
3099                TEST_COMPARE(Compare_Same);
3100               
3101                TEST_THAT(ServerIsAlive(bbackupd_pid));
3102                TEST_THAT(ServerIsAlive(bbstored_pid));
3103                if (!ServerIsAlive(bbackupd_pid)) return 1;
3104                if (!ServerIsAlive(bbstored_pid)) return 1;
3105
3106                // Check that no read error has been reported yet
3107                TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1"));
3108
3109                // Check that modifying files with old timestamps
3110                // still get added
3111                printf("\n==== Modify existing file, but change timestamp "
3112                        "to rather old\n");
3113                wait_for_sync_end();
3114
3115                // Then modify an existing file
3116                {
3117                        // in the archive, it's read only
3118                        #ifdef WIN32
3119                                TEST_THAT(::system("chmod 0777 testfiles"
3120                                        "/TestDir1/sub23/rand.h") == 0);
3121                        #else
3122                                TEST_THAT(chmod("testfiles/TestDir1/sub23"
3123                                        "/rand.h", 0777) == 0);
3124                        #endif
3125
3126                        FILE *f = fopen("testfiles/TestDir1/sub23/rand.h", 
3127                                "w+");
3128
3129                        if (f == 0)
3130                        {
3131                                perror("Failed to open");
3132                        }
3133
3134                        TEST_THAT(f != 0);
3135
3136                        if (f != 0)
3137                        {
3138                                fprintf(f, "MODIFIED!\n");
3139                                fclose(f);
3140                        }
3141
3142                        // and then move the time backwards!
3143                        struct timeval times[2];
3144                        BoxTimeToTimeval(SecondsToBoxTime(
3145                                (time_t)(365*24*60*60)), times[1]);
3146                        times[0] = times[1];
3147                        TEST_THAT(::utimes("testfiles/TestDir1/sub23/rand.h", 
3148                                times) == 0);
3149                }
3150
3151                // Wait and test
3152                wait_for_sync_end(); // files too new
3153                wait_for_sync_end(); // should (not) be backed up this time
3154
3155                TEST_COMPARE(Compare_Same);
3156
3157                TEST_THAT(ServerIsAlive(bbackupd_pid));
3158                TEST_THAT(ServerIsAlive(bbstored_pid));
3159                if (!ServerIsAlive(bbackupd_pid)) return 1;
3160                if (!ServerIsAlive(bbstored_pid)) return 1;
3161
3162                // Check that no read error has been reported yet
3163                TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1"));
3164
3165                // Add some files and directories which are marked as excluded
3166                printf("\n==== Add files and dirs for exclusion test\n");
3167                #ifdef WIN32
3168                        TEST_THAT(::system("tar xzvf testfiles/testexclude.tgz "
3169                                "-C testfiles") == 0);
3170                #else
3171                        TEST_THAT(::system("gzip -d < "
3172                                "testfiles/testexclude.tgz "
3173                                "| ( cd testfiles && tar xf - )") == 0);
3174                #endif
3175
3176                // Wait and test
3177                wait_for_sync_end();
3178                wait_for_sync_end();
3179               
3180                // compare with exclusions, should not find differences
3181                TEST_COMPARE(Compare_Same);
3182
3183                // compare without exclusions, should find differences
3184                compareReturnValue = ::system(BBACKUPQUERY " "
3185                        "-c testfiles/bbackupd.conf "
3186                        "-l testfiles/query3n.log "
3187                        "-Werror \"compare -acEQ\" quit");
3188                TEST_RETURN(compareReturnValue,
3189                        BackupQueries::ReturnCode::Compare_Different);
3190                TestRemoteProcessMemLeaks("bbackupquery.memleaks");
3191
3192                TEST_THAT(ServerIsAlive(bbackupd_pid));
3193                TEST_THAT(ServerIsAlive(bbstored_pid));
3194                if (!ServerIsAlive(bbackupd_pid)) return 1;
3195                if (!ServerIsAlive(bbstored_pid)) return 1;
3196
3197                // check that the excluded files did not make it
3198                // into the store, and the included files did
3199                printf("\n==== Check that exclude/alwaysinclude commands "
3200                        "actually work\n");
3201
3202                {
3203                        std::auto_ptr<BackupProtocolClient> client = 
3204                                ConnectAndLogin(context,
3205                                BackupProtocolLogin::Flags_ReadOnly);
3206                       
3207                        std::auto_ptr<BackupStoreDirectory> dir = 
3208                                ReadDirectory(*client);
3209
3210                        int64_t testDirId = SearchDir(*dir, "Test1");
3211                        TEST_THAT(testDirId != 0);
3212                        dir = ReadDirectory(*client, testDirId);
3213                               
3214                        TEST_THAT(!SearchDir(*dir, "excluded_1"));
3215                        TEST_THAT(!SearchDir(*dir, "excluded_2"));
3216                        TEST_THAT(!SearchDir(*dir, "exclude_dir"));
3217                        TEST_THAT(!SearchDir(*dir, "exclude_dir_2"));
3218                        // xx_not_this_dir_22 should not be excluded by
3219                        // ExcludeDirsRegex, because it's a file
3220                        TEST_THAT(SearchDir (*dir, "xx_not_this_dir_22"));
3221                        TEST_THAT(!SearchDir(*dir, "zEXCLUDEu"));
3222                        TEST_THAT(SearchDir (*dir, "dont.excludethis"));
3223                        TEST_THAT(SearchDir (*dir, "xx_not_this_dir_ALWAYSINCLUDE"));
3224
3225                        int64_t sub23id = SearchDir(*dir, "sub23");
3226                        TEST_THAT(sub23id != 0);
3227                        dir = ReadDirectory(*client, sub23id);
3228
3229                        TEST_THAT(!SearchDir(*dir, "xx_not_this_dir_22"));
3230                        TEST_THAT(!SearchDir(*dir, "somefile.excludethis"));
3231                        client->QueryFinished();
3232                        sSocket.Close();
3233                }
3234
3235                TEST_THAT(ServerIsAlive(bbackupd_pid));
3236                TEST_THAT(ServerIsAlive(bbstored_pid));
3237                if (!ServerIsAlive(bbackupd_pid)) return 1;
3238                if (!ServerIsAlive(bbstored_pid)) return 1;
3239
3240#ifndef WIN32
3241                // These tests only work as non-root users.
3242                if(::getuid() != 0)
3243                {
3244                        // Check that the error has not been reported yet
3245                        TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1"));
3246
3247                        // Check that read errors are reported neatly
3248                        printf("\n==== Add unreadable files\n");
3249                       
3250                        {
3251                                // Dir and file which can't be read
3252                                TEST_THAT(::mkdir("testfiles/TestDir1/sub23"
3253                                        "/read-fail-test-dir", 0000) == 0);
3254                                int fd = ::open("testfiles/TestDir1"
3255                                        "/read-fail-test-file", 
3256                                        O_CREAT | O_WRONLY, 0000);
3257                                TEST_THAT(fd != -1);
3258                                ::close(fd);
3259                        }
3260
3261                        // Wait and test...
3262                        wait_for_backup_operation("bbackupd to try to sync "
3263                                "unreadable file");
3264
3265                        // should fail with an error due to unreadable file
3266                        TEST_COMPARE(Compare_Error);
3267
3268                        // Check that it was reported correctly
3269                        TEST_THAT(TestFileExists("testfiles/notifyran.read-error.1"));
3270
3271                        // Check that the error was only reported once
3272                        TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.2"));
3273
3274                        // Set permissions on file and dir to stop
3275                        // errors in the future
3276                        TEST_THAT(::chmod("testfiles/TestDir1/sub23"
3277                                "/read-fail-test-dir", 0770) == 0);
3278                        TEST_THAT(::chmod("testfiles/TestDir1"
3279                                "/read-fail-test-file", 0770) == 0);
3280                }
3281#endif
3282
3283                TEST_THAT(ServerIsAlive(bbackupd_pid));
3284                TEST_THAT(ServerIsAlive(bbstored_pid));
3285                if (!ServerIsAlive(bbackupd_pid)) return 1;
3286                if (!ServerIsAlive(bbstored_pid)) return 1;
3287
3288                printf("\n==== Continuously update file, "
3289                        "check isn't uploaded\n");
3290               
3291                // Make sure everything happens at the same point in the
3292                // sync cycle: wait until exactly the start of a sync
3293                wait_for_sync_start();
3294
3295                // Then wait a second, to make sure the scan is complete
3296                ::safe_sleep(1);
3297
3298                {
3299                        // Open a file, then save something to it every second
3300                        for(int l = 0; l < 12; ++l)
3301                        {
3302                                FILE *f = ::fopen("testfiles/TestDir1/continousupdate", "w+");
3303                                TEST_THAT(f != 0);
3304                                fprintf(f, "Loop iteration %d\n", l);
3305                                fflush(f);
3306                                fclose(f);
3307
3308                                printf(".");
3309                                fflush(stdout);
3310                                safe_sleep(1);
3311                        }
3312                        printf("\n");
3313                        fflush(stdout);
3314                       
3315                        // Check there's a difference
3316                        compareReturnValue = ::system("perl testfiles/"
3317                                "extcheck1.pl");
3318
3319                        TEST_RETURN(compareReturnValue, 1);
3320                        TestRemoteProcessMemLeaks("bbackupquery.memleaks");
3321
3322                        printf("\n==== Keep on continuously updating file, "
3323                                "check it is uploaded eventually\n");
3324
3325                        for(int l = 0; l < 28; ++l)
3326                        {
3327                                FILE *f = ::fopen("testfiles/TestDir1/"
3328                                        "continousupdate", "w+");
3329                                TEST_THAT(f != 0);
3330                                fprintf(f, "Loop 2 iteration %d\n", l);
3331                                fflush(f);
3332                                fclose(f);
3333
3334                                printf(".");
3335                                fflush(stdout);
3336                                safe_sleep(1);
3337                        }
3338                        printf("\n");
3339                        fflush(stdout);
3340
3341                        compareReturnValue = ::system("perl testfiles/"
3342                                "extcheck2.pl");
3343
3344                        TEST_RETURN(compareReturnValue, 1);
3345                        TestRemoteProcessMemLeaks("bbackupquery.memleaks");
3346                }
3347               
3348                TEST_THAT(ServerIsAlive(bbackupd_pid));
3349                TEST_THAT(ServerIsAlive(bbstored_pid));
3350                if (!ServerIsAlive(bbackupd_pid)) return 1;
3351                if (!ServerIsAlive(bbstored_pid)) return 1;
3352
3353                printf("\n==== Delete directory, change attributes\n");
3354       
3355                // Delete a directory
3356                TEST_THAT(::system("rm -rf testfiles/TestDir1/x1") == 0);
3357                // Change attributes on an original file.
3358                ::chmod("testfiles/TestDir1/df9834.dsf", 0423);
3359               
3360                // Wait and test
3361                wait_for_backup_operation("bbackupd to sync deletion "
3362                        "of directory");
3363
3364                TEST_COMPARE(Compare_Same);
3365       
3366                printf("\n==== Restore files and directories\n");
3367                int64_t deldirid = 0;
3368                int64_t restoredirid = 0;
3369                {
3370                        // connect and log in
3371                        std::auto_ptr<BackupProtocolClient> client = 
3372                                ConnectAndLogin(context,
3373                                        BackupProtocolLogin::Flags_ReadOnly);
3374
3375                        // Find the ID of the Test1 directory
3376                        restoredirid = GetDirID(*client, "Test1", 
3377                                BackupProtocolListDirectory::RootDirectory);
3378                        TEST_THAT(restoredirid != 0);
3379
3380                        // Test the restoration
3381                        TEST_THAT(BackupClientRestore(*client, restoredirid, 
3382                                "Test1" /* remote */,
3383                                "testfiles/restore-Test1" /* local */,
3384                                true /* print progress dots */,
3385                                false /* restore deleted */,
3386                                false /* undelete after */,
3387                                false /* resume */,
3388                                false /* keep going */) 
3389                                == Restore_Complete);
3390
3391                        // On Win32 we can't open another connection
3392                        // to the server, so we'll compare later.
3393
3394                        // Make sure you can't restore a restored directory
3395                        TEST_THAT(BackupClientRestore(*client, restoredirid, 
3396                                "Test1", "testfiles/restore-Test1", 
3397                                true /* print progress dots */,
3398                                false /* restore deleted */,
3399                                false /* undelete after */,
3400                                false /* resume */,
3401                                false /* keep going */) 
3402                                == Restore_TargetExists);
3403                       
3404                        // Find ID of the deleted directory
3405                        deldirid = GetDirID(*client, "x1", restoredirid);
3406                        TEST_THAT(deldirid != 0);
3407
3408                        // Just check it doesn't bomb out -- will check this
3409                        // properly later (when bbackupd is stopped)
3410                        TEST_THAT(BackupClientRestore(*client, deldirid, 
3411                                "Test1", "testfiles/restore-Test1-x1",
3412                                true /* print progress dots */, 
3413                                true /* restore deleted */,
3414                                false /* undelete after */,
3415                                false /* resume */,
3416                                false /* keep going */) 
3417                                == Restore_Complete);
3418
3419                        // Make sure you can't restore to a nonexistant path
3420                        printf("\n==== Try to restore to a path "
3421                                "that doesn't exist\n");
3422                        fflush(stdout);
3423
3424                        {
3425                                Logging::Guard guard(Log::FATAL);
3426                                TEST_THAT(BackupClientRestore(*client,
3427                                        restoredirid, "Test1",
3428                                        "testfiles/no-such-path/subdir", 
3429                                        true /* print progress dots */, 
3430                                        true /* restore deleted */,
3431                                        false /* undelete after */,
3432                                        false /* resume */,
3433                                        false /* keep going */) 
3434                                        == Restore_TargetPathNotFound);
3435                        }
3436
3437                        // Log out
3438                        client->QueryFinished();
3439                        sSocket.Close();
3440                }
3441
3442                // Compare the restored files
3443                TEST_COMPARE(Compare_Same);
3444               
3445                TEST_THAT(ServerIsAlive(bbackupd_pid));
3446                TEST_THAT(ServerIsAlive(bbstored_pid));
3447                if (!ServerIsAlive(bbackupd_pid)) return 1;
3448                if (!ServerIsAlive(bbstored_pid)) return 1;
3449
3450#ifdef WIN32
3451                // make one of the files read-only, expect a compare failure
3452                compareReturnValue = ::system("attrib +r "
3453                        "testfiles\\restore-Test1\\f1.dat");
3454                TEST_RETURN(compareReturnValue, 0);
3455
3456                TEST_COMPARE(Compare_Different);
3457       
3458                // set it back, expect no failures
3459                compareReturnValue = ::system("attrib -r "
3460                        "testfiles\\restore-Test1\\f1.dat");
3461                TEST_RETURN(compareReturnValue, 0);
3462
3463                TEST_COMPARE(Compare_Same);
3464
3465                // change the timestamp on a file, expect a compare failure
3466                char* testfile = "testfiles\\restore-Test1\\f1.dat";
3467                HANDLE handle = openfile(testfile, O_RDWR, 0);
3468                TEST_THAT(handle != INVALID_HANDLE_VALUE);
3469               
3470                FILETIME creationTime, lastModTime, lastAccessTime;
3471                TEST_THAT(GetFileTime(handle, &creationTime, &lastAccessTime, 
3472                        &lastModTime) != 0);
3473                TEST_THAT(CloseHandle(handle));
3474
3475                FILETIME dummyTime = lastModTime;
3476                dummyTime.dwHighDateTime -= 100;
3477
3478                // creation time is backed up, so changing it should cause
3479                // a compare failure
3480                TEST_THAT(set_file_time(testfile, dummyTime, lastModTime,
3481                        lastAccessTime));
3482
3483                TEST_COMPARE(Compare_Different);
3484
3485                // last access time is not backed up, so it cannot be compared
3486                TEST_THAT(set_file_time(testfile, creationTime, lastModTime,
3487                        dummyTime));
3488                TEST_COMPARE(Compare_Same);
3489
3490                // last write time is backed up, so changing it should cause
3491                // a compare failure
3492                TEST_THAT(set_file_time(testfile, creationTime, dummyTime,
3493                        lastAccessTime));
3494                TEST_COMPARE(Compare_Different);
3495
3496                // set back to original values, check that compare succeeds
3497                TEST_THAT(set_file_time(testfile, creationTime, lastModTime,
3498                        lastAccessTime));
3499                TEST_COMPARE(Compare_Same);
3500#endif // WIN32
3501
3502                TEST_THAT(ServerIsAlive(bbackupd_pid));
3503                TEST_THAT(ServerIsAlive(bbstored_pid));
3504                if (!ServerIsAlive(bbackupd_pid)) return 1;
3505                if (!ServerIsAlive(bbstored_pid)) return 1;
3506
3507                printf("\n==== Add files with current time\n");
3508       
3509                // Add some more files and modify others
3510                // Use the m flag this time so they have a recent modification time
3511                #ifdef WIN32
3512                        TEST_THAT(::system("tar xzvmf testfiles/test3.tgz "
3513                                "-C testfiles") == 0);
3514                #else
3515                        TEST_THAT(::system("gzip -d < testfiles/test3.tgz "
3516                                "| ( cd testfiles && tar xmf - )") == 0);
3517                #endif
3518               
3519                // Wait and test
3520                wait_for_backup_operation("bbackupd to sync new files");
3521
3522                TEST_COMPARE(Compare_Same);
3523               
3524                TEST_THAT(ServerIsAlive(bbackupd_pid));
3525                TEST_THAT(ServerIsAlive(bbstored_pid));
3526                if (!ServerIsAlive(bbackupd_pid)) return 1;
3527                if (!ServerIsAlive(bbstored_pid)) return 1;
3528
3529                // Rename directory
3530                printf("\n==== Rename directory\n");
3531                TEST_THAT(rename("testfiles/TestDir1/sub23/dhsfdss", 
3532                        "testfiles/TestDir1/renamed-dir") == 0);
3533
3534                wait_for_backup_operation("bbackupd to sync renamed directory");
3535
3536                TEST_COMPARE(Compare_Same);
3537
3538                // and again, but with quick flag
3539                compareReturnValue = ::system(BBACKUPQUERY " "
3540                        "-c testfiles/bbackupd.conf "
3541                        "-l testfiles/query6q.log "
3542                        "-Wwarning \"compare -acqQ\" quit");
3543                TEST_RETURN(compareReturnValue,
3544                        BackupQueries::ReturnCode::Compare_Same);
3545                TestRemoteProcessMemLeaks("bbackupquery.memleaks");
3546
3547                // Rename some files -- one under the threshold, others above
3548                printf("\n==== Rename files\n");
3549                TEST_THAT(rename("testfiles/TestDir1/continousupdate", 
3550                        "testfiles/TestDir1/continousupdate-ren") == 0);
3551                TEST_THAT(rename("testfiles/TestDir1/df324", 
3552                        "testfiles/TestDir1/df324-ren") == 0);
3553                TEST_THAT(rename("testfiles/TestDir1/sub23/find2perl", 
3554                        "testfiles/TestDir1/find2perl-ren") == 0);
3555
3556                wait_for_backup_operation("bbackupd to sync renamed files");
3557
3558                TEST_COMPARE(Compare_Same);
3559
3560                TEST_THAT(ServerIsAlive(bbackupd_pid));
3561                TEST_THAT(ServerIsAlive(bbstored_pid));
3562                if (!ServerIsAlive(bbackupd_pid)) return 1;
3563                if (!ServerIsAlive(bbstored_pid)) return 1;
3564
3565                // Check that modifying files with madly in the future
3566                // timestamps still get added
3567                printf("\n==== Create a file with timestamp way ahead "
3568                        "in the future\n");
3569
3570                // Time critical, so sync
3571                wait_for_sync_start();
3572
3573                // Then wait a second, to make sure the scan is complete
3574                ::safe_sleep(1);
3575
3576                // Then modify an existing file
3577                {
3578                        FILE *f = fopen("testfiles/TestDir1/sub23/"
3579                                "in-the-future", "w");
3580                        TEST_THAT(f != 0);
3581                        fprintf(f, "Back to the future!\n");
3582                        fclose(f);
3583                        // and then move the time forwards!
3584                        struct timeval times[2];
3585                        BoxTimeToTimeval(GetCurrentBoxTime() + 
3586                                SecondsToBoxTime((time_t)(365*24*60*60)), 
3587                                times[1]);
3588                        times[0] = times[1];
3589                        TEST_THAT(::utimes("testfiles/TestDir1/sub23/"
3590                                "in-the-future", times) == 0);
3591                }
3592
3593                // Wait and test
3594                wait_for_backup_operation("bbackup to sync future file");
3595                TEST_COMPARE(Compare_Same);
3596
3597                TEST_THAT(ServerIsAlive(bbackupd_pid));
3598                TEST_THAT(ServerIsAlive(bbstored_pid));
3599                if (!ServerIsAlive(bbackupd_pid)) return 1;
3600                if (!ServerIsAlive(bbstored_pid)) return 1;
3601
3602                printf("\n==== Change client store marker\n");
3603
3604                // Then... connect to the server, and change the
3605                // client store marker. See what that does!
3606                {
3607                        bool done = false;
3608                        int tries = 4;
3609                        while(!done && tries > 0)
3610                        {
3611                                try
3612                                {
3613                                        std::auto_ptr<BackupProtocolClient>
3614                                                protocol = Connect(context);
3615                                        // Make sure the marker isn't zero,
3616                                        // because that's the default, and
3617                                        // it should have changed
3618                                        std::auto_ptr<BackupProtocolLoginConfirmed> loginConf(protocol->QueryLogin(0x01234567, 0));
3619                                        TEST_THAT(loginConf->GetClientStoreMarker() != 0);
3620                                       
3621                                        // Change it to something else
3622                                        protocol->QuerySetClientStoreMarker(12);
3623                                       
3624                                        // Success!
3625                                        done = true;
3626                                       
3627                                        // Log out
3628                                        protocol->QueryFinished();
3629                                        sSocket.Close();
3630                                }
3631                                catch(...)
3632                                {
3633                                        tries--;
3634                                }
3635                        }
3636                        TEST_THAT(done);
3637                }
3638               
3639                TEST_THAT(ServerIsAlive(bbackupd_pid));
3640                TEST_THAT(ServerIsAlive(bbstored_pid));
3641                if (!ServerIsAlive(bbackupd_pid)) return 1;
3642                if (!ServerIsAlive(bbstored_pid)) return 1;
3643
3644                printf("\n==== Check change of store marker pauses daemon\n");
3645               
3646                // Make a change to a file, to detect whether or not
3647                // it's hanging around waiting to retry.
3648                {
3649                        FILE *f = ::fopen("testfiles/TestDir1/fileaftermarker", "w");
3650                        TEST_THAT(f != 0);
3651                        ::fprintf(f, "Lovely file you got there.");
3652                        ::fclose(f);
3653                }
3654
3655                // Wait a little bit longer than usual
3656                wait_for_operation((TIME_TO_WAIT_FOR_BACKUP_OPERATION * 
3657                        3) / 2, "bbackupd to detect changed store marker");
3658
3659                // Test that there *are* differences
3660                TEST_COMPARE(Compare_Different);
3661       
3662                TEST_THAT(ServerIsAlive(bbackupd_pid));
3663                TEST_THAT(ServerIsAlive(bbstored_pid));
3664                if (!ServerIsAlive(bbackupd_pid)) return 1;
3665                if (!ServerIsAlive(bbstored_pid)) return 1;
3666
3667                // 100 seconds - (12*3/2)
3668                wait_for_operation(82, "bbackupd to recover");
3669
3670                TEST_THAT(ServerIsAlive(bbackupd_pid));
3671                TEST_THAT(ServerIsAlive(bbstored_pid));
3672                if (!ServerIsAlive(bbackupd_pid)) return 1;
3673                if (!ServerIsAlive(bbstored_pid)) return 1;
3674
3675#ifndef WIN32
3676                printf("\n==== Interrupted restore\n");
3677                {
3678                        do_interrupted_restore(context, restoredirid);
3679                        int64_t resumesize = 0;
3680                        TEST_THAT(FileExists("testfiles/"
3681                                "restore-interrupt.boxbackupresume", 
3682                                &resumesize));
3683                        // make sure it has recorded something to resume
3684                        TEST_THAT(resumesize > 16);     
3685
3686                        printf("\n==== Resume restore\n");
3687
3688                        std::auto_ptr<BackupProtocolClient> client = 
3689                                ConnectAndLogin(context,
3690                                BackupProtocolLogin::Flags_ReadOnly);
3691
3692                        // Check that the restore fn returns resume possible,
3693                        // rather than doing anything
3694                        TEST_THAT(BackupClientRestore(*client, restoredirid, 
3695                                "Test1", "testfiles/restore-interrupt", 
3696                                true /* print progress dots */, 
3697                                false /* restore deleted */, 
3698                                false /* undelete after */, 
3699                                false /* resume */,
3700                                false /* keep going */) 
3701                                == Restore_ResumePossible);
3702
3703                        // Then resume it
3704                        TEST_THAT(BackupClientRestore(*client, restoredirid, 
3705                                "Test1", "testfiles/restore-interrupt", 
3706                                true /* print progress dots */, 
3707                                false /* restore deleted */, 
3708                                false /* undelete after */, 
3709                                true /* resume */,
3710                                false /* keep going */) 
3711                                == Restore_Complete);
3712
3713                        client->QueryFinished();
3714                        sSocket.Close();
3715
3716                        // Then check it has restored the correct stuff
3717                        compareReturnValue = ::system(BBACKUPQUERY " "
3718                                "-c testfiles/bbackupd.conf "
3719                                "-l testfiles/query14.log "
3720                                "-Wwarning \"compare -cEQ Test1 "
3721                                "testfiles/restore-interrupt\" quit");
3722                        TEST_RETURN(compareReturnValue,
3723                                BackupQueries::ReturnCode::Compare_Same);
3724                        TestRemoteProcessMemLeaks("bbackupquery.memleaks");
3725                }
3726#endif // !WIN32
3727
3728                TEST_THAT(ServerIsAlive(bbackupd_pid));
3729                TEST_THAT(ServerIsAlive(bbstored_pid));
3730                if (!ServerIsAlive(bbackupd_pid)) return 1;
3731                if (!ServerIsAlive(bbstored_pid)) return 1;
3732
3733                printf("\n==== Check restore deleted files\n");
3734
3735                {
3736                        std::auto_ptr<BackupProtocolClient> client = 
3737                                ConnectAndLogin(context, 0 /* read-write */);
3738
3739                        // Do restore and undelete
3740                        TEST_THAT(BackupClientRestore(*client, deldirid, 
3741                                "Test1", "testfiles/restore-Test1-x1-2", 
3742                                true /* print progress dots */, 
3743                                true /* deleted files */, 
3744                                true /* undelete after */,
3745                                false /* resume */,
3746                                false /* keep going */) 
3747                                == Restore_Complete);
3748
3749                        client->QueryFinished();
3750                        sSocket.Close();
3751
3752                        // Do a compare with the now undeleted files
3753                        compareReturnValue = ::system(BBACKUPQUERY " "
3754                                "-c testfiles/bbackupd.conf "
3755                                "-l testfiles/query11.log "
3756                                "-Wwarning "
3757                                "\"compare -cEQ Test1/x1 "
3758                                "testfiles/restore-Test1-x1-2\" quit");
3759                        TEST_RETURN(compareReturnValue,
3760                                BackupQueries::ReturnCode::Compare_Same);
3761                        TestRemoteProcessMemLeaks("bbackupquery.memleaks");
3762                }
3763               
3764                // Final check on notifications
3765                TEST_THAT(!TestFileExists("testfiles/notifyran.store-full.2"));
3766                TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.2"));
3767
3768                TEST_THAT(ServerIsAlive(bbackupd_pid));
3769                TEST_THAT(ServerIsAlive(bbstored_pid));
3770                if (!ServerIsAlive(bbackupd_pid)) return 1;
3771                if (!ServerIsAlive(bbstored_pid)) return 1;
3772
3773#ifdef WIN32
3774                printf("\n==== Testing locked file behaviour:\n");
3775
3776                // Test that locked files cannot be backed up,
3777                // and the appropriate error is reported.
3778                // Wait for the sync to finish, so that we have time to work
3779                wait_for_sync_end();
3780                // Now we have about three seconds to work
3781
3782                handle = openfile("testfiles/TestDir1/lockedfile",
3783                        O_CREAT | O_EXCL | O_LOCK, 0);
3784                TEST_THAT(handle != INVALID_HANDLE_VALUE);
3785
3786                if (handle != 0)
3787                {
3788                        // first sync will ignore the file, it's too new
3789                        wait_for_sync_end();
3790                        TEST_THAT(!TestFileExists("testfiles/"
3791                                "notifyran.read-error.1"));
3792                }
3793
3794                TEST_THAT(ServerIsAlive(bbackupd_pid));
3795                TEST_THAT(ServerIsAlive(bbstored_pid));
3796                if (!ServerIsAlive(bbackupd_pid)) return 1;
3797                if (!ServerIsAlive(bbstored_pid)) return 1;
3798
3799                if (handle != 0)
3800                {
3801                        // this sync should try to back up the file,
3802                        // and fail, because it's locked
3803                        wait_for_sync_end();
3804                        TEST_THAT(TestFileExists("testfiles/"
3805                                "notifyran.read-error.1"));
3806                        TEST_THAT(!TestFileExists("testfiles/"
3807                                "notifyran.read-error.2"));
3808                }
3809
3810                TEST_THAT(ServerIsAlive(bbackupd_pid));
3811                TEST_THAT(ServerIsAlive(bbstored_pid));
3812                if (!ServerIsAlive(bbackupd_pid)) return 1;
3813                if (!ServerIsAlive(bbstored_pid)) return 1;
3814
3815                if (handle != 0)
3816                {
3817                        // now close the file and check that it is
3818                        // backed up on the next run.
3819                        CloseHandle(handle);
3820                        wait_for_sync_end();
3821
3822                        // still no read errors?
3823                        TEST_THAT(!TestFileExists("testfiles/"
3824                                "notifyran.read-error.2"));
3825                }
3826
3827                TEST_THAT(ServerIsAlive(bbackupd_pid));
3828                TEST_THAT(ServerIsAlive(bbstored_pid));
3829                if (!ServerIsAlive(bbackupd_pid)) return 1;
3830                if (!ServerIsAlive(bbstored_pid)) return 1;
3831
3832                if (handle != 0)
3833                {
3834                        // compare, and check that it works
3835                        // reports the correct error message (and finishes)
3836                        TEST_THAT(compare_all(false));
3837                }
3838
3839                TEST_THAT(ServerIsAlive(bbackupd_pid));
3840                TEST_THAT(ServerIsAlive(bbstored_pid));
3841                if (!ServerIsAlive(bbackupd_pid)) return 1;
3842                if (!ServerIsAlive(bbstored_pid)) return 1;
3843
3844                if (handle != 0)
3845                {
3846                        // open the file again, compare and check that compare
3847                        // reports the correct error message (and finishes)
3848                        handle = openfile("testfiles/TestDir1/lockedfile",
3849                                O_LOCK, 0);
3850                        TEST_THAT(handle != INVALID_HANDLE_VALUE);
3851
3852                        TEST_COMPARE(Compare_Error);
3853
3854                        // close the file again, check that compare
3855                        // works again
3856                        CloseHandle(handle);
3857                }
3858
3859                TEST_THAT(ServerIsAlive(bbackupd_pid));
3860                TEST_THAT(ServerIsAlive(bbstored_pid));
3861                if (!ServerIsAlive(bbackupd_pid)) return 1;
3862                if (!ServerIsAlive(bbstored_pid)) return 1;
3863
3864                if (handle != 0)
3865                {
3866                        TEST_COMPARE(Compare_Same);
3867                }
3868#endif
3869
3870                // Kill the daemon
3871                terminate_bbackupd(bbackupd_pid);
3872               
3873                // Start it again
3874                cmd = BBACKUPD " " + bbackupd_args +
3875                        " testfiles/bbackupd.conf";
3876                bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid");
3877
3878                TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0);
3879
3880                TEST_THAT(ServerIsAlive(bbackupd_pid));
3881                TEST_THAT(ServerIsAlive(bbstored_pid));
3882                if (!ServerIsAlive(bbackupd_pid)) return 1;
3883                if (!ServerIsAlive(bbstored_pid)) return 1;
3884
3885                if(bbackupd_pid != -1 && bbackupd_pid != 0)
3886                {
3887                        // Wait and compare (a little bit longer than usual)
3888                        wait_for_operation(
3889                                (TIME_TO_WAIT_FOR_BACKUP_OPERATION*3) / 2,
3890                                "bbackupd to sync everything"); 
3891                        TEST_COMPARE(Compare_Same);
3892
3893                        // Kill it again
3894                        terminate_bbackupd(bbackupd_pid);
3895                }
3896        }
3897
3898        /*
3899        // List the files on the server - why?
3900        ::system(BBACKUPQUERY " -q -c testfiles/bbackupd.conf "
3901                "-l testfiles/queryLIST.log \"list -rotdh\" quit");
3902        TestRemoteProcessMemLeaks("bbackupquery.memleaks");
3903        */
3904
3905        #ifndef WIN32   
3906                if(::getuid() == 0)
3907                {
3908                        ::printf("WARNING: This test was run as root. "
3909                                "Some tests have been omitted.\n");
3910                }
3911        #endif
3912       
3913        return 0;
3914}
3915
3916int test(int argc, const char *argv[])
3917{
3918        {
3919                BackupDaemon daemon;
3920
3921                TEST_EQUAL(1234, daemon.ParseSyncAllowScriptOutput("test", "1234"));
3922                TEST_EQUAL(0, daemon.GetMaxBandwidthFromSyncAllowScript());
3923
3924                TEST_EQUAL(1234, daemon.ParseSyncAllowScriptOutput("test", "1234 5"));
3925                TEST_EQUAL(5, daemon.GetMaxBandwidthFromSyncAllowScript());
3926
3927                TEST_EQUAL(-1, daemon.ParseSyncAllowScriptOutput("test", "now"));
3928                TEST_EQUAL(0, daemon.GetMaxBandwidthFromSyncAllowScript());
3929        }
3930
3931        // SSL library
3932        SSLLib::Initialise();
3933
3934        // Keys for subsystems
3935        BackupClientCryptoKeys_Setup("testfiles/bbackupd.keys");
3936
3937        // Initial files
3938        #ifdef WIN32
3939                TEST_THAT(::system("tar xzvf testfiles/test_base.tgz "
3940                        "-C testfiles") == 0);
3941        #else
3942                TEST_THAT(::system("gzip -d < testfiles/test_base.tgz "
3943                        "| ( cd testfiles && tar xf - )") == 0);
3944        #endif
3945
3946        // Do the tests
3947
3948        int r = test_basics();
3949        if(r != 0) return r;
3950       
3951        r = test_setupaccount();
3952        if(r != 0) return r;
3953
3954        r = test_run_bbstored();
3955        TEST_THAT(r == 0);
3956        if(r != 0) return r;
3957       
3958        r = test_bbackupd();
3959        if(r != 0)
3960        {
3961                if (bbackupd_pid)
3962                {
3963                        KillServer(bbackupd_pid);
3964                }
3965                if (bbstored_pid)
3966                {
3967                        KillServer(bbstored_pid);
3968                }
3969                return r;
3970        }
3971       
3972        test_kill_bbstored();
3973
3974        return 0;
3975}
Note: See TracBrowser for help on using the repository browser.