Added 'make headers_check', 'make checkstack' and 'make namespacecheck'.
[mirror/scst/.git] / scripts / run-regression-tests
1 #!/bin/bash
2
3 ############################################################################
4 #
5 # Script for running those SCST regression tests that can be run automatically.
6 #
7 # Copyright (C) 2008 Bart Van Assche <bart.vanassche@gmail.com>
8 #
9 # This program is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU General Public License
11 # as published by the Free Software Foundation, version 2
12 # of the License.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 ############################################################################
20
21 ############################################################################
22 # This script performs the following actions:
23 # - Creates a temporary directory for storing the output of the regression
24 #   tests. No existing files are modified by this script.
25 # - Verifies whether the top-level *.patch files apply cleanly to the SCST
26 #   tree.
27 # - Duplicates the entire source tree to the temporary directory and
28 #   compiles the SCST source code.
29 # - Duplicates the entire source tree to the temporary directory, applies
30 #   the full-perf patches and again compiles the SCST source code.
31 # - Checks whether the kernel version specified through option -k is present
32 #   in the directory specified through option -c.
33 # - If the source code of the kernel specified through -k is not present,
34 #   download it.
35 # - Convert the SCST source code into a kernel patch.
36 # - Extract the kernel sources.
37 # - Run checkpatch on the SCST kernel patch.
38 # - Apply the SCST kernel patch to the kernel tree.
39 # - Run 'make allmodconfig'.
40 # - Run the sparse source code checker on the SCST directory.
41 # - Run 'make headers_check'.
42 # - Compile the kernel tree.
43 # - Run 'make checkstack'.
44 # - Run 'make namespacecheck'.
45 #
46 # Note: the results of the individual steps are not verified by this script
47 # -- the output generated by the individual steps has to be verified by
48 # reviewing the output files written into the temporary directory.
49 ############################################################################
50
51
52 ########################
53 # Function definitions #
54 ########################
55
56 function usage {
57   echo "Usage: $0 [-c] [-h] [-k <kver1>] [-k <kver2>] ..."
58   echo "        -c - cache directory for Linux kernel tarballs."
59   echo "        -h - display this help information."
60   echo "        -k <kver> - kernel version to use during test."
61 }
62
63 # First three components of the kernel version number.
64 function kernel_version {
65   if [ "${1#[0-9]*.[0-9]*.[0-9]*.[0-9]*}" != "$1" ]; then
66     echo "${1%.[0-9]*}"
67   else
68     echo "$1"
69   fi
70 }
71
72 # Last component of the kernel version, or the empty string if $1 has only
73 # three components.
74 function patchlevel {
75   if [ "${1#[0-9]*.[0-9]*.[0-9]*.}" = "$1" ]; then
76     echo ""
77   else
78     echo "${1#[0-9]*.[0-9]*.[0-9]*.}"
79   fi
80 }
81
82 # Create a linux-$1 tree in the current directory, where $1 is a kernel
83 # version number with either three or four components.
84 function extract_kernel_tree {
85   local kver="$(kernel_version $1)"
86   local plevel="$(patchlevel $1)"
87   local tmpdir=kernel-tree-tmp-$$
88
89   rm -rf "linux-$1" "${tmpdir}"
90   mkdir "${tmpdir}" || return $?
91   (
92     cd "${tmpdir}" || return $?
93     tar xjf "${kernel_sources}/linux-${kver}.tar.bz2" || return $?
94     cd "linux-${kver}" || return $?
95     if [ "${plevel}" != "" ]; then
96       bzip2 -cd "${kernel_sources}/patch-$1.bz2" | patch -p1 -f -s || return $?
97     fi
98     cd ..
99     mv "linux-${kver}" "../linux-$1"
100   )
101   rmdir "${tmpdir}"
102 }
103
104 # Test whether the *.patch files in the SCST top-level directory apply cleanly
105 # to the SCST tree. Does not modify any files nor produce any output files.
106 function test_scst_tree_patches {
107   echo "Testing whether the SCST patches apply cleanly to the SCST tree ..."
108   for p in *.patch
109   do
110     patch -p0 -f --dry-run -s <$p >&/dev/null \
111     || echo "ERROR: patch $p does not apply cleanly."
112   done
113 }
114
115 # Copy the entire SCST source code tree except the regression-* directories
116 # from "$1" into the current directory.
117 function duplicate_scst_source_tree {
118   if [ -e "$1/AskingQuestions" ]; then
119     tar -C "$1" --exclude=regression-* -c -f - . | tar -x -f -
120   else
121     return 1
122   fi
123 }
124
125 # Compile the unpatched SCST source code.
126 function compile_scst_unpatched {
127   local scst="$PWD"
128   local outputfile="${outputdir}/compilation-output-unpatched.txt"
129   local workingdirectory="${outputdir}/scst-unpatched"
130
131   echo "Testing whether the SCST tree compiles fine ..."
132   (
133     if mkdir -p "${workingdirectory}"  \
134        && cd "${workingdirectory}"     \
135        && duplicate_scst_source_tree "${scst}"  \
136        && (make -s clean \
137            && make -s scst iscsi-scst  \
138            && if "${scst_local}" = "true" ; then make -C scst_local clean; fi \
139            && if "${scst_local}" = "true" ; then make -C scst_local -s   ; fi \
140            && if "${mpt_scst}"   = "true" ; then make -C mpt clean; fi \
141            && if "${mpt_scst}"   = "true" ; then make -C mpt -s   ; fi \
142            && make -C srpt -s clean    \
143            && make -C srpt -s )    \
144            >& "${outputfile}"
145     then
146       true
147     else
148       echo "FAILED"
149     fi
150   )
151 }
152
153 # Test out-of-tree compilation agains the kernel header files in
154 # /lib/modules/$(uname -r)/build.
155 function compile_scst_patched {
156   local scst="$PWD"
157   local outputfile="${outputdir}/compilation-output-patched.txt"
158   local workingdirectory="${outputdir}/scst-patched"
159
160   echo "Testing whether the full-perf SCST tree compiles fine ..."
161   (
162     if mkdir -p "${workingdirectory}"  \
163        && cd "${workingdirectory}"     \
164        && duplicate_scst_source_tree "${scst}"  \
165        && patch -p0 -f -s <"${scst}/iscsi-full_perf.patch"    \
166        && patch -p0 -f -s <"${scst}/qla2x00t-full_perf.patch" \
167        && patch -p0 -f -s <"${scst}/scst-full_perf.patch"     \
168        && (make -s clean               \
169            && make -s scst iscsi-scst  \
170            && if "${scst_local}" = "true" ; then make -C scst_local clean; fi \
171            && if "${scst_local}" = "true" ; then make -C scst_local -s   ; fi \
172            && if "${mpt_scst}"   = "true" ; then make -C mpt clean; fi \
173            && if "${mpt_scst}"   = "true" ; then make -C mpt -s   ; fi \
174            && make -C srpt -s clean    \
175            && make -C srpt -s )    \
176           >& "${outputfile}"
177     then
178       true
179     else
180       echo "FAILED"
181     fi
182   )
183 }
184
185 # Download the file from URL $1 and save it in the current directory.
186 function download_file {
187   if [ ! -e "$(basename "$1")" ]; then
188     echo "Downloading $1 ..."
189     if ! wget -q -nc "$1"; then
190       echo "Downloading $1 failed."
191       return 1
192     fi
193   fi
194 }
195
196 # Make sure the kernel tarball and patch file are present in directory
197 # ${kernel_sources}. Download any missing files from ${kernel_mirror}.
198 function download_kernel {
199   local kver="$(kernel_version $1)"
200   local plevel="$(patchlevel $1)"
201
202   mkdir -p "${kernel_sources}" || return $?
203   test -w "${kernel_sources}" || return $?
204   (
205     cd "${kernel_sources}" || return $?
206     download_file "${kernel_mirror}/linux-$(kernel_version $1).tar.bz2" \
207       || return $?
208     if [ "${plevel}" != "" ]; then
209       download_file "${kernel_mirror}/patch-$1.bz2" || return $?
210     fi
211   )
212 }
213
214 # Generate a kernel patch from the SCST source tree for kernel version $1.
215 function generate_kernel_patch {
216   scripts/generate-kernel-patch \
217     $([ "${scst_local}" = "true" ] && echo -- "-l") \
218     $([ "${mpt_scst}"   = "true" ] && echo -- "-m") \
219     $([ "${qla2x00t}"   = "true" ] && echo -- "-q") \
220     $1
221 }
222
223 # Generate a kernel patch through scripts/generate-kernel-patch and test
224 # whether it applies cleanly to kernel version $1. Leaves a vanilla kernel
225 # in directory "${outputdir}/linux-$1" at exit.
226 function test_if_patch_applies_cleanly {
227   local kver="$(kernel_version $1)"
228   local plevel="$(patchlevel $1)"
229   local outputfile="${outputdir}/kernel-$1-patch-output.txt"
230   local rc=0
231
232   echo "Testing whether the generated kernel patch applies cleanly to $1 ..."
233   ( cd "${outputdir}" && extract_kernel_tree "$1" )
234   generate_kernel_patch $1 \
235   | (cd "${outputdir}/linux-$1" && patch -p1 --dry-run -f >& "${outputfile}")
236   if [ $? != 0 ]; then
237     echo "FAILED"
238     rc=1
239   fi
240   return $rc
241 }
242
243 # Run checkpatch on the generated kernel patch. Assumes that there is a
244 # vanilla kernel tree present in directory "${outputdir}/linux-$1", and leaves
245 # this kernel tree clean.
246 function run_checkpatch  {
247   local kver="$(kernel_version $1)"
248   local plevel="$(patchlevel $1)"
249   local outputfile="${outputdir}/checkpatch-$1-output.txt"
250
251   echo "Running checkpatch version $1 on the SCST kernel patch ..."
252   generate_kernel_patch $1 \
253   | (cd "${outputdir}/linux-$1" && scripts/checkpatch.pl - >& "${outputfile}")
254   # For now, only display checkpatch errors.
255   local errors=$(grep -c '^ERROR' "${outputfile}")
256   local warnings=$(grep -c '^WARNING' "${outputfile}")
257   echo "${errors} errors / ${warnings} warnings."
258   return 0
259 }
260
261 function patch_and_configure_kernel {
262   local patchfile="${outputdir}/scst-$1-kernel.patch"
263
264   echo "Patching and configuring kernel $1 ..."
265   generate_kernel_patch "$1" > "${patchfile}"
266   (
267     cd "${outputdir}/linux-$1"                                  \
268     && patch -p1 -f -s <"${patchfile}"                          \
269                        >"${outputdir}/patch-command-output.txt" \
270     && make -s allmodconfig &>/dev/null
271   )
272 }
273
274 # Patches and compiles a kernel tree. Assumes that there is a vanilla kernel
275 # tree present in directory "${outputdir}/linux-$1".
276 function compile_patched_kernel {
277   local kver="$(kernel_version $1)"
278   local plevel="$(patchlevel $1)"
279   local outputfile="${outputdir}/kernel-$1-compilation-output.txt"
280
281   echo "Compiling kernel $1 ..."
282   (
283     (
284       cd "${outputdir}/linux-$1" \
285       && LC_ALL=C make -s -k -j3 bzImage modules
286     )
287   ) >& "${outputfile}"
288   echo "See also ${outputfile}."
289   return 0
290 }
291
292 # Run the source code verification tool 'sparse' on the SCST code. Assumes that
293 # there is a patched kernel tree present in directory "${outputdir}/linux-$1".
294 function run_sparse {
295   local kver="$(kernel_version $1)"
296   local plevel="$(patchlevel $1)"
297   local outputfile="${outputdir}/sparse-$1-output.txt"
298
299   echo "Running sparse on the patched $1 kernel ..."
300   (
301     cd "${outputdir}/linux-$1" \
302     && make -s prepare \
303     && make -s scripts \
304     && LC_ALL=C make -k C=2 M=drivers/scst
305   ) >& "${outputfile}"
306   echo "See also ${outputfile}."
307   return 0
308 }
309
310 function run_checkstack {
311   local kver="$(kernel_version $1)"
312   local plevel="$(patchlevel $1)"
313   local outputfile="${outputdir}/checkstack-$1-output.txt"
314
315   echo "Running checkstack on the patched $1 kernel ..."
316   (
317     cd "${outputdir}/linux-$1" \
318     && make -s prepare \
319     && make -s scripts \
320     && LC_ALL=C make -k checkstack
321   ) >& "${outputfile}"
322   echo "See also ${outputfile}."
323   return 0
324 }
325
326 function run_namespacecheck {
327   local kver="$(kernel_version $1)"
328   local plevel="$(patchlevel $1)"
329   local outputfile="${outputdir}/namespacecheck-$1-output.txt"
330
331   echo "Running namespacecheck on the patched $1 kernel ..."
332   (
333     cd "${outputdir}/linux-$1" \
334     && make -s prepare \
335     && make -s scripts \
336     && LC_ALL=C make -k namespacecheck
337   ) >& "${outputfile}"
338   echo "See also ${outputfile}."
339   return 0
340 }
341
342 function run_headers_check {
343   local kver="$(kernel_version $1)"
344   local plevel="$(patchlevel $1)"
345   local outputfile="${outputdir}/headers_check-$1-output.txt"
346
347   echo "Running headers check on the patched $1 kernel ..."
348   (
349     cd "${outputdir}/linux-$1" \
350     && make -s prepare \
351     && make -s scripts \
352     && LC_ALL=C make -k headers_check
353   ) >& "${outputfile}"
354   echo "See also ${outputfile}."
355   return 0
356 }
357
358
359 #########################
360 # Argument verification #
361 #########################
362
363 if [ ! -e scst -o ! -e iscsi-scst -o ! -e srpt ]; then
364   echo "Please run this script from inside the SCST subversion source tree."
365   exit 1
366 fi
367
368 # Where to store persistenly downloaded kernel tarballs and kernel patches.
369 kernel_sources="$HOME/software/downloads"
370 # URL for downloading kernel tarballs and kernel patches.
371 kernel_mirror="ftp://ftp.eu.kernel.org/pub/linux/kernel/v2.6"
372 kernel_versions=""
373 # Directory in which the regression test output files will be stored.
374 outputdir=$PWD/regression-test-output-$(date +%Y-%m-%d_%Hh%Mm%Ss)
375 # Driver configuration.
376 mpt_scst="false"
377 qla2x00t="false"
378 scst_local="true"
379
380 set -- $(/usr/bin/getopt "c:hk:" "$@")
381 while [ "$1" != "${1#-}" ]
382 do
383   case "$1" in
384     '-c') kernel_sources="$2"; shift; shift;;
385     '-h') usage; exit 1;;
386     '-k') kernel_versions="${kernel_versions} $2"; shift; shift;;
387     '--') shift;;
388     *)    usage; exit 1;;
389   esac
390 done
391
392 if [ $# != 0 ]; then
393   usage
394   exit 1
395 fi
396
397 # Default kernel versions to use for the test.
398 if [ "${kernel_versions}" = "" ]; then
399   #kernel_versions="2.6.24.7 2.6.25.20 2.6.26.8 2.6.27.7"
400   kernel_versions="2.6.27.7"
401 fi
402
403
404 ####################
405 # Regression tests #
406 ####################
407
408 rm -rf "${outputdir}"
409 mkdir -p "${outputdir}" || exit $?
410
411 test_scst_tree_patches || exit $?
412 compile_scst_unpatched || exit $?
413 compile_scst_patched || exit $?
414
415 for k in ${kernel_versions}
416 do
417   if download_kernel $k && test_if_patch_applies_cleanly $k; then
418     run_checkpatch $k
419     patch_and_configure_kernel $k
420     run_sparse $k
421     run_headers_check $k
422     compile_patched_kernel $k
423     run_checkstack $k
424     run_namespacecheck $k
425   else
426     echo "FAILED for kernel $k"
427   fi
428 done