-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbashUnit.sh
404 lines (358 loc) · 10.5 KB
/
bashUnit.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
#!/bin/bash
#==============================================================================
# BASH UNIT Testing library
#------------------------------------------------------------------------------
# Description:
# This library is designed to deliver unit testing capabilities and
# xUnit reports compatibility to bash scripts.
#
# Version: 1.0.0
# Author TriYop
#==============================================================================
#===
# TODO: some more assertions are still in progress
# - File max permissions
# - File owner group
#
# Load custom configuration
[ -f /etc/bashunitrc ] && source /etc/bashunitrc
[ -f $HOME/.bashunitrc ] && source $HOME/.bashunitrc
if [ -z "${BASH_TEST_OUTDIR}" ]; then
BASH_TEST_OUTDIR=$(pwd)/TestResults
fi
if [ ! -d ${BASH_TEST_OUTDIR} ]; then
echo "Creating output directory: ${BASH_TEST_OUTDIR}"
mkdir ${BASH_TEST_OUTDIR}
fi
if [ -z "${BASH_TEST_OUTFILE}" ]; then
BASH_TEST_OUTFILE="${BASH_TEST_OUTDIR}/$(basename $0.xml)"
fi
#======================================
# Starts a new TestSuite result file.
#
# @param $1 Script full name ($0 from calling script)
function beginTestSuite {
SCRIPT_FULLNAME=$1
TIMESTAMP=$( date +'%Y-%m-%d %H:%M:%S' )
PROPERTIES='PATH HOME PPID SHELL TERM PWD STY USER UID HOSTNAME HOSTTYPE MACHTYPE'
echo "<testsuite hostname='${HOSTNAME}' name='${SCRIPT_FULLNAME}' timestamp='${TIMESTAMP}'>" > $BASH_TEST_OUTFILE
echo "<properties>" >> $BASH_TEST_OUTFILE
for property in $PROPERTIES; do
# FIXME escape $property and $VALUE
prop='${'$property'}'
VALUE=$( eval "echo $prop" )
echo "<property name='${property}' value='${VALUE}'></property>" >> $BASH_TEST_OUTFILE
done
echo "</properties>" >> $BASH_TEST_OUTFILE
}
#======================================a
# Ends a test suite result file
#
function endTestSuite {
echo "</testsuite>" >> $BASH_TEST_OUTFILE
}
#======================================
# Ends a generic test suite in error
# @param $1 the error code to return as exit code
# @param $2 the error message to log
# @param $3 the log file
function exitTestSuite {
returnCode=$1
errorMessage=$2
logFile=$3
echo "Error: ${errorMessage}" | tee -a ${logFile}
echo "More details in log file '${logFile}'."
endTestSuite
exit $returnCode
}
#=======================================
# Starts a new generic test case
# @param $1 Test class
# @param $2 Test Name
function beginTestCase {
# FIXME: escape $CASE and $NAME before storing them into XML
CASE=$1
NAME=$2
echo "<testcase classname=\"org.bash.${CASE}\" name=\"${NAME}\">" >> $BASH_TEST_OUTFILE
}
#======================================
# Ends a generic test case
function endTestCase {
echo "</testcase>" >> $BASH_TEST_OUTFILE
}
#======================================
# Adds a failure to a given test case.
#
# @param $1 failure message
# @param $2 failure type
# @param $3 stack trace / failure trace
function fail {
# FIXME: excape $msg, $type and $trace before storing them into XML
msg=$( echo $1 | sed -e 's/\"/_/g' )
type=$2
trace=$3
export lastTestError=1
echo "Failure: ${msg}"
echo "<failure message=\"${msg}\" type=\"${type}\">${trace}</failure>" >> $BASH_TEST_OUTFILE
}
#======================================
# Checks if param 2 is not empty
#
# @param $1 failure message
# @param $2 result
function assertNotEmpty {
export lastTestError=0
msg=$1
actual=$2
beginTestCase NotEmpty "Check if not empty"
[ -z "$actual" ] && fail "${msg}" 'NOT EMPTY' "Expected not empty, found '${actual}' instead."
endTestCase
}
#======================================
# Check if param 2 is empty
#
# @param $1 failure message
# @param $2 result
function assertEmpty {
export lastTestError=0
msg=$1
actual=$2
beginTestCase Empty "Check if empty"
[ -z "$actual" ] || fail "${msg}" 'EMPTY' "Expected empty, found '${actual}' instead."
endTestCase
}
#======================================
# Check if param 3 is equal to parameter 2
#
# @param $1 failure message
# @param $2 expected value
# @param $3 actual value
function assertEquals {
export lastTestError=0
msg=$1
expect=$2
actual=$3
beginTestCase Equality "Check for equality"
[ "${expect}" = "${actual}" ] || fail "${msg}" 'EQUALITY' "Expected '${expect}', found '${actual}' instead."
endTestCase
}
#======================================
# Check if param 3 differs from parameter 2
#
# @param $1 failure message
# @param $2 expected value
# @param $3 actal value
function assertDiffers {
export lastTestError=0
msg=$1
expect=$2
actual=$3
beginTestCase Difference "Check for difference"
[ "${expect}" = "${actual}" ] && fail "${msg}" 'INEQUALITY' "Expected '${expect}', found '${actual}' instead."
endTestCase
}
#======================================
# Check if param 2 points to an existing file
#
# @param $1 failure message
# @param $2 file name to check
function assertExists {
export lastTestError=0
msg=$1
filename=$2
beginTestCase Existence "Check for file ${filename} existence"
[ -e "${filename}" ] || fail "${msg}" 'FILE EXISTS' "File ${filename} does not exist in filesystem."
endTestCase
}
#======================================
# Check if param 2 points to an existing regular file
#
# @param $1 failure message
# @param $2 file name to check
function assertIsFile {
export lastTestError=0
msg=$1
filename=$2
beginTestCase RegularFile "Check if file ${filename} is regular file"
[ -f "${filename}" ] || fail "${msg}" 'REGULAR FILE' "File ${filename} is not a regular file."
endTestCase
}
#======================================
# Check if param 2 points to an existing readable file
#
# @param $1 failure message
# @param $2 file name to check
function assertIsReadableFile {
export lastTestError=0
msg=$1
filename=$2
beginTestCase ReadableFile "Check if file ${filename} is readable"
[ -f "${filename}" ] || fail "${msg}" 'READABLE FILE' "File ${filename} is not a regular file."
endTestCase
}
#======================================
# Check if param 2 points to an existing directory
#
# @param $1 failure message
# @param $2 file name to check
function assertIsDirectory {
export lastTestError=0
msg=$1
filename=$2
beginTestCase Directory "Check if file '${filename}' is Directory"
[ -d "${filename}" ] || fail "${msg}" 'DIRECTORY' "File ${filename} is not a directory."
endTestCase
}
#======================================
# Check if param 2 points to an existing symbolic link
# pointing to a regular file
#
# @param $1 failure message
# @param $2 file name to check
function assertIsSymLink {
export lastTestError=0
msg=$1
filename=$2
beginTestCase SymLink "Check if file ${filename} is valid symbolic link"
[ -L "${filename}" ] || fail "${msg}" 'SYMBOLIC LINK' "File ${filename} is not a symbolic link."
[ -f $(readlink -f ${filename}) ] || fail "${msg}" 'SYMBOLIC LINK' "File ${filename} does not point to any file"
endTestCase
}
#======================================
# Check if script/command line execution is successful
#
# @param $1 failure message
# @param $2 command line
function assertScriptOk {
export lastTestError=0
msg=$1
scriptname=$2
unset IFS
beginTestCase RunScript "Check if script runs successfully"
echo "Commande: $scriptname"
$scriptname || fail "${msg}" 'SCRIPT' "Command '${scriptname}' failed to execute."
endTestCase
}
#======================================
# Check if SQL command on the given database returns the expected number of lines
#
# @param $1 failure message
# @param $2 postgresql database
# @param $3 sql script to run.
# @param $4 expected number of lines
# @param $5 optional PostgreSQL database user (defaults to postgres)
# @param $6 optional PostgreSQL database server host IP Address (defaults to 127.0.0.1)
# @param $7 optional PostgreSQL database server tcp port (defaults to 5432)
function assertPgSQLLines {
export lastTestError=0
msg=$1
database=$2
# TODO: escape SQL
sql=$(echo "$3" | sed -e 's/\\/\\\\/g' -e 's/\"/\\\"/g')
expLines=$4
sqlUser=postgres
if [ "" != "$5" ]; then
sqlUser=$5
fi
sqlHost=127.0.0.1
if [ "" != "$6" ]; then
sqlHost=$6
fi
sqlPort=5432
if [ "" != "$7" ]; then
sqlPort=$7
fi
beginTestCase SQLCountLines "Check number of returned lines for ${sql}"
lines=$(psql -U ${sqlUser} -h ${sqlHost} -p ${sqlPort} -d ${database} -c "${sql}" -Aqt | wc -l)
[ $expLines -eq $lines ] || fail "$msg" 'SQL RESULTS COUNT' "SQL Script [ ${sql} ] returned invalid rows count: $lines (expected: $expLines)."
# psql ...
endTestCase
}
# assertUserId
# Checks if a user has the expected UID.
#
function assertUserId {
export lastTestError=0
msg=$1
user=$2
expuid=$3
actuid=$(id -u $user) >> /dev/null 2>&1
if [ '' == "$actuid" ]; then
# echo "User does not exist. Test is skipped"
return;
fi
beginTestCase UserID "Check user ID for $user"
if [ "$expuid" != "$actuid" ]; then
fail "$msg" 'USER ID' "User ID for account $user is $actuid (expected: $expuid)."
fi
endTestCase
}
#
# Check if file is owned by provided user
#
function assertFileOwner {
export lastTestError=0
msg=$1
file=$2
if [ ! -e $file ]; then
echo "File $file does not exist, skipping test"
return
fi
expOwner=$(id -u $3)
if [ '' == "$expOwner" ]; then
echo "Bad owner provided. Skipping test"
return
fi
# get owner number
beginTestCase Ownership "Check ownership for ${file} is to ${expOwner}"
owner=$(stat -c %u $file)
if [ $expOwner != $owner ]; then
fail "$msg" 'FILE OWNER' "Owner of '$file' is $owner (expected: $expOwner)"
fi
endTestCase
}
function assertFileGroup {
echo "not implemented"
}
function assertFileMaxPerms {
echo "not implemented"
}
function assertFilesOwner {
unset IFS
for fic in $(find $2 -type f); do
assertFileOwner "$1" $fic "$3"
done
}
function assertFilesGroup {
unset IFS
for fic in $(find $2 -type f); do
assertFileGroup "$1" $fic "$3"
done
}
function assertFilesMaxPerms {
unset IFS
for fic in $(find $2 -type f); do
assertFileMaxPerms "$1" $fic "$3"
done
}
#======================================
# Export public functions to allow
# scripts to use them.
export -f beginTestSuite
export -f endTestSuite
export -f assertNotEmpty
export -f assertEmpty
export -f assertEquals
export -f assertDiffers
export -f assertExists
export -f assertIsFile
export -f assertIsDirectory
export -f assertIsSymLink
export -f assertScriptOk
export -f assertPgSQLLines
export -f assertFileOwner
export -f assertFileGroup
export -f assertFileMaxPerms
export -f assertFilesOwner
export -f assertFilesGroup
export -f assertFilesMaxPerms