Разработка, HowTo

PHPStorm: Запускаем тесты на удаленной машине с возможностью отладки

2018-07-11-21:10:29_373x236Не секрет, что современные среды разработки полны полезного функционала, освоение которого позволяет поднять продуктивность разработки до невероятных высот.

Сегодня мы реализуем возможность запуска тестов на проекте в каком-либо контейнере (докер, вагрант, удаленное железо), просмотре их выполнения и возможности анализа результатов. И все это не переключаясь на отдельную консоль.

Почему это удобно? Я уже неоднократно ссылался на удобство контейнеров поскольку они обеспечивают повторяемость окружения, скорость развертывания рабочего проекта и схожесть окружений у всех разработчиков в команде.

Долгое время неудобством выступало то, что для тестирования и непосредственной отладки требовалось выполнить переключение на консоль тестовой машины.

Дано:

  • окружение под vagrant (один из способов собрать такое окружение описан в соответствующей статье).

Надо:

  • запускать и отлаживать тесты не выходя из ide

Читать далее

Разработка

PHP: Самые распространенные проблемы при работе с сессиями

phpsessionsС сессиями в php существует множество непонятных проблем. С появлением виртуальных окружений проблем стало больше.

Рассмотрим наиболее часто встречающиеся проблемы сессий на файлах (мы не будем затрагивать сессии в бд и кастомные обработчики).

session_start(): open(filename, O_RDWR) failed: No such file or directory

Очевидно, что ошибка возникает, когда не существует пути, по которому пишутся данные. Но при этом вы знаете, что на диске каталог, который был указан как аргумент session_save_path(), существует.

Например.

$ mkdir /tmp/sessions
$ chmod 777 /tmp/sessions
session_save_path('/tmp/sessions');
session_start();

Вы увидите на экране или в логах ошибку из заголовка (не во всех дистрибутивах).

Можно посмотреть audit.log из selinux, но если там нет ничего подозрительного и каталог действительно есть (а вы его создали выше), то причина такого поведения достаточно неожиданна.

Происходит это потому что вы работаете в centos 7 версии (или redhat\fedora) и выше. Именно в этой версии ввели параметр PrivateTmp для сервисов. Что это означает для нас?

Сделайте второй скрипт, который перечисляет содержимое директории /tmp, а так же выводит реальный путь каталога /tmp/sessions.

var_dump(glob('/tmp/*'));

Откройте скрипт в браузере. Вы увидите, что содержимое в браузере кардинально отличается от содержимого реальной папки /tmp. На скриншоте мы видем вывод из консоли и из браузера — результат совершенно разный.

2018-06-02-12:32:03_1625x863

Как это побороть? Использовать другой каталог для хранения сессий. Или перед стартом приложения проверять и создавать в случае необходимости нужную файловую структуру.

session_start(): Session data file is not created by your uid

Не самая распространенная ошибка. Чаще всего возникает в виртуальных окружениях.

Ошибка возникает в случае, когда uid владельца файла сессии не совпадает с uid текущего пользователя под которым запущен интерпретатор.

Как проверить, что это именно наш случай? Нужно создать скрипт, которыый создает файл в каталоге, в котором вы планируете размещать сессии и сверяет uid владельца файла и uid владельца процесса.

$file = __DIR__ . DIRECTORY_SEPARATOR . 'file.name';
$fd = fopen($file, 'w');
fwrite($fd, 'test data');
fclose($fd);
if (file_exists($file)) {
    $stat = stat($file);
    var_dump($stat['uid'] == posix_getuid());
}

Если мы увидим false, то да. Проблема имеет мысто быть. И вам нужно переместить сессии в другое место.

Так же подобное поведение характерно при некоторых способах монтирования nfs.

session_start(): open(filename, O_RDWR) failed: Permission denied

Каталог недоступен для записи и достаточно дать права 777. Но тут не все так очевидно и данный трюк действует не всегда. Если вы работаете в дистрибутивах, которые используют selinux, то даже при установке полных прав система можем вам не позволить писать по выбранному пути.

Это происходит потому что контекст процесса отличается от контекста папки. Вы всегда можете посмотреть в /var/log/audit/audit.log чтобы убедиться.

Как обращаться с контекстами можно подробнее посмотреть в документации и в книге.

Литература

Разработка, HowTo

PHP: Отлаживаем скрипты командной строки на удаленной машине

01-ПревьюОтладка бекенда на PHP уже ни у кого не вызывает проблем: достаточно правильно настроить расширение xdebug (или zend debugger), поставить  расширение в свой браузер и можно отлаживать, трассировать или профилировать бекенд.

Но что делать, когда нам требуется отладить консольную утилиту на удаленном сервере? В браузере выбрать пункте enable xdebug нельзя, а если у нас и получится передать IDE_KEY, то оно не знает, где располагается среда разработки и куда делать connect_back.

Это все легко решается одним маленьким скриптом (Важно сделать замечание: это будет работать только когда мы подключены по SSH).

#!/usr/bin/env bash
IP=`echo $SSH_CLIENT | awk "{print $1}"​`
PHP='/usr/bin/php -d 'xdebug.remote_host=${IP}' -d 'xdebug.remote_autostart=1''
$PHP $@

Теперь достаточно скомандовать

$ php-debug.sh yii

И на рабочей машине мы сразу увидим запрос на подключение.

02-Запрос на настройку путей

Разработка

PHP: и 64х битные числа

Мне понадобилось в одном из проектов работать с 64х битными числами в качестве масок.

Раньше не доводилось использовать столь большие константы в системах и я был несколько удивлен поведением интерпретатора.

var_dump(1 & 0xffffffffffffffff);

Этот код выведет вам на экран

int(0)

Хотя другой код выводит ровно так, как и должно быть.

var_dump(1 & ~0);
int(1)

Но при этом

var_dump(1 & hexdec(dechex(~0)), 1 & ~0);
int(0)
int(1)

Такое поведение показалось немного странным и, как позже выяснилось, все упирается в константу PHP_INT_MAX, которая на 64х битных системах равна 0x7fffffffffffffff. Семерка в начале идет потому что первый бит зарезервирован под знак.

В чем же тут дело? Если мы хотим записать очень большое число (8 байт ff), то пишем мы это число как положительное целое. Вот так: 0xffffffffffffffff. Интерпретатор сравнивает число с PHP_INT_MAX и если оно его не провосходит, то все будет сконвертировано в int, а если превосходит, то во float. Убедиться в этом можно следующим кодом.

var_dump(0xffffffffffffffff);
float(1.844674407371E+19)

А все это лишь из-за того, что в php нет типа unsigned (и модификатора для данного типа тоже нет). Поэтому записывать числа нам позволено лишь от PHP_INT_MIN до PHP_INT_MAX. Все остальное будет float’ом.

Но мы же по прежнему можем работать с 8-ми байтными числами. Для примера -1 в дополнительном коде это то самое число, которое нам нужно!

var_dump(dechex(-1));
int(0xffffffffffffffff)

Очевидный ответ: либо вспоминать способы формирования чисел в дополнительном коде, либо работать с битовыми операциями.

var_dump(1 & ((0xffffffff << 32) | 0xffffffff), 1 & ~0);
int(1)
int(1)

Разумеется все вышеописанное характерно и для 32з битныз платформ с поправкой на PHP_INT_SIZE (размер инта в байтах).

Литература:

Разработка, HowTo

Часть 9: Codeception. Настройка. Unit-тесты (Тестирование ПО)

codeceptionОглавление

Продолжаем цикл статей Тестирование ПО. В этой части рассмотрим установку и настройку фреймворка codeception. Попутно перенесем все ранее написанные тесты на новую платформу.

Прежде, чем двигаться дальше нам необходимо познакомиться с таким фреймворком как codeception. На базе PHPUnit можно делать лишь блочные и модульные тесты. Его предназначение полностью расшифровывается в названии. Поскольку изначально он был заточен под применение исключительно для юнит-тестирования (и модульного конечно же).

PHPUnit никуда не делся, но так как найти абсолютно все ошибки лишь модульными тестами нельзя, то со временем стали появляться различные инструменты для проведения функционального или приемочного тестирования — одни из них это selenium, который открывает браузер при проверяет соответствие сгенерированной страницы том, что ожидает пользователь и имеет возможность заполнять формы и отправлять запросы.

Появилась потребность в инструментах более высокого уровня, которые могли бы позволить манипулировать всем этим разнообразием консольных команд, приложений и всем тем, что позволяет искать ошибки в приложениях. Одним из таких инструментов стал Codeception — надстройка над PHPUnit, которая помимо прочего умеет выполнять тесты в браузере, осуществлять сетевые запросы, заполнять формы и много чего еще.

Читать далее

Разработка, HowTo

Часть 7: PHPUnit (Тестирование ПО)

php-unit-logo-bigОглавление

Продолжаем цикл статей по разработке веб-приложений с использованием методологии TDD.

Ранее утверждалось, что для понимания того, как функционирует тот или иной фреймворк или технология нужно сначала попытаться реализовать похожий функционал самостоятельно. И только затем пытаться использовать уже существующие наработки.

В предыдущей части мы попытались создать собственный минималистичный код, который осуществляет тестирование проекта. Если продолжать и дальше, то в конечном счете можно довести имеющиеся наработки до вида, годного для использования в маленьких или не очень проектах. Но так делать не стоит ибо современная индустрия разработки требует высокой скорости создания продуктов и высокого их качества. Тратить усилия на поддержание уже не раз придуманного и реализованного, но своего — это не совсем хорошая идея. Поэтому в этой главе мы познакомимся с PHPUnit и научимся правильно его применять вместе с yii.

Читать далее

Разработка, HowTo

Часть 5: Подготовка базы данных, миграции (Тестирование ПО)

00-titleОглавление

Перед вами очередная часть цикла Тестирование ПО. В предыдущей части мы развернули инфраструктуру для работы с проектом на базе Yii2-advanced-template. В этой части мы разберемся как работать с базой данных и что такое миграции.

Читать далее