1272343Sngie# $NetBSD: t_ps.sh,v 1.2 2014/01/16 04:16:32 mlelstv Exp $ 2272343Sngie# 3272343Sngie# Copyright (c) 2007 The NetBSD Foundation, Inc. 4272343Sngie# All rights reserved. 5272343Sngie# 6272343Sngie# Redistribution and use in source and binary forms, with or without 7272343Sngie# modification, are permitted provided that the following conditions 8272343Sngie# are met: 9272343Sngie# 1. Redistributions of source code must retain the above copyright 10272343Sngie# notice, this list of conditions and the following disclaimer. 11272343Sngie# 2. Redistributions in binary form must reproduce the above copyright 12272343Sngie# notice, this list of conditions and the following disclaimer in the 13272343Sngie# documentation and/or other materials provided with the distribution. 14272343Sngie# 15272343Sngie# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 16272343Sngie# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17272343Sngie# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18272343Sngie# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19272343Sngie# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20272343Sngie# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21272343Sngie# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22272343Sngie# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23272343Sngie# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24272343Sngie# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25272343Sngie# POSSIBILITY OF SUCH DAMAGE. 26272343Sngie# 27272343Sngie 28272343Sngie# the implementation of "ps" to test 29272343Sngie: ${TEST_PS:="ps"} 30272343Sngie# tab and newline characters 31272343Sngietab="$(printf '\t')" 32272343Sngie# nl="$(printf '\n')" doesn't work 33272343Sngienl=' 34272343Sngie' 35272343Sngie 36272343Sngie# 37272343Sngie# Parse the "keywords" file into a load of shell variables 38272343Sngie# 39272343Sngiesetup_keywords() 40272343Sngie{ 41272343Sngie # Set variables representing the header text 42272343Sngie # for all normal keywords (except aliases), and 43272343Sngie # for regular expressions to match the text in left- or 44272343Sngie # right-justified columns. 45272343Sngie # For example, head_text_p_cpu="%CPU" head_regexp_p_cpu=" *%CPU". 46272343Sngie while read keyword heading flag 47272343Sngie do 48272343Sngie case "$keyword" in 49272343Sngie ''|\#*) continue 50272343Sngie ;; 51272343Sngie esac 52272343Sngie [ x"$flag" = x"ALIAS" ] && continue 53272343Sngie kvar="${keyword}" 54272343Sngie case "${keyword}" in 55272343Sngie %*) kvar="p_${keyword#%}" 56272343Sngie ;; 57272343Sngie esac 58272343Sngie eval head_text_${kvar}=\'"${heading}"\' 59272343Sngie case "${flag}" in 60272343Sngie '') # right justified 61272343Sngie eval head_regexp_${kvar}=\'" *${heading}"\' 62272343Sngie ;; 63272343Sngie LJUST) # left justified 64272343Sngie eval head_regexp_${kvar}=\'"${heading} *"\' 65272343Sngie ;; 66272343Sngie *) atf_fail "unknown flag in keywords" 67272343Sngie ;; 68272343Sngie esac 69272343Sngie done <"$(atf_get_srcdir)/keywords" 70272343Sngie 71272343Sngie # Now do the aliases. 72272343Sngie while read keyword heading flag 73272343Sngie do 74272343Sngie case "$keyword" in 75272343Sngie ''|\#*) continue 76272343Sngie ;; 77272343Sngie esac 78272343Sngie [ x"$flag" != x"ALIAS" ] && continue 79272343Sngie kvar="${keyword}" 80272343Sngie avar="${heading}" 81272343Sngie case "${keyword}" in 82272343Sngie %*) kvar="p_${keyword#%}" 83272343Sngie ;; 84272343Sngie esac 85272343Sngie case "${heading}" in 86272343Sngie %*) avar="p_${heading#%}" 87272343Sngie ;; 88272343Sngie esac 89272343Sngie eval head_text_${kvar}=\"\$head_text_${avar}\" 90272343Sngie eval head_regexp_${kvar}=\"\$head_regexp_${avar}\" 91272343Sngie done <"$(atf_get_srcdir)/keywords" 92272343Sngie 93272343Sngie # default sets of keywords 94272343Sngie default_keywords='pid tty stat time command' 95272343Sngie j_keywords='user pid ppid pgid sess jobc state tt time command' 96272343Sngie l_keywords='uid pid ppid cpu pri nice vsz rss wchan state tt time command' 97272343Sngie s_keywords='uid pid ppid cpu lid nlwp pri nice vsz rss wchan lstate tt ltime command' 98272343Sngie u_keywords='user pid %cpu %mem vsz rss tt state start time command' 99272343Sngie v_keywords='pid state time sl re pagein vsz rss lim tsiz %cpu %mem command' 100272343Sngie} 101272343Sngie 102272343Sngie# Convert a list of keywords like "pid comm" to a regexp 103272343Sngie# like " *PID COMMAND *" 104272343Sngieheading_keywords_to_regexp() 105272343Sngie{ 106272343Sngie local keywords="$1" 107272343Sngie local regexp 108272343Sngie regexp="$(echo "$keywords" | \ 109272343Sngie sed -E -e 's/\%/p_/g' -e 's/(^| )/\1\$head_regexp_/g')" 110272343Sngie eval regexp=\""${regexp}"\" 111272343Sngie regexp="^${regexp}\$" 112272343Sngie echo "$regexp" 113272343Sngie} 114272343Sngie 115272343Sngie# 116272343Sngie# Check that a string matches a regexp; use the specified id 117272343Sngie# in error or success messages. 118272343Sngie# 119272343Sngiecheck_regexp() { 120272343Sngie local id="$1" string="$2" regexp="$3" 121272343Sngie if ! expr "$string" : "$regexp" >/dev/null 122272343Sngie then 123272343Sngie atf_fail "${id}: expected [${regexp}], got [${string}]" 124272343Sngie false 125272343Sngie fi 126272343Sngie} 127272343Sngie 128272343Sngie# 129272343Sngie# Run "ps $args -p $$"; check that only one line is printed, 130272343Sngie# without a preceding header line. 131272343Sngie# 132272343Sngiecheck_no_heading_line() 133272343Sngie{ 134272343Sngie local args="$1" 135272343Sngie local output="$(eval "${TEST_PS} $args -p $$")" 136272343Sngie case "$output" in 137272343Sngie *"$nl"*) 138272343Sngie local firstline="${output%%${nl}*}" 139272343Sngie atf_fail "check_no_heading_line [$args] got [$firstline]" 140272343Sngie ;; 141272343Sngie *) 142272343Sngie ;; 143272343Sngie esac 144272343Sngie} 145272343Sngie 146272343Sngie# 147272343Sngie# Run "ps $args"; check that the heading matches the expected regexp. 148272343Sngie# 149272343Sngiecheck_heading_regexp() 150272343Sngie{ 151272343Sngie args="$1" 152272343Sngie regexp="$2" 153272343Sngie actual="$( eval "${TEST_PS} $args" | sed -e 1q )" 154272343Sngie check_regexp "heading [$args]" "${actual}" "${regexp}" 155272343Sngie} 156272343Sngie 157272343Sngie# 158272343Sngie# Run "ps $args"; check that the heading matches a regexp constructed 159272343Sngie# from the specified keywords. 160272343Sngie# 161272343Sngiecheck_heading_keywords() 162272343Sngie{ 163272343Sngie args="$1" 164272343Sngie keywords="$2" 165272343Sngie check_heading_regexp "$args" "$(heading_keywords_to_regexp "$keywords")" 166272343Sngie} 167272343Sngie 168272343Sngie# 169272343Sngie# Try several variations on "ps $flag", "ps -$flag", etc., 170272343Sngie# and check that the heading always has the correct keywords. 171272343Sngie# 172272343Sngiecheck_heading_variations() 173272343Sngie{ 174272343Sngie flag="$1" 175272343Sngie keywords="$2" 176272343Sngie for args in "$flag" "-$flag" "-$flag$flag -$flag"; do 177272343Sngie check_heading_keywords "$args" "$keywords" 178272343Sngie done 179272343Sngie} 180272343Sngie 181272343Sngieatf_test_case default_columns 182272343Sngiedefault_columns_head() 183272343Sngie{ 184272343Sngie atf_set "descr" "Checks that the default set of columns is correct" \ 185272343Sngie "and also check that the columns printed by the -j," \ 186272343Sngie "-l, -s, -u and -v flags alone are correct" 187272343Sngie} 188272343Sngiedefault_columns_body() 189272343Sngie{ 190272343Sngie setup_keywords 191272343Sngie check_heading_keywords '' "$default_keywords" 192272343Sngie check_heading_variations 'j' "$j_keywords" 193272343Sngie check_heading_variations 'l' "$l_keywords" 194272343Sngie check_heading_variations 's' "$s_keywords" 195272343Sngie check_heading_variations 'u' "$u_keywords" 196272343Sngie check_heading_variations 'v' "$v_keywords" 197272343Sngie} 198272343Sngie 199272343Sngieatf_test_case minus_O 200272343Sngieminus_O_head() 201272343Sngie{ 202272343Sngie atf_set "descr" "Checks that 'ps -O foo' inserts columns just after" \ 203272343Sngie "the pid column" 204272343Sngie} 205272343Sngieminus_O_body() 206272343Sngie{ 207272343Sngie setup_keywords 208272343Sngie check_heading_keywords '-O %cpu,%mem' \ 209272343Sngie "$(echo "${default_keywords}" | sed -e 's/pid/pid %cpu %mem/')" 210272343Sngie check_heading_keywords '-O %cpu -O %mem' \ 211272343Sngie "$(echo "${default_keywords}" | sed -e 's/pid/pid %cpu %mem/')" 212272343Sngie check_heading_keywords '-O%cpu -O%mem' \ 213272343Sngie "$(echo "${default_keywords}" | sed -e 's/pid/pid %cpu %mem/')" 214272343Sngie} 215272343Sngie 216272343Sngieatf_test_case minus_o 217272343Sngieminus_o_head() 218272343Sngie{ 219272343Sngie atf_set "descr" "Checks simple cases of 'ps -o foo' to control which" \ 220272343Sngie "columns are printed; this does not test header" \ 221272343Sngie "overriding via 'ps -o foo=BAR'" 222272343Sngie} 223272343Sngieminus_o_body() 224272343Sngie{ 225272343Sngie setup_keywords 226272343Sngie # Keywords for "-o name" override the default display 227272343Sngie check_heading_keywords '-o pid,%cpu,%mem' \ 228272343Sngie "pid %cpu %mem" 229272343Sngie check_heading_keywords '-o pid -o %cpu,%mem' \ 230272343Sngie "pid %cpu %mem" 231272343Sngie check_heading_keywords '-opid -o %cpu,%mem' \ 232272343Sngie "pid %cpu %mem" 233272343Sngie # Space works like comma 234272343Sngie check_heading_keywords '-opid -o "%cpu %mem"' \ 235272343Sngie "pid %cpu %mem" 236272343Sngie # Check missing pid 237272343Sngie check_heading_keywords '-o comm' \ 238272343Sngie "comm" 239272343Sngie # Check pid present but not first 240272343Sngie check_heading_keywords '-o comm,pid' \ 241272343Sngie "comm pid" 242272343Sngie} 243272343Sngie 244272343Sngieatf_test_case override_heading_simple 245272343Sngieoverride_heading_simple_head() 246272343Sngie{ 247272343Sngie atf_set "descr" "Tests simple uses of header overriding via" \ 248272343Sngie "'ps -o foo=BAR'. This does not test columns " \ 249272343Sngie "with null headings, or headings with embedded" \ 250272343Sngie "space, ',' or '='." 251272343Sngie} 252272343Sngieoverride_heading_simple_body() 253272343Sngie{ 254272343Sngie setup_keywords 255272343Sngie check_heading_regexp '-o pid=PPP -o comm' \ 256272343Sngie '^ *PPP '"${head_text_comm}"'$' # no trailing space 257272343Sngie check_heading_regexp '-o pid=PPP -o comm=CCC' \ 258272343Sngie '^ *PPP CCC$' 259272343Sngie check_heading_regexp '-o pid,comm=CCC' \ 260272343Sngie '^'"${head_regexp_pid}"' CCC$' 261272343Sngie check_heading_regexp '-o pid -o comm=CCC' \ 262272343Sngie '^'"${head_regexp_pid}"' CCC$' 263272343Sngie # Check missing pid 264272343Sngie check_heading_regexp '-o comm=CCC' \ 265272343Sngie '^CCC$' 266272343Sngie # Check pid present but not first 267272343Sngie check_heading_regexp '-o comm=CCC -o pid=PPP' \ 268272343Sngie '^CCC *PPP$' 269272343Sngie check_heading_regexp '-o comm,pid=PPP' \ 270272343Sngie '^'"${head_regexp_comm}"' *PPP$' 271272343Sngie} 272272343Sngie 273272343Sngieatf_test_case override_heading_embedded_specials 274272343Sngieoverride_heading_embedded_specials_head() 275272343Sngie{ 276272343Sngie atf_set "descr" "Tests header overriding with embedded space," \ 277272343Sngie "',' or '='. Everything after the first '='" \ 278272343Sngie "is part of the heading." 279272343Sngie} 280272343Sngieoverride_heading_embedded_specials_body() 281272343Sngie{ 282272343Sngie setup_keywords 283272343Sngie # Check embedded "," or "=" in override header. 284272343Sngie check_heading_regexp '-o comm,pid==' \ 285272343Sngie '^'"${head_regexp_comm}"' *=$' 286272343Sngie check_heading_regexp '-o comm,pid=,' \ 287272343Sngie '^'"${head_regexp_comm}"' *,$' 288272343Sngie check_heading_regexp '-o pid=PPP,comm' \ 289272343Sngie '^ *PPP,comm$' # not like '-o pid=PPP -o comm' 290272343Sngie check_heading_regexp '-o pid=PPP,comm=CCC' \ 291272343Sngie '^ *PPP,comm=CCC$' # not like '-o pid=PPP -o comm=CCC' 292272343Sngie check_heading_regexp '-o comm,pid=PPP,QQQ' \ 293272343Sngie '^'"${head_regexp_comm}"' *PPP,QQQ$' 294272343Sngie check_heading_regexp '-o comm,pid=ppid,tty=state' \ 295272343Sngie '^'"${head_regexp_comm}"' *ppid,tty=state$' 296272343Sngie # Check embedded space or tab in override header. 297272343Sngie check_heading_regexp '-o comm,pid="PPP QQQ"' \ 298272343Sngie '^'"${head_regexp_comm}"' *PPP QQQ$' 299272343Sngie check_heading_regexp '-o comm,pid="PPP${tab}QQQ"' \ 300272343Sngie '^'"${head_regexp_comm}"' *PPP'"${tab}"'QQQ$' 301272343Sngie} 302272343Sngie 303272343Sngieatf_test_case override_heading_some_null 304272343Sngieoverride_heading_some_null_head() 305272343Sngie{ 306272343Sngie atf_set "descr" "Tests simple uses of null column headings" \ 307272343Sngie "overriding via 'ps -o foo=BAR -o baz='. This" \ 308272343Sngie "does not test the case where all columns have" \ 309272343Sngie "null headings." 310272343Sngie} 311272343Sngieoverride_heading_some_null_body() 312272343Sngie{ 313272343Sngie setup_keywords 314272343Sngie check_heading_regexp '-o pid=PPP -o comm=' \ 315272343Sngie '^ *PPP *$' 316272343Sngie check_heading_regexp '-o pid= -o comm=CCC' \ 317272343Sngie '^ * CCC$' 318272343Sngie check_heading_regexp '-o pid -o comm=' \ 319272343Sngie '^'"${head_regexp_pid}"' *$' 320272343Sngie # Check missing pid 321272343Sngie check_heading_regexp '-o ppid= -o comm=CCC' \ 322272343Sngie '^ * CCC$' 323272343Sngie check_heading_regexp '-o ppid=PPP -o comm=' \ 324272343Sngie '^ *PPP *$' 325272343Sngie # Check pid present but not first 326272343Sngie check_heading_regexp '-o comm= -o pid=PPP' \ 327272343Sngie '^ * PPP$' 328272343Sngie check_heading_regexp '-o comm,pid=' \ 329272343Sngie '^'"${head_regexp_comm}"' *$' 330272343Sngie # A field with a null custom heading retains a minimum width 331272343Sngie # derived from the default heading. This does not apply 332272343Sngie # to a field with a very short (non-null) custom heading. 333272343Sngie # 334272343Sngie # We choose "holdcnt" as a column whose width is likely to be 335272343Sngie # determined entirely by the header width, because the values 336272343Sngie # are likely to be very small. 337272343Sngie check_heading_regexp '-o holdcnt -o holdcnt -o holdcnt' \ 338272343Sngie '^HOLDCNT HOLDCNT HOLDCNT$' 339272343Sngie check_heading_regexp '-o holdcnt -o holdcnt= -o holdcnt' \ 340272343Sngie '^HOLDCNT HOLDCNT$' 341272343Sngie check_heading_regexp '-o holdcnt -o holdcnt=HH -o holdcnt' \ 342272343Sngie '^HOLDCNT HH HOLDCNT$' 343272343Sngie} 344272343Sngie 345272343Sngieatf_test_case override_heading_all_null 346272343Sngieoverride_heading_all_null_head() 347272343Sngie{ 348272343Sngie atf_set "descr" "Tests the use of 'ps -o foo= -o bar=' (with a" \ 349272343Sngie "null heading for every column). The heading" \ 350272343Sngie "should not be printed at all in this case." 351272343Sngie} 352272343Sngieoverride_heading_all_null_body() 353272343Sngie{ 354272343Sngie setup_keywords 355272343Sngie # A heading with a space is not a null heading, 356272343Sngie # so should not be suppressed 357272343Sngie check_heading_regexp '-o comm=" "' \ 358272343Sngie '^ *$' 359272343Sngie # Null headings should be suppressed 360272343Sngie check_no_heading_line '-o pid= -o comm=' 361272343Sngie check_no_heading_line '-o pid= -o comm=' 362272343Sngie # Check missing pid 363272343Sngie check_no_heading_line '-o ppid=' 364272343Sngie check_no_heading_line '-o comm=' 365272343Sngie check_no_heading_line '-o command=' 366272343Sngie check_no_heading_line '-o ppid= -o comm=' 367272343Sngie check_no_heading_line '-o comm= -o ppid=' 368272343Sngie # Check pid present but not first 369272343Sngie check_no_heading_line '-o comm= -o pid=' 370272343Sngie check_no_heading_line '-o ppid= -o pid= -o command=' 371272343Sngie} 372272343Sngie 373272343Sngieatf_test_case duplicate_column 374272343Sngieduplicate_column_head() 375272343Sngie{ 376272343Sngie atf_set "descr" "Tests the use of -o options to display the" \ 377272343Sngie "same column more than once" 378272343Sngie} 379272343Sngieduplicate_column_body() 380272343Sngie{ 381272343Sngie setup_keywords 382272343Sngie # two custom headers 383272343Sngie check_heading_regexp '-o pid=PPP -o pid=QQQ' \ 384272343Sngie '^ *PPP *QQQ$' 385272343Sngie # one custom header, before and after default header 386272343Sngie check_heading_regexp '-o pid=PPP -o pid' \ 387272343Sngie '^ *PPP '"${head_regexp_pid}"'$' 388272343Sngie check_heading_regexp '-o pid -o pid=QQQ' \ 389272343Sngie '^'"${head_regexp_pid}"' *QQQ$' 390272343Sngie # custom headers both before and after default header 391272343Sngie check_heading_regexp '-o pid=PPP -o pid -o pid=QQQ' \ 392272343Sngie '^ *PPP '"${head_regexp_pid}"' *QQQ$' 393272343Sngie} 394272343Sngie 395272343Sngieatf_init_test_cases() { 396272343Sngie atf_add_test_case default_columns 397272343Sngie atf_add_test_case minus_O 398272343Sngie atf_add_test_case minus_o 399272343Sngie atf_add_test_case override_heading_simple 400272343Sngie atf_add_test_case override_heading_embedded_specials 401272343Sngie atf_add_test_case override_heading_some_null 402272343Sngie atf_add_test_case override_heading_all_null 403272343Sngie atf_add_test_case duplicate_column 404272343Sngie} 405