ЁЯФм рдзрдбрд╛ 12 тАФ Debugging рдЖрдгрд┐ testing: рдкрд╛рд╣рд╛, рд╕рд┐рджреНрдз рдХрд░рд╛
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 12 ┬╖ ЁЯОУ рд╢реЗрд╡рдЯрдЪрд╛
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рдзрдбреЗ 01тАУ12 тАФ рдкреВрд░реНрдг рдХреЛрд░реНрд╕. script рдУрд│-рдУрд│ рдЪрд╛рд▓рддрд╛рдирд╛ рдкрд╛рд╣рдгреЗ, linter, рдЖрдгрд┐ bash рдЪреНрдпрд╛ рд╕реБрдорд╛рд░реЗ рддреАрд╕ рдУрд│реАрдВрдордзрд▓рд╛ test runner тАФ рдЖрдгрд┐ capstone рдореНрд╣рдгреВрди backup.
- tests/run_tests.sh тАФ 14 checks: рдиреЛрдВрджрд╡рд╣реА tool рдЪреЗ рдпрд╢рд╛рдЪреЗ рдЖрдгрд┐ рдЕрдкрдпрд╢рд╛рдЪреЗ рдорд╛рд░реНрдЧ, backup рдЪрд╛ dry run, verification, rotation рдЖрдгрд┐ lock
- bin/backup.sh тАФ рдЬреНрдпрд╛рдЪрд╛ test рд╣реЛрдд рдЖрд╣реЗ рддреА рдЧреЛрд╖реНрдЯ
ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ
рдХреЗрдЕрд░рдЯреЗрдХрд░ рдХрд╛рд╣реАрддрд░реА рд╡рд┐рдЪрд┐рддреНрд░ рдХрд░рддреЛ рддреЗрд╡реНрд╣рд╛ рддреБрдореНрд╣реА рддреНрдпрд╛рд▓рд╛ рдкреНрд░рддреНрдпреЗрдХ рдЖрджреЗрд╢ рдХрд░рддрд╛рдирд╛ рддреЛ рдореЛрдареНрдпрд╛рдиреЗ
рдореНрд╣рдгрд╛рдпрд▓рд╛ рд╕рд╛рдВрдЧрддрд╛ тАФ bash -x. рд░рд╛рддреНрд░реА рдШрдВрдЯрд╛ рдХрд╛рд░реНрдбреЗ рдЪрд╛рд▓рд╡рдгреНрдпрд╛рдЖрдзреА рддреА рдмрд░реЛрдмрд░ рдЖрд╣реЗрдд рдпрд╛рдЪреА
рдЦрд╛рддреНрд░реА рдХрд░рд╛рдпрдЪреА рдЕрд╕реЗрд▓, рддрд░ рддреБрдореНрд╣реА рдкреНрд░рддреНрдпреЗрдХрд╛рдЪреА рддрд╛рд▓реАрдо рдШреЗрддрд╛ рдЖрдгрд┐ рддреБрд▓рдирд╛ рдХрд░рддрд╛ тАФ рдЬреЗ рдЭрд╛рд▓реЗ
рдЖрдгрд┐ рдЬреЗ рд╡реНрд╣рд╛рдпрд▓рд╛ рд╣рд╡реЗ рд╣реЛрддреЗ рддреНрдпрд╛рдЪреА: рд╣рд╛рдЪ test. bash рдордзрд▓рд╛ test рдореНрд╣рдгрдЬреЗ
рдлрдХреНрдд: command рдЪрд╛рд▓рд╡рд╛, рддреНрдпрд╛рдЪреЗ output рдЖрдгрд┐ exit code рдкрд╛рд╣рд╛, pass рдореЛрдЬрд╛.
framework рдЖрд╡реГрддреНрддреАрд▓рд╛ bats рдореНрд╣рдгрддрд╛рдд; рдХрд▓реНрдкрдирд╛ рдПрдХрд╛ рдХрд╛рд░реНрдбрд╡рд░ рдорд╛рд╡рддреЗ.
ЁЯЧ║я╕П рдЖрдХреГрддреА
flowchart LR
T["check 'name' 'wanted' \"$(cmd)\""] --> C{"got contains wanted?"}
C -->|yes| P["тЬЕ pass++"]
C -->|no| F["тЭМ fail++ ┬╖ show wanted vs got"]
P & F --> S["N passed, M failed ┬╖ exit 1 if any failed"]
тЭУ рдХрд╛рдп
bash -x script.shрдкреНрд░рддреНрдпреЗрдХ command рдЪрд╛рд▓рд╡рд▓реНрдпрд╛рдкреНрд░рдорд╛рдгреЗ, expand рдХрд░реВрди рдЫрд╛рдкрддреЛ. рдПрдХрд╛ block рднреЛрд╡рддреАset -x/set +x.PS4='+ ${BASH_SOURCE}:${LINENO}: 'file рдЖрдгрд┐ рдУрд│ рдЬреЛрдбрддреЛ.bash -nрдлрдХреНрдд syntax рддрдкрд╛рд╕рддреЛ.bash -vрдУрд│реА expand рди рдХрд░рддрд╛ рдЫрд╛рдкрддреЛ.shellcheck: unquoted variables,[рд╡рд┐рд░реБрджреНрдз[[, рдирд┐рд░реБрдкрдпреЛрдЧреАcat,-rрд╢рд┐рд╡рд╛рдпread, dead code. рддреЛ CI рдордзреНрдпреЗ рдЪрд╛рд▓рд╡рд╛.- test рдореНрд╣рдгрдЬреЗ: рдПрдХ рдирд╡рд╛ fixture (рдкреНрд░рддреНрдпреЗрдХ run рд╕рд╛рдареА temp рдиреЛрдВрджрд╡рд╣реА), command, рдПрдХ
рддреБрд▓рдирд╛ (output рдордзреНрдпреЗ рдЖрд╣реЗ, рдХрд┐рдВрд╡рд╛ exit code рдмрд░реЛрдмрд░ рдЖрд╣реЗ), рдПрдХ рдореЛрдЬрдгреА, CI рд╕рд╛рдареА рдПрдХ
exit code. рдЕрдкрдпрд╢рд╛рдЪреЗ рдорд╛рд░реНрдЧ test рдХрд░рд╛ тАФ
set -eрддреЗ рдХрд░рдд рдирд╛рд╣реА. bats:@test "name" { run cmd; [ "$status" -eq 0 ]; [[ "$output" == *x* ]]; }тАФ рддреЛрдЪ рдЖрдХрд╛рд░, setup/teardown рдЖрдгрд┐ TAP output рд╕рд╣.
ЁЯдФ рдХрд╛
"рдЪрд╛рд▓рдгрд╛рд░реА" script рддрд┐рдЪреНрдпрд╛ рд▓реЗрдЦрдХрд╛рдиреЗ рдлрдХреНрдд рдпрд╢рд╛рдЪреНрдпрд╛ рдорд╛рд░реНрдЧрд╛рд╡рд░ рдЪрд╛рд▓рд╡рд▓реЗрд▓реА рдЕрд╕рддреЗ. рджреЗрдЦрд░реЗрдЦреАрд╢рд┐рд╡рд╛рдп рдЪрд╛рд▓рдгрд╛рд▒реНрдпрд╛ scripts рдирд╛ рдмрд╛рдХреА рд╕рдЧрд│реЗ рдорд╛рд░реНрдЧ рднреЗрдЯрддрд╛рдд. рдЪреМрджрд╛ рдЫреЛрдЯреЗ checks regression рдШрдВрдЯреЗрдЪреНрдпрд╛ рдЖрдзреА рдкрдХрдбрддрд╛рдд.
ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)
run_tests.sh: check() [[ "$got" == *"$want"* ]] рдиреЗ рддреБрд▓рдирд╛ рдХрд░рддреЗ;
exit_code() $? рдкрдХрдбрддреЗ; trap рд╕рд╣ mktemp рдордзреВрди temp рдиреЛрдВрджрд╡рд╣реА;
backup tests temp --dest рд╡рд╛рдкрд░рддрд╛рдд, rotation рд╕рд╛рдареА рддреАрдирджрд╛ рдЪрд╛рд▓рддрд╛рдд, рдЖрдгрд┐
рдирдХрд╛рд░ рд╕рд┐рджреНрдз рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА lock рд╣рд╛рддрд╛рдиреЗ рдмрдирд╡рддрд╛рдд; рд╢реЗрд╡рдЯрдЪреА рдУрд│ [[ $fail -eq 0 ]]
рд╣рд╛ CI рд╡рд╛рдЪрддреЛ рддреЛ exit code рдЖрд╣реЗ.
ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛
bash tests/run_tests.sh
bash -x bin/school.sh list --class 3A 2>&1 | head -12 # every expansion, every command
PS4='+ ${LINENO}: ' bash -x bin/school.sh report 2>&1 | grep '^+' | head -5
command -v shellcheck && shellcheck bin/*.sh lib/*.sh tests/*.sh && echo "shellcheck clean"
# break something on purpose, watch a test catch it:
sed -i.bak 's/valid_class "\$class" || die/true || die/' bin/school.sh; bash tests/run_tests.sh | grep -E 'тЭМ|passed'; mv bin/school.sh.bak bin/school.sh
тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ
14 passed, 0 failed рдЖрдгрд┐ exit 0; trace рдордзреНрдпреЗ values рднрд░рд▓реЗрд▓реНрдпрд╛ + local class=, + tail,
+ grep рдУрд│реА рджрд┐рд╕рддрд╛рдд; рдореБрджреНрджрд╛рдо рдмрд┐рдШрдбрд╡рд▓реНрдпрд╛рд╡рд░ рдиреЗрдордХрд╛ рдПрдХрдЪ test
fail рд╣реЛрддреЛ (enrol rejects a bad class) рдЖрдгрд┐ рд╕рд╛рд░рд╛рдВрд╢ 13 passed, 1 failed рд╕рд╛рдВрдЧрддреЛ;
file рдкреВрд░реНрд╡рд╡рдд рдХреЗрд▓реНрдпрд╛рд╡рд░ рдкреБрдиреНрд╣рд╛ рд╣рд┐рд░рд╡реЗ рд╣реЛрддреЗ.
ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ
рддреБрдореНрд╣реА рдХреЛрдгрддреНрдпрд╛рд╣реА script рд▓рд╛ рд╡рд┐рдЪрд╛рд░ рдХрд░рддрд╛рдирд╛ рдкрд╛рд╣реВ рд╢рдХрддрд╛, рддрд┐рд▓рд╛ lint рдХрд░реВ рд╢рдХрддрд╛, рдЖрдгрд┐ рдЕрдкрдпрд╢рд╛рдЪреНрдпрд╛ рдорд╛рд░реНрдЧрд╛рддрд▓рд╛ regression рдкрдХрдбрдгрд╛рд░рд╛ test рд▓рд┐рд╣реВ рд╢рдХрддрд╛ тАФ bash рдкрд▓реАрдХрдбреЗ рдХреЛрдгрддреНрдпрд╛рд╣реА tools рд╢рд┐рд╡рд╛рдп.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- рдлрдХреНрдд рдпрд╢рд╛рдЪрд╛ рдорд╛рд░реНрдЧ test рдХрд░рдгреЗ. рджреЗрдЦрд░реЗрдЦреАрд╢рд┐рд╡рд╛рдп рдЪрд╛рд▓рдгрд╛рд▒реНрдпрд╛ scripts рдЕрдкрдпрд╢рд╛рдЪреНрдпрд╛ рдорд╛рд░реНрдЧрд╛рдВрд╡рд░рдЪ рддреБрдЯрддрд╛рдд.
- рдЦрд░реА data file рд╡рд╛рдкрд░рдгрд╛рд░реЗ tests. рдиреЗрд╣рдореА fixtures.
- 300 рдУрд│реАрдВрдЪреНрдпрд╛ script рд╡рд░
PS4рдУрд│ рдХреНрд░рдорд╛рдВрдХрд╛рдВрд╢рд┐рд╡рд╛рдпbash -xoutput рд╡рд╛рдЪрдгреЗ.
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: deploy script рд╕реБрджреНрдзрд╛ code рдЖрд╣реЗ. рддрд┐рд▓рд╛ рдЗрддрд░ рд╕рдЧрд│реНрдпрд╛рдВрд╕рд╛рд░рдЦрд╛ linter, tests рдЖрдгрд┐ CI job рдорд┐рд│рддреЛ, рдирд╛рд╣реАрддрд░ рдкрд╣рд╛рдЯреЗ 3 рд╡рд╛рдЬрддрд╛ page рдпреЗрддреЛ.
ЁЯПЖ Capstone
backup.sh scheduled, locked, rotated, verified рдЖрдгрд┐ tested рдЖрд╣реЗ. рдПрдХ
feature рд╕реБрд░реБрд╡рд╛рддреАрдкрд╛рд╕реВрди рд╢реЗрд╡рдЯрдкрд░реНрдпрдВрдд рдЬреЛрдбрд╛: --include data/*.csv (рдПрдХрдЪ рдирд╛рд╣реА, рдкреНрд░рддреНрдпреЗрдХ рдиреЛрдВрджрд╡рд╣реАрдЪрд╛ backup),
рдпрд╢рд╛рдЪреНрдпрд╛ рдорд╛рд░реНрдЧрд╛рд╕рд╛рдареА рдПрдХ test рдЖрдгрд┐ рдЪреБрдХреАрдЪреНрдпрд╛ pattern рд╕рд╛рдареА рдПрдХ test рд╕рд╣. рдордЧ рддреЛ
cron рдХрд┐рдВрд╡рд╛ CI schedule рдордзреВрди рдПрдХ рдЖрдард╡рдбрд╛ рдЪрд╛рд▓рд╡рд╛ рдЖрдгрд┐ log рд╡рд╛рдЪрд╛.
ЁЯОУ рдХреЛрд░реНрд╕ рдкреВрд░реНрдг рдЭрд╛рд▓рд╛
рдЕрднреНрдпрд╛рд╕ рдпреЛрдЬрдирд╛ рдмрд╛рд░рд╛рд╣реА рдзрдбреНрдпрд╛рдВрд╡рд░ рдЦреВрдг рдХрд░рддреЗ; quiz рддреЗ рддрдкрд╛рд╕рддреЗ; CI/CD рд╢рд╛рд│рд╛ рдпрд╛ scripts рдкреНрд░рддреНрдпреЗрдХ push рд╡рд░ рдЪрд╛рд▓рд╡рддреЗ, рдЖрдгрд┐ School portal рд╡рд░ certificate рдЖрд╣реЗ.