Linux - де-факто является мировым стандартом для серверных операционных систем (хотя необходимость размещать серверные компоненты на Windows-серверах всё же существует и её нельзя отрицать). В виду этого многие тест-инженеры тратят значительную часть своего времени, выполняя задачи ручного тестирования в Linux средах с использованием удаленного подключения по ssh через терминал. Существует ряд принципов, команд и хитростей, которые могут помочь повысить эффективность выполнения подобных задач. О них мы сегодня и поговорим:
- Понимание концепции привилегий и разрешений
- Эффективная навигация по каталогам
- Объединение нескольких команд в одну
- Анализ иерархии процессов
- Мониторинг содержимого каталога
- Использование переменных окружения
- Использование эффективных фильтров с grep
- "Трогаем" файлы с touch. Зачем нам это нужно?
- Мониторинг логов при помощи tail
- Поиск дополнительных логов
Рассмотрим каждый пункт более детально.
Понимание концепции привилегий и разрешений
Когда вы выполняете задачи ручного тестирования в Linux, ваше тестируемое приложение может испытвать проблемы с доступом к некоторым файлам или устройствам (которые также являются файлами в Linux). Бывает также, что вам необходимо намеренно создать такие проблемы. Понимание концепции разрешений и привилегий может поднять эффективность тестирования и локализации проблем на качественно новый уровень.
Если вы создадите файл в каком-ибо каталоге и затем взглянете на содержимое этого каталога командой ls -la
, вы скорее всего увидите что-то подобное:
drwxr-xr-x 2 alexey alexey 4096 may 29 14:38 . drwxr-xr-x 3 alexey alexey 4096 may 29 14:38 .. -rw-r--r-- 1 alexey alexey 0 may 29 14:38 myFile
Вывод, который мы видим, состоит из 7 колонок:
Параметры доступа к файлу (разрешения)
Количество "жёстких" ссылок к элементу
Имя пользователя, ассоциированное с элементом
Группа пользователей, ассоциированная с элементом
Размер элемента
Дата последнего изменения элемента
Имя элемента
Кроме самого файла, в результирующем списке мы видим еще два элемента:
.
и..
. Элемент.
определяет текущий каталог, в котором находятся просматриваемые файлы. Элемент..
определяет родительский каталог в котором находится просматриваемый каталог.
Нам, в основном, интересно содержимое колонок 1
, 3
и 4
потому что как раз они и определяют кто может иметь доступ к файлу, а кто нет.
Каждое значение в колонке 1
состоит из 10 позиций. Первая позиция показывает нам является ли запись каталогом или нет. Для каталогов на первой позиции стоит значение d
.
Что всё это означает?
Следующие 9 позиций разделены на 3 группы привилегий. Первая группа определяет что владелец (колонка номер 3
) файла может с ним делать, вторая группа определяет что может делать с файлом группа пользователей (колонка номер 4
), ассоциированная с этим файлом, третья же группа привилегий определяет что могут делать с файлом все остальные пользователи.
Каждая группа привилегий состоит из 3-х позиций: разрешение на чтение (read), разрешение на запись (write) и разрешение на выполнение (execute). Если разрешение включено, позиция заполняется соответствующей буквой, если нет - прочерком (-
).
Если разрешение на выполнение (execute) активировано для каталога, это означает, что пользователь может в этот каталог "зайти".
Если взглянуть на пример выше, мы можем увидеть, что файл не имеет знака d
в первой позиции (т.к. это действительно не каталог), файл ассоциирован с владельцем alexey
и группой пользователей, названной alexey
(каждый пользователь в Linux имеет собственную группу, названную по имени этого пользователя). Владелец может читать из файла, а также писать в него (но не исполнять - исходя из позиций привилегий rw-
). Пользователям из группы alexey
разрешено только читать из файла (r--
), как и всем остальным пользователям (r--
). Давайте изменим это положение вещей.
Изменение привилегий в Linux
Пример: Для файла, созданного нами ранее, мы хотим изменить некоторые привилегии доступа. Допустим, в нашей системе существует группа пользователей, названная
webelementclick
. Только пользователям из этой группы (кроме самого владельца) должно быть разрешено чтение из файла. Все остальные пользователи не должны иметь на файл никаких прав.
Для того чтобы реализовать задумку, нам потребуются две команды: chgrp
для изменения группы пользователей, с которой файл ассоциируется, и chmod
для изменения самих привилегий. Вы также можете изменить и владельца файла, используя команду chown
, но для наших текущих целей в этом нет необходимости. Итак, давайте попробуем изменить группу, снова взглянем на содержимое каталога и посмотим что же изменилось.
sudo chgrp webelementclick myFile ls -la total 8 drwxr-xr-x 2 alexey alexey 4096 may 29 14:38 . drwxr-xr-x 3 alexey alexey 4096 may 29 14:38 .. -rw-r--r-- 1 alexey webelementclick 0 may 29 14:38 myFile
Мы можем увидеть, что единственной вещью, которая поменялась стала группа, ассоциированная с нашим файлом (колонка 4
). Теперь нам необходимо изменить привилегии, используя команду chmod
. Но как мы сообщим Linux какие разрешения включить, а какие выключить?
Сообщаем мы это передавая команде chmod
соответствующие аргумент. Аргумент этот имеет формат XYZ. Где X определяет чьи привилегии мы будем менять. Возможно одно из трёх значений: u
означает, что мы будем менять привилегии владеющего файлом пользователя (user); g
означает, что менять мы будем привилегии, данные ассоциированной с файлом группе пользователей (group); o
- все остальные пользователя (other users). Y может принимать значение +
если мы хотим добавить привилегию, либо -
если мы хотим убрать привилегию. Z определяет какую именно привилегию мы хотим изменить. Для Z возможны следующие значения: r
- хотим изменить привилегию чтения (read), w
- хотим изменить привилегию записи (write), x
- хотим изменить привилегию запуска (execute).
В нашем примере нам необходимо убрать привилегию чтения у остальных пользователей. Что означает, что мы должны выполнить команду chmod o-r myFile
которую можно прочитать как "Изменить привилегии для файла myFile
таким образом, что все остальные пользователи (o
), которые не являются владельцем файла alexey
, а также не входят в группу пользователей webelementclick
потеряют привилегию (-
) на чтение (r
) данного файла".
Давайте ещё раз взглянем на содержимое нашего каталога:
drwxr-xr-x 2 alexey alexey 4096 may 29 14:38 . drwxr-xr-x 3 alexey alexey 4096 may 29 14:38 .. -rw-r----- 1 alexey webelementclick 0 may 29 14:38 myFile
Мы можем видеть, что ключ r
, который заполнял 8-ю позицию, теперь изменился на -
, что означает, что "все остальные пользователи" не имеют никакого доступа к файлу (---
).
Эффективная навигация по каталогам
Тестировщикам, работающим с ветвистой структурой каталогов необходимо иметь удобный способ навигации по такой структуре, а также способ быстрого перехода в некоторые части этой структуры, где работа происходит чаще чем в других местах. В любом из этих случаев не лишним будет знать в каком каталоге вы находитесь в текущий момент. Узнать это можно с помощью команды pwd
:
alexey@master-host:~$ pwd /home/alexey
Автозаполнение при помощи кнопки Tab
Так как выполняя задачи ручного тестирования в терминале Linux у вас нет возможности использовать графический интерфейс, вы можете испытывать неудобства, работая с длинными именами файлов, каталогов или команд. К счастью, оболочка bash предлагает решение этой проблемы.
Если вы начнете набирать имя файла или название команды, и затем нажмете tab
, bash найдет все файлы в текущем каталоге, начинающиеся с введенной вами части (либо доступные команды) и автоматически дополнит введенную часть до места, где в результирующем наборе появится расхождение. Если результат автозаполнения не соответствует команде, которую вы хотите набрать, вам следует добавить символы, которые помогут оболочке различить какую команду из нескольких подходящих вы имели в виду.
В случае, когда bash определил несколько подходящих результатов, соответствующих изначальному вводу, вы можете нажать
tab
дважды, чтобы посмотреть список доступных вариантов.
Допустим, что в нашем распоряжении есть такой каталог:
drwxr-xr-x 2 alexey alexey 4096 may 30 13:29 . drwxr-xr-x 3 alexey alexey 4096 may 29 14:38 .. -rw-r----- 1 alexey webelementclick 0 may 29 14:38 myFile -rw-r--r-- 1 alexey alexey 0 may 30 13:29 myFile.backup
Предположим также, что мы хотели бы просмотреть содержимое файла myFile.backup
, используя для этого команду cat
. Мы можем набрать в командной строке часть команды cat my
и нажать клавишу tab
. После нажатия на tab
, bash автоматически дополнит команду до cat myFile
, т.к. ему не известно имели ли мы в виду файл myFile
, или файл myFile.backup
потому как оба этих файла начинаются с одинаковой последовательности символов. Т.к. мы хотим указать второй файл, мы добавляем к тому, что уже заполнила система, символ .
(при этом введенная часть команды в командной строке будет выглядеть так: cat myFile.
) и снова нажимаем клавишу tab
. Теперь bash точно знает что мы имеем ввиду, ведь других файлов, начинающихся с myFile.
в каталоге нет. Это позволяет ему дополнить команду до конца.
Овладев этой нехитрой техникой, вы сможете многократно повысить эффективность работы с файлами и командами.
Навигационные ярлыки (шорткаты)
Linux (кое-где в паре с оболочкой bash) предоставляет ряд "ярлыков", упрощающих навигацию по структуре каталогов системы. Такими "шорткатами" являются ~
(способ, предоставляемый оболочкой bash), .
и ..
. Шорткат ~
ведет в домашний каталог текущего пользователя. Если в вашем домашнем каталоге есть файл (например myFile
), то доступ к нему вы сможете получить используя путь ~/myFile
в каком бы каталоге вы в данный момент не находились.
Шорткаты .
и ..
уже обсуждались ранее. Они ссылаются на текущий и на родительский каталоги соответственно. Вы можете комбинировать эти шорткаты для построения эффективных путей. Например, если вы хотите перейти в родительский каталог вашего домашнего каталога, вы можете использовать команду cd ~/..
(опять же из любого текущего положения).
Вы можете создавать свои собственные ярлыки, называемые "мягкими ссылками" (soft links) или "символьными ссылками" (symbolic links). Хорошем решением является размещение таких ссылок в домашнем каталоге (доступном через шорткат ~
).
Например, представьте, что существует некий каталог, расположенный где-то в глубине файловой структуры (/mnt/mywork/mainfolder
), и вам необходимо часто выполнять в нем некоторые задачи. Вы можете создать ссылку, которая бы располагалась в домашнем каталоге и имела бы простое имя (например - main
) используя следующую команду:
ln -s /mnt/mywork/mainfolder ~/main
Теперь вы можете перейти в каталог /mnt/mywork/mainfolder
из любого места, используя команду cd ~/main
Объединение нескольких команд в одну
Когда инженер-тестировщик выполняет задачи ручного тестирования в операционной системе Linux, часто бывает полезным объединять несколько команд в одну таким образом, что выход предыдущей команды будет сразу подаваться на вход следующей. Такой вид склеивания выполняется при помощи символа |
.
Наиболее часто встречающейся задачей, где такая склейка может пригодиться, является фильтрация вывода с использованием команды grep
. Например команда cat mylog | grep error
будет разбита на две части: cat mylog
выведет содержимое файла mylog
. Команда grep error
отфильтрует все данные поданные на вход таким образом, что на выходе останутся, только строки, содержащие подстроку error
. Символ |
означает, что данные, выведенные командой cat mylog
будут перенаправлены на вход команды grep error
.
Такое объединение может включать сколь угодно много звеньев. Например при тестировании часто бывает необходимым просматривать файлы (в том числе и уже отфильтрованные), размером многократно превышающие размеры окна терминала. Для больших файлов имеет смысл использовать команду less
, которая позволяет прокручивать содержимое файла используя клавиши Up
, Down
, PgUp
и PgDown
. В таком случае команда может выглядеть так:
cat mylog | grep error | less
Пример выше состоит из трёх подкоманд: cat mylog
выводит всё содержимое файла, grep error
оставляет только строки включающие подстроку error
, а less
берёт отфильтрованный вывод и оборачивает его в удобный механизм прокрутки.
Анализ иерархии процессов
Когда вы выполняете ручное тестирование в среде Linux, вы можете сталкиваться с необходимостью контролировать состояние процессов в системе. Linux предлагает довольно мощный инструмент для такого рода задач, а именно - команду ps
. Иногда тестировщику бывает необходимо узнать, какое место в общей иерархии занимает тот или иной процесс. Это бывает полезно в том случае, если вам необходимо принудительно завершить целую ветку процессов, имеющих общего родителя. Зная идентификатор такого родителя, вы можете принудительно завершить только его. Остальные при этом завершатся автоматически.
Для команды ps
существует специальный ключ --forest
, сообщающий утилите, что вывод необходимо отформатировать в виде иерархии. Например результат выполнения команды ps -a --forest
будет выглядеть так:
PID TTY TIME CMD 28670 pts/0 00:00:00 ps 1957 tty2 00:00:00 gnome-session-b 2061 tty2 00:05:35 \_ gnome-shell 2106 tty2 00:00:09 | \_ ibus-daemon 2110 tty2 00:00:00 | | \_ ibus-dconf 2362 tty2 00:00:02 | | \_ ibus-engine-sim 5706 tty2 00:00:00 | \_ idea.sh 5771 tty2 00:15:33 | \_ java 5855 tty2 00:00:03 | \_ fsnotifier64 6237 tty2 00:00:13 | \_ java 27809 tty2 00:00:05 | \_ java 2182 tty2 00:00:00 \_ gsd-power 2183 tty2 00:00:00 \_ gsd-print-notif
Если дерево слишком велико, вы опять же можете объединить команду вывода списка процессов с командой less
, как было показано в ранее: ps -a --forest | less
. Это позволит вам использовать удобный механизм прокрутки результата вывода команды ps
.
Мониторинг содержимого каталога
Ещё одной стандартной задачей при выполнении ручного тестирования является мониторинг содержимого каталога. К примеру, вам может быть интересен момент появления некоторого файла в каталоге или изменение свойств такого файла. Linux предоставляет инструмент наблюдения за чем либо - команду watch
. Такая команда принимает любую другую в качестве аргумента и последовательно её запускает с некоторыми заданными интервалами (равными по умолчанию 2-м секундам).
В случае необходимости использовать её для мониторинга содержимого каталога, вы можете выполнить следующую команду в командной строке вашего терминала: watch ls -la
.
Использование переменных окружения
Одним из стандартных подходов к реализации независимости приложения от среды исполнения является использование так называемых переменных окружения. Когда приложению необходимо узнать значение той или иной настройки в данной конкретной среде исполнения (например, путь к каталогу в котором приложению разрешено сохранять свои отчеты), приложение обращается к системной функции чтения переменной окружения (с заранее определенным именем), установленной в данной конкретной среде ответственным лицом (например devops инженером).
Наверняка вы ранее встречались с подобными переменными (такими переменными являются, например, JAVA_HOME
или PATH
). Если вы выполняете задачи ручного тестирования, вам, возможно, приходилось сталкиваться с необходимостью запуска тестируемого приложения с различным набором значений переменных окружения. Далее мы взглянем на ряд моментов, позволяющих повысить эффективность взаимодействия с этим инструментом.
Пять вещей, которые необходимо знать при работе с переменными окружения
-
Значение для переменной окружения устанавливаемся с помощью команды
export
в форматеexport VAR_NAME=VAR_VALUE
. -
При задании значения для переменной окружения могут быть использованы значения других переменных. Например
export MY_VAR=Hello
установит значениеHello
для переменной с именемMY_VAR
. Дальнейшее выполнение командыexport MY_OTHER_VAR="$MY_VAR, World!"
установит значениеHello, World!
для переменнойMY_OTHER_VAR
. -
Если вы используете значение некоторой переменной внутри значения некоторой другой переменной, может случиться так, что вам понадобится добавить символы в значение новой переменной сразу после значения существующей. Для того чтобы дать знать оболочке bash где заканчивается имя переменной, а где начинается добавленный текст, используется следующая конструкция:
export MY_VAR=Hel
,export MY_OTHER_VAR=${MY_VAR}lo
. -
Значение переменной можно получить либо обращением
$VAR_NAME
либо обращением${VAR_NAME}
(см. пример выше). Например, вы можете вывести значение переменнойMY_VAR
, используя командуecho
одним из следующий способов: либоecho $MY_VAR
либоecho ${MY_VAR}
. -
Когда для установки значения переменной вы используете команду
export
, все процессы, порожденные из командной строки либо скрипта, в котором эта команда была вызвана, наследуют значение установленное для переменной. Таким образом, имея несколько скриптов, устанавливающих разный набор переменных и запускающих одно и то же приложение, вы сможете иметь несколько параллельно работающих в различных условиях приложений.
Использование эффективных фильтров с grep
Мы уже упоминали команду grep
когда говорили об объединении команд. Команда grep
в повседневной практике ручного тестирования в Linux встречается, пожалуй, чаще остальных. В комбинации с cat
(вывод содержимого файлов) и, возможно, less
(вывод в режиме прокрутки содержимого), команда grep
предлагает действительно мощный механизм для анализа логов или конфигурационных файлов. Ниже я покажу несколько хитростей, которые помогут вам повысить эффективность выполнения подобных задач.
В качестве примера мы будем использовать файл
myTest.log
со следующим содержимым:DEBUG 13:43:59 Running in dev mode INFO 13:44:01 Reading value a: 5.25 INFO 13:44:02 Reading value b: 0.0 INFO 13:44:02 Evaluating division ERROR 13:44:03 Division by zero error! INFO 13:44:04 Sending email report.. DEBUG 13:44:04 Mail subj: "INFORMATION ABOUT SERVICE FAILURE"Такой лог достаточно репрезентативен с точки зрения тех нюансов, которые мы собираемся рассмотреть.
Простой случай
Вы можете посмотреть на все записи, содержащие подстроку DEBUG
используя следующую команду:
cat myTest.log | grep DEBUG
Очень просто. По умолчанию поиск регистрозависимый. Это означает, что команда выше найдет записи, содержащие слово DEBUG
, но не найдет записей со словом debug
(в нижнем регистре). Чтобы изменить такое поведение, вы можете использовать ключ -i
. Таким образом, для того, чтобы найти и записи с DEBUG
и записи с debug
, вам будет необходимо выполнить такую команду:
cat myTest.log | grep -i DEBUG
Если вам нужно найти строки по некоторой последовательности, содержащей пробелы, такую последовательность надо будет взять в кавычки:
cat myTest.log | grep "Evaluating division"
Отображаем близлежащие данные
При помощи grep
вы можете отобразить некоторый контекст для каждого результата, найденного командой. Используя ключи -B
(before) и -A
(after) вы можете указать количество строк, отображаемых до и после найденной по указанному условию информации. Например, если вы хотите отображать 3
строчки до и 1
строчку после каждой записи, содержащей подстроку ERROR
, вы можете использовать такую команду:
cat myTest.log | grep -B3 -A1 ERROR
Усиливаем поиск регулярными выражениями
Поисковая строка, передаваемая в grep
в качестве аргумента, может быть трактована утилитой несколькими различными способами: либо как фиксированная строка либо как регулярное выражение. Кроме того, регулярные выражения также могут делиться на различные типы. В различных реализациях утилиты grep
может поддерживаться различный набор таких типов (воспользуйтесь командой man grep
для получения помощи по вашей версии утилиты). Мы же будем говорить о реализации, называемой GNU grep. Такая утилита поставляется с большинством свободно распространяемых сборок ОС Linux.
Пример, описанный выше, содержит намеренную ловушку. Когда мы используем команду
cat myTest.log | grep DEBUG
мы получаем то, что ожидаем потому как словоDEBUG
появляется только в колонке, отвечающей за тип сообщения. Однако, если бы мы использовали тот же самый запрос, но для типа сообщенийINFO
мы бы получили такой результат:INFO 13:44:01 Reading value a: 5.25 INFO 13:44:02 Reading value b: 0.0 INFO 13:44:02 Evaluating division INFO 13:44:04 Sending email report.. DEBUG 13:44:04 Mail subj: "INFORMATION ABOUT SERVICE FAILURE"Последнюю запись мы вряд ли ожидали бы здесь увидеть, однако она включается в результирующий вывод, потому как слово
INFORMATION
начинается с подстрокиINFO
.
Использование языка регулярных выражений может помочь нам построить более точные поисковые запросы. Однако покрытие даже базовых аспектов этого языка - тема для отдельной объемной статьи, поэтому здесь я просто покажу несколько примеров, которые помогут вам увидеть ценность такого подхода.
Следующая команда покажет вам только те записи, которые начинаются с подстроки INFO
(символ ^
означает начало строки, поэтому ^INFO
не сматчится с последней строкой, представляющей дебаг-сообщение):
cat myTest.log | grep ^INFO
А вот более сложный пример, отображающий все записи, имеющие временную отметку 13:44
(здесь мы используем классы символов):
cat myTest.log | grep ^[[:alpha:]]*[[:space:]]*13:44
Кстати, ничто не мешает вам объединять команду
grep
с другими командамиgrep
. Например:cat myTest.log | grep ^INFO | grep [[:digit:]]$покажет вам записи, начинающиеся с
INFO
и заканчивающиеся цифрой ($
обозначает конец строки).
"Трогаем" файлы с touch. Зачем нам это нужно?
Команда touch
реализует несколько полезных функций, которым тестировщики, выполняющие задачи ручного тестирования в Linux могут найти применение в своей повседневной практике. Просто говоря, эта команда изменяет свойство файла, хранящее время его последнего изменения. Заменять она его может либо на текущее время, либо на заданное аргументом к команде. Если указанного файла не существует, он создается пустым (таким образом touch
предоставляет быстрый и удобный способ создания нового файла).
Такого рода функция весьма полезна когда ваше приложение следит за фактом изменения файла. Дело в том, что чаще всего изменение файла определяется фактом изменения времени его модификации (иначе приложению бы пришлось хранить где-то копию файла и непрерывно выполнять сравнение с ней). К примеру, такой подход использует JBoss. Если вы хостите своё приложение (например myapp.ear
) в этом контейнере, и вам необходимо передеплоить его, вам надо просто зайти в каталог deployments
и выполнить там команду touch myapp.ear
.
Мониторинг логов при помощи tail
Иногда, выполняя задачи ручного тестирования приложения, вы сталкиваетесь с необходимостью просматривать логи в режиме реального времени (чтобы не пропустить момент наступления некоторого события). В Linux для таких задач существует утилита tail
. Вызов этой команды, как и многих других в Linux, может быть осуществлён многими разными способами, но для решения большинства проблем вполне достаточно запомнить две вещи:
-
Используйте ключ
-F
(аналог использования двух ключей--follow=name --retry
). Он сообщитtail
о необходимости обновлять вывод при поступлении в файл новых данных, а также ждать если возникли проблемы чтения из файла. Последняя особенность важна, когда вы мониторите логи, ограниченные размером. В таком случае, при достижении предельного размера, лог переименовывается и создается новый с таким же именем. Без использования ключа--retry
ваша утилитаtail
"потеряла" бы файл и перестала следить за ним. -
Объединяйте
tail
иgrep
чтобы вывод командыtail
фильтровался бы в реальном времени.
Пример объединения команд:
tail -F myapp.log | grep ^INFO
Поиск дополнительных логов
Если вы уверены, что во время тестирования в вашем приложении что-то пошло не так, но релевантных сообщений в логах приложения не наблюдается, существуют места, где можно поискать подсказку.
В каталоге /var/log
Linux хранит логи, которые заполняются специальным системным сервисом. В принципе, любое приложение может обращаться к этому сервису и через него добавлять в логи свои сообщения. Если что-то пошло не так, существует вероятность, что информацию о проблеме можно будет почерпнуть из таких логов.
Даже если вы не обнаружите сообщений, отправленных именно вашим приложением, вы можете обнаружить проблемы инфраструктурного характера (например неудавшуюся попытку авторизации или заблокированные фаерволом пакеты) косвенно или прямо влияющие на тестируемую вами функциональность.
Знание этих базовых принципов и хитростей поможет вам выполнять задачи ручного тестирования с более высокой эффективностью. Если у вас остались вопросы, задавайте их тут. Я постараюсь дополнить статью опираясь на ваши замечания.