1 #!/bin/ksh
   2 #
   3 # This file and its contents are supplied under the terms of the
   4 # Common Development and Distribution License ("CDDL"), version 1.0.
   5 # You may only use this file in accordance with the terms of version
   6 # 1.0 of the CDDL.
   7 #
   8 # A full copy of the text of the CDDL should have accompanied this
   9 # source.  A copy of the CDDL is also available via the Internet at
  10 # http://www.illumos.org/license/CDDL.
  11 #
  12 
  13 #
  14 # Copyright 2019 Robert Mustacchi
  15 # Copyright 2020 Joyent, Inc.
  16 #
  17 
  18 #
  19 # Basic tests of sleep(1). sleep is a little hard to test, especially
  20 # for longer running cases. Therefore to test it, we basically take
  21 # advantage of our knowledge of how it is implemented. We see that it
  22 # properly is sleeping for the right amount of time by looking at the
  23 # call to nanosleep in libc and make sure that the structures time is
  24 # what we expect.
  25 #
  26 
  27 unalias -a
  28 set -o pipefail
  29 
  30 #
  31 # Set the locale for the start of the test to be C.UTF-8 to make sure
  32 # that we have a good starting point and correct fractional
  33 # interpretation.
  34 #
  35 export LC_ALL=C.UTF-8
  36 
  37 sleep_arg0="$(basename $0)"
  38 sleep_prog=/usr/bin/sleep
  39 sleep_dir="$(dirname $0)"
  40 sleep_dscript=$sleep_dir/sleep.d
  41 sleep_awk=$sleep_dir/sleep.awk
  42 sleep_exit=0
  43 
  44 #
  45 # This is the factor by which we're going to basically say that the slp
  46 # microstate has to complete within. Because the system will usually
  47 # have a bit of additional latency, we will usually be greater than that
  48 # as well. This determines how much we should actually do that by.
  49 #
  50 sleep_factor=1.5
  51 
  52 warn()
  53 {
  54         typeset msg="$*"
  55         [[ -z "$msg" ]] && msg="failed"
  56         echo "TEST FAILED: $sleep_arg0: $msg" >&2
  57 }
  58 
  59 sleep_bound()
  60 {
  61         typeset min=$1
  62         typeset test="sleep $min: bounding"
  63 
  64         ptime -m $sleep_prog $min 2>&1 | nawk -f $sleep_awk min=$min \
  65             factor=$sleep_factor
  66         if [[ $? -ne 42 ]]; then
  67                 warn "$test"
  68                 sleep_exit=1
  69         else
  70                 printf "TEST PASSED: %s\n" "$test"
  71         fi
  72 }
  73 
  74 sleep_one()
  75 {
  76         typeset arg=$1
  77         typeset secs=$2
  78         typeset nsecs=$3
  79         typeset test="sleep $arg: $secs secs $nsecs ns"
  80 
  81         if ! dtrace -qws $sleep_dscript -c "$sleep_prog $arg" $secs $nsecs; then
  82                 warn "$test"
  83                 sleep_exit=1
  84         else
  85                 printf "TEST PASSED: %s\n" "$test"
  86         fi
  87 }
  88 
  89 sleep_err()
  90 {
  91         typeset test="negative test: sleep $*"
  92 
  93         if $sleep_prog $* 2>/dev/null; then
  94                 warn "$test"
  95                 sleep_exit=1
  96         else
  97                 printf "TEST PASSED: %s\n" "$test"
  98         fi
  99 }
 100 
 101 if [[ -n $SLEEP ]]; then
 102         sleep_prog=$SLEEP
 103 fi
 104 
 105 #
 106 # First test basic integer values. Both in base 10 and hex.
 107 #
 108 sleep_one 1 1 0
 109 sleep_one 23 23 0
 110 sleep_one 0xff 0xff 0
 111 sleep_one 123456789 123456789 0
 112 sleep_one 1e8 100000000 0
 113 
 114 #
 115 # Fractional values.
 116 #
 117 sleep_one 2.5 2 500000000
 118 sleep_one 0.9 0 900000000
 119 sleep_one 34.0051 34 5100000
 120 sleep_one 0x654.100 0x654 62500000
 121 
 122 #
 123 # Large values that are basically the same as infinity. The current
 124 # implementation will do a sleep in groups of INT32_MAX at a time. So
 125 # make sure our large values are the same.
 126 #
 127 sleep_one Inf 0x7fffffff 0
 128 sleep_one +Inf 0x7fffffff 0
 129 sleep_one 1e100 0x7fffffff 0
 130 sleep_one 0x123456789abc 0x7fffffff 0
 131 
 132 #
 133 # That all of our suffixes for time increments work and make sense.
 134 #
 135 sleep_one 1s 1 0
 136 sleep_one 1m 60 0
 137 sleep_one 1h 3600 0
 138 sleep_one 1d 86400 0
 139 sleep_one 1w 604800 0
 140 sleep_one 1y 31536000 0
 141 
 142 sleep_one 3.5s 3 500000000
 143 sleep_one 3.6d 311040 0
 144 sleep_one 2.001y 63103536 0
 145 
 146 #
 147 # Now we need to go through and use ptime -m to get the slp time for
 148 # things and make sure it is always greater than what we asked for and
 149 # less than a bound.
 150 #
 151 sleep_bound 0.01
 152 sleep_bound 0.1
 153 sleep_bound 0.25
 154 sleep_bound 0.5
 155 sleep_bound 0.75
 156 
 157 #
 158 # The next set of tests are negative tests that make sure that sleep
 159 # does not correctly execute in these cases.
 160 #
 161 sleep_err \"\"
 162 sleep_err 1 2 3
 163 sleep_err 1@23
 164 sleep_err 0,56
 165 sleep_err "hello"
 166 sleep_err s
 167 sleep_err 1z
 168 sleep_err -- -0.3
 169 
 170 #
 171 # Test a locale that uses a ',' character (de_DE.UTF-8 is one) as the
 172 # decimal point to make sure that sleep is correctly using LC_NUMERIC.
 173 export LC_ALL=de_DE.UTF-8
 174 sleep_err 21.45
 175 sleep_one 2,5 2 500000000
 176 sleep_one 34,0051 34 5100000
 177 sleep_one 3,6d 311040 0
 178 export LC_ALL=C.UTF-8
 179 
 180 exit $sleep_exit