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