1 /*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18 #include <testUtil.h>
19
20 #include <assert.h>
21 #include <errno.h>
22 #include <math.h>
23 #include <stdarg.h>
24 #include <stdbool.h>
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/time.h>
30 #include <sys/wait.h>
31 #include <time.h>
32
33 #include <log/log.h>
34
35 #define ALEN(a) (sizeof(a) / sizeof((a)[0])) // Array length
36
37 #define MAXSTR 200
38
39 static const char *logCatTag;
40 static const unsigned int uSecsPerSec = 1000000;
41 static const unsigned int nSecsPerSec = 1000000000;
42
43 // struct timespec to double
ts2double(const struct timespec * val)44 double ts2double(const struct timespec *val)
45 {
46 double rv;
47
48 rv = val->tv_sec;
49 rv += (double) val->tv_nsec / nSecsPerSec;
50
51 return rv;
52 }
53
54 // struct timeval to double
tv2double(const struct timeval * val)55 double tv2double(const struct timeval *val)
56 {
57 double rv;
58
59 rv = val->tv_sec;
60 rv += (double) val->tv_usec / uSecsPerSec;
61
62 return rv;
63 }
64
65 // double to struct timespec
double2ts(double amt)66 struct timespec double2ts(double amt)
67 {
68 struct timespec rv;
69
70 rv.tv_sec = floor(amt);
71 rv.tv_nsec = (amt - rv.tv_sec) * nSecsPerSec;
72 // TODO: Handle cases where amt is negative
73 while ((unsigned) rv.tv_nsec >= nSecsPerSec) {
74 rv.tv_nsec -= nSecsPerSec;
75 rv.tv_sec++;
76 }
77
78 return rv;
79 }
80
81 // double to struct timeval
double2tv(double amt)82 struct timeval double2tv(double amt)
83 {
84 struct timeval rv;
85
86 rv.tv_sec = floor(amt);
87 rv.tv_usec = (amt - rv.tv_sec) * uSecsPerSec;
88 // TODO: Handle cases where amt is negative
89 while ((unsigned) rv.tv_usec >= uSecsPerSec) {
90 rv.tv_usec -= uSecsPerSec;
91 rv.tv_sec++;
92 }
93
94 return rv;
95 }
96
97 // Delta (difference) between two struct timespec.
98 // It is expected that the time given by the structure pointed to by
99 // second, is later than the time pointed to by first.
tsDelta(const struct timespec * first,const struct timespec * second)100 struct timespec tsDelta(const struct timespec *first,
101 const struct timespec *second)
102 {
103 struct timespec rv;
104
105 assert(first != NULL);
106 assert(second != NULL);
107 assert(first->tv_nsec >= 0 && first->tv_nsec < nSecsPerSec);
108 assert(second->tv_nsec >= 0 && second->tv_nsec < nSecsPerSec);
109 rv.tv_sec = second->tv_sec - first->tv_sec;
110 if (second->tv_nsec >= first->tv_nsec) {
111 rv.tv_nsec = second->tv_nsec - first->tv_nsec;
112 } else {
113 rv.tv_nsec = (second->tv_nsec + nSecsPerSec) - first->tv_nsec;
114 rv.tv_sec--;
115 }
116
117 return rv;
118 }
119
120 // Delta (difference) between two struct timeval.
121 // It is expected that the time given by the structure pointed to by
122 // second, is later than the time pointed to by first.
tvDelta(const struct timeval * first,const struct timeval * second)123 struct timeval tvDelta(const struct timeval *first,
124 const struct timeval *second)
125 {
126 struct timeval rv;
127
128 assert(first != NULL);
129 assert(second != NULL);
130 assert(first->tv_usec >= 0 && first->tv_usec < uSecsPerSec);
131 assert(second->tv_usec >= 0 && second->tv_usec < uSecsPerSec);
132 rv.tv_sec = second->tv_sec - first->tv_sec;
133 if (second->tv_usec >= first->tv_usec) {
134 rv.tv_usec = second->tv_usec - first->tv_usec;
135 } else {
136 rv.tv_usec = (second->tv_usec + uSecsPerSec) - first->tv_usec;
137 rv.tv_sec--;
138 }
139
140 return rv;
141 }
142
testPrint(FILE * stream,const char * fmt,...)143 void testPrint(FILE *stream, const char *fmt, ...)
144 {
145 char line[MAXSTR];
146 va_list args;
147
148 va_start(args, fmt);
149 vsnprintf(line, sizeof(line), fmt, args);
150 if (stream == stderr) {
151 ALOG(LOG_ERROR, logCatTag, "%s", line);
152 } else {
153 ALOG(LOG_INFO, logCatTag, "%s", line);
154 }
155 vfprintf(stream, fmt, args);
156 fputc('\n', stream);
157 }
158
159 // Set tag used while logging to the logcat error interface
testSetLogCatTag(const char * tag)160 void testSetLogCatTag(const char *tag)
161 {
162 logCatTag = tag;
163 }
164
165 // Obtain pointer to current log to logcat error interface tag
testGetLogCatTag(void)166 const char * testGetLogCatTag(void)
167 {
168 return logCatTag;
169 }
170
171 /*
172 * Random
173 *
174 * Returns a pseudo random number in the range [0:2^32-1].
175 *
176 * Precondition: srand48() called to set the seed of
177 * the pseudo random number generator.
178 */
testRand(void)179 uint32_t testRand(void)
180 {
181 uint32_t val;
182
183 // Use lrand48() to obtain 31 bits worth
184 // of randomness.
185 val = lrand48();
186
187 // Make an additional lrand48() call and merge
188 // the randomness into the most significant bits.
189 val ^= lrand48() << 1;
190
191 return val;
192 }
193
194 /*
195 * Random Modulus
196 *
197 * Pseudo randomly returns unsigned integer in the range [0, mod).
198 *
199 * Precondition: srand48() called to set the seed of
200 * the pseudo random number generator.
201 */
testRandMod(uint32_t mod)202 uint32_t testRandMod(uint32_t mod)
203 {
204 // Obtain the random value
205 // Use lrand48() when it would produce a sufficient
206 // number of random bits, otherwise use testRand().
207 const uint32_t lrand48maxVal = ((uint32_t) 1 << 31) - 1;
208 uint32_t val = (mod <= lrand48maxVal) ? (uint32_t) lrand48() : testRand();
209
210 /*
211 * The contents of individual bytes tend to be less than random
212 * across different seeds. For example, srand48(x) and
213 * srand48(x + n * 4) cause lrand48() to return the same sequence of
214 * least significant bits. For small mod values this can produce
215 * noticably non-random sequnces. For mod values of less than 2
216 * bytes, will use the randomness from all the bytes.
217 */
218 if (mod <= 0x10000) {
219 val = (val & 0xffff) ^ (val >> 16);
220
221 // If mod less than a byte, can further combine down to
222 // a single byte.
223 if (mod <= 0x100) {
224 val = (val & 0xff) ^ (val >> 8);
225 }
226 }
227
228 return val % mod;
229 }
230
231 /*
232 * Random Boolean
233 *
234 * Pseudo randomly returns 0 (false) or 1 (true).
235 *
236 * Precondition: srand48() called to set the seed of
237 * the pseudo random number generator.
238 */
testRandBool(void)239 int testRandBool(void)
240 {
241 return (testRandMod(2));
242 }
243
244 /*
245 * Random Fraction
246 *
247 * Pseudo randomly return a value in the range [0.0, 1.0).
248 *
249 * Precondition: srand48() called to set the seed of
250 * the pseudo random number generator.
251 */
testRandFract(void)252 double testRandFract(void)
253 {
254 return drand48();
255 }
256
257 // Delays for the number of seconds specified by amt or a greater amount.
258 // The amt variable is of type float and thus non-integer amounts
259 // of time can be specified. This function automatically handles cases
260 // where nanosleep(2) returns early due to reception of a signal.
testDelay(float amt)261 void testDelay(float amt)
262 {
263 struct timespec start, current, delta;
264 struct timespec remaining;
265
266 // Get the time at which we started
267 clock_gettime(CLOCK_MONOTONIC, &start);
268
269 do {
270 // Get current time
271 clock_gettime(CLOCK_MONOTONIC, ¤t);
272
273 // How much time is left
274 delta = tsDelta(&start, ¤t);
275 if (ts2double(&delta) > amt) { break; }
276
277 // Request to sleep for the remaining time
278 remaining = double2ts(amt - ts2double(&delta));
279 (void) nanosleep(&remaining, NULL);
280 } while (true);
281 }
282
283 // Delay spins for the number of seconds specified by amt or a greater
284 // amount. The amt variable is of type float and thus non-integer amounts
285 // of time can be specified. Differs from testDelay() in that
286 // testDelaySpin() performs a spin loop, instead of using nanosleep().
testDelaySpin(float amt)287 void testDelaySpin(float amt)
288 {
289 struct timespec start, current, delta;
290
291 // Get the time at which we started
292 clock_gettime(CLOCK_MONOTONIC, &start);
293
294 do {
295 // Get current time
296 clock_gettime(CLOCK_MONOTONIC, ¤t);
297
298 // How much time is left
299 delta = tsDelta(&start, ¤t);
300 if (ts2double(&delta) > amt) { break; }
301 } while (true);
302 }
303
304 /*
305 * Hex Dump
306 *
307 * Displays in hex the contents of the memory starting at the location
308 * pointed to by buf, for the number of bytes given by size.
309 * Each line of output is indented by a number of spaces that
310 * can be set by calling xDumpSetIndent(). It is also possible
311 * to offset the displayed address by an amount set by calling
312 * xDumpSetOffset.
313 */
314 static uint8_t xDumpIndent;
315 static uint64_t xDumpOffset;
316 void
testXDump(const void * buf,size_t size)317 testXDump(const void *buf, size_t size)
318 {
319 const unsigned int bytesPerLine = 16;
320 int rv;
321 char line[MAXSTR];
322 const unsigned char *ptr = buf, *start = buf;
323 size_t num = size;
324 char *linep = line;
325
326 while (num) {
327 if (((ptr - start) % bytesPerLine) == 0) {
328 if (linep != line) {
329 testPrintE("%s", line);
330 }
331 linep = line;
332 rv = snprintf(linep, ALEN(line) - (linep - line),
333 "%*s%06llx:", xDumpIndent, "",
334 (long long) (ptr - start) + xDumpOffset);
335 linep += rv;
336 }
337
338 // Check that there is at least room for 4
339 // more characters. The 4 characters being
340 // a space, 2 hex digits and the terminating
341 // '\0'.
342 assert((ALEN(line) - 4) >= (linep - line));
343 rv = snprintf(linep, ALEN(line) - (linep - line),
344 " %02x", *ptr++);
345 linep += rv;
346 num--;
347 }
348 if (linep != line) {
349 testPrintE("%s", line);
350 }
351 }
352
353 // Set an indent of spaces for each line of hex dump output
354 void
testXDumpSetIndent(uint8_t indent)355 testXDumpSetIndent(uint8_t indent)
356 {
357 xDumpIndent = indent;
358 }
359
360 // Obtain the current hex dump indent amount
361 uint8_t
testXDumpGetIndent(void)362 testXDumpGetIndent(void)
363 {
364 return xDumpIndent;
365 }
366
367 // Set the hex dump address offset amount
368 void
testXDumpSetOffset(uint64_t offset)369 testXDumpSetOffset(uint64_t offset)
370 {
371 xDumpOffset = offset;
372 }
373
374 // Get the current hex dump address offset amount
375 uint64_t
testXDumpGetOffset(void)376 testXDumpGetOffset(void)
377 {
378 return xDumpOffset;
379 }
380
381 /*
382 * Execute Command
383 *
384 * Executes the command pointed to by cmd. Output from the
385 * executed command is captured and sent to LogCat Info. Once
386 * the command has finished execution, it's exit status is captured
387 * and checked for an exit status of zero. Any other exit status
388 * causes diagnostic information to be printed and an immediate
389 * testcase failure.
390 */
testExecCmd(const char * cmd)391 void testExecCmd(const char *cmd)
392 {
393 FILE *fp;
394 int status;
395 char str[MAXSTR];
396
397 // Display command to be executed
398 testPrintI("cmd: %s", cmd);
399
400 // Execute the command
401 fflush(stdout);
402 if ((fp = popen(cmd, "r")) == NULL) {
403 testPrintE("execCmd popen failed, errno: %i", errno);
404 exit(100);
405 }
406
407 // Obtain and display each line of output from the executed command
408 while (fgets(str, sizeof(str), fp) != NULL) {
409 if ((strlen(str) > 1) && (str[strlen(str) - 1] == '\n')) {
410 str[strlen(str) - 1] = '\0';
411 }
412 testPrintI(" out: %s", str);
413 }
414
415 // Obtain and check return status of executed command.
416 // Fail on non-zero exit status
417 status = pclose(fp);
418 if (!(WIFEXITED(status) && (WEXITSTATUS(status) == 0))) {
419 testPrintE("Unexpected command failure");
420 testPrintE(" status: %#x", status);
421 if (WIFEXITED(status)) {
422 testPrintE("WEXITSTATUS: %i", WEXITSTATUS(status));
423 }
424 if (WIFSIGNALED(status)) {
425 testPrintE("WTERMSIG: %i", WTERMSIG(status));
426 }
427 exit(101);
428 }
429 }
430