[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Несколько вопросов вразброс



26.06.2012 20:14, "Артём Н." пишет:
26.06.2012 12:54, Igor Chumak пишет:
25.06.2012 18:03, "Артём Н." пишет:
Я "наворачиваю" не для того, чтобы "круто на баш написать" и не из-за проблем с
головой, а для того, чтобы попробовать TDD (или хотя бы просто unit тесты) там,
где его обычно не используют... На перспективу. Пока что, не особенно хорошо
получается. :-)


Было бы интересно посмотреть.
Да что там интересного? Я только пытаюсь, пока-что. Взял небольшую задачу,
которую требуется выполнить. Конкретно: требуется бэкап-скрипт. Но нужно
сохранять не только иерархию каталогов, но и некоторые служебные данные: LVM,
LUKS заголовки, дамп БД и т.п.. Причём, используя для бэкапа тот же самый
rdiff-backup, который используется для сохранения каталогов.
Каталоги для сохранения - в отдельном списке.
Развернуть bacula будет быстрее ;)

На очереди задачка побольше, поэтому думаю, стоит попробовать на совсем небольшом.
Для этого я сделал:
1. Функцию assert:
###TESTING
assert()
# $1 - message;
# $2 - comannd.
{
    echo "Command: $2"
    eval $2 || { echo "$1"&&  exit 1; }
    return 0;
}
###/TESTING

2. Теги ###TESTING ###/TESTING.
Не мудрствуя лукаво, реализовав обработку на awk:
#!/bin/sh

fl="$1"
fl=${-:-$fl}

awk '
    BEGIN {
       prf = 0;
    }

    /^#!\/bin\/bash/ {
       print "#!/bin/sh";
       next;
    }

    /###TESTING/ {
       prf = pfm + 1;
       next;
    }

    /###\/TESTING/ {
       if (prf == 0)
       {
          print "Error: unexpected ###\/TESTING">  "/dev/stderr";
          exit 1;
       }
       prf = prf - 1;
       next;
    }

    {
       if (prf == 0) print;
    }

    END {
       if (prf>  0)
       {
          print "Error: unclosed ###TESTING";
          exit 1;
       }
    }
' "$fl"

Это мы проверяем скрипт на связность тегов ###TESTING и ###/TESTING?
А смысл?
grep "###/*TESTING" script.sh выведет теги на экран, глаз несвязность и так заметит. Единоразово прокатит, а автоматически проверять - не вижу смысла.
3. Функцию dbg со товарищи, для вывода сообщений, соответствующих уровню
"разговорчивости":
dbg()
# $1 - verbosity level;
# $2 - message.
{
    [ "$V_LEVEL" -ge "$1" ]&&  echo "$2">  /dev/stderr
}

err()
# $1 - message.
{
    dbg 1 "$1"
    dbg 0 "Backup failed..." # failed...&&  exit 1
    return 1
}

Вложенные функции (в функции сохранения служебной информации каждое действие
оформлено маленькой функцией, вложенной в основную) проверяются модульными
тестами внутри "функции-родителя" (в тегах ###TESTING).
Каждая внешняя функция проверяется в главной функции, заменяющей реальную главную.
(Например, вызывается main, которая переопределяется в тегах ###TESTING, на
вызов тестирующей функции).

В итоге получается какой-то намёк на модульные тесты, плюс на что-то
"интегративное".

Внутри каждой тестирующей функции проверяется правильное поведение и реакция на
ошибку (в случае ошибки, функция должна возвращать свой код отличный от нуля или
$?, если была выполнена команда перед завершением). Ну и "граничные условия",
если имеются.
К примеру:
    assert "backup_kernel_conf error 0" "backup_kernel_conf bla-bla-bla...
\"$PWD/_config\"||true"
    assert "backup_kernel_conf error 1" "backup_kernel_conf \"$LINUX_CONFIG\"
\"$PWD/_config\""

Сделано грязновато, но хоть что-то... К TDD это относится мало. Разве что, я
пытаюсь вначале писать тесты.

Собственно, на этом всё.


Как-то все сложно.. Зачем TDD в обертке вокруг rdiff-backup? Я вижу процесс архивирования так:
прочитали конфиг || свалились по ошибке
запустили pre-backup скрипт || свалились по ошибке
запустили backup || свалились по ошибке
запустили post-backup скрипт || свалились по ошибке
обновили каталог || свалились по ошибке
отправили уведомления

не вижу я здесь места для 100500 вложенных функций с кучей параметров ;)




Reply to: