Lustre Script Coding Style: Difference between revisions
Jump to navigation
Jump to search
(→Bash Style: minor improvements) |
(→Subtests: add tests/except dir) |
||
| (18 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
== Bash Style == | == Bash Style == | ||
* Bash is a programming language. It includes functions. Shell code outside of functions is effectively code in an implicit main() function. An entire function should be fully seen on one page (~70-90 lines) and be readily comprehensible. If you have any doubts, then it is too complicated. Make it easier to understand by separating it into subroutines. | * Bash is a programming language. It includes functions. Shell code outside of functions is effectively code in an implicit main() function. An entire function should be fully seen on one page (~70-90 lines) and be readily comprehensible. If you have any doubts, then it is too complicated. Make it easier to understand by separating it into subroutines. | ||
* Scripts should start with <code>#!/usr/bin/bash</code>, unless they need to run in MacOS Terminals, which need <code>/bin/bash</code>. | |||
* The total length of a line (including comment) must not exceed 80 characters. Take advantage of bash's <code>+=</code> operator for constants or linefeed escapes <code>\</code>. | * The total length of a line (including comment) must not exceed 80 characters. Take advantage of bash's <code>+=</code> operator for constants or linefeed escapes <code>\</code>. | ||
* Lines can be split without the need for a linefeed escape after <code>|</code>, <code>||</code>, <code>&</code> and <code>&&</code> operators. | ** Lines can be split without the need for a linefeed escape after <code>|</code>, <code>||</code>, <code>&</code> and <code>&&</code> operators at the end of the line. | ||
* The indentation must use 8-column tabs and not spaces. For line continuation, an additional tab should be used to indent the continued line, or align after <code>[</code> or <code>(</code> for continued logic operations. | * The indentation must use 8-column tabs and not spaces. For line continuation, an additional tab should be used to indent the continued line, or align after <code>[</code> or <code>(</code> for continued logic operations. | ||
* Comments are just as important in a shell script as in C code. | * Comments are just as important in a shell script as in C code. | ||
* Use <code>$(...)</code> instead of <code>`...`</code> for subshell commands: | |||
* Use <code>$(...)</code> instead of <code>`...`</code> for subshell commands | ** <code>$(...)</code> is easier to see the start and end of the subshell command | ||
** <code>$(...)</code> avoids confusion between <code>'...'</code> and <code>`...`</code> with a small font | |||
** <code>$(...)</code> can be nested | |||
* Use the subshell syntax only when necessary: | |||
** When you need to capture the output of a separate program | |||
** Using the construct with functions leads to stray output and/or convoluted code struggling to avoid output pollution | |||
** It is more computationally efficient to not fork() the Bash process. Bash is slow enough already. | |||
* Use "here string" like <code>function <<<$var</code> instead of <code>echo $var | function</code> to avoid forking a subshell and pipe | * Use "here string" like <code>function <<<$var</code> instead of <code>echo $var | function</code> to avoid forking a subshell and pipe | ||
* Use built-in Bash [https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html Parameter Expansion] for variable/string manipulation rather than forking sed/tr | * Use file arguments like <code>awk '...' $file</code> or input redirection like <code>function << $file</code> instead of a [http://porkmail.org/era/unix/award.html useless use of <code>cat</code>] | ||
* Use built-in Bash [https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html Parameter Expansion] for variable/string manipulation rather than forking <code>sed/tr</code>: | |||
** Use <code>${VAR#prefix}</code> or <code>${VAR%suffix}</code> to remove <code>prefix</code> or <code>suffix</code> respectively | |||
** Use <code>${VAR/pattern/string}</code> to replace <code>pattern</code> with </code>string</code> instead of <code>echo $VAR | sed</code> | |||
* Avoid use of "<code>grep foo | awk '{ print $2 }'</code>" since "<code>awk '/foo/ { print $2 }'</code> works just as well and avoids a separate fork + pipe | * Avoid use of "<code>grep foo | awk '{ print $2 }'</code>" since "<code>awk '/foo/ { print $2 }'</code> works just as well and avoids a separate fork + pipe | ||
* If a variable is intended to be used as a boolean, then it must be assigned as | * If a variable is intended to be used as a boolean, then it must be assigned as follows: | ||
<nowiki> | <nowiki> | ||
local mybool=false # or true | local mybool=false # or true | ||
if $mybool; then | |||
if $mybool; then | |||
fi | do_stuff | ||
fi | |||
</nowiki> | </nowiki> | ||
* for loops it is possible to avoid a subshell for <code>$(seq 10)</code> using the built-in iterator for fixed-length loops | * for loops it is possible to avoid a subshell for <code>$(seq 10)</code> using the built-in iterator for fixed-length loops: | ||
** Unfortunately, <code>{1..$var}</code> does not work, so use the <code>(( ... ))</code> arithmetic operator | |||
<nowiki> | <nowiki> | ||
for i | for ((i=0; i < $var; i++)); do | ||
something_with $i | |||
done | done | ||
</nowiki> | </nowiki> | ||
* Use <code>export FOOBAR=val</code> instead of <code>FOOBAR=val; export FOOBAR</code> for clarity and simplicity | * Use <code>export FOOBAR=val</code> instead of <code>FOOBAR=val; export FOOBAR</code> for clarity and simplicity | ||
* Use <code><nowiki>[[ expr ]]</nowiki></code> instead of <code><nowiki>[ expr ]</nowiki></code> | * Use <code><nowiki>[[ expr ]]</nowiki></code> for bash instead of <code><nowiki>[ expr ]</nowiki></code> | ||
* Use <code>$((...))</code> for | ** The <code>[[</code> test understands regular expression matching with the <code>=~</code> operator | ||
* Use <code> | ** The easiest way to use it is by putting the expression in a variable and expanding it after the operator without quotes. | ||
* Use <code><nowiki>(( expr ))</nowiki></code> instead of <code><nowiki>[ expr ]</nowiki></code> or <code>let expr</code> when evaluating numerical expressions | |||
** This can include mathematical operators like <code>$((...))</code> | |||
** Will properly compare numeric values, unlike <code>[[ ... ]]</code> that is comparing strings | |||
<nowiki> | |||
# wrong: this is surprisingly "true" because '5' > '3' and the rest of the string is ignored | |||
[[ 5 > 33 ]] && echo "y" || echo "n" | |||
y | |||
# right: this is what you expect for the '>' operator | |||
(( 5 > 33 )) && echo "y" || echo "n" | |||
n | |||
</nowiki> | |||
** This uses normal <code><=</code>, <code>>=</code>, <code>==</code> comparisons instead of <code>-lt</code>, <code>-eq</code>, <code>-gt</code> | |||
** Can use <code><nowiki>for (( i=0; i <= END; i++ )); do</nowiki></code> and other numerical expressions instead of an external subshell for <code>seq</code> | |||
* Use <code>$((...))</code> for arithmetic expressions instead of <code>expr ...</code> | |||
** No need for <code>$</code> when referencing variable names inside <code>$((...))</code> | |||
** <code>$((...))</code> can handle hex values and common math operators | |||
* Error checks should prefer the form <code><nowiki>[[ check ]] || action</nowiki></code> to avoid leaving a dangling "false" on the return stack | |||
** Otherwise, <code><nowiki>[[ check ]] && action</nowiki></code> will leave a dangling "false" on the stack if <code>check</code> fails and an immediately following return/end of function will return an error | |||
== Test Framework == | == Test Framework == | ||
=== Variables === | === Variables === | ||
* Names of variables local to current | * Names of variables local to current test function which are not exported to the environment should be declared with "<code>local</code>" and use lowercase letters | ||
* Names of global variables or variables that exported to the environment should be | * Names of global variables or variables that are exported to the environment should be UPPERCASE letters | ||
* Use <code>$TMP/</code> for temporary non-Lustre files instead of <code>/tmp/</code> | |||
* Use <code>$SECONDS</code> to get the current time when measuring test ''durations'' instead of <code>$(date +%s)</code> fork+exec: | |||
<nowiki> | |||
local start=$SECONDS | |||
do something | |||
local elapsed=$((SECONDS - start)) | |||
</nowiki> | |||
or | |||
<nowiki> | |||
local end=$((SECONDS + delay)) | |||
while ((SECONDS < end)); do | |||
something | |||
done | |||
</nowiki> | |||
=== Functions === | === Functions === | ||
| Line 46: | Line 94: | ||
# expected output and/or return value(s) | # expected output and/or return value(s) | ||
</nowiki> | </nowiki> | ||
* Function arguments should be given local variable names for clarity, rather than being used as <code>$1 $2 $3</code> in the function | |||
<nowiki> | |||
local facet=$1 | |||
local file="$2" | |||
local size=$3 | |||
</nowiki> | |||
* Use <code>sleep 0.1</code> instead of <code>usleep 100000</code>, since <code>usleep</code> is RHEL-specific | |||
=== Tests and Libraries === | === Tests and Libraries === | ||
* To avoid clustering a single <code>test-framework.sh</code> file, there should be a <code><nowiki><test-lib>.sh</nowiki></code> file for each test that contains specific functions and variables for that test. | * To avoid clustering a single <code>test-framework.sh</code> file, there should be a <code><nowiki><test-lib>.sh</nowiki></code> file for each test that contains specific functions and variables for that test. | ||
* Any functions, variables that global to all tests should be put in <code>test-framework.sh</code> | * Any functions, variables that global to all tests should be put in <code>test-framework.sh</code> | ||
* A test file only need to source <code>test-framework.sh</code> and necessary <code><nowiki><test-lib>.sh</nowiki></code> file | * A test file only need to source <code>test-framework.sh</code> and necessary <code><nowiki><test-lib>.sh</nowiki></code> file | ||
=== Subtests === | |||
* subtest names/numbers are not strictly meaningful in themselves, but there are some conventions that should be followed | |||
** prefer subtest numbers below 1000 by convention | |||
*** some wrapper scripts (e.g. sanity-compr.sh) run other scripts like sanity.sh and sanityn.sh as well as their own subtests | |||
** it is convenient to cluster related tests together when adding new subtests | |||
*** easier to find related subtests to determine if there is coverage for some functionality | |||
*** adding subtests in different parts of the script (instead of at the end) avoids needless context patch conflicts | |||
*** adding subtests with disjoint numbers avoids semantic test numbering conflicts | |||
** when adding subtests at the end of the file it is convenient to leave occasional gaps in the numbering (e.g. 100, 150, 200 instead of 33, 34, 35,) | |||
*** this leaves room for other subtests to be added with fewer context/number conflicts | |||
* '''do not''' mix pure numbered subtests with suffixes for the same number (e.g. 56 and 56a) | |||
** test-framework.sh allows running groups of subtests together (e.g. all 56X subtests), but if there is also plain-numbered subtest (e.g. 56) then it cannot be run in isolation | |||
** if a numbered subtest is growing a new variant, rename the original subtest to the <code>a</code> suffix (e.g. 56->56a) then add the new variant with the <code>b</code> suffix | |||
** if the plain a-z suffixes are occupied or you want to make a variant of an already-suffixed subtest, use <code>aa</code>, <code>ab</code> (or <code>ea</code> or similar) and locate it after <code>a</code> (or <code>e</code>) | |||
** continue a-z suffixes with A-Z, but do not add aa, ab, etc. '''after''' the z or Z suffix to avoid clashes of subtest names | |||
* subtests should not reference their test number explicitly, since the subtest name may change in the future (for various reasons). | |||
** the <code>$testnum</code> variable holds the test number (e.g. <code>11</code> or <code>27M</code>) | |||
** the <code>$TESTNAME</code> variable holds the test name (e.g. <code>test_27</code>) | |||
* test files should be named <code>$tfile</code> for the filename, or base name like <code>$tfile.1</code> or <code>$tfile.source</code> to simplify debugging | |||
* test directories should be named <code>$tdir</code>, and should be used insetad of <code>$DIR</code> if more than a handful files are created for the subtest | |||
* small/few test files/dirs do not need to be explicitly deleted at the end of the test, that is done by test-framework.sh at the start/end of each test script | |||
* large (over 1MB)/many (over 50) test files/dirs in a subtest should be cleaned up explicitly with a <code>stack_trap</code> so that they are always cleaned up even if the test exits with an error, and do not fill the test filesystem | |||
<nowiki> | |||
stack_trap "rm -f $DIR/$tfile.big" | |||
fallocate -l 100M $DIR/$tfile.big || error "$tfile.big create failed" | |||
stack_trap "unlinkmany $DIR/$tdir/$tfile- 1000" | |||
createmany -o $DIR/$tdir/$tfile- 1000 || error "$tfile creation failed" | |||
</nowiki> | |||
* creating large test files is by far the fastest with "fallocate" *when supported* (ldiskfs only), as determined by <code>check_set_fallocate</code> | |||
** fallocate'd files will only produce zeroes when read, so it is not useful where the data contents are used since it is identical to a sparse file except by allocated blocks | |||
* use <code>test_mkdir</code> to add some variety to directory creation (random local, striped, remote) if directory location is not critical to the test | |||
* ensure that directory location and MDS facet are aligned. Since 2.14.54 directories may be created on any MDT, so "<code>do_facet mds1 ...</code>" may be on the wrong MDS. | |||
* Use "<code>mkdir_on_mdt0 $DIR/$tdir</code>" if necessary to create directories on MDT0000 for use with <code>mds1</code>, or preferentially "<code>$LFS getdirstripe -m $DIR/$tdir</code>" to determine MDT index, and "<code>mds$((idx+1))</code>" for facet name. | |||
* the <code>error</code> messages in a subtest should be unique so that it is easy to determine which check failed | |||
<nowiki> | |||
lfs migrate -c3 $tfile || error "'lfs migrate -c3' failed" | |||
lfs migrate -c1 $tfile || error "second 'lfs migrate -c1' failed" | |||
</nowiki> | |||
* use <code>skip</code> to skip subtests that should not run because of permanent functional deficiency (e.g. non-existent functionality in backing filesystem, older version of client/server, wrong configuration) | |||
<nowiki> | |||
(( MDS1_VERSION_CODE >= $(version_code 2.17.58.63) )) || | |||
skip "need MDS >= 2.15.53 to check foobar works" | |||
[[ $mds1_FSTYPE == "ldiskfs" ]] || skip "MDT0000 is not ldiskfs" | |||
</nowiki> | |||
* version checks for interoperability depend on where the change being tested runs: | |||
** a subtest for a server-side change should check the server version against the version of the patched build itself, as reported by <code><nowiki>git describe --match "[0-9]*"</nowiki></code> on the patch (e.g. <code>2.17.58-63-g1234abc</code> is <code>2.17.58.63</code>), and never the next release, since that would skip the subtest on the patched build. Use <code>MDS1_VERSION</code> for an MDS-side change, and <code>OST1_VERSION</code> for an OST-side change | |||
** a subtest for a client-only change that is tested on the local client does not need a version check, since the tests are run from the client's own lustre-tests package | |||
** a subtest for a change that is exercised on another client node should check the version of that node, e.g. with <code>$(version_code $(lustre_build_version_node $node))</code> | |||
** if a patch is making a change that causes an old client to fail against a new server, then an exception can be added in <code>lustre/tests/except/$TEST_SCRIPT.ex</code> | |||
* use <code>skip_env</code> for minor environmental deficiency in developer test environment (e.g. missing binary) that _should_ exist in autotest: | |||
<nowiki> | |||
kinit || skip_env "Kerberos not installed" | |||
</nowiki> | |||
* when subtests are run in a loop with <code>ONLY_REPEAT=N</code> or <code>ONLY_MINUTES=M</code> then <code>$ONLY_REPEAT_ITER</code> holds the iteration number (1-based). In some cases this can be useful for adapting the test case to handle running many iterations in a row (e.g. adding <code>wait_delete_completed</code>) that isn't needed when run in isolation. | |||
[[Category: Development]] | [[Category: Development]] | ||
Latest revision as of 02:53, 1 October 2026
Bash Style
- Bash is a programming language. It includes functions. Shell code outside of functions is effectively code in an implicit main() function. An entire function should be fully seen on one page (~70-90 lines) and be readily comprehensible. If you have any doubts, then it is too complicated. Make it easier to understand by separating it into subroutines.
- Scripts should start with
#!/usr/bin/bash, unless they need to run in MacOS Terminals, which need/bin/bash. - The total length of a line (including comment) must not exceed 80 characters. Take advantage of bash's
+=operator for constants or linefeed escapes\.- Lines can be split without the need for a linefeed escape after
|,||,&and&&operators at the end of the line.
- Lines can be split without the need for a linefeed escape after
- The indentation must use 8-column tabs and not spaces. For line continuation, an additional tab should be used to indent the continued line, or align after
[or(for continued logic operations. - Comments are just as important in a shell script as in C code.
- Use
$(...)instead of`...`for subshell commands:$(...)is easier to see the start and end of the subshell command$(...)avoids confusion between'...'and`...`with a small font$(...)can be nested
- Use the subshell syntax only when necessary:
- When you need to capture the output of a separate program
- Using the construct with functions leads to stray output and/or convoluted code struggling to avoid output pollution
- It is more computationally efficient to not fork() the Bash process. Bash is slow enough already.
- Use "here string" like
function <<<$varinstead ofecho $var | functionto avoid forking a subshell and pipe - Use file arguments like
awk '...' $fileor input redirection likefunction << $fileinstead of a useless use ofcat - Use built-in Bash Parameter Expansion for variable/string manipulation rather than forking
sed/tr:- Use
${VAR#prefix}or${VAR%suffix}to removeprefixorsuffixrespectively - Use
${VAR/pattern/string}to replacepatternwith string instead ofecho $VAR | sed
- Use
- Avoid use of "
grep foo | awk '{ print $2 }'" since "awk '/foo/ { print $2 }'works just as well and avoids a separate fork + pipe - If a variable is intended to be used as a boolean, then it must be assigned as follows:
local mybool=false # or true
if $mybool; then
do_stuff
fi
- for loops it is possible to avoid a subshell for
$(seq 10)using the built-in iterator for fixed-length loops:- Unfortunately,
{1..$var}does not work, so use the(( ... ))arithmetic operator
- Unfortunately,
for ((i=0; i < $var; i++)); do
something_with $i
done
- Use
export FOOBAR=valinstead ofFOOBAR=val; export FOOBARfor clarity and simplicity - Use
[[ expr ]]for bash instead of[ expr ]- The
[[test understands regular expression matching with the=~operator - The easiest way to use it is by putting the expression in a variable and expanding it after the operator without quotes.
- The
- Use
(( expr ))instead of[ expr ]orlet exprwhen evaluating numerical expressions- This can include mathematical operators like
$((...)) - Will properly compare numeric values, unlike
...that is comparing strings
- This can include mathematical operators like
# wrong: this is surprisingly "true" because '5' > '3' and the rest of the string is ignored
[[ 5 > 33 ]] && echo "y" || echo "n"
y
# right: this is what you expect for the '>' operator
(( 5 > 33 )) && echo "y" || echo "n"
n
- This uses normal
<=,>=,==comparisons instead of-lt,-eq,-gt - Can use
for (( i=0; i <= END; i++ )); doand other numerical expressions instead of an external subshell forseq
- This uses normal
- Use
$((...))for arithmetic expressions instead ofexpr ...- No need for
$when referencing variable names inside$((...)) $((...))can handle hex values and common math operators
- No need for
- Error checks should prefer the form
[[ check ]] || actionto avoid leaving a dangling "false" on the return stack- Otherwise,
[[ check ]] && actionwill leave a dangling "false" on the stack ifcheckfails and an immediately following return/end of function will return an error
- Otherwise,
Test Framework
Variables
- Names of variables local to current test function which are not exported to the environment should be declared with "
local" and use lowercase letters - Names of global variables or variables that are exported to the environment should be UPPERCASE letters
- Use
$TMP/for temporary non-Lustre files instead of/tmp/ - Use
$SECONDSto get the current time when measuring test durations instead of$(date +%s)fork+exec:
local start=$SECONDS
do something
local elapsed=$((SECONDS - start))
or
local end=$((SECONDS + delay))
while ((SECONDS < end)); do
something
done
Functions
- Each function must have a section describing what it does and explain the list of parameters
# One line description of this function's purpose
#
# More detailed description of what the function is doing if necessary
#
# usage: function_name [--option argument] {required_argument} ...
# option: meaning of "option" and its argument
# required_argument: meaning of "required_argument"
#
# expected output and/or return value(s)
- Function arguments should be given local variable names for clarity, rather than being used as
$1 $2 $3in the function
local facet=$1
local file="$2"
local size=$3
- Use
sleep 0.1instead ofusleep 100000, sinceusleepis RHEL-specific
Tests and Libraries
- To avoid clustering a single
test-framework.shfile, there should be a<test-lib>.shfile for each test that contains specific functions and variables for that test. - Any functions, variables that global to all tests should be put in
test-framework.sh - A test file only need to source
test-framework.shand necessary<test-lib>.shfile
Subtests
- subtest names/numbers are not strictly meaningful in themselves, but there are some conventions that should be followed
- prefer subtest numbers below 1000 by convention
- some wrapper scripts (e.g. sanity-compr.sh) run other scripts like sanity.sh and sanityn.sh as well as their own subtests
- prefer subtest numbers below 1000 by convention
- it is convenient to cluster related tests together when adding new subtests
- easier to find related subtests to determine if there is coverage for some functionality
- adding subtests in different parts of the script (instead of at the end) avoids needless context patch conflicts
- adding subtests with disjoint numbers avoids semantic test numbering conflicts
- when adding subtests at the end of the file it is convenient to leave occasional gaps in the numbering (e.g. 100, 150, 200 instead of 33, 34, 35,)
- this leaves room for other subtests to be added with fewer context/number conflicts
- it is convenient to cluster related tests together when adding new subtests
- do not mix pure numbered subtests with suffixes for the same number (e.g. 56 and 56a)
- test-framework.sh allows running groups of subtests together (e.g. all 56X subtests), but if there is also plain-numbered subtest (e.g. 56) then it cannot be run in isolation
- if a numbered subtest is growing a new variant, rename the original subtest to the
asuffix (e.g. 56->56a) then add the new variant with thebsuffix - if the plain a-z suffixes are occupied or you want to make a variant of an already-suffixed subtest, use
aa,ab(oreaor similar) and locate it aftera(ore) - continue a-z suffixes with A-Z, but do not add aa, ab, etc. after the z or Z suffix to avoid clashes of subtest names
- subtests should not reference their test number explicitly, since the subtest name may change in the future (for various reasons).
- the
$testnumvariable holds the test number (e.g.11or27M) - the
$TESTNAMEvariable holds the test name (e.g.test_27)
- the
- test files should be named
$tfilefor the filename, or base name like$tfile.1or$tfile.sourceto simplify debugging - test directories should be named
$tdir, and should be used insetad of$DIRif more than a handful files are created for the subtest - small/few test files/dirs do not need to be explicitly deleted at the end of the test, that is done by test-framework.sh at the start/end of each test script
- large (over 1MB)/many (over 50) test files/dirs in a subtest should be cleaned up explicitly with a
stack_trapso that they are always cleaned up even if the test exits with an error, and do not fill the test filesystem
stack_trap "rm -f $DIR/$tfile.big"
fallocate -l 100M $DIR/$tfile.big || error "$tfile.big create failed"
stack_trap "unlinkmany $DIR/$tdir/$tfile- 1000"
createmany -o $DIR/$tdir/$tfile- 1000 || error "$tfile creation failed"
- creating large test files is by far the fastest with "fallocate" *when supported* (ldiskfs only), as determined by
check_set_fallocate- fallocate'd files will only produce zeroes when read, so it is not useful where the data contents are used since it is identical to a sparse file except by allocated blocks
- use
test_mkdirto add some variety to directory creation (random local, striped, remote) if directory location is not critical to the test - ensure that directory location and MDS facet are aligned. Since 2.14.54 directories may be created on any MDT, so "
do_facet mds1 ..." may be on the wrong MDS. - Use "
mkdir_on_mdt0 $DIR/$tdir" if necessary to create directories on MDT0000 for use withmds1, or preferentially "$LFS getdirstripe -m $DIR/$tdir" to determine MDT index, and "mds$((idx+1))" for facet name. - the
errormessages in a subtest should be unique so that it is easy to determine which check failed
lfs migrate -c3 $tfile || error "'lfs migrate -c3' failed"
lfs migrate -c1 $tfile || error "second 'lfs migrate -c1' failed"
- use
skipto skip subtests that should not run because of permanent functional deficiency (e.g. non-existent functionality in backing filesystem, older version of client/server, wrong configuration)
(( MDS1_VERSION_CODE >= $(version_code 2.17.58.63) )) ||
skip "need MDS >= 2.15.53 to check foobar works"
[[ $mds1_FSTYPE == "ldiskfs" ]] || skip "MDT0000 is not ldiskfs"
- version checks for interoperability depend on where the change being tested runs:
- a subtest for a server-side change should check the server version against the version of the patched build itself, as reported by
git describe --match "[0-9]*"on the patch (e.g.2.17.58-63-g1234abcis2.17.58.63), and never the next release, since that would skip the subtest on the patched build. UseMDS1_VERSIONfor an MDS-side change, andOST1_VERSIONfor an OST-side change - a subtest for a client-only change that is tested on the local client does not need a version check, since the tests are run from the client's own lustre-tests package
- a subtest for a change that is exercised on another client node should check the version of that node, e.g. with
$(version_code $(lustre_build_version_node $node)) - if a patch is making a change that causes an old client to fail against a new server, then an exception can be added in
lustre/tests/except/$TEST_SCRIPT.ex
- a subtest for a server-side change should check the server version against the version of the patched build itself, as reported by
- use
skip_envfor minor environmental deficiency in developer test environment (e.g. missing binary) that _should_ exist in autotest:
kinit || skip_env "Kerberos not installed"
- when subtests are run in a loop with
ONLY_REPEAT=NorONLY_MINUTES=Mthen$ONLY_REPEAT_ITERholds the iteration number (1-based). In some cases this can be useful for adapting the test case to handle running many iterations in a row (e.g. addingwait_delete_completed) that isn't needed when run in isolation.