Home | History | Annotate | Download | only in testUtil
      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
     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
     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
     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
     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.
    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.
    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 
    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
    160 void testSetLogCatTag(const char *tag)
    161 {
    162     logCatTag = tag;
    163 }
    164 
    165 // Obtain pointer to current log to logcat error interface tag
    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  */
    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  */
    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  */
    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  */
    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.
    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, &current);
    272 
    273         // How much time is left
    274         delta = tsDelta(&start, &current);
    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().
    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, &current);
    297 
    298         // How much time is left
    299         delta = tsDelta(&start, &current);
    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
    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
    355 testXDumpSetIndent(uint8_t indent)
    356 {
    357     xDumpIndent = indent;
    358 }
    359 
    360 // Obtain the current hex dump indent amount
    361 uint8_t
    362 testXDumpGetIndent(void)
    363 {
    364     return xDumpIndent;
    365 }
    366 
    367 // Set the hex dump address offset amount
    368 void
    369 testXDumpSetOffset(uint64_t offset)
    370 {
    371     xDumpOffset = offset;
    372 }
    373 
    374 // Get the current hex dump address offset amount
    375 uint64_t
    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  */
    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