Проблема с подключением к БД в тестах

Всё про тестирование в Yii 2.0
Ответить
Аватара пользователя
Sereja3578
Сообщения: 201
Зарегистрирован: 2016.09.21, 11:15
Контактная информация:

Проблема с подключением к БД в тестах

Сообщение Sereja3578 »

Всем привет! Смотр сейчас видео Дмитрия Елисеева по rest api. Возникла проблема.
У Дмитрия в уроке окружение локальное, у меня на докере.
В докере есть два сервиса для баз данных, mariadb и mariadb-test.

В common/main-local

Код: Выделить всё

'db' => [
            'class' => 'yii\db\Connection',
            'dsn' => 'mysql:host=mariadb;port=3306;dbname=advance_events',
            'username' => 'advance_events',
            'password' => 'advance_events_password',
            'charset' => 'utf8',
            'enableSchemaCache' => false,
            'on afterOpen' => function (yii\base\Event $event) {
                /* @var $db \yii\db\Connection */
                $db = $event->sender;
                $db->createCommand('SET time_zone = :timeZone;', ['timeZone' => date('P')])->execute();
            }
        ],
В common/test-local

Код: Выделить всё

'db' => [
            'class' => 'yii\db\Connection',
            'dsn' => 'mysql:host=mariadb-test;port=33307;dbname=advance_events_test',
            'username' => 'advance_events_test',
            'password' => 'advance_events_password_test',
            'charset' => 'utf8',
            'enableSchemaCache' => false,
            'on afterOpen' => function (yii\base\Event $event) {
                /* @var $db \yii\db\Connection */
                $db = $event->sender;
                $db->createCommand('SET time_zone = :timeZone;', ['timeZone' => date('P')])->execute();
            }
        ],
При этом, когда запускаю тесты, фикстуры не могут накатиться, пишет

Код: Выделить всё

[yii\db\Exception] SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: nodename nor servname provided, or not known
При запуске ./yii_test migrate/up миграции накатываются. То есть все таки до базы можно достучаться, а в тестах нет.

Методом тыка дошел до такого решения - в common/test-local меняю в dsn host с mariadb-test (как он называется в докере) на 127.0.0.1 и порт соответсвенно не внутренний (3306) а прокинутый из докера наружу 33307, тогда при запуске тестов базу видно.

Дальше решил проверить миграции. Выполняю ./yii_test migrate/up и пишет conection refused.

То есть чтобы запускать тесты в настройках нужно писать 127.0.0.1 и внешний (прокинутый из docker) порт, а чтобы выполнять миграции нужно писать хост из докера mariadb-test и внутренний (в сети докера) порт 3306.

В чем разница?

Аватара пользователя
Sereja3578
Сообщения: 201
Зарегистрирован: 2016.09.21, 11:15
Контактная информация:

Re: Проблема с подключением к БД в тестах

Сообщение Sereja3578 »

Тут разобрался. Я запускал миграции внутри контейнера через docker exec -it, а тесты снаружи. Нужно разумеется все делать либо в контейнере, либо снаружи. То есть если подключение в конфигах идет на локальный адрес 127.0.0.1 с проброшенным портом, то мы и выполняем все команды снаружи, а если в конфигах указать в хосте название сервиса в докере, и внутренний порт, то все команды выполняем внутри докера. Правда у меня теперь появилась другая проблема)))

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

Но ругается при выполнении тестов на то, что типа путь /auth не найден

Код: Выделить всё

<?php

namespace api\tests;

use api\tests\ApiTester;
use common\fixtures\UserFixture;
use common\fixtures\UserProfileFixture;

/**
 * Class AuthCest
 * @package api\tests
 */
class AuthCest
{
    public function _before(ApiTester $I)
    {
        $I->haveFixtures([
            'user' => [
                'class' => UserFixture::class,
                'dataFile' => codecept_data_dir() . 'user.php'
            ],
            'user_profile' => [
                'class' => UserProfileFixture::class,
                'dataFile' => codecept_data_dir() . 'user_profile.php'
            ],
        ]);
    }

    public function badMethod(ApiTester $I)
    {
        $I->haveHttpHeader('accept', 'application/json');

        $I->sendGET('/auth');

        $I->seeResponseCodeIs(405);
        $I->seeResponseIsJson();
    }

    public function wrongCredentials(ApiTester $I)
    {
        $I->haveHttpHeader('accept', 'application/json');

        $I->sendPOST('/auth', [
            'username' => 'test_user_expired_auth_key',
            'password' => 'wrong-password',
        ]);

        $I->seeResponseCodeIs(422);
        $I->seeResponseContainsJson([
            'field' => 'password',
            'message' => 'Incorrect username or password.'
        ]);
    }

    public function success(ApiTester $I)
    {
        $I->haveHttpHeader('accept', 'application/json');

        $I->sendPOST('/auth', [
            'username' => 'test_user1',
            'password' => 'password_0',
        ]);

        $I->seeResponseCodeIs(200);
        $I->seeResponseIsJson();

        $I->seeResponseJsonMatchesJsonPath('$.token');
        $I->seeResponseJsonMatchesJsonPath('$.expired');
    }
}
Если я убираю в настройках codeception для api в url /index-test.php, то перестает ругаться, что адрес не найден. Вообще зачем он там, если мы указываем в настройках модуля Yii2 entryScript: index-test.php?

Код: Выделить всё

actor: ApiTester
modules:
    enabled:
        - REST:
              depends: PhpBrowser
              url: 'http://127.0.0.1:8080/index-test.php'
              part: [json]
        - Yii2:
            part: [orm, fixtures]
            entryScript: index-test.php
Но при этом если в url убрать /index-test.php то начинает поять ругаться на коннект к базе. Так как видимо запрос идет на обычный index.php, где в конфиге подключение к другой базе. Но с другой стороны, ну что, пусть подключение к другой, но все равно не должен ведь ругаться, что не может подключиться.

Аватара пользователя
Sereja3578
Сообщения: 201
Зарегистрирован: 2016.09.21, 11:15
Контактная информация:

Re: Проблема с подключением к БД в тестах

Сообщение Sereja3578 »

Запустил тесты в режиме дебага, вижу что идет запрос на 127.0.0.1:8080/index-test.php/auth, а этот путь неправильный, видимо nginx не правильно настроен, а я в нем не особо силен пока.

Код: Выделить всё

server {
    charset utf-8;
    client_max_body_size 128M;

    ## listen for ipv4
    listen 80;
    #listen [::]:80 default_server ipv6only=on; ## listen for ipv6

    server_name api.advance-event.local;
    root /var/www/code/api/web/;
    index index.php;

    access_log  /var/log/nginx/api-access.log combined;
    error_log   /var/log/nginx/api-error.log warn;

    # uncomment to avoid processing of calls to non-existing static files by Yii
    #location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ {
    #    try_files $uri =404;
    #}
    #error_page 404 /404.html;

    # redirect all not existing in index.php requests files to index.php
    location / {
        if (!-e $request_filename) {
            rewrite ^(.*)$ /index.php;
        }
    }

     # deny accessing php files for the /assets directory
    location ~ ^/assets/.*\.php$ {
        deny all;
    }

    # fastcgi config
    location ~ \.php {
        include /etc/nginx/fastcgi.conf;
        fastcgi_pass php-fpm:9000;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_read_timeout 1000;
        fastcgi_index  index.php;
        try_files $uri =404;
    }

    # change root directory for assets files
    location ~ \.(css|js|jpg|jpeg|png|gif|eot|svg)$ {
        root /var/www/code/api/web/;
    }
}
Может, кто подскажет в чем может быть дело? Может типа то что редирект идет не найденных файлов на index.php? Если да, то как сделать редирект и туда и сюда? Пробовал так

Код: Выделить всё

    # redirect all not existing in index-test.php requests files to index.php
    location /index-test.php/ {
        try_files $uri $uri/ /index-test.php?$args;
    }

    # redirect all not existing in index.php requests files to index.php
    location /index.php {
        if (!-e $request_filename) {
            rewrite ^(.*)$ /index.php;
        }
    }

Аватара пользователя
Sereja3578
Сообщения: 201
Зарегистрирован: 2016.09.21, 11:15
Контактная информация:

Re: Проблема с подключением к БД в тестах

Сообщение Sereja3578 »

Я даже пробовал поменять index.php на index-test.php в конфиге, но не работает.

Аватара пользователя
Sereja3578
Сообщения: 201
Зарегистрирован: 2016.09.21, 11:15
Контактная информация:

Re: Проблема с подключением к БД в тестах

Сообщение Sereja3578 »

На всякий случай вот мои настройки urlManager api/main

Код: Выделить всё

'urlManager' => [
            'enablePrettyUrl' => true,
            'enableStrictParsing' => true,
            'showScriptName' => false,
            'rules' => [
                '' => 'site/index',
                'auth' => 'site/login',

                ['class' => 'yii\rest\UrlRule', 'controller' => 'post'],
            ],
        ],

Аватара пользователя
Sereja3578
Сообщения: 201
Зарегистрирован: 2016.09.21, 11:15
Контактная информация:

Re: Проблема с подключением к БД в тестах

Сообщение Sereja3578 »

В общем проблему с тем, что запросы на index-test возвращали Not Found решил. Дело реально было в nginx, сделал так

Код: Выделить всё

server {
    charset utf-8;
    client_max_body_size 128M;

    ## listen for ipv4
    listen 80;
    #listen [::]:80 default_server ipv6only=on; ## listen for ipv6

    server_name api.advance-event.local;
    root /var/www/code/api/web/;
    index index.php;

    access_log  /var/log/nginx/api-access.log combined;
    error_log   /var/log/nginx/api-error.log warn;

    location /index-test.php/ {
        try_files $uri $uri/ /index-test.php?$args;
    }

    location / {
        # Redirect everything that isn't a real file to index.php
        try_files $uri $uri/ /index.php$is_args$args;
    }

    # uncomment to avoid processing of calls to non-existing static files by Yii
    #location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ {
    #    try_files $uri =404;
    #}
    #error_page 404 /404.html;

    # deny accessing php files for the /assets directory
    location ~ ^/assets/.*\.php$ {
        deny all;
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        include /etc/nginx/fastcgi.conf;
        fastcgi_pass php-fpm:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_read_timeout 1000;
        fastcgi_index  index.php;
        try_files $uri =404;
    }

    location ~* /\. {
        deny all;
    }

    # change root directory for assets files
    location ~ \.(css|js|jpg|jpeg|png|gif|eot|svg)$ {
        root /var/www/code/api/web/;
    }
}
Сейчас появилась такая проблема - при запуске миграций на обычную базу и на тестовую все окей, при запуске тестов фикстуры накатываются в тестовую базу, но после этого, в момент выполнения скрипта авторизации, выпадает ошибка, что не удается подключиться к базе данных, connection refused. тесты запускаю не в контейнере, а снаружи контейнера. Правильно ли это? Коннект к базе настроен так

common/config/test-local.php

Код: Выделить всё

<?php
return [
    'components' => [
        'db' => [
            'class' => 'yii\db\Connection',
            'dsn' => 'mysql:host=127.0.0.1;port=33307;dbname=advance_events_test',
            'username' => 'advance_events_test',
            'password' => 'advance_events_password_test',
            'charset' => 'utf8',
            'enableSchemaCache' => false,
            'on afterOpen' => function (yii\base\Event $event) {
                /* @var $db \yii\db\Connection */
                $db = $event->sender;
                $db->createCommand('SET time_zone = :timeZone;', ['timeZone' => date('P')])->execute();
            }
        ],
    ],
];
То есть для подключения извне контейнера по 127.0.0.1 по проброшенному из докера порту 33307.

Аватара пользователя
Sereja3578
Сообщения: 201
Зарегистрирован: 2016.09.21, 11:15
Контактная информация:

Re: Проблема с подключением к БД в тестах

Сообщение Sereja3578 »

Вот лог теста

Код: Выделить всё

{
    "name": "Database Exception",
    "message": "SQLSTATE[HY000] [2002] Connection refused",
    "code": 2002,
    "type": "yii\\db\\Exception",
    "file": "/var/www/code/vendor/yiisoft/yii2/db/Connection.php",
    "line": 642,
    "stack-trace": [
        "#0 /var/www/code/vendor/yiisoft/yii2/db/Connection.php(1030): yii\\db\\Connection->open()",
        "#1 /var/www/code/vendor/yiisoft/yii2/db/Connection.php(1017): yii\\db\\Connection->getMasterPdo()",
        "#2 /var/www/code/vendor/yiisoft/yii2/db/Command.php(258): yii\\db\\Connection->getSlavePdo()",
        "#3 /var/www/code/vendor/yiisoft/yii2/db/Command.php(1160): yii\\db\\Command->prepare(true)",
        "#4 /var/www/code/vendor/yiisoft/yii2/db/Command.php(407): yii\\db\\Command->queryInternal('fetchAll', NULL)",
        "#5 /var/www/code/vendor/yiisoft/yii2/db/mysql/Schema.php(319): yii\\db\\Command->queryAll()",
        "#6 /var/www/code/vendor/yiisoft/yii2/db/mysql/Schema.php(125): yii\\db\\mysql\\Schema->findColumns(Object(yii\\db\\TableSchema))",
        "#7 /var/www/code/vendor/yiisoft/yii2/db/Schema.php(758): yii\\db\\mysql\\Schema->loadTableSchema('user')",
        "#8 /var/www/code/vendor/yiisoft/yii2/db/Schema.php(194): yii\\db\\Schema->getTableMetadata('user', 'schema', false)",
        "#9 /var/www/code/vendor/yiisoft/yii2/db/ActiveRecord.php(435): yii\\db\\Schema->getTableSchema('user')",
        "#10 /var/www/code/vendor/yiisoft/yii2/db/ActiveRecord.php(262): yii\\db\\ActiveRecord::getTableSchema()",
        "#11 /var/www/code/vendor/yiisoft/yii2/db/ActiveRecord.php(234): yii\\db\\ActiveRecord::filterValidColumnNames(Object(yii\\db\\Connection), Array)",
        "#12 /var/www/code/vendor/yiisoft/yii2/db/ActiveRecord.php(191): yii\\db\\ActiveRecord::filterCondition(Array, Array)",
        "#13 /var/www/code/vendor/yiisoft/yii2/db/BaseActiveRecord.php(112): yii\\db\\ActiveRecord::findByCondition(Array)",
        "#14 /var/www/code/common/models/User.php(69): yii\\db\\BaseActiveRecord::findOne(Array)",
        "#15 /var/www/code/api/forms/LoginForm.php(84): common\\models\\User::findByUsername('test_user_expir...')",
        "#16 /var/www/code/api/forms/LoginForm.php(50): api\\forms\\LoginForm->getUser()",
        "#17 /var/www/code/vendor/yiisoft/yii2/validators/InlineValidator.php(84): api\\forms\\LoginForm->validatePassword('password', NULL, Object(yii\\validators\\InlineValidator), 'wrong-password')",
        "#18 /var/www/code/vendor/yiisoft/yii2/validators/Validator.php(261): yii\\validators\\InlineValidator->validateAttribute(Object(api\\forms\\LoginForm), 'password')",
        "#19 /var/www/code/vendor/yiisoft/yii2/base/Model.php(368): yii\\validators\\Validator->validateAttributes(Object(api\\forms\\LoginForm), Array)",
        "#20 /var/www/code/api/forms/LoginForm.php(63): yii\\base\\Model->validate()",
        "#21 /var/www/code/api/controllers/SiteController.php(33): api\\forms\\LoginForm->auth()",
        "#22 [internal function]: api\\controllers\\SiteController->actionLogin()",
        "#23 /var/www/code/vendor/yiisoft/yii2/base/InlineAction.php(57): call_user_func_array(Array, Array)",
        "#24 /var/www/code/vendor/yiisoft/yii2/base/Controller.php(181): yii\\base\\InlineAction->runWithParams(Array)",
        "#25 /var/www/code/vendor/yiisoft/yii2/base/Module.php(534): yii\\base\\Controller->runAction('login', Array)",
        "#26 /var/www/code/vendor/yiisoft/yii2/web/Application.php(104): yii\\base\\Module->runAction('site/login', Array)",
        "#27 /var/www/code/vendor/yiisoft/yii2/base/Application.php(392): yii\\web\\Application->handleRequest(Object(yii\\web\\Request))",
        "#28 /var/www/code/api/web/index-test.php(28): yii\\base\\Application->run()",
        "#29 {main}"
    ],
    "error-info": [
        "HY000",
        2002,
        "Connection refused"
    ],
    "previous": {
        "name": "Exception",
        "message": "SQLSTATE[HY000] [2002] Connection refused",
        "code": 2002,
        "type": "PDOException",
        "file": "/var/www/code/vendor/yiisoft/yii2/db/Connection.php",
        "line": 710,
        "stack-trace": [
            "#0 /var/www/code/vendor/yiisoft/yii2/db/Connection.php(710): PDO->__construct('mysql:host=127....', 'advance_events_...', 'advance_events_...', NULL)",
            "#1 /var/www/code/vendor/yiisoft/yii2/db/Connection.php(631): yii\\db\\Connection->createPdoInstance()",
            "#2 /var/www/code/vendor/yiisoft/yii2/db/Connection.php(1030): yii\\db\\Connection->open()",
            "#3 /var/www/code/vendor/yiisoft/yii2/db/Connection.php(1017): yii\\db\\Connection->getMasterPdo()",
            "#4 /var/www/code/vendor/yiisoft/yii2/db/Command.php(258): yii\\db\\Connection->getSlavePdo()",
            "#5 /var/www/code/vendor/yiisoft/yii2/db/Command.php(1160): yii\\db\\Command->prepare(true)",
            "#6 /var/www/code/vendor/yiisoft/yii2/db/Command.php(407): yii\\db\\Command->queryInternal('fetchAll', NULL)",
            "#7 /var/www/code/vendor/yiisoft/yii2/db/mysql/Schema.php(319): yii\\db\\Command->queryAll()",
            "#8 /var/www/code/vendor/yiisoft/yii2/db/mysql/Schema.php(125): yii\\db\\mysql\\Schema->findColumns(Object(yii\\db\\TableSchema))",
            "#9 /var/www/code/vendor/yiisoft/yii2/db/Schema.php(758): yii\\db\\mysql\\Schema->loadTableSchema('user')",
            "#10 /var/www/code/vendor/yiisoft/yii2/db/Schema.php(194): yii\\db\\Schema->getTableMetadata('user', 'schema', false)",
            "#11 /var/www/code/vendor/yiisoft/yii2/db/ActiveRecord.php(435): yii\\db\\Schema->getTableSchema('user')",
            "#12 /var/www/code/vendor/yiisoft/yii2/db/ActiveRecord.php(262): yii\\db\\ActiveRecord::getTableSchema()",
            "#13 /var/www/code/vendor/yiisoft/yii2/db/ActiveRecord.php(234): yii\\db\\ActiveRecord::filterValidColumnNames(Object(yii\\db\\Connection), Array)",
            "#14 /var/www/code/vendor/yiisoft/yii2/db/ActiveRecord.php(191): yii\\db\\ActiveRecord::filterCondition(Array, Array)",
            "#15 /var/www/code/vendor/yiisoft/yii2/db/BaseActiveRecord.php(112): yii\\db\\ActiveRecord::findByCondition(Array)",
            "#16 /var/www/code/common/models/User.php(69): yii\\db\\BaseActiveRecord::findOne(Array)",
            "#17 /var/www/code/api/forms/LoginForm.php(84): common\\models\\User::findByUsername('test_user_expir...')",
            "#18 /var/www/code/api/forms/LoginForm.php(50): api\\forms\\LoginForm->getUser()",
            "#19 /var/www/code/vendor/yiisoft/yii2/validators/InlineValidator.php(84): api\\forms\\LoginForm->validatePassword('password', NULL, Object(yii\\validators\\InlineValidator), 'wrong-password')",
            "#20 /var/www/code/vendor/yiisoft/yii2/validators/Validator.php(261): yii\\validators\\InlineValidator->validateAttribute(Object(api\\forms\\LoginForm), 'password')",
            "#21 /var/www/code/vendor/yiisoft/yii2/base/Model.php(368): yii\\validators\\Validator->validateAttributes(Object(api\\forms\\LoginForm), Array)",
            "#22 /var/www/code/api/forms/LoginForm.php(63): yii\\base\\Model->validate()",
            "#23 /var/www/code/api/controllers/SiteController.php(33): api\\forms\\LoginForm->auth()",
            "#24 [internal function]: api\\controllers\\SiteController->actionLogin()",
            "#25 /var/www/code/vendor/yiisoft/yii2/base/InlineAction.php(57): call_user_func_array(Array, Array)",
            "#26 /var/www/code/vendor/yiisoft/yii2/base/Controller.php(181): yii\\base\\InlineAction->runWithParams(Array)",
            "#27 /var/www/code/vendor/yiisoft/yii2/base/Module.php(534): yii\\base\\Controller->runAction('login', Array)",
            "#28 /var/www/code/vendor/yiisoft/yii2/web/Application.php(104): yii\\base\\Module->runAction('site/login', Array)",
            "#29 /var/www/code/vendor/yiisoft/yii2/base/Application.php(392): yii\\web\\Application->handleRequest(Object(yii\\web\\Request))",
            "#30 /var/www/code/api/web/index-test.php(28): yii\\base\\Application->run()",
            "#31 {main}"
        ]
    }
}

Аватара пользователя
Sereja3578
Сообщения: 201
Зарегистрирован: 2016.09.21, 11:15
Контактная информация:

Re: Проблема с подключением к БД в тестах

Сообщение Sereja3578 »

В общем проблему решил. Суть в том - тесты нужно запускать в контейнере. И все конфиги на коннект с базой нужно настраивать на работу внутри сети докера, а значит использовать внутренний порт 3306 и название хостов как в конфиге докера. Например так

Код: Выделить всё

<?php
return [
    'components' => [
        'db' => [
            'class' => 'yii\db\Connection',
            'dsn' => 'mysql:host=mariadb-test;port=3306;dbname=advance_events_test',
            'username' => 'advance_events_test',
            'password' => 'advance_events_password_test',
            'charset' => 'utf8',
            'enableSchemaCache' => false,
            'on afterOpen' => function (yii\base\Event $event) {
                /* @var $db \yii\db\Connection */
                $db = $event->sender;
                $db->createCommand('SET time_zone = :timeZone;', ['timeZone' => date('P')])->execute();
            }
        ],
    ],
];
И не забыть прописать в конфиге тестов, в url тоже внутренний хост

api.suite.yml

Код: Выделить всё

actor: ApiTester
modules:
    enabled:
        - REST:
              depends: [PhpBrowser, Yii2]
              url: 'http://nginx:80/index-test.php'
              part: [json]
        - Yii2:
            part: [orm, fixtures]
            entryScript: index-test.php
Всем успехов и рабочего кода без багов)

Ответить