Support for split testsuite, launchmon in testsuite
[dyninst.git] / testsuite / src / test_driver.C
1 /*
2  * Copyright (c) 1996-2009 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31
32 // $Id: test_driver.C,v 1.7 2008/10/30 19:16:50 legendre Exp $
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <stdarg.h>
36 #include <string.h>
37 #include <string>
38 #include <errno.h>
39 #include <vector>
40 #include <iostream>
41 #include <sstream>
42 #include <assert.h>
43 #include <algorithm>
44 #include <sys/stat.h>
45 #include <time.h>
46 #include <limits.h>
47
48 #if defined(os_windows_test)
49 #define vsnprintf _vsnprintf
50 #define snprintf _snprintf
51 #pragma warning(disable:4786)
52 #include <direct.h>
53 #else
54 #include <fnmatch.h>
55 #include <dirent.h>
56 #include <unistd.h>
57 #include <sys/times.h>
58 #include <strings.h>
59 #endif
60
61 #include "ParameterDict.h"
62 #include "test_lib.h"
63 #include "error.h"
64 #include "ResumeLog.h"
65 #include "TestOutputDriver.h"
66 #include "StdOutputDriver.h"
67 #include "comptester.h"
68 #include "CmdLine.h"
69 #include "module.h"
70 #include "MutateeStart.h"
71 #include "remotetest.h"
72
73 using namespace std;
74
75 int testsRun = 0;
76
77 FILE *outlog = NULL;
78 FILE *errlog = NULL;
79 char *logfilename;
80
81 int gargc;
82 char **gargv;
83
84 void initModuleIfNecessary(RunGroup *group, std::vector<RunGroup *> &groups, 
85                            ParameterDict &params);
86 int LMONInvoke(RunGroup *, ParameterDict params, char *test_args[], char *daemon_args[], bool attach);
87
88 int setupLogs(ParameterDict &params);
89
90 #if !defined(os_windows_test)
91 int runScript(const char *name, ...)
92 {
93    char test[1024];
94    int result;
95    va_list ap;
96    va_start(ap, name);
97    vsnprintf(test, 1024, name, ap);
98    va_end(ap);
99
100    char test2[1024];
101    if ((outlog != NULL) && (outlog != stdout)) {
102       snprintf(test2, 1024, "sh -c \"%s\" >>%s 2>&1", test, logfilename);
103    } else {
104       snprintf(test2, 1024, "%s", test);
105    }
106
107    // Flush before/after script run
108    flushOutputLog();
109    flushErrorLog();
110    result = system(test2);
111    flushOutputLog();
112    flushErrorLog();
113
114    return result;
115 }
116 #else
117 int runScript(const char *name, ...) {
118    getOutput()->log(STDERR, "runScript not implemented on Windows\n");
119    assert(0);
120    return -1;
121 }
122 #endif
123
124 #if !defined(os_windows_test)
125 static void *mem_start;
126 static struct tms start_time;
127
128 #include <unistd.h>
129
130 void measureStart(ParameterDict &params)
131 {
132    if (!params["measure_memcpu"]->getInt())
133       return;
134
135    mem_start = sbrk(0);
136    times(&start_time);
137 }
138
139 void measureEnd(ParameterDict &params)
140 {
141    if (!params["measure_memcpu"]->getInt())
142       return;
143
144    void *mem_end = sbrk(0);
145    struct tms end_time;
146    times(&end_time);
147
148    signed long mem_diff = ((char *) mem_end) - ((char *) mem_start);
149    clock_t utime = end_time.tms_utime - start_time.tms_utime;
150    clock_t stime = end_time.tms_stime - start_time.tms_stime;
151
152    char *measureFileName = params["measure_memcpu_name"]->getString();
153    FILE *measure_file = NULL;
154    bool using_stdout;
155    if (strcmp(measureFileName, "-") == 0) {
156       using_stdout = true;
157       measure_file = stdout;
158    }
159    else {
160       using_stdout = false;
161       measure_file = fopen(measureFileName, "a");
162    }
163    if (!measure_file)
164    {
165       perror("Unable to open file for CPU/MEM measurement");
166       return;
167    }
168
169    fprintf(measure_file, "mem=%ld\tutime=%ld\tstime=%ld\n",
170            mem_diff, utime, stime);
171    if (!using_stdout)
172       fclose(measure_file);
173 }
174
175 #else
176
177 void measureStart(ParameterDict &)
178 {
179 }
180
181 void measureEnd(ParameterDict &)
182 {
183 }
184
185 #endif
186
187 void printLogMutateeHeader(const char *mutatee, test_linktype_t linktype)
188 {
189    flushOutputLog();
190    flushErrorLog();
191    // Mutatee Description
192    // Mutatee Info
193    if ( (mutatee != NULL) && (strcmp(mutatee, "") != 0) ) {
194       getOutput()->log(LOGINFO, "[Tests with %s]\n", mutatee);
195 #if !defined(os_windows_test)
196       runScript("ls -lLF %s", mutatee);
197       if( linktype == DynamicLink ) 
198          runScript("ldd %s", mutatee);
199       else
200          getOutput()->log(LOGINFO, "%s: statically linked\n", mutatee);
201 #endif
202    } else {
203       getOutput()->log(LOGINFO, "[Tests with none]\n");
204    }
205
206    getOutput()->log(LOGINFO, "\n");
207    flushOutputLog();
208    flushErrorLog();
209 }
210
211 void printLogOptionHeader(TestInfo *tinfo, ParameterDict &params)
212 {
213    if (!params["printMutateeLogHeader"]->getInt())
214       return;
215    getOutput()->log(LOGINFO, "test-info: %s\n", tinfo->label);
216    flushOutputLog();
217    flushErrorLog();
218 }
219
220 void printHumanTestHeader(test_data_t &test, char *mutatee, bool useAttach)
221 {
222    flushOutputLog();
223    flushErrorLog();
224    // Test Header
225    getOutput()->log(LOGINFO, "Running: %s", test.name);
226    if ( strcmp(mutatee, "") != 0 )
227    {
228       getOutput()->log(LOGINFO, " with mutatee: %s", mutatee);
229    }
230    if ( useAttach )
231    {
232       getOutput()->log(LOGINFO, " in attach mode");
233    }
234    getOutput()->log(LOGINFO, ".\n");
235
236
237    flushOutputLog();
238    flushErrorLog();
239 }
240
241 struct formatStrings
242 {
243    formatStrings(const std::string& pass, const std::string& skip, const std::string& fail, const std::string& crash, 
244                  const std::string& create, const std::string& attach, const std::string& testNameFormat) :
245       passStr(pass), skipStr(skip), failStr(fail), crashStr(crash), createStr(create), attachStr(attach), testNameFormatStr(testNameFormat) 
246    {
247    }
248    formatStrings() 
249    {
250    }
251   
252    std::string passStr;
253    std::string skipStr;
254    std::string failStr;
255    std::string crashStr;
256    std::string createStr;
257    std::string attachStr;
258    std::string testNameFormatStr;
259 };
260
261 static formatStrings verboseStrings("PASSED\n", "SKIPPED\n", "FAILED\n", "CRASHED\n", "create\tresult: ", "attach\tresult: ", "%s: mutatee: %s create_mode: ");
262 static formatStrings compactStrings(".", "S", "F", "C", "", "", "");
263
264 struct failureInfo
265 {
266    std::string testName;
267    bool createMode;
268    bool wasCrash;
269 };
270
271 void setupRemoteTests(vector<RunGroup *> &groups)
272 {
273    for (unsigned i=0; i < groups.size(); i++) {
274       if (groups[i]->disabled)
275          continue;
276       if (groups[i]->mutator_location == remote) {
277          groups[i]->modname = "remote::" + groups[i]->modname;
278       }
279    }
280 }
281
282 int setupRemoteMutator(RunGroup *group)
283 {
284    int count = 0;
285    for (unsigned i=0; i<group->tests.size(); i++) {
286       if (group->tests[i]->disabled)
287          continue;
288       group->tests[i]->mutator = RemoteTestFE::createRemoteTestFE(group->tests[i], getConnection());
289       count++;
290    }
291    return count;
292 }
293
294 int numUnreportedTests(RunGroup *group)
295 {
296    int num_unreported = 0;
297
298    for (unsigned i=0; i<group->tests.size(); i++)
299    {
300       if (shouldRunTest(group, group->tests[i]))
301       {
302          num_unreported++;
303       }
304    }
305
306    return num_unreported;
307 }
308
309 void executeTest(ComponentTester *tester,
310                  RunGroup *group, TestInfo *test, 
311                  ParameterDict param)
312 {
313    std::map<std::string, std::string> attrs;
314    TestOutputDriver::getAttributesMap(test, group, attrs);
315
316    std::vector<ParamString*> new_params;
317    int group_num = group->index;
318    int test_num = test->index;
319
320    std::map<std::string, std::string>::iterator i = attrs.begin();
321    for (; i != attrs.end(); i++)
322    {
323       ParamString *pstr = new ParamString((*i).second.c_str());
324       param[(*i).first] = pstr;
325       new_params.push_back(pstr);
326    }
327
328    if (shouldRunTest(group, test))
329    {
330       log_teststart(group_num, test_num, test_setup_rs);
331       test->results[test_setup_rs] = tester->test_setup(test, param);
332       log_testresult(test->results[test_setup_rs]);
333    }
334
335    if (shouldRunTest(group, test))
336    {
337       log_teststart(group_num, test_num, test_execute_rs);
338       test->results[test_execute_rs] = test->mutator->executeTest();
339       log_testresult(test->results[test_execute_rs]);
340    }
341
342    if (shouldRunTest(group, test))
343    {
344       log_teststart(group_num, test_num, test_teardown_rs);
345       test->results[test_teardown_rs] = tester->test_teardown(test, param);
346       log_testresult(test->results[test_teardown_rs]);
347    }
348
349    for (unsigned j=0; j<new_params.size(); j++)
350       delete new_params[j];
351 }
352
353 volatile int dont_optimize = 0;
354 void tests_breakpoint()
355 {
356   dont_optimize++;
357   //Breakpoint here to get a binary with test libraries loaded.
358 }
359
360 static void clearConnection()
361 {
362    Connection *con = getConnection();
363    if (!con)
364       return;
365    delete con;
366    setConnection(NULL);
367 }
368
369 bool setupConnectionToRemote(RunGroup *group, ParameterDict &params)
370 {
371    clearConnection();
372    Connection *con = new Connection();
373    setConnection(con);
374
375    //Setup connection
376    std::string hostname;
377    int port;
378    bool result = con->server_setup(hostname, port);
379    if (!result) {
380       fprintf(stderr, "Could not setup server socket\n");
381       return false;
382    }
383
384    //Mutatee params
385    string mutatee_exec;
386    vector<string> mutatee_args;
387    result = getMutateeParams(group, params, mutatee_exec, mutatee_args);
388    if (!result) {
389       fprintf(stderr, "Failed to collect mutatee params\n");
390    }
391    char **c_mutatee_args = getCParams(mutatee_exec, mutatee_args);
392
393    //driver params;
394    vector<string> driver_args;
395 #if defined(RUN_IN_VALGRIND) 
396    string driver_exec = "valgrind";
397    driver_args.push_back("--tool=memcheck");
398    driver_args.push_back("testdriver_be");
399 #else
400    string driver_exec = "testdriver_be";
401 #endif
402    char port_s[32];
403    snprintf(port_s, 32, "%d", port);
404    driver_args.push_back("-hostname");
405    driver_args.push_back(hostname);
406    driver_args.push_back("-port");
407    driver_args.push_back(port_s);
408    for (unsigned i=0; i<gargc; i++) {
409       driver_args.push_back(gargv[i]);
410    }
411    char **c_driver_args = getCParams(driver_exec, driver_args);
412
413    bool attach_mode = (group->createmode == USEATTACH);
414    int result_i = LMONInvoke(group, params, c_mutatee_args, c_driver_args, attach_mode);
415
416    result = con->server_accept();
417    if (!result) {
418       fprintf(stderr, "Failed to accept connection from client\n");
419       return false;
420    }
421 }
422
423 void executeGroup(RunGroup *group,
424                   vector<RunGroup *> &groups,
425                   ParameterDict param)
426 {
427    setMutateeDict(group, param);
428
429    bool is_remote = (group->mutator_location == remote);
430    if (is_remote && !group->disabled)
431       setupConnectionToRemote(group, param);
432
433    initModuleIfNecessary(group, groups, param);
434
435    test_results_t result;
436    // setupMutatorsForRunGroup creates TestMutator objects and
437    // sets a pointer in the TestInfo object to point to the TestMutator for
438    // each test.
439    int tests_found;
440    if (group->mutator_location == remote)
441       tests_found = setupRemoteMutator(group);
442    else
443       tests_found = setupMutatorsForRunGroup(group);
444
445    if (tests_found <= 0)
446       return;
447    tests_breakpoint();
448
449    int groupnum = group->index;
450
451    ParameterDict::iterator pdi = param.find("given_mutatee");
452    if (pdi != param.end())
453    {
454       registerMutatee(pdi->second->getString());
455    }
456
457    for (unsigned i=0; i<group->tests.size(); i++)
458    {
459       if (shouldRunTest(group, group->tests[i]))
460          testsRun++;
461    }
462
463    ComponentTester *tester = group->mod->tester;
464
465    log_teststart(groupnum, 0, group_setup_rs);
466    result = tester->group_setup(group, param);
467    log_testresult(result);
468    if (result != PASSED && result != SKIPPED && result != UNKNOWN) {
469       getOutput()->log(LOGERR, "Group setup failed: %s\n", 
470                        tester->getLastErrorMsg().c_str());
471    }
472    if (result != UNKNOWN) {
473       for (unsigned int i = 0; i < group->tests.size(); i++) {
474          group->tests[i]->results[group_setup_rs] = result;
475       }
476    }
477
478    for(unsigned i = 0; i < group->tests.size(); i++)
479    {
480       // Print mutator log header
481       assert(group->tests[i]);
482       printLogOptionHeader(group->tests[i], param);
483
484       if (shouldRunTest(group, group->tests[i])) {
485          log_teststart(groupnum, i, test_init_rs);
486          if(group->tests[i]->mutator)
487          {
488             test_results_t setup_res = group->tests[i]->mutator->setup(param);
489             group->tests[i]->results[test_init_rs] = setup_res;
490             if (setup_res != PASSED)
491             {
492                logerror("%s[%d]:  setup failed (%d) for test %s\n", 
493                         FILE__, __LINE__, (int) setup_res, group->tests[i]->name);
494             }
495          }
496          else
497          {
498             logerror("No mutator object found for test: %s\n", group->tests[i]->name);
499             group->tests[i]->results[test_init_rs] = FAILED;
500          }
501          log_testresult(group->tests[i]->results[test_init_rs]);
502       }
503    }
504       
505    for (size_t i = 0; i < group->tests.size(); i++) {
506       executeTest(tester, group, group->tests[i], param);
507    }
508
509    log_teststart(groupnum, 0, group_teardown_rs);
510    result = tester->group_teardown(group, param);
511    log_testresult(result);
512    if (result != PASSED && result != SKIPPED && result != UNKNOWN) {
513       getOutput()->log(LOGERR, "Group teardown failed: %s\n", 
514                        tester->getLastErrorMsg().c_str());
515    }
516    if (result != UNKNOWN) {
517       for (unsigned int i = 0; i < group->tests.size(); i++) {
518          group->tests[i]->results[group_teardown_rs] = result;
519       }
520    }
521
522    for (int i = 0; i < group->tests.size(); i++) {
523       reportTestResult(group, group->tests[i]);
524    }
525 }
526
527 void initModuleIfNecessary(RunGroup *group, std::vector<RunGroup *> &groups, 
528                            ParameterDict &params)
529 {
530    if (group->disabled)
531       return;
532
533    bool is_remote = (group->mutator_location == remote);
534    Module::registerGroupInModule(group->modname, group, is_remote);
535
536    bool hasEnabledTest = false;
537    for (unsigned j=0; j<group->tests.size(); j++) {
538       if (!group->tests[j]->disabled)
539          hasEnabledTest = true;
540    }
541    if (!hasEnabledTest)
542       return;
543
544    bool initModule = false;
545    if (group->mod && !group->mod->setupRun())
546       initModule = true;
547    if (group->mutator_location == remote)
548       initModule = true;
549    if (!initModule)
550       return;
551
552    log_teststart(group->index, 0, program_setup_rs);
553    test_results_t result = group->mod->tester->program_setup(params);
554    log_testresult(result);
555
556    group->mod->setSetupRun(true);
557
558    for (unsigned i=0; i<groups.size(); i++) {
559       if (groups[i]->disabled || groups[i]->modname != group->modname)
560          continue;
561       if (groups[i]->mutator_location == remote && groups[i] != group)
562          continue;
563       for (unsigned j=0; j<groups[i]->tests.size(); j++) {
564          if (groups[i]->tests[j]->disabled)
565             continue;
566          groups[i]->tests[j]->results[program_setup_rs] = result;
567          if (result != PASSED)
568             reportTestResult(groups[i], groups[i]->tests[j]);
569       }
570    }
571 }
572
573 void startAllTests(std::vector<RunGroup *> &groups, ParameterDict &param)
574 {
575    // Begin setting up test parameters
576    unsigned i;
577    bool aborted_group = false;
578
579    // Print Test Log Header
580    getOutput()->log(LOGINFO, "Commencing test(s) ...\n");
581 #if !defined(os_windows_test)
582    runScript("date");
583    runScript("uname -a");
584    getOutput()->log(LOGINFO, "TESTDIR=%s\n", getenv("PWD"));
585 #else
586         char* cwd = _getcwd(NULL, 0);
587         if(cwd) {
588            getOutput()->log(LOGINFO, "TESTDIR=%s\n", cwd);
589         } else {
590                 getOutput()->log(LOGERR, "Couldn't get working directory!\n");
591         }
592         free(cwd);
593 #endif
594
595    setupRemoteTests(groups);
596
597    measureStart(param);
598
599    for (i = 0; i < groups.size(); i++) {
600       if (groups[i]->disabled)
601          continue;
602
603       //If we fail then have the log resume us at this group
604       log_resumepoint(i, 0);
605
606       // Print mutatee (run group) header
607       printLogMutateeHeader(groups[i]->mutatee, groups[i]->linktype);
608
609       int before_group = numUnreportedTests(groups[i]);
610       if (!before_group)
611          continue;
612
613       executeGroup(groups[i], groups, param);
614       int after_group = numUnreportedTests(groups[i]);
615    
616       if (after_group) {
617          if (before_group == after_group) {
618             //This should be uncommon.  We made no forward progress
619             // running tests in the group, and we have tests that didn't run.
620             // Mark the group as failed, as we don't want to just spin here.
621             for (unsigned j=0; j<groups[i]->tests.size(); j++) {
622                if (!shouldRunTest(groups[i], groups[i]->tests[j]))
623                   continue;
624                groups[i]->tests[j]->results[group_teardown_rs] = FAILED;
625                reportTestResult(groups[i], groups[i]->tests[j]);
626             }
627          }
628          else {
629             aborted_group = true;
630             break;
631          }
632       }
633    }
634
635    unsigned final_group = i;
636    
637    for (i = 0; i < final_group; i++) {
638      Module *mod = groups[i]->mod;
639      if (!mod || !mod->isInitialized() || groups[i]->disabled)
640        continue;
641      
642      log_teststart(groups[i]->index, 0, program_teardown_rs);
643      test_results_t result = mod->tester->program_teardown(param);
644      log_testresult(result);
645
646      for (unsigned j=0; j < groups[i]->tests.size(); j++)
647      {
648        if (!groups[i]->tests[j]->disabled) {
649           groups[i]->tests[j]->results[program_teardown_rs] = result;
650        }
651        reportTestResult(groups[i], groups[i]->tests[j]);
652      }
653      mod->setInitialized(false);
654    }
655
656    if (!aborted_group) {      
657      if (param["limited_tests"]->getInt()) {
658         int next_resume_group = param["next_resume_group"]->getInt();
659         int next_resume_test = param["next_resume_test"]->getInt();
660         if (next_resume_group != -1 && next_resume_test != -1)
661            log_resumepoint(next_resume_group, next_resume_test);
662         else
663            log_clear();
664      } else {
665        log_clear();
666      }
667    }
668       
669    clearConnection();
670    measureEnd(param);
671
672    return;
673 } // startAllTests()
674
675 void DebugPause() {
676 #if defined(os_windows_test)
677    getOutput()->log(STDERR, "Waiting for attach by debugger\n");
678    DebugBreak();
679 #else
680    getOutput()->log(STDERR, "Waiting for attach by debugger to %d\n", getpid());
681    static volatile int set_me = 0;
682    while (!set_me)
683      P_sleep(1);
684 #endif
685 }
686
687 void updateSearchPaths(const char *filename) {
688 #if !defined(os_windows_test)
689    // First, find the directory we reside in
690
691     bool include_cwd_always = false;
692 #if defined(os_aix_test)
693     // AIX strips a ./ from the start of argv[0], so
694     // we will execute ./test_driver and see test_driver
695
696     include_cwd_always = true;
697 #endif
698
699    char *execpath;
700    char pathname[PATH_MAX];
701    getcwd(pathname, PATH_MAX);
702
703    if (filename[0] == '/') {
704       // If it begins with a slash, it's an absolute path
705       execpath = strdup(filename);
706    } else if (strchr(filename,'/') || include_cwd_always) {
707       // If it contains slashes, it's a relative path
708       char *filename_copy = strdup(filename);
709       
710       execpath = (char *) ::malloc(strlen(pathname) + strlen(filename_copy) + 2);
711       strcpy(execpath,pathname);
712       strcat(execpath,"/");
713       strcat(execpath,filename_copy);
714       ::free(filename_copy);
715    } else {
716       // If it's just a name, it was found in PATH. 
717       // Add current directory to the search path
718       const char *pathenv = getenv("PATH");
719       char *newpath = (char *) malloc (strlen(pathenv)+3);
720       strcat(newpath, pathenv);
721       strcat(newpath, ":.");
722       execpath = searchPath(newpath, filename);
723       if(execpath == NULL) {
724          //  Not found in PATH - we'll assume it should be in CWD
725          return;
726       }
727    }
728
729    *strrchr(execpath, '/') = '\0';
730    // Now update PATH and LD_LIBRARY_PATH/LIBPATH
731
732    char *envCopy;
733
734    char *envPath = getenv("PATH");
735    envCopy = (char *) ::malloc(((envPath && strlen(envPath)) ? strlen(envPath) + 1 : 0) + strlen(execpath) + 6);
736    strcpy(envCopy, "PATH=");
737    if (envPath && strlen(envPath)) {
738       strcat(envCopy, envPath);
739       strcat(envCopy, ":");
740    }
741    strcat(envCopy, execpath);
742    assert(!putenv(envCopy));
743     
744    char *envLibPath;
745 #if defined(os_aix_test)
746    envLibPath = getenv("LIBPATH");
747 #else
748    envLibPath = getenv("LD_LIBRARY_PATH");
749 #endif
750     
751    envCopy = (char *) ::malloc(((envLibPath && strlen(envLibPath)) ? strlen(envLibPath) + 1 : 0) + strlen(execpath) + 17);
752 #if defined(os_aix_test)
753    strcpy(envCopy, "LIBPATH=");
754 #else
755    strcpy(envCopy, "LD_LIBRARY_PATH=");
756 #endif
757    if (envLibPath && strlen(envLibPath)) {
758       strcat(envCopy, envLibPath);
759       strcat(envCopy, ":");
760    }
761    strcat(envCopy, execpath);
762    assert(!putenv(envCopy));
763
764    //fprintf(stderr, "%s[%d]:  set LD_LIBRARY_PATH to %s\n", FILE__, __LINE__, getenv("LD_LIBRARY_PATH"));
765    ::free(execpath);
766 #endif
767 }
768
769 bool testsRemain(std::vector<RunGroup *> &groups)
770 {
771    for (unsigned  i = 0; i < groups.size(); i++) {
772       if (groups[i]->disabled)
773          continue;
774       for (unsigned j=0; j<groups[i]->tests.size(); j++) {
775          if (shouldRunTest(groups[i], groups[i]->tests[j]))
776             return true;
777       }
778    }
779    return false;
780 }
781
782 int main(int argc, char *argv[]) {
783    updateSearchPaths(argv[0]);
784    setOutput(new StdOutputDriver(NULL));
785
786    ParameterDict params;
787    int result = parseArgs(argc, argv, params);
788    if (result)
789       exit(result);
790
791    gargc = argc;
792    gargv = argv;
793
794    if ( params["debugbreak"]->getInt() ) {
795       DebugPause();
796    }
797
798    // Fill in tests vector with lists of test to run
799    std::vector<RunGroup *> groups;
800    getGroupList(groups, params);
801
802    result = setupLogs(params);
803    if (result)
804       exit(result);
805
806    startAllTests(groups, params);
807
808    if ((outlog != NULL) && (outlog != stdout)) {
809       fclose(outlog);
810    }
811    fflush(stdout);
812
813    if (!testsRemain(groups) && !params["limited_tests"]->getInt())
814       return NOTESTS;
815    return 0;
816 }
817
818 int setupLogs(ParameterDict &params)
819 {
820    logfilename = params["logfilename"]->getString();
821    // Set up the logging file..
822    if (strcmp(logfilename, "-") == 0) 
823    {
824       outlog = stdout;
825       errlog = stderr;
826    }
827    else
828    {
829       outlog = fopen(logfilename, "a");
830       if (!outlog) {
831          getOutput()->log(STDERR, "Error opening log file '%s'\n", logfilename);
832          return NOTESTS;
833       }
834       errlog = outlog;
835    } 
836
837    setOutputLog(outlog);
838    setErrorLog(errlog);
839    setOutputLogFilename(logfilename);
840    setErrorLogFilename(logfilename);
841
842    if ((logfilename != NULL) && (strcmp(logfilename, "-") != 0)) {
843       getOutput()->redirectStream(LOGINFO, logfilename);
844       getOutput()->redirectStream(LOGERR, logfilename);
845    }
846
847    if (params["usehumanlog"]->getInt()) {
848       getOutput()->redirectStream(HUMAN, params["humanlogname"]->getString());
849    } else {
850       getOutput()->redirectStream(HUMAN, NULL);
851    }
852
853    char *dbname = params["dboutput"]->getString();
854    if (dbname) {
855       TestOutputDriver *newoutput = loadOutputDriver(const_cast<char *>("DatabaseOutputDriver"), dbname);
856       //make sure it loaded correctly before replacing default output
857       if (newoutput != NULL) {
858          setOutput(newoutput);
859       }      
860    }
861
862    int unique_id = params["unique_id"]->getInt();
863    if (unique_id) {
864       char id_string[32];
865       snprintf(id_string, 32, "%d", unique_id);
866       std::string newname = std::string("resumelog.") +  std::string(id_string);
867       set_resumelog_name(strdup(newname.c_str()));
868    }
869    else {
870       set_resumelog_name(const_cast<char *>("resumelog"));
871    }
872
873    if (params["no_header"]->getInt()) {
874       getOutput()->setNeedsHeader(false);
875    }
876    else {
877       getOutput()->setNeedsHeader(true);
878    }
879    
880    return 0;
881 }