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
27unalias -a
28set -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#
35export LC_ALL=C.UTF-8
36
37sleep_arg0="$(basename $0)"
38sleep_prog=/usr/bin/sleep
39sleep_dir="$(dirname $0)"
40sleep_dscript=$sleep_dir/sleep.d
41sleep_awk=$sleep_dir/sleep.awk
42sleep_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#
50sleep_factor=1.5
51
52warn()
53{
54	typeset msg="$*"
55	[[ -z "$msg" ]] && msg="failed"
56	echo "TEST FAILED: $sleep_arg0: $msg" >&2
57}
58
59sleep_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
74sleep_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
89sleep_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
101if [[ -n $SLEEP ]]; then
102	sleep_prog=$SLEEP
103fi
104
105#
106# First test basic integer values. Both in base 10 and hex.
107#
108sleep_one 1 1 0
109sleep_one 23 23 0
110sleep_one 0xff 0xff 0
111sleep_one 123456789 123456789 0
112sleep_one 1e8 100000000 0
113
114#
115# Fractional values.
116#
117sleep_one 2.5 2 500000000
118sleep_one 0.9 0 900000000
119sleep_one 34.0051 34 5100000
120sleep_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#
127sleep_one Inf 0x7fffffff 0
128sleep_one +Inf 0x7fffffff 0
129sleep_one 1e100 0x7fffffff 0
130sleep_one 0x123456789abc 0x7fffffff 0
131
132#
133# That all of our suffixes for time increments work and make sense.
134#
135sleep_one 1s 1 0
136sleep_one 1m 60 0
137sleep_one 1h 3600 0
138sleep_one 1d 86400 0
139sleep_one 1w 604800 0
140sleep_one 1y 31536000 0
141
142sleep_one 3.5s 3 500000000
143sleep_one 3.6d 311040 0
144sleep_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#
151sleep_bound 0.01
152sleep_bound 0.1
153sleep_bound 0.25
154sleep_bound 0.5
155sleep_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#
161sleep_err \"\"
162sleep_err 1 2 3
163sleep_err 1@23
164sleep_err 0,56
165sleep_err "hello"
166sleep_err s
167sleep_err 1z
168sleep_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.
173export LC_ALL=de_DE.UTF-8
174sleep_err 21.45
175sleep_one 2,5 2 500000000
176sleep_one 34,0051 34 5100000
177sleep_one 3,6d 311040 0
178export LC_ALL=C.UTF-8
179
180exit $sleep_exit
181