-
Notifications
You must be signed in to change notification settings - Fork 37
/
testing.sh
1414 lines (1017 loc) · 35.4 KB
/
testing.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
echo "${__INTERNAL_SOURCED}" | grep -qF -- " ${BASH_SOURCE} " && return || __INTERNAL_SOURCED+=" ${BASH_SOURCE} "
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Name: testing.sh - part of the BeakerLib project
# Description: Asserting functions, watchdog and report
#
# Author: Ondrej Hudlicky <ohudlick@redhat.com>
# Author: Petr Muller <pmuller@redhat.com>
# Author: Jan Hutar <jhutar@redhat.com>
# Author: Petr Splichal <psplicha@redhat.com>
# Author: Ales Zelinka <azelinka@redhat.com>
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Copyright (c) 2008-2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing
# to use, modify, copy, or redistribute it subject to the terms
# and conditions of the GNU General Public License version 2.
#
# This program is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with this program; if not, write to the Free
# Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
export __INTERNAL_DEFAULT_REPORT_RESULT=/bin/true
: <<'=cut'
=pod
=head1 NAME
BeakerLib - testing - asserting functions, watchdog and report
=head1 DESCRIPTION
This file contains functions related directly to testing. These functions are
various asserts affecting final result of the phase. Watchdog and the report
result function is included as well.
=head1 FUNCTIONS
=cut
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Internal Stuff
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
. $BEAKERLIB/logging.sh
. $BEAKERLIB/journal.sh
__INTERNAL_LogAndJournalPass() {
rljAddTest "$1 $2" "PASS" "$3"
}
__INTERNAL_LogAndJournalFail() {
rljAddTest "$1 $2" "FAIL" "$3"
}
# __INTERNAL_ConditionalAssert comment status [failed-comment] [executed command-line]
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__INTERNAL_ConditionalAssert() {
if [ "$2" == "0" ]; then
__INTERNAL_LogAndJournalPass "$1" "$3" "$4"
return 0
else
__INTERNAL_LogAndJournalFail "$1" "$3" "$4"
return 1
fi
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlPass
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head2 Manual Asserts
=head3 rlPass
Manual assertion, asserts and logs PASS.
rlPass comment
=over
=item comment
Short test summary.
=back
Returns 0 and asserts PASS.
=cut
rlPass() {
__INTERNAL_LogAndJournalPass "$1"
return 0
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlFail
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlFail
Manual assertion, asserts and logs FAIL.
rlFail comment
=over
=item comment
Short test summary.
=back
Returns 1 and asserts FAIL.
=cut
rlFail() {
__INTERNAL_LogAndJournalFail "$1"
return 1
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssert0
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head2 Arithmetic Asserts
=head3 rlAssert0
Assertion checking for the equality of parameter to zero.
rlAssert0 comment value
=over
=item comment
Short test summary, e.g. "Test if compilation ended successfully".
=item value
Integer value (usually return code of a command).
=back
Returns 0 and asserts PASS when C<value == 0>.
=cut
rlAssert0() {
__INTERNAL_ConditionalAssert "$1" "$2" "(Assert: expected 0, got $2)"
return $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertEquals
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlAssertEquals
Assertion checking for the equality of two parameters.
rlAssertEquals comment value1 value2
=over
=item comment
Short test summary, e.g. "Test if all 3 packages have been downloaded".
=item value1
First parameter to compare, can be a number or a string
=item value2
Second parameter to compare, can be a number or a string
=back
Returns 0 and asserts PASS when C<value1 == value2>.
=cut
rlAssertEquals() {
if [ $# -lt 3 ] ; then
__INTERNAL_LogAndJournalFail "rlAssertEquals called without all needed parameters" ""
return 1
fi
__INTERNAL_ConditionalAssert "$1" "$([ "$2" == "$3" ]; echo $?)" "(Assert: '$2' should equal '$3')"
return $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertNotEquals
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlAssertNotEquals
Assertion checking for the non-equality of two parameters.
rlAssertNotEquals comment value1 value2
=over
=item comment
Short test summary, e.g. "Test if return code is not 139".
=item value1
First parameter to compare, can be a number or a string
=item value2
Second parameter to compare, can be a number or a string
=back
Returns 0 and asserts PASS when C<value1 != value2>.
=cut
rlAssertNotEquals() {
if [ $# -lt 3 ] ; then
__INTERNAL_LogAndJournalFail "rlAssertNotEquals called without all needed parameters" ""
return 1
fi
__INTERNAL_ConditionalAssert "$1" "$([ "$2" != "$3" ]; echo $?)" "(Assert: \"$2\" should not equal \"$3\")"
return $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertGreater
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlAssertGreater
Assertion checking whether first parameter is greater than the second one.
rlAssertGreater comment value1 value2
=over
=item comment
Short test summary, e.g. "Test whether there are running more instances of program."
=item value1
Integer value.
=item value2
Integer value.
=back
Returns 0 and asserts PASS when C<value1 E<gt> value2>.
=cut
rlAssertGreater() {
__INTERNAL_ConditionalAssert "$1" "$([ "$2" -gt "$3" ]; echo $?)" "(Assert: \"$2\" should be greater than \"$3\")"
return $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertGreaterOrEqual
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlAssertGreaterOrEqual
Assertion checking whether first parameter is greater or equal to the second one.
rlAssertGreaterOrEqual comment value1 value2
=over
=item comment
Short test summary (e.g. "There should present at least one...")
=item value1
Integer value.
=item value2
Integer value.
=back
Returns 0 and asserts PASS when C<value1 E<ge>= value2>.
=cut
rlAssertGreaterOrEqual() {
__INTERNAL_ConditionalAssert "$1" "$([ "$2" -ge "$3" ]; echo $?)" "(Assert: \"$2\" should be >= \"$3\")"
return $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertLesser
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlAssertLesser
Assertion checking whether first parameter is lesser than the second one.
rlAssertLesser comment value1 value2
=over
=item comment
Short test summary, e.g. "Test whether there are running more instances of program."
=item value1
Integer value.
=item value2
Integer value.
=back
Returns 0 and asserts PASS when C<value1 E<le> value2>.
=cut
rlAssertLesser() {
__INTERNAL_ConditionalAssert "$1" "$([ "$2" -le "$3" ]; echo $?)" "(Assert: \"$2\" should be lesser than \"$3\")"
return $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertLesserOrEqual
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlAssertLesserOrEqual
Assertion checking whether first parameter is lesser or equal to the second one.
rlAssertLesserOrEqual comment value1 value2
=over
=item comment
Short test summary (e.g. "There should present at least one...")
=item value1
Integer value.
=item value2
Integer value.
=back
Returns 0 and asserts PASS when C<value1 E<le>= value2>.
=cut
rlAssertLesserOrEqual() {
__INTERNAL_ConditionalAssert "$1" "$([ "$2" -le "$3" ]; echo $?)" "(Assert: \"$2\" should be <= \"$3\")"
return $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertExists
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head2 File Asserts
=head3 rlAssertExists
Assertion checking for the existence of a file or a directory.
rlAssertExists file|directory
=over
=item file|directory
Path to the file or directory.
=back
Returns 0 and asserts PASS when C<file> exists.
=cut
rlAssertExists(){
if [ -z "$1" ] ; then
__INTERNAL_LogAndJournalFail "rlAssertExists called without parameter" ""
return 1
fi
local FILE="File"
if [ -d "$1" ] ; then
FILE="Directory"
fi
__INTERNAL_ConditionalAssert "$FILE $1 should exist" "$([ -e "$1" ]; echo $?)"
return $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertNotExists
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlAssertNotExists
Assertion checking for the non-existence of a file or a directory.
rlAssertNotExists file|directory
=over
=item file|directory
Path to the file or directory.
=back
Returns 0 and asserts PASS when C<file> does not exist.
=cut
rlAssertNotExists(){
if [ -z "$1" ] ; then
__INTERNAL_LogAndJournalFail "rlAssertNotExists called without parameter" ""
return 1
fi
local FILE="File"
if [ -d "$1" ] ; then
FILE="Directory"
fi
__INTERNAL_ConditionalAssert "$FILE $1 should not exist" "$([ ! -e "$1" ]; echo $?)"
return $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertGrep
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlAssertGrep
Assertion checking if the file contains a pattern.
rlAssertGrep pattern file [options]
=over
=item pattern
Regular expression to be searched for.
=item file
Path to the file.
=item options
Optional parameters to be passed to grep, default is C<-q>. Can be
used to perform case insensitive matches (-i), or using
extended (-E) or perl (-P) regular expressions.
=back
Returns 0 and asserts PASS when C<file> exists and contains given
C<pattern>.
=cut
rlAssertGrep(){
if [ ! -e "$2" ] ; then
__INTERNAL_LogAndJournalFail "rlAssertGrep: failed to find file $2"
return 2
fi
local options=${3:--q}
grep $options -- "$1" "$2"
__INTERNAL_ConditionalAssert "File '$2' should contain '$1'" $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertNotGrep
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlAssertNotGrep
Assertion checking that the file does not contain a pattern.
rlAssertNotGrep pattern file [options]
=over
=item pattern
Regular expression to be searched for.
=item file
Path to the file.
=item options
Optional parameters to be passed to grep, default is C<-q>. Can be
used to perform case insensitive matches (-i), or using
extended (-E) or perl (-P) regular expressions.
=back
Returns 0 and asserts PASS when C<file> exists and does not
contain given C<pattern>.
=cut
rlAssertNotGrep(){
if [ ! -e "$2" ] ; then
__INTERNAL_LogAndJournalFail "rlAssertNotGrep: failed to find file $2"
return 2
fi
local options=${3:--q}
! grep $options -- "$1" "$2"
__INTERNAL_ConditionalAssert "File '$2' should not contain '$1'" $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertDiffer
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlAssertDiffer
Assertion checking that two files differ (are not identical).
rlAssertDiffer file1 file2
=over
=item file1
Path to first file1
=item file2
Path to second file
=back
Returns 0 and asserts PASS when C<file1> and C<file2> differs.
=cut
rlAssertDiffer(){
local file
local IFS
for file in "$1" "$2"; do
if [ ! -e "$file" ]; then
__INTERNAL_LogAndJournalFail "rlAssertDiffer: file $file was not found"
return 2
fi
done
! cmp -s "$1" "$2"
__INTERNAL_ConditionalAssert "Files $1 and $2 should differ" $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlAssertNotDiffer
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlAssertNotDiffer
Assertion checking that two files do not differ (are identical).
rlAssertNotDiffer file1 file2
=over
=item file1
Path to first file1
=item file2
Path to second file
=back
Returns 0 and asserts PASS when C<file1> and C<file2> do not differ.
=cut
rlAssertNotDiffer() {
local file
local ISF
for file in "$1" "$2"; do
if [ ! -e "$file" ]; then
__INTERNAL_LogAndJournalFail "rlAssertNotDiffer: file $file was not found"
return 2
fi
done
cmp -s "$1" "$2"
__INTERNAL_ConditionalAssert "Files $1 and $2 should not differ" $?
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlRun
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head2 Run, Watch, Report
=head3 rlRun
Run command with optional comment and make sure its exit code
matches expectations.
rlRun [-t] [-l] [-c] [-s] command [status[,status...] [comment]]
=over
=item -t
If specified, stdout and stderr of the command output will be tagged
with strigs 'STDOUT: ' and 'STDERR: '.
=item -l
If specified, output of the command (tagged, if -t was specified) is
logged using rlLog function. This is intended for short outputs, and
therefore only last 50 lines are logged this way. Longer outputs should
be analysed separately, or uploaded via rlFileSubmit or rlBundleLogs.
=item -c
Same as C<-l>, but only log the commands output if it failed.
=item -s
Store stdout and stderr to a file (mixed together, as the user would see
it on a terminal) and set $rlRun_LOG variable to name of the file. Caller
is responsible for removing the file. When -t option is used, the content
of the file becomes tagged too.
If the -s option is not used, $rlRun_LOG is not modified and keeps its
content from the last "rlRun -s".
=item command
Command to run.
=item status
Expected exit code(s). Optional, default 0. If you expect more
exit codes, separate them with comma (e.g. "0,1" when both 0 and 1
are OK and expected), or use from-to notation (i.e. "2-5" for "2,3,4,5"),
or combine them (e.g. "2-4,26" for "2,3,4,26").
=item comment
Short summary describing the action (optional, but recommended -
explain what are you doing here).
=back
Returns the exit code of the command run. Asserts PASS when
command\'s exit status is in the list of expected exit codes.
Note:
=over
=item
The output of rlRun is buffered when using C<-t>, C<-l> or C<-s>
option (they use unix pipes, which are buffered by nature). If you
need an unbuffered output just make sure that C<expect> package is
installed on your system (its "unbuffer" tool will automatically
be used to produce unbuffered output).
=item
Be aware that there are some variables which can collide with your code executed
within rlRun. You should avoid using __INTERNAL_rlRun_* variables.
=item
When any of C<-t> C<-l>, C<-c>, or C<-s> option is used, special file
descriptors 111 and 112 are used to avoid the issue with incomplete log file,
bz1361246. As there might be an indefinite loop, there's a timeout of two
minutes implemented as a fix for bz1416796. Also an error message is issued to
signal the possibility of running subprocess which keeps the file descriptors
open.
Do not use these options if you expect process forking and continuouse run. Try
your own apropriate solution instead.
=back
B<Warning:> using C<unbuffer> tool is now disabled because of bug 547686.
=cut
#'
rlRun() {
local __INTERNAL_rlRun_GETOPT=$(getopt -o lcts -- "$@" 2> >(while read -r line; do rlLogError "$FUNCNAME: $line"; done))
eval set -- "$__INTERNAL_rlRun_GETOPT"
local __INTERNAL_rlRun_DO_LOG=false
local __INTERNAL_rlRun_DO_TAG=false
local __INTERNAL_rlRun_DO_KEEP=false
local __INTERNAL_rlRun_DO_CON=false
local __INTERNAL_rlRun_TAG_OUT=''
local __INTERNAL_rlRun_TAG_ERR=''
local __INTERNAL_rlRun_LOG_FILE=''
local IFS
while true ; do
case "$1" in
-l)
__INTERNAL_rlRun_DO_LOG=true;
shift;;
-c)
__INTERNAL_rlRun_DO_LOG=true;
__INTERNAL_rlRun_DO_CON=true;
shift;;
-t)
__INTERNAL_rlRun_DO_TAG=true;
__INTERNAL_rlRun_TAG_OUT='STDOUT: '
__INTERNAL_rlRun_TAG_ERR='STDERR: '
shift;;
-s)
__INTERNAL_rlRun_DO_KEEP=true
shift;;
--)
shift;
break;;
*)
shift;;
esac
done
local __INTERNAL_rlRun_command=$1
local __INTERNAL_rlRun_expected_orig=${2:-0}
local __INTERNAL_rlRun_expected=${2:-0}
local __INTERNAL_rlRun_comment
local __INTERNAL_rlRun_comment_begin
if [[ -z "$3" ]]; then
__INTERNAL_rlRun_comment_begin="Running '$__INTERNAL_rlRun_command'"
__INTERNAL_rlRun_comment="Command '$__INTERNAL_rlRun_command'"
else
__INTERNAL_rlRun_comment_begin="$3 :: actually running '$__INTERNAL_rlRun_command'"
__INTERNAL_rlRun_comment="$3"
fi
# here we can do various sanity checks of the $command
if [[ "$__INTERNAL_rlRun_command" =~ ^[[:space:]]*$ ]] ; then
rlFail "rlRun: got empty or blank command '$__INTERNAL_rlRun_command'!"
return 1
elif false ; then
# this an example check
rlFail "rlRun: sanity check of command '$__INTERNAL_rlRun_command' failed!"
return 1
fi
# create __INTERNAL_rlRun_LOG_FILE if needed
if $__INTERNAL_rlRun_DO_LOG || $__INTERNAL_rlRun_DO_KEEP
then
__INTERNAL_rlRun_LOG_FILE=$( mktemp -p $__INTERNAL_PERSISTENT_TMP rlRun_LOG.XXXXXXXX )
if [ ! -e "$__INTERNAL_rlRun_LOG_FILE" ]
then
rlFail "rlRun: Internal file creation failed"
rlLogError "rlRun: Please report this issue to RH Bugzilla for Beakerlib component"
rlLogError "rlRun: Turning off any -l, -c or -s options of rlRun"
rlLogError "rlRun: Unless the test relies on them, rest of the test can be trusted."
__INTERNAL_rlRun_DO_LOG=false
__INTERNAL_rlRun_DO_KEEP=false
__INTERNAL_rlRun_LOG_FILE=/dev/null
fi
fi
# in case expected exit code is provided as "2-5,26", expand it to "2,3,4,5,26"
while echo "$__INTERNAL_rlRun_expected" | grep -q '[0-9]-[0-9]'; do
local __INTERNAL_rlRun_interval=$(echo "$__INTERNAL_rlRun_expected" | sed "s/.*\(\<[0-9]\+-[0-9]\+\>\).*/\1/")
if [ -z "$__INTERNAL_rlRun_interval" ]; then
rlLogWarning "rlRun: Something happened when getting interval, using '0-0'"
__INTERNAL_rlRun_interval='0-0'
fi
local __INTERNAL_rlRun_interval_a=$(echo "$__INTERNAL_rlRun_interval" | cut -d '-' -f 1)
local __INTERNAL_rlRun_interval_b=$(echo "$__INTERNAL_rlRun_interval" | cut -d '-' -f 2)
if [ -z "$__INTERNAL_rlRun_interval_a" -o -z "$__INTERNAL_rlRun_interval_b" ]; then
rlLogWarning "rlRun: Something happened when getting boundaries of interval, using '0' and '0'"
__INTERNAL_rlRun_interval_a=0
__INTERNAL_rlRun_interval_b=0
fi
if [ $__INTERNAL_rlRun_interval_a -gt $__INTERNAL_rlRun_interval_b ]; then
rlLogWarning "rlRun: First boundary have to be smaller then second one, using '$__INTERNAL_rlRun_interval_b' and '$__INTERNAL_rlRun_interval_b'"
__INTERNAL_rlRun_interval_a=$__INTERNAL_rlRun_interval_b
fi
local __INTERNAL_rlRun_replacement="$__INTERNAL_rlRun_interval_a"
let __INTERNAL_rlRun_interval_a=$__INTERNAL_rlRun_interval_a+1
local __INTERNAL_rlRun_i
for __INTERNAL_rlRun_i in $(seq $__INTERNAL_rlRun_interval_a $__INTERNAL_rlRun_interval_b); do
__INTERNAL_rlRun_replacement="$__INTERNAL_rlRun_replacement,$__INTERNAL_rlRun_i"
done
__INTERNAL_rlRun_expected="${__INTERNAL_rlRun_expected//$__INTERNAL_rlRun_interval/$__INTERNAL_rlRun_replacement/}"
done
rlLogDebug "rlRun: Running command: $__INTERNAL_rlRun_command"
__INTERNAL_PrintText "$__INTERNAL_rlRun_comment_begin" "BEGIN"
if $__INTERNAL_rlRun_DO_LOG || $__INTERNAL_rlRun_DO_TAG || $__INTERNAL_rlRun_DO_KEEP; then
# handle issue with incomplete logs (bz1361246), this could be improved using coproc
# in RHEL-6 and higher
# open file descriptors to parsing processes
exec 111> >(sed -u -e "s/^/$__INTERNAL_rlRun_TAG_OUT/g" | tee -a $__INTERNAL_rlRun_LOG_FILE)
local __INTERNAL_rlRun_OUTpid=$!
exec 112> >(sed -u -e "s/^/$__INTERNAL_rlRun_TAG_ERR/g" | tee -a $__INTERNAL_rlRun_LOG_FILE)
local __INTERNAL_rlRun_ERRpid=$!
eval "$__INTERNAL_rlRun_command" 2>&112 1>&111
local __INTERNAL_rlRun_exitcode=$?
# close parsing processes
exec 111>&-
exec 112>&-
# wait for parsing processes to finish their job
local __INTERNAL_rlRun_counter=0
while kill -0 $__INTERNAL_rlRun_OUTpid 2>/dev/null || kill -0 $__INTERNAL_rlRun_ERRpid 2>/dev/null; do
[[ $((__INTERNAL_rlRun_counter++)) -gt 12000 ]] && {
rlLogError "waiting for flushing the output timed out"
rlLogError " check whether the command you run is not forking to background which causes the output pipe to be kept open"
rlLogError " if there are such processes, their outputs might not be complete"
break
}
sleep 0.01;
done
rlLogDebug "waiting for parsing processes took $__INTERNAL_rlRun_counter cycles"
else
eval "$__INTERNAL_rlRun_command"
local __INTERNAL_rlRun_exitcode=$?
fi
rlLogDebug "rlRun: command = '$__INTERNAL_rlRun_command'; exitcode = $__INTERNAL_rlRun_exitcode; expected = $__INTERNAL_rlRun_expected"
if $__INTERNAL_rlRun_DO_LOG || $__INTERNAL_rlRun_DO_TAG || $__INTERNAL_rlRun_DO_KEEP; then
sync
fi
echo "$__INTERNAL_rlRun_expected" | grep -q "\<$__INTERNAL_rlRun_exitcode\>" # symbols \< and \> match the empty string at the beginning and end of a word
local __INTERNAL_rlRun_result=$?
if $__INTERNAL_rlRun_DO_LOG && ( ! $__INTERNAL_rlRun_DO_CON || ( $__INTERNAL_rlRun_DO_CON && [ $__INTERNAL_rlRun_result -ne 0 ] ) ); then
rlLog "Output of '$__INTERNAL_rlRun_command':"
rlLog "--------------- OUTPUT START ---------------"
local __INTERNAL_rlRun_line
tail -n 50 "$__INTERNAL_rlRun_LOG_FILE" | while read __INTERNAL_rlRun_line
do
rlLog "$__INTERNAL_rlRun_line"
done
rlLog "--------------- OUTPUT END ---------------"
fi
if $__INTERNAL_rlRun_DO_KEEP; then
rlRun_LOG=$__INTERNAL_rlRun_LOG_FILE
export rlRun_LOG
elif $__INTERNAL_rlRun_DO_LOG; then
rm $__INTERNAL_rlRun_LOG_FILE
fi
rlLogDebug "rlRun: Command finished with exit code: $__INTERNAL_rlRun_exitcode, expected: $__INTERNAL_rlRun_expected_orig"
__INTERNAL_ConditionalAssert "$__INTERNAL_rlRun_comment" $__INTERNAL_rlRun_result "(Expected $__INTERNAL_rlRun_expected_orig, got $__INTERNAL_rlRun_exitcode)" "$__INTERNAL_rlRun_command"
return $__INTERNAL_rlRun_exitcode
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# rlWatchdog
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
=pod
=head3 rlWatchdog
Run C<command>. If it does not finish in specified time, then kill
it using C<signal>.
rlWatchdog command timeout [signal] [callback]
=over
=item command
Command to run.
=item timeout
Timeout to wait, in seconds.
=item signal
Signal to use (optional, default KILL).
=item callback
Callback function to be called before the signal is send (optional, none
by default). The callback function will have one argument available -- PGID
of the process group.
=back
Returns 0 if the command ends normally, without need to be killed.
=cut
rlWatchdog() {
# Save current shell options
local shell_options=$(set +o)
set -m
local command=$1
local timeout=$2
local killer=${3:-"KILL"}
local callback=${4:-""}
rm -f __INTERNAL_FINISHED __INTERNAL_TIMEOUT
rlLog "Runnning $command, with $timeout seconds timeout"
eval "$command; touch __INTERNAL_FINISHED" &
local pidcmd=$!
eval "sleep $timeout; touch __INTERNAL_TIMEOUT" &
local pidsleep=$!
while true; do
if [ -e __INTERNAL_FINISHED ]; then
rlLog "Command ended itself, I am not killing it."
/bin/kill -- -$pidsleep
sleep 1
rm -f __INTERNAL_FINISHED __INTERNAL_TIMEOUT
# Restore previous shell options
eval "$shell_options"
return 0
elif [ -e __INTERNAL_TIMEOUT ]; then
rlLog "Command is still running, I am killing it with $killer"
if [ -n "$callback" ] \
&& type $callback 2>/dev/null | grep -q "$callback is a function"
then
rlLog "Function $callback is present, I am calling it"
$callback $pidcmd
fi
/bin/kill -$killer -- -$pidcmd
sleep 1
rm -f __INTERNAL_FINISHED __INTERNAL_TIMEOUT
eval "$shell_options"