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