Temporary checkpoint
[dyninst.git] / newtestsuite / src / runTests.C
1 #ifdef os_windows_test
2 //needed for Sleep
3 #include <windows.h>
4 #define sleep(x) Sleep(x * 1000)
5 #endif
6
7 #include <stdlib.h>
8 #include <sstream>
9 #include <string>
10 #include <iostream>
11 #include <stdio.h>
12 #include <vector>
13
14 #include <string.h>
15 #include <errno.h>
16 #include <signal.h>
17
18 #include "runTests-utils.h"
19 #include "error.h"
20 #include "help.h"
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <cstring>
24
25 // To prevent run away never run test_driver more the MAX_ITER times
26 #define MAX_ITER 1000
27
28 // Default name for the resume log file
29 #define DEFAULT_RESUMELOG "bresumelog"
30 // Default name for the crash log file
31 #define DEFAULT_CRASHLOG "crashlog"
32
33 #define MEMCPU_DEFAULT_LOG "memcpu_tmp.log";
34 const char *memcpu_name = NULL;
35 const char *memcpu_orig_name = NULL;
36
37 bool staticTests = false;
38 bool useLog = false;
39 string logfile;
40 string pdscrdir;
41
42 // Run No more than testLimit tests before re-exec'ing test_driver
43 int testLimit = 10;
44
45 vector<char *> child_argv;
46
47 void parseMEMCPUFile()
48 {
49    if (!memcpu_name || !memcpu_orig_name)
50       return;
51
52    signed long mem_total = 0, utime_total = 0, stime_total = 0;
53    FILE *f = fopen(memcpu_name, "r");
54    if (!f)
55       return;
56
57    for (;;)
58    {
59       signed long mem, utime, stime;
60       int res = fscanf(f, "mem=%ld\tutime=%ld\tstime=%ld\n",
61                        &mem, &utime, &stime);
62       if (res != 3)
63          break;
64       mem_total += mem;
65       utime_total += utime;
66       stime_total += stime;
67    }
68    fclose(f);
69    _unlink(memcpu_name);
70
71    if (strcmp(memcpu_orig_name, "-") == 0)
72    {
73       f = stdout;
74    }
75    else {
76       f = fopen(memcpu_orig_name, "w");
77       if (!f)
78          return;
79    }
80    
81    fprintf(f, "mem=%ld\tutime=%ld\tstime=%ld\n",
82            mem_total, utime_total, stime_total);
83    if (f != stdout)
84       fclose(f);
85 }
86
87 // isRegFile:
88 // Returns true if filename is a regular file
89 bool isRegFile(const string& filename)
90 {
91    struct stat results;
92
93    if ( stat(filename.c_str(), &results) !=  0 )
94    {
95       return false;
96    }
97
98    return S_ISREG(results.st_mode);
99 }
100
101 // isDir:
102 // Returns true if filename is a directory
103 bool isDir(const string& filename)
104 {
105    struct stat results;
106
107    if ( stat(filename.c_str(), &results) !=  0 )
108    {
109       return false;
110    }
111
112    return S_ISDIR(results.st_mode);
113 }
114
115 // getInput:
116 // Run filename and store stdout in the output string.
117 void getInput(const char *filename, string& output)
118 {
119    FILE *text;
120    char *result;
121    result = (char *) calloc(1024,sizeof(char));
122    text = popen(filename, "r");
123    // Wait for program to terminate
124    fscanf(text, "%s\n", result);
125    pclose(text);
126
127    output = result;
128
129    free(result);
130 }
131
132 // parseParameters:
133 // Interpret arguments, and collect uninterpretted arguments to be passed
134 // to test_driver.
135 void parseParameters(int argc, char *argv[])
136 {
137 #if defined(STATIC_TEST_DRIVER)
138    staticTests = true;
139 #endif
140
141    for ( int i = 1; i < argc; i++ )
142    {
143       if (strncmp(argv[i], "-limit", 6) == 0) {
144          if (i == (argc-1)) {
145             fprintf(stderr, "Error: -limit requires a parameter\n");
146          }
147          else {
148             unsigned int limit = atoi(argv[i+1]);
149             testLimit = limit;
150             i++;
151          }
152       } else if ((strcmp(argv[i], "-help") == 0) ||
153                  (strcmp(argv[i], "--help") == 0)) {
154          print_help();
155          exit(0);
156       } else if (strcmp(argv[i], "-static") == 0) {
157          staticTests = true;
158       } else if (strcmp(argv[i], "-dynamic") == 0) {
159          staticTests = false;
160       }
161       else if ((strcmp(argv[i], "-memcpu") == 0) ||
162                (strcmp(argv[i], "-cpumem") == 0))
163       {
164          memcpu_name = MEMCPU_DEFAULT_LOG;
165          
166          if ((i+1 < argc) &&
167              (argv[i+1][0] != '-' || argv[i+1][1] == '\0'))
168          {
169             i++;
170             memcpu_orig_name = argv[i];
171          }
172          else
173          {
174             memcpu_orig_name = "-";
175          }
176       }
177       else
178       {
179          // Pass uninterpreted arguments to test_driver
180          child_argv.push_back(argv[i]);
181       }
182    }
183 }
184
185 // ReplaceAllWith:
186 // Replaces all occurances of 'replace' in string 'in' with the text in string
187 // 'with', the result is returned.
188 string ReplaceAllWith(const string &in, const string &replace, const string &with)
189 {
190    string cur;
191    
192    string::size_type match_pos = in.find(replace);
193    string::size_type r_len = replace.length();
194    if ( match_pos == string::npos )
195    {
196       return in;
197    } 
198    else
199    {
200       return in.substr(0,match_pos) + with + 
201          ReplaceAllWith(in.substr(match_pos + r_len, in.length()), replace, with);
202    }
203    
204    
205 }
206
207 int main(int argc, char *argv[])
208 {
209    parseParameters(argc, argv);
210    setupVars(useLog, logfile);
211
212    setLibPath();
213
214    int result = 0;
215    int invocation = 0;
216
217    // Remove a stale resumelog, if it exists
218    if ( getenv("RESUMELOG") && isRegFile(string(getenv("RESUMELOG"))) )
219    {
220       _unlink(getenv("RESUMELOG"));
221    } else if (isRegFile(string(DEFAULT_RESUMELOG))) {
222       _unlink(DEFAULT_RESUMELOG);
223    }
224
225    // Remove a stale crashlog, if it exists
226    if (getenv("CRASHLOG") && isRegFile(string(getenv("CRASHLOG")))) {
227       _unlink(getenv("CRASHLOG"));
228    } else if (isRegFile(string(DEFAULT_CRASHLOG))) {
229       _unlink(DEFAULT_CRASHLOG);
230    }
231
232    // Create a PIDs file, to track mutatee PIDs
233    char *pidFilename = new char[80];
234    initPIDFilename(pidFilename, 80);
235    // result == 2 indicates that there are no more tests to run
236    while ( result != NOTESTS && invocation < MAX_ITER )
237    {
238       result = RunTest(invocation, useLog, staticTests, logfile, testLimit,
239                        child_argv, pidFilename, memcpu_name);
240       invocation++;
241       // I want to kill any remaining mutatees now, to clean up.  I should also
242       // set a timer in RunTest in case something goes weird with test_driver.
243       // (I think we'd be better off moving away from timer.pl)
244       cleanupMutatees(pidFilename);
245       if (-3 == result) {
246          // User interrupted the test run; allow them a couple of seconds to do
247          // it again and kill runTests
248          // TODO Make sure this is portable to Windows
249          fprintf(stderr, "Press ctrl-c again with-in 2 seconds to abort runTests.\n");
250          sleep(2);
251       }
252       if (-4 == (signed char) result) {
253          fprintf(stderr, "Could not execute test_driver\n");
254          break;
255       }
256       if (-5 == (signed char) result) {
257          break;
258       }
259    }
260
261    // Remove the PID file, now that we're done with it
262    if (pidFilename && isRegFile(string(pidFilename))) {
263       _unlink(pidFilename);
264    }
265    _unlink(DEFAULT_RESUMELOG);
266    _unlink("");
267    
268
269    parseMEMCPUFile();
270    return 0;
271 }