]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/netbsd-tests/bin/ps/t_ps.sh
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / netbsd-tests / bin / ps / t_ps.sh
1 # $NetBSD: t_ps.sh,v 1.2 2014/01/16 04:16:32 mlelstv Exp $
2 #
3 # Copyright (c) 2007 The NetBSD Foundation, Inc.
4 # All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 # 1. Redistributions of source code must retain the above copyright
10 #    notice, this list of conditions and the following disclaimer.
11 # 2. Redistributions in binary form must reproduce the above copyright
12 #    notice, this list of conditions and the following disclaimer in the
13 #    documentation and/or other materials provided with the distribution.
14 #
15 # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
16 # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 # PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
19 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 # POSSIBILITY OF SUCH DAMAGE.
26 #
27
28 # the implementation of "ps" to test
29 : ${TEST_PS:="ps"}
30 # tab and newline characters
31 tab="$(printf '\t')"
32 # nl="$(printf '\n')" doesn't work
33 nl='
34 '
35
36 #
37 # Parse the "keywords" file into a load of shell variables
38 #
39 setup_keywords()
40 {
41         # Set variables representing the header text
42         # for all normal keywords (except aliases), and
43         # for regular expressions to match the text in left- or
44         # right-justified columns.
45         # For example, head_text_p_cpu="%CPU" head_regexp_p_cpu=" *%CPU".
46         while read keyword heading flag
47         do
48                 case "$keyword" in
49                 ''|\#*) continue
50                         ;;
51                 esac
52                 [ x"$flag" = x"ALIAS" ] && continue
53                 kvar="${keyword}"
54                 case "${keyword}" in
55                 %*)     kvar="p_${keyword#%}"
56                         ;;
57                 esac
58                 eval head_text_${kvar}=\'"${heading}"\'
59                 case "${flag}" in
60                 '')     # right justified
61                         eval head_regexp_${kvar}=\'" *${heading}"\'
62                         ;;
63                 LJUST)  # left justified
64                         eval head_regexp_${kvar}=\'"${heading} *"\'
65                         ;;
66                 *)      atf_fail "unknown flag in keywords"
67                         ;;
68                 esac
69         done <"$(atf_get_srcdir)/keywords"
70
71         # Now do the aliases.
72         while read keyword heading flag
73         do
74                 case "$keyword" in
75                 ''|\#*) continue
76                         ;;
77                 esac
78                 [ x"$flag" != x"ALIAS" ] && continue
79                 kvar="${keyword}"
80                 avar="${heading}"
81                 case "${keyword}" in
82                 %*)     kvar="p_${keyword#%}"
83                         ;;
84                 esac
85                 case "${heading}" in
86                 %*)     avar="p_${heading#%}"
87                         ;;
88                 esac
89                 eval head_text_${kvar}=\"\$head_text_${avar}\"
90                 eval head_regexp_${kvar}=\"\$head_regexp_${avar}\"
91         done <"$(atf_get_srcdir)/keywords"
92
93         # default sets of keywords
94         default_keywords='pid tty stat time command'
95         j_keywords='user pid ppid pgid sess jobc state tt time command'
96         l_keywords='uid pid ppid cpu pri nice vsz rss wchan state tt time command'
97         s_keywords='uid pid ppid cpu lid nlwp pri nice vsz rss wchan lstate tt ltime command'
98         u_keywords='user pid %cpu %mem vsz rss tt state start time command'
99         v_keywords='pid state time sl re pagein vsz rss lim tsiz %cpu %mem command'
100 }
101
102 # Convert a list of keywords like "pid comm" to a regexp
103 # like " *PID COMMAND *"
104 heading_keywords_to_regexp()
105 {
106         local keywords="$1"
107         local regexp
108         regexp="$(echo "$keywords" | \
109                 sed -E -e 's/\%/p_/g' -e 's/(^| )/\1\$head_regexp_/g')"
110         eval regexp=\""${regexp}"\"
111         regexp="^${regexp}\$"
112         echo "$regexp"
113 }
114
115 #
116 # Check that a string matches a regexp; use the specified id
117 # in error or success messages.
118 #
119 check_regexp() {
120         local id="$1" string="$2" regexp="$3"
121         if ! expr "$string" : "$regexp" >/dev/null
122         then
123                 atf_fail "${id}: expected [${regexp}], got [${string}]"
124                 false
125         fi
126 }
127
128 #
129 # Run "ps $args -p $$"; check that only one line is printed,
130 # without a preceding header line.
131 #
132 check_no_heading_line()
133 {
134         local args="$1"
135         local output="$(eval "${TEST_PS} $args -p $$")"
136         case "$output" in
137         *"$nl"*)
138                 local firstline="${output%%${nl}*}"
139                 atf_fail "check_no_heading_line [$args] got [$firstline]"
140                 ;;
141         *)
142                 ;;
143         esac
144 }
145
146 #
147 # Run "ps $args"; check that the heading matches the expected regexp.
148 #
149 check_heading_regexp()
150 {
151         args="$1"
152         regexp="$2"
153         actual="$( eval "${TEST_PS} $args" | sed -e 1q )"
154         check_regexp "heading [$args]" "${actual}" "${regexp}"
155 }
156
157 #
158 # Run "ps $args"; check that the heading matches a regexp constructed
159 # from the specified keywords.
160 #
161 check_heading_keywords()
162 {
163         args="$1"
164         keywords="$2"
165         check_heading_regexp "$args" "$(heading_keywords_to_regexp "$keywords")"
166 }
167
168 #
169 # Try several variations on "ps $flag", "ps -$flag", etc.,
170 # and check that the heading always has the correct keywords.
171 #
172 check_heading_variations()
173 {
174         flag="$1"
175         keywords="$2"
176         for args in "$flag" "-$flag" "-$flag$flag -$flag"; do
177                 check_heading_keywords "$args" "$keywords"
178         done
179 }
180
181 atf_test_case default_columns
182 default_columns_head()
183 {
184         atf_set "descr" "Checks that the default set of columns is correct" \
185                         "and also check that the columns printed by the -j," \
186                         "-l, -s, -u and -v flags alone are correct"
187 }
188 default_columns_body()
189 {
190         setup_keywords
191         check_heading_keywords '' "$default_keywords"
192         check_heading_variations 'j' "$j_keywords"
193         check_heading_variations 'l' "$l_keywords"
194         check_heading_variations 's' "$s_keywords"
195         check_heading_variations 'u' "$u_keywords"
196         check_heading_variations 'v' "$v_keywords"
197 }
198
199 atf_test_case minus_O
200 minus_O_head()
201 {
202         atf_set "descr" "Checks that 'ps -O foo' inserts columns just after" \
203                         "the pid column"
204 }
205 minus_O_body()
206 {
207         setup_keywords
208         check_heading_keywords '-O %cpu,%mem' \
209                 "$(echo "${default_keywords}" | sed -e 's/pid/pid %cpu %mem/')"
210         check_heading_keywords '-O %cpu -O %mem' \
211                 "$(echo "${default_keywords}" | sed -e 's/pid/pid %cpu %mem/')"
212         check_heading_keywords '-O%cpu -O%mem' \
213                 "$(echo "${default_keywords}" | sed -e 's/pid/pid %cpu %mem/')"
214 }
215
216 atf_test_case minus_o
217 minus_o_head()
218 {
219         atf_set "descr" "Checks simple cases of 'ps -o foo' to control which" \
220                         "columns are printed; this does not test header" \
221                         "overriding via 'ps -o foo=BAR'"
222 }
223 minus_o_body()
224 {
225         setup_keywords
226         # Keywords for "-o name" override the default display
227         check_heading_keywords '-o pid,%cpu,%mem' \
228                 "pid %cpu %mem"
229         check_heading_keywords '-o pid -o %cpu,%mem' \
230                 "pid %cpu %mem"
231         check_heading_keywords '-opid -o %cpu,%mem' \
232                 "pid %cpu %mem"
233         # Space works like comma
234         check_heading_keywords '-opid -o "%cpu %mem"' \
235                 "pid %cpu %mem"
236         # Check missing pid
237         check_heading_keywords '-o comm' \
238                 "comm"
239         # Check pid present but not first
240         check_heading_keywords '-o comm,pid' \
241                 "comm pid"
242 }
243
244 atf_test_case override_heading_simple
245 override_heading_simple_head()
246 {
247         atf_set "descr" "Tests simple uses of header overriding via" \
248                         "'ps -o foo=BAR'.  This does not test columns " \
249                         "with null headings, or headings with embedded" \
250                         "space, ',' or '='."
251 }
252 override_heading_simple_body()
253 {
254         setup_keywords
255         check_heading_regexp '-o pid=PPP -o comm' \
256                 '^ *PPP '"${head_text_comm}"'$' # no trailing space
257         check_heading_regexp '-o pid=PPP -o comm=CCC' \
258                 '^ *PPP CCC$'
259         check_heading_regexp '-o pid,comm=CCC' \
260                 '^'"${head_regexp_pid}"' CCC$'
261         check_heading_regexp '-o pid -o comm=CCC' \
262                 '^'"${head_regexp_pid}"' CCC$'
263         # Check missing pid
264         check_heading_regexp '-o comm=CCC' \
265                 '^CCC$'
266         # Check pid present but not first
267         check_heading_regexp '-o comm=CCC -o pid=PPP' \
268                 '^CCC  *PPP$'
269         check_heading_regexp '-o comm,pid=PPP' \
270                 '^'"${head_regexp_comm}"'  *PPP$'
271 }
272
273 atf_test_case override_heading_embedded_specials
274 override_heading_embedded_specials_head()
275 {
276         atf_set "descr" "Tests header overriding with embedded space," \
277                         "',' or '='.  Everything after the first '='" \
278                         "is part of the heading."
279 }
280 override_heading_embedded_specials_body()
281 {
282         setup_keywords
283         # Check embedded "," or "=" in override header.
284         check_heading_regexp '-o comm,pid==' \
285                 '^'"${head_regexp_comm}"'  *=$'
286         check_heading_regexp '-o comm,pid=,' \
287                 '^'"${head_regexp_comm}"'  *,$'
288         check_heading_regexp '-o pid=PPP,comm' \
289                 '^ *PPP,comm$' # not like '-o pid=PPP -o comm'
290         check_heading_regexp '-o pid=PPP,comm=CCC' \
291                 '^ *PPP,comm=CCC$' # not like '-o pid=PPP -o comm=CCC'
292         check_heading_regexp '-o comm,pid=PPP,QQQ' \
293                 '^'"${head_regexp_comm}"'  *PPP,QQQ$'
294         check_heading_regexp '-o comm,pid=ppid,tty=state' \
295                 '^'"${head_regexp_comm}"'  *ppid,tty=state$'
296         # Check embedded space or tab in override header.
297         check_heading_regexp '-o comm,pid="PPP QQQ"' \
298                 '^'"${head_regexp_comm}"'  *PPP QQQ$'
299         check_heading_regexp '-o comm,pid="PPP${tab}QQQ"' \
300                 '^'"${head_regexp_comm}"'  *PPP'"${tab}"'QQQ$'
301 }
302
303 atf_test_case override_heading_some_null
304 override_heading_some_null_head()
305 {
306         atf_set "descr" "Tests simple uses of null column headings" \
307                         "overriding via 'ps -o foo=BAR -o baz='.  This" \
308                         "does not test the case where all columns have" \
309                         "null headings."
310 }
311 override_heading_some_null_body()
312 {
313         setup_keywords
314         check_heading_regexp '-o pid=PPP -o comm=' \
315                 '^ *PPP *$'
316         check_heading_regexp '-o pid= -o comm=CCC' \
317                 '^ * CCC$'
318         check_heading_regexp '-o pid -o comm=' \
319                 '^'"${head_regexp_pid}"' *$'
320         # Check missing pid
321         check_heading_regexp '-o ppid= -o comm=CCC' \
322                 '^ * CCC$'
323         check_heading_regexp '-o ppid=PPP -o comm=' \
324                 '^ *PPP *$'
325         # Check pid present but not first
326         check_heading_regexp '-o comm= -o pid=PPP' \
327                 '^ * PPP$'
328         check_heading_regexp '-o comm,pid=' \
329                 '^'"${head_regexp_comm}"' *$'
330         # A field with a null custom heading retains a minimum width
331         # derived from the default heading.  This does not apply
332         # to a field with a very short (non-null) custom heading.
333         #
334         # We choose "holdcnt" as a column whose width is likely to be
335         # determined entirely by the header width, because the values
336         # are likely to be very small.
337         check_heading_regexp '-o holdcnt -o holdcnt -o holdcnt' \
338                 '^HOLDCNT HOLDCNT HOLDCNT$'
339         check_heading_regexp '-o holdcnt -o holdcnt= -o holdcnt' \
340                 '^HOLDCNT         HOLDCNT$'
341         check_heading_regexp '-o holdcnt -o holdcnt=HH -o holdcnt' \
342                 '^HOLDCNT HH HOLDCNT$'
343 }
344
345 atf_test_case override_heading_all_null
346 override_heading_all_null_head()
347 {
348         atf_set "descr" "Tests the use of 'ps -o foo= -o bar=' (with a" \
349                         "null heading for every column).  The heading" \
350                         "should not be printed at all in this case."
351 }
352 override_heading_all_null_body()
353 {
354         setup_keywords
355         # A heading with a space is not a null heading,
356         # so should not be suppressed
357         check_heading_regexp '-o comm=" "' \
358                 '^ *$'
359         # Null headings should be suppressed
360         check_no_heading_line '-o pid= -o comm='
361         check_no_heading_line '-o pid= -o comm='
362         # Check missing pid
363         check_no_heading_line '-o ppid='
364         check_no_heading_line '-o comm='
365         check_no_heading_line '-o command='
366         check_no_heading_line '-o ppid= -o comm='
367         check_no_heading_line '-o comm= -o ppid='
368         # Check pid present but not first
369         check_no_heading_line '-o comm= -o pid='
370         check_no_heading_line '-o ppid= -o pid= -o command='
371 }
372
373 atf_test_case duplicate_column
374 duplicate_column_head()
375 {
376         atf_set "descr" "Tests the use of -o options to display the" \
377                         "same column more than once"
378 }
379 duplicate_column_body()
380 {
381         setup_keywords
382         # two custom headers
383         check_heading_regexp '-o pid=PPP -o pid=QQQ' \
384                 '^ *PPP  *QQQ$'
385         # one custom header, before and after default header
386         check_heading_regexp '-o pid=PPP -o pid' \
387                 '^ *PPP '"${head_regexp_pid}"'$'
388         check_heading_regexp '-o pid -o pid=QQQ' \
389                 '^'"${head_regexp_pid}"'  *QQQ$'
390         # custom headers both before and after default header
391         check_heading_regexp '-o pid=PPP -o pid -o pid=QQQ' \
392                 '^ *PPP '"${head_regexp_pid}"'  *QQQ$'
393 }
394
395 atf_init_test_cases() {
396         atf_add_test_case default_columns
397         atf_add_test_case minus_O
398         atf_add_test_case minus_o
399         atf_add_test_case override_heading_simple
400         atf_add_test_case override_heading_embedded_specials
401         atf_add_test_case override_heading_some_null
402         atf_add_test_case override_heading_all_null
403         atf_add_test_case duplicate_column
404 }