mirror of
https://github.com/elyby/accounts.git
synced 2024-11-30 02:32:26 +05:30
Merge branch 'develop' into sentry
This commit is contained in:
commit
4623063074
50
.env-dist
50
.env-dist
@ -1,21 +1,57 @@
|
||||
# Основные параметры
|
||||
# Параметры приложения
|
||||
## Env приложения
|
||||
YII_DEBUG=true
|
||||
YII_ENV=dev
|
||||
|
||||
## Параметры, отвечающие за безопасность
|
||||
JWT_USER_SECRET=
|
||||
|
||||
## Внешние сервисы
|
||||
RECAPTCHA_PUBLIC=
|
||||
RECAPTCHA_SECRET=
|
||||
SENTRY_DSN=
|
||||
|
||||
## SMTP параметры
|
||||
SMTP_USER=
|
||||
SMTP_PASS=
|
||||
SMTP_PORT=
|
||||
|
||||
## Параметры подключения к базе данных
|
||||
DB_HOST=db
|
||||
DB_DATABASE=ely_accounts
|
||||
DB_USER=ely_accounts_user
|
||||
DB_PASSWORD=ely_accounts_password
|
||||
|
||||
## Параметры подключения к redis
|
||||
REDIS_HOST=redis
|
||||
REDIS_PORT=6379
|
||||
REDIS_DATABASE=0
|
||||
REDIS_PASSWORD=
|
||||
|
||||
## Параметры подключения к redis
|
||||
REDIS_HOST=redis
|
||||
REDIS_PORT=6379
|
||||
REDIS_DATABASE=0
|
||||
REDIS_PASS=
|
||||
|
||||
## Параметры подключения к rabbitmq
|
||||
RABBITMQ_HOST=rabbitmq
|
||||
RABBITMQ_PORT=5672
|
||||
RABBITMQ_USER=ely-accounts-app
|
||||
RABBITMQ_PASS=ely-accounts-app-password
|
||||
RABBITMQ_VHOST=/ely.by
|
||||
|
||||
## Конфигурация для Dev.
|
||||
XDEBUG_CONFIG=remote_host=10.254.254.254
|
||||
PHP_IDE_CONFIG=serverName=docker
|
||||
|
||||
|
||||
# Web
|
||||
VIRTUAL_HOST=account.ely.by,authserver.ely.by
|
||||
AUTHSERVER_HOST=authserver.ely.by
|
||||
# LETSENCRYPT_HOST=account.ely.by
|
||||
# LETSENCRYPT_EMAIL=erickskrauch@ely.by
|
||||
|
||||
# SMTP (только для production)
|
||||
SMTP_USER=
|
||||
SMTP_PASS=
|
||||
|
||||
# MySQL
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD=yes
|
||||
MYSQL_ROOT_PASSWORD=
|
||||
@ -27,7 +63,3 @@ MYSQL_PASSWORD=ely_accounts_password
|
||||
RABBITMQ_DEFAULT_USER=ely-accounts-app
|
||||
RABBITMQ_DEFAULT_PASS=ely-accounts-app-password
|
||||
RABBITMQ_DEFAULT_VHOST=/ely.by
|
||||
|
||||
# Конфигурация для Dev.
|
||||
XDEBUG_CONFIG=remote_host=10.254.254.254
|
||||
PHP_IDE_CONFIG=serverName=docker
|
||||
|
@ -4,21 +4,40 @@ stages:
|
||||
- release
|
||||
|
||||
variables:
|
||||
CONTAINER_IMAGE: registry.ely.by/elyby/accounts
|
||||
DOCKER_DRIVER: aufs
|
||||
CONTAINER_IMAGE: "registry.ely.by/elyby/accounts"
|
||||
|
||||
test:backend:
|
||||
image: jonaskello/docker-and-compose:1.12.1-1.8.0
|
||||
image: docker:latest
|
||||
services:
|
||||
- docker:1.12.1-dind
|
||||
- mariadb:10.0
|
||||
- redis:3.0-alpine
|
||||
variables:
|
||||
# mariadb config
|
||||
MYSQL_RANDOM_ROOT_PASSWORD: "true"
|
||||
MYSQL_DATABASE: "ely_accounts_test"
|
||||
MYSQL_USER: "ely_accounts_tester"
|
||||
MYSQL_PASSWORD: "ely_accounts_tester_password"
|
||||
stage: test
|
||||
before_script:
|
||||
- docker login -u gitlab-ci -p $CI_BUILD_TOKEN registry.ely.by
|
||||
- echo "$SSH_PRIVATE_KEY" > id_rsa
|
||||
- docker-compose -f tests/docker-compose.yml build --pull testphp
|
||||
after_script:
|
||||
- docker-compose -f tests/docker-compose.yml down -v
|
||||
script:
|
||||
- docker-compose -f tests/docker-compose.yml run --rm testphp ./vendor/bin/codecept run -c tests
|
||||
- export TEMP_DEV_IMAGE="${CONTAINER_IMAGE}:ci-${CI_BUILD_ID}"
|
||||
- docker build --pull -f Dockerfile-dev -t $TEMP_DEV_IMAGE .
|
||||
- >
|
||||
docker run --rm
|
||||
--add-host=mariadb:`getent hosts mariadb | awk '{ print $1 ; exit }'`
|
||||
--add-host=redis:`getent hosts redis | awk '{ print $1 ; exit }'`
|
||||
-e YII_DEBUG="true"
|
||||
-e YII_ENV="test"
|
||||
-e DB_HOST="mariadb"
|
||||
-e DB_DATABASE="ely_accounts_test"
|
||||
-e DB_USER="ely_accounts_tester"
|
||||
-e DB_PASSWORD="ely_accounts_tester_password"
|
||||
-e REDIS_HOST="redis"
|
||||
$TEMP_DEV_IMAGE
|
||||
php vendor/bin/codecept run -c tests
|
||||
|
||||
test:frontend:
|
||||
image: node:5.12
|
||||
@ -28,8 +47,8 @@ test:frontend:
|
||||
- frontend/node_modules
|
||||
script:
|
||||
- cd frontend
|
||||
- npm i --silent
|
||||
- npm run test
|
||||
- npm i --silent > /dev/null
|
||||
- npm run test --silent
|
||||
|
||||
build:production:
|
||||
image: docker:latest
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM registry.ely.by/elyby/accounts-php:1.1.2
|
||||
FROM registry.ely.by/elyby/accounts-php:1.2.0
|
||||
|
||||
# Вносим конфигурации для крона и воркеров
|
||||
COPY docker/cron/* /etc/cron.d/
|
||||
@ -32,7 +32,7 @@ COPY ./frontend/scripts /var/www/frontend/scripts
|
||||
COPY ./frontend/webpack-utils /var/www/frontend/webpack-utils
|
||||
|
||||
RUN cd ../frontend \
|
||||
&& npm install \
|
||||
&& npm install --quiet --depth -1 \
|
||||
&& cd -
|
||||
|
||||
# Удаляем ключи из production контейнера на всякий случай
|
||||
@ -46,7 +46,7 @@ RUN mkdir -p api/runtime api/web/assets console/runtime \
|
||||
# Билдим фронт
|
||||
&& cd frontend \
|
||||
&& ln -s /var/www/frontend/node_modules $PWD/node_modules \
|
||||
&& npm run build \
|
||||
&& npm run build:quite --quiet \
|
||||
&& rm node_modules \
|
||||
# Копируем билд наружу, чтобы его не затёрло volume в dev режиме
|
||||
&& cp -r ./dist /var/www/dist \
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM registry.ely.by/elyby/accounts-php:1.1.2-dev
|
||||
FROM registry.ely.by/elyby/accounts-php:1.2.0-dev
|
||||
|
||||
# Вносим конфигурации для крона и воркеров
|
||||
COPY docker/cron/* /etc/cron.d/
|
||||
@ -32,7 +32,7 @@ COPY ./frontend/scripts /var/www/frontend/scripts
|
||||
COPY ./frontend/webpack-utils /var/www/frontend/webpack-utils
|
||||
|
||||
RUN cd ../frontend \
|
||||
&& npm install \
|
||||
&& npm install --quiet --depth -1 \
|
||||
&& cd -
|
||||
|
||||
# Наконец переносим все сорцы внутрь контейнера
|
||||
@ -43,7 +43,7 @@ RUN mkdir -p api/runtime api/web/assets console/runtime \
|
||||
# Билдим фронт
|
||||
&& cd frontend \
|
||||
&& ln -s /var/www/frontend/node_modules $PWD/node_modules \
|
||||
&& npm run build \
|
||||
&& npm run build:quite --quiet \
|
||||
&& rm node_modules \
|
||||
# Копируем билд наружу, чтобы его не затёрло volume в dev режиме
|
||||
&& cp -r ./dist /var/www/dist \
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace api\controllers;
|
||||
|
||||
use api\filters\NginxCache;
|
||||
use Yii;
|
||||
use yii\helpers\ArrayHelper;
|
||||
|
||||
@ -11,6 +12,12 @@ class OptionsController extends Controller {
|
||||
'authenticator' => [
|
||||
'except' => ['index'],
|
||||
],
|
||||
'nginxCache' => [
|
||||
'class' => NginxCache::class,
|
||||
'rules' => [
|
||||
'index' => 3600, // 1h
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
|
35
api/filters/NginxCache.php
Normal file
35
api/filters/NginxCache.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
namespace api\filters;
|
||||
|
||||
use Yii;
|
||||
use yii\base\ActionFilter;
|
||||
|
||||
class NginxCache extends ActionFilter {
|
||||
|
||||
/**
|
||||
* @var array|callable массив или callback, содержащий пары роут -> сколько кэшировать.
|
||||
*
|
||||
* Период можно задавать 2-умя путями:
|
||||
* - если значение начинается с префикса @, оно задаёт абсолютное время в unix timestamp,
|
||||
* до которого ответ может быть закэширован.
|
||||
* - в ином случае значение интерпретируется как количество секунд, на которое необходимо
|
||||
* закэшировать ответ
|
||||
*/
|
||||
public $rules;
|
||||
|
||||
public function afterAction($action, $result) {
|
||||
$rule = $this->rules[$action->id] ?? null;
|
||||
if ($rule !== null) {
|
||||
if (is_callable($rule)) {
|
||||
$cacheTime = $rule($action);
|
||||
} else {
|
||||
$cacheTime = $rule;
|
||||
}
|
||||
|
||||
Yii::$app->response->headers->set('X-Accel-Expires', $cacheTime);
|
||||
}
|
||||
|
||||
return parent::afterAction($action, $result);
|
||||
}
|
||||
|
||||
}
|
@ -28,15 +28,19 @@ class ChangeUsernameForm extends ApiForm {
|
||||
];
|
||||
}
|
||||
|
||||
public function change() {
|
||||
public function change() : bool {
|
||||
if (!$this->validate()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$transaction = Yii::$app->db->beginTransaction();
|
||||
$account = $this->getAccount();
|
||||
$oldNickname = $account->username;
|
||||
if ($this->username === $account->username) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$transaction = Yii::$app->db->beginTransaction();
|
||||
try {
|
||||
$oldNickname = $account->username;
|
||||
$account->username = $this->username;
|
||||
if (!$account->save()) {
|
||||
throw new ErrorException('Cannot save account model with new username');
|
||||
|
@ -6,22 +6,5 @@ return [
|
||||
'schemaCacheDuration' => 3600,
|
||||
'schemaCache' => 'cache',
|
||||
],
|
||||
'mailer' => [
|
||||
'useFileTransport' => false,
|
||||
'transport' => [
|
||||
'class' => Swift_SmtpTransport::class,
|
||||
'host' => 'ely.by',
|
||||
'username' => getenv('SMTP_USER'),
|
||||
'password' => getenv('SMTP_PASS'),
|
||||
'port' => 587,
|
||||
'encryption' => 'tls',
|
||||
'streamOptions' => [
|
||||
'ssl' => [
|
||||
'allow_self_signed' => true,
|
||||
'verify_peer' => false,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
@ -8,9 +8,9 @@ return [
|
||||
],
|
||||
'db' => [
|
||||
'class' => yii\db\Connection::class,
|
||||
'dsn' => 'mysql:host=db;dbname=' . getenv('MYSQL_DATABASE'),
|
||||
'username' => getenv('MYSQL_USER'),
|
||||
'password' => getenv('MYSQL_PASSWORD'),
|
||||
'dsn' => 'mysql:host=' . (getenv('DB_HOST') ?: 'db') . ';dbname=' . getenv('DB_DATABASE'),
|
||||
'username' => getenv('DB_USER'),
|
||||
'password' => getenv('DB_PASSWORD'),
|
||||
'charset' => 'utf8',
|
||||
'schemaMap' => [
|
||||
'mysql' => common\db\mysql\Schema::class,
|
||||
@ -19,6 +19,20 @@ return [
|
||||
'mailer' => [
|
||||
'class' => yii\swiftmailer\Mailer::class,
|
||||
'viewPath' => '@common/mail',
|
||||
'transport' => [
|
||||
'class' => Swift_SmtpTransport::class,
|
||||
'host' => 'ely.by',
|
||||
'username' => getenv('SMTP_USER'),
|
||||
'password' => getenv('SMTP_PASS'),
|
||||
'port' => getenv('SMTP_PORT') ?: 587,
|
||||
'encryption' => 'tls',
|
||||
'streamOptions' => [
|
||||
'ssl' => [
|
||||
'allow_self_signed' => true,
|
||||
'verify_peer' => false,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'sentry' => [
|
||||
'class' => mito\sentry\SentryComponent::class,
|
||||
@ -35,18 +49,18 @@ return [
|
||||
],
|
||||
'redis' => [
|
||||
'class' => common\components\Redis\Connection::class,
|
||||
'hostname' => 'redis',
|
||||
'password' => null,
|
||||
'port' => 6379,
|
||||
'database' => 0,
|
||||
'hostname' => getenv('REDIS_HOST') ?: 'redis',
|
||||
'password' => getenv('REDIS_PASS') ?: null,
|
||||
'port' => getenv('REDIS_PORT') ?: 6379,
|
||||
'database' => getenv('REDIS_DATABASE') ?: 0,
|
||||
],
|
||||
'amqp' => [
|
||||
'class' => common\components\RabbitMQ\Component::class,
|
||||
'host' => 'rabbitmq',
|
||||
'port' => 5672,
|
||||
'user' => getenv('RABBITMQ_DEFAULT_USER'),
|
||||
'password' => getenv('RABBITMQ_DEFAULT_PASS'),
|
||||
'vhost' => getenv('RABBITMQ_DEFAULT_VHOST'),
|
||||
'host' => getenv('RABBITMQ_HOST') ?: 'rabbitmq',
|
||||
'port' => getenv('RABBITMQ_PORT') ?: 5672,
|
||||
'user' => getenv('RABBITMQ_USER'),
|
||||
'password' => getenv('RABBITMQ_PASS'),
|
||||
'vhost' => getenv('RABBITMQ_VHOST'),
|
||||
],
|
||||
'guzzle' => [
|
||||
'class' => GuzzleHttp\Client::class,
|
||||
|
@ -15,7 +15,7 @@
|
||||
"minimum-stability": "stable",
|
||||
"require": {
|
||||
"php": "^7.0.6",
|
||||
"yiisoft/yii2": "2.0.9",
|
||||
"yiisoft/yii2": "2.0.10",
|
||||
"yiisoft/yii2-swiftmailer": "*",
|
||||
"ramsey/uuid": "^3.5.0",
|
||||
"league/oauth2-server": "dev-improvements#b9277ccd664dcb80a766b73674d21de686cb9dda",
|
||||
|
@ -13,7 +13,7 @@ services:
|
||||
env_file: .env
|
||||
|
||||
web:
|
||||
build: ./docker/nginx
|
||||
image: registry.ely.by/elyby/accounts-nginx:latest
|
||||
volumes_from:
|
||||
- app
|
||||
links:
|
||||
|
@ -9,7 +9,7 @@ services:
|
||||
env_file: .env
|
||||
|
||||
web:
|
||||
build: ./docker/nginx
|
||||
image: registry.ely.by/elyby/accounts-nginx:1.0.2
|
||||
volumes_from:
|
||||
- app
|
||||
links:
|
||||
|
0
docker/cron/.gitkeep
Normal file
0
docker/cron/.gitkeep
Normal file
@ -1,2 +0,0 @@
|
||||
# https://crontab.guru/every-hour
|
||||
0 * * * * root /usr/local/bin/php /var/www/html/yii cleanup/access-tokens >/dev/null 2>&1
|
@ -1,11 +0,0 @@
|
||||
FROM nginx:1.11-alpine
|
||||
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
COPY account.ely.by.conf.template /etc/nginx/conf.d/account.ely.by.conf.template
|
||||
COPY run.sh /run.sh
|
||||
|
||||
RUN rm /etc/nginx/conf.d/default.conf \
|
||||
&& chmod a+x /run.sh
|
||||
|
||||
ENTRYPOINT ["/run.sh"]
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
@ -1,78 +0,0 @@
|
||||
server {
|
||||
listen 80;
|
||||
|
||||
root $root_path;
|
||||
charset utf-8;
|
||||
index index.html;
|
||||
etag on;
|
||||
|
||||
# Это можно раскоментить для целей отладки
|
||||
# rewrite_log on;
|
||||
# error_log /var/log/nginx/error.log debug;
|
||||
|
||||
set $root_path '/var/www/html';
|
||||
set $frontend_path '${root_path}/frontend/dist';
|
||||
|
||||
set $request_url $request_uri;
|
||||
set $host_with_uri '${host}${request_uri}';
|
||||
|
||||
if ($host_with_uri ~ '^${AUTHSERVER_HOST}/auth') {
|
||||
set $request_url '/api/authserver${request_uri}';
|
||||
rewrite ^/auth /api/authserver$uri last;
|
||||
}
|
||||
|
||||
if ($host_with_uri ~ '^${AUTHSERVER_HOST}/session') {
|
||||
set $request_url '/api/minecraft${request_uri}';
|
||||
rewrite ^/session /api/minecraft$uri last;
|
||||
}
|
||||
|
||||
if ($host_with_uri ~ '^${AUTHSERVER_HOST}/api/(user|profiles)') {
|
||||
set $request_url '/api/mojang${request_uri}';
|
||||
rewrite ^/api/(user|profiles) /api/mojang$uri last;
|
||||
}
|
||||
|
||||
location / {
|
||||
alias $frontend_path;
|
||||
try_files $uri /index.html =404;
|
||||
}
|
||||
|
||||
location /api {
|
||||
try_files $uri $uri /api/web/index.php$is_args$args;
|
||||
}
|
||||
|
||||
location ~* \.php$ {
|
||||
fastcgi_pass php:9000;
|
||||
include fastcgi_params;
|
||||
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param SERVER_NAME $host;
|
||||
fastcgi_param REQUEST_URI $request_url;
|
||||
fastcgi_param REMOTE_ADDR $http_x_real_ip;
|
||||
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
# html файлы идут отдельно, для них будет применяться E-Tag кэширование
|
||||
location ~* \.html$ {
|
||||
root $frontend_path;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# Раздача статики для frontend с указанием max-кэша. Сброс будет по #hash после ребилда webpackом
|
||||
location ~* ^.+\.(jpg|jpeg|gif|png|svg|js|json|css|zip|rar|eot|ttf|woff|woff2|ico)$ {
|
||||
root $frontend_path;
|
||||
expires max;
|
||||
etag off;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# Запросы к статике для email, их нужно запустить внутрь vendor
|
||||
location ^~ /images/emails/assets {
|
||||
rewrite ^/images/emails/assets/(.+)$ /vendor/ely/emails-renderer/dist/assets/$1 last;
|
||||
}
|
||||
|
||||
location ^~ /vendor/ely/emails-renderer/dist/assets {
|
||||
alias '${root_path}/vendor/ely/email-renderer/dist/assets';
|
||||
try_files $uri =404;
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
user nginx;
|
||||
worker_processes 1;
|
||||
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
sendfile on;
|
||||
keepalive_timeout 10;
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
envsubst '$AUTHSERVER_HOST' < /etc/nginx/conf.d/account.ely.by.conf.template > /etc/nginx/conf.d/default.conf
|
||||
|
||||
exec "$@"
|
@ -1,5 +1,6 @@
|
||||
namespace: tests\codeception\api
|
||||
actor: Tester
|
||||
params: [env]
|
||||
paths:
|
||||
tests: .
|
||||
log: _output
|
||||
|
@ -4,23 +4,16 @@ modules:
|
||||
- Filesystem
|
||||
- Yii2
|
||||
- tests\codeception\common\_support\FixtureHelper
|
||||
- tests\codeception\common\_support\amqp\Helper
|
||||
- Redis
|
||||
- AMQP
|
||||
- Asserts
|
||||
- REST:
|
||||
depends: Yii2
|
||||
config:
|
||||
Yii2:
|
||||
configFile: '../config/api/functional.php'
|
||||
cleanup: true
|
||||
cleanup: false
|
||||
Redis:
|
||||
host: testredis
|
||||
host: "%REDIS_HOST%"
|
||||
port: 6379
|
||||
database: 0
|
||||
AMQP:
|
||||
host: testrabbit
|
||||
port: 5672
|
||||
username: 'ely-accounts-tester'
|
||||
password: 'tester-password'
|
||||
vhost: '/account.ely.by/tests'
|
||||
queues: ['account-operations']
|
||||
|
@ -3,6 +3,8 @@ modules:
|
||||
enabled:
|
||||
- Yii2:
|
||||
part: [orm, email, fixtures]
|
||||
- tests\codeception\common\_support\amqp\Helper
|
||||
config:
|
||||
Yii2:
|
||||
configFile: '../config/api/unit.php'
|
||||
cleanup: false
|
||||
|
57
tests/codeception/api/unit/filters/NginxCacheTest.php
Normal file
57
tests/codeception/api/unit/filters/NginxCacheTest.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
namespace tests\codeception\api\unit\filters;
|
||||
|
||||
use api\filters\NginxCache;
|
||||
use tests\codeception\api\unit\TestCase;
|
||||
use Yii;
|
||||
use yii\base\Action;
|
||||
use yii\web\Controller;
|
||||
use yii\web\HeaderCollection;
|
||||
use yii\web\Request;
|
||||
|
||||
class NginxCacheTest extends TestCase {
|
||||
|
||||
public function testAfterAction() {
|
||||
$this->testAfterActionInternal(3600, 3600);
|
||||
$this->testAfterActionInternal('@' . (time() + 30), '@' . (time() + 30));
|
||||
$this->testAfterActionInternal(function() {
|
||||
return 3000;
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
private function testAfterActionInternal($ruleConfig, $expected) {
|
||||
/** @var HeaderCollection|\PHPUnit_Framework_MockObject_MockObject $headers */
|
||||
$headers = $this->getMockBuilder(HeaderCollection::class)
|
||||
->setMethods(['set'])
|
||||
->getMock();
|
||||
|
||||
$headers->expects($this->once())
|
||||
->method('set')
|
||||
->with('X-Accel-Expires', $expected);
|
||||
|
||||
/** @var Request|\PHPUnit_Framework_MockObject_MockObject $request */
|
||||
$request = $this->getMockBuilder(Request::class)
|
||||
->setMethods(['getHeaders'])
|
||||
->getMock();
|
||||
|
||||
$request->expects($this->any())
|
||||
->method('getHeaders')
|
||||
->willReturn($headers);
|
||||
|
||||
Yii::$app->set('response', $request);
|
||||
|
||||
/** @var Controller|\PHPUnit_Framework_MockObject_MockObject $controller */
|
||||
$controller = $this->getMockBuilder(Controller::class)
|
||||
->setConstructorArgs(['mock', Yii::$app])
|
||||
->getMock();
|
||||
|
||||
$component = new NginxCache([
|
||||
'rules' => [
|
||||
'index' => $ruleConfig,
|
||||
],
|
||||
]);
|
||||
|
||||
$component->afterAction(new Action('index', $controller), '');
|
||||
}
|
||||
|
||||
}
|
@ -25,9 +25,15 @@ class ConfirmEmailFormTest extends TestCase {
|
||||
$this->assertInstanceOf(AccountSession::class, $result->getSession(), 'session was generated');
|
||||
$activationExists = EmailActivation::find()->andWhere(['key' => $fixture['key']])->exists();
|
||||
$this->assertFalse($activationExists, 'email activation key is not exist');
|
||||
/** @var Account $user */
|
||||
$user = Account::findOne($fixture['account_id']);
|
||||
$this->assertEquals(Account::STATUS_ACTIVE, $user->status, 'user status changed to active');
|
||||
/** @var Account $account */
|
||||
$account = Account::findOne($fixture['account_id']);
|
||||
$this->assertEquals(Account::STATUS_ACTIVE, $account->status, 'user status changed to active');
|
||||
|
||||
$message = $this->tester->grabLastSentAmqpMessage('events');
|
||||
$body = json_decode($message->getBody(), true);
|
||||
$this->assertEquals($account->id, $body['accountId']);
|
||||
$this->assertEquals($account->username, $body['newUsername']);
|
||||
$this->assertNull($body['oldUsername']);
|
||||
}
|
||||
|
||||
private function createModel($key) {
|
||||
|
@ -18,9 +18,8 @@ class ConfirmNewEmailFormTest extends TestCase {
|
||||
}
|
||||
|
||||
public function testChangeEmail() {
|
||||
$accountId = $this->tester->grabFixture('accounts', 'account-with-change-email-finish-state')['id'];
|
||||
/** @var Account $account */
|
||||
$account = Account::findOne($accountId);
|
||||
$account = Account::findOne($this->getAccountId());
|
||||
$newEmailConfirmationFixture = $this->tester->grabFixture('emailActivations', 'newEmailConfirmation');
|
||||
$model = new ConfirmNewEmailForm($account, [
|
||||
'key' => $newEmailConfirmationFixture['key'],
|
||||
@ -32,6 +31,23 @@ class ConfirmNewEmailFormTest extends TestCase {
|
||||
]));
|
||||
$data = unserialize($newEmailConfirmationFixture['_data']);
|
||||
$this->assertEquals($data['newEmail'], $account->email);
|
||||
$this->tester->canSeeAmqpMessageIsCreated('events');
|
||||
}
|
||||
|
||||
public function testCreateTask() {
|
||||
/** @var Account $account */
|
||||
$account = Account::findOne($this->getAccountId());
|
||||
$model = new ConfirmNewEmailForm($account);
|
||||
$model->createTask(1, 'test1@ely.by', 'test@ely.by');
|
||||
$message = $this->tester->grabLastSentAmqpMessage('events');
|
||||
$body = json_decode($message->getBody(), true);
|
||||
$this->assertEquals(1, $body['accountId']);
|
||||
$this->assertEquals('test1@ely.by', $body['newEmail']);
|
||||
$this->assertEquals('test@ely.by', $body['oldEmail']);
|
||||
}
|
||||
|
||||
private function getAccountId() {
|
||||
return $this->tester->grabFixture('accounts', 'account-with-change-email-finish-state')['id'];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ class ChangeUsernameFormTest extends TestCase {
|
||||
$this->assertTrue($model->change());
|
||||
$this->assertEquals('my_new_nickname', Account::findOne($this->getAccountId())->username);
|
||||
$this->assertInstanceOf(UsernameHistory::class, UsernameHistory::findOne(['username' => 'my_new_nickname']));
|
||||
$this->tester->canSeeAmqpMessageIsCreated('events');
|
||||
}
|
||||
|
||||
public function testChangeWithoutChange() {
|
||||
@ -49,7 +50,8 @@ class ChangeUsernameFormTest extends TestCase {
|
||||
'AND',
|
||||
'username' => $username,
|
||||
['>=', 'applied_in', $callTime],
|
||||
]), 'no new UsernameHistory record, if we don\'t change nickname');
|
||||
]), 'no new UsernameHistory record, if we don\'t change username');
|
||||
$this->tester->cantSeeAmqpMessageIsCreated('events');
|
||||
}
|
||||
|
||||
public function testChangeCase() {
|
||||
@ -65,13 +67,17 @@ class ChangeUsernameFormTest extends TestCase {
|
||||
UsernameHistory::findOne(['username' => $newUsername]),
|
||||
'username should change, if we change case of some letters'
|
||||
);
|
||||
$this->tester->canSeeAmqpMessageIsCreated('events');
|
||||
}
|
||||
|
||||
public function testCreateTask() {
|
||||
$model = new ChangeUsernameForm();
|
||||
$model->createEventTask('1', 'test1', 'test');
|
||||
// TODO: у меня пока нет идей о том, чтобы это как-то успешно протестировать, увы
|
||||
// но по крайней мере можно убедиться, что оно не падает где-то на этом шаге
|
||||
$model->createEventTask(1, 'test1', 'test');
|
||||
$message = $this->tester->grabLastSentAmqpMessage('events');
|
||||
$body = json_decode($message->getBody(), true);
|
||||
$this->assertEquals(1, $body['accountId']);
|
||||
$this->assertEquals('test1', $body['newUsername']);
|
||||
$this->assertEquals('test', $body['oldUsername']);
|
||||
}
|
||||
|
||||
private function getAccountId() {
|
||||
|
94
tests/codeception/common/_support/amqp/Helper.php
Normal file
94
tests/codeception/common/_support/amqp/Helper.php
Normal file
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
namespace tests\codeception\common\_support\amqp;
|
||||
|
||||
use Codeception\Exception\ModuleException;
|
||||
use Codeception\Module;
|
||||
use Codeception\Module\Yii2;
|
||||
|
||||
class Helper extends Module {
|
||||
|
||||
/**
|
||||
* Checks that message is created.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* // check that at least 1 message was created
|
||||
* $I->seeAmqpMessageIsCreated();
|
||||
*
|
||||
* // check that only 3 messages were created
|
||||
* $I->seeAmqpMessageIsCreated(3);
|
||||
* ```
|
||||
*
|
||||
* @param string|null $exchange
|
||||
* @param int|null $num
|
||||
*/
|
||||
public function seeAmqpMessageIsCreated($exchange = null, $num = null) {
|
||||
if ($num === null) {
|
||||
$this->assertNotEmpty($this->grabSentAmqpMessages($exchange), 'message were created');
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: заменить на assertCount() после релиза Codeception 2.2.7
|
||||
// https://github.com/Codeception/Codeception/pull/3802
|
||||
/** @noinspection PhpUnitTestsInspection */
|
||||
$this->assertEquals(
|
||||
$num,
|
||||
count($this->grabSentAmqpMessages($exchange)),
|
||||
'number of created messages is equal to ' . $num
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that no messages was created
|
||||
*
|
||||
* @param string|null $exchange
|
||||
*/
|
||||
public function dontSeeAmqpMessageIsCreated($exchange = null) {
|
||||
$this->seeAmqpMessageIsCreated($exchange, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns last sent message
|
||||
*
|
||||
* @param string|null $exchange
|
||||
* @return \PhpAmqpLib\Message\AMQPMessage
|
||||
*/
|
||||
public function grabLastSentAmqpMessage($exchange = null) {
|
||||
$this->seeAmqpMessageIsCreated();
|
||||
$messages = $this->grabSentAmqpMessages($exchange);
|
||||
|
||||
return end($messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of all sent amqp messages.
|
||||
* Each message is `\PhpAmqpLib\Message\AMQPMessage` instance.
|
||||
* Useful to perform additional checks using `Asserts` module.
|
||||
*
|
||||
* @param string|null $exchange
|
||||
* @return \PhpAmqpLib\Message\AMQPMessage[]
|
||||
* @throws ModuleException
|
||||
*/
|
||||
public function grabSentAmqpMessages($exchange = null) {
|
||||
$amqp = $this->grabComponent('amqp');
|
||||
if (!$amqp instanceof TestComponent) {
|
||||
throw new ModuleException($this, 'AMQP module is not mocked, can\'t test messages');
|
||||
}
|
||||
|
||||
return $amqp->getSentMessages($exchange);
|
||||
}
|
||||
|
||||
private function grabComponent(string $component) {
|
||||
return $this->getYii2()->grabComponent($component);
|
||||
}
|
||||
|
||||
private function getYii2() : Yii2 {
|
||||
$yii2 = $this->getModule('Yii2');
|
||||
if (!$yii2 instanceof Yii2) {
|
||||
throw new ModuleException($this, 'Yii2 module must be configured');
|
||||
}
|
||||
|
||||
return $yii2;
|
||||
}
|
||||
|
||||
}
|
58
tests/codeception/common/_support/amqp/TestComponent.php
Normal file
58
tests/codeception/common/_support/amqp/TestComponent.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
namespace tests\codeception\common\_support\amqp;
|
||||
|
||||
use common\components\RabbitMQ\Component;
|
||||
use PhpAmqpLib\Connection\AbstractConnection;
|
||||
|
||||
class TestComponent extends Component {
|
||||
|
||||
private $sentMessages = [];
|
||||
|
||||
public function init() {
|
||||
\yii\base\Component::init();
|
||||
}
|
||||
|
||||
public function getConnection() {
|
||||
/** @noinspection MagicMethodsValidityInspection */
|
||||
/** @noinspection PhpMissingParentConstructorInspection */
|
||||
return new class extends AbstractConnection {
|
||||
public function __construct(
|
||||
$user,
|
||||
$password,
|
||||
$vhost,
|
||||
$insist,
|
||||
$login_method,
|
||||
$login_response,
|
||||
$locale,
|
||||
\PhpAmqpLib\Wire\IO\AbstractIO $io,
|
||||
$heartbeat
|
||||
) {
|
||||
// ничего не делаем
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public function sendToExchange($exchangeName, $routingKey, $message, $exchangeArgs = [], $publishArgs = []) {
|
||||
$this->sentMessages[$exchangeName][] = $this->prepareMessage($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $exchangeName
|
||||
* @return \PhpAmqpLib\Message\AMQPMessage[]
|
||||
*/
|
||||
public function getSentMessages(string $exchangeName = null) : array {
|
||||
if ($exchangeName !== null) {
|
||||
return $this->sentMessages[$exchangeName] ?? [];
|
||||
} else {
|
||||
$messages = [];
|
||||
foreach($this->sentMessages as $exchangeGroup) {
|
||||
foreach ($exchangeGroup as $message) {
|
||||
$messages[] = $message;
|
||||
}
|
||||
}
|
||||
|
||||
return $messages;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
namespace: tests\codeception\common
|
||||
actor: Tester
|
||||
params: [env]
|
||||
paths:
|
||||
tests: .
|
||||
log: _output
|
||||
|
@ -6,3 +6,4 @@ modules:
|
||||
config:
|
||||
Yii2:
|
||||
configFile: '../config/common/unit.php'
|
||||
cleanup: false
|
||||
|
@ -10,30 +10,16 @@ return [
|
||||
],
|
||||
],
|
||||
'components' => [
|
||||
'db' => [
|
||||
'dsn' => 'mysql:host=testdb;dbname=ely_accounts_test',
|
||||
'username' => 'ely_accounts_tester',
|
||||
'password' => 'ely_accounts_tester_password',
|
||||
],
|
||||
'mailer' => [
|
||||
'useFileTransport' => true,
|
||||
],
|
||||
'urlManager' => [
|
||||
'showScriptName' => true,
|
||||
],
|
||||
'redis' => [
|
||||
'hostname' => 'testredis',
|
||||
],
|
||||
'amqp' => [
|
||||
'host' => 'testrabbit',
|
||||
'user' => 'ely-accounts-tester',
|
||||
'password' => 'tester-password',
|
||||
'vhost' => '/account.ely.by/tests',
|
||||
],
|
||||
'security' => [
|
||||
// Для тестов нам не сильно важна безопасность, а вот время прохождения тестов значительно сокращается
|
||||
'passwordHashCost' => 4,
|
||||
],
|
||||
'amqp' => [
|
||||
'class' => tests\codeception\common\_support\amqp\TestComponent::class,
|
||||
],
|
||||
'sentry' => [
|
||||
'enabled' => false,
|
||||
],
|
||||
|
@ -1,5 +1,6 @@
|
||||
namespace: tests\codeception\console
|
||||
actor: Tester
|
||||
params: [env]
|
||||
paths:
|
||||
tests: .
|
||||
log: _output
|
||||
|
@ -6,3 +6,4 @@ modules:
|
||||
config:
|
||||
Yii2:
|
||||
configFile: '../config/console/unit.php'
|
||||
cleanup: false
|
||||
|
@ -9,18 +9,21 @@ services:
|
||||
depends_on:
|
||||
- testdb
|
||||
- testredis
|
||||
- testrabbit
|
||||
volumes:
|
||||
- ./codeception/_output:/var/www/html/tests/codeception/_output
|
||||
- ./codeception/api/_output:/var/www/html/tests/codeception/api/_output
|
||||
- ./codeception/common/_output:/var/www/html/tests/codeception/common/_output
|
||||
- ./codeception/console/_output:/var/www/html/tests/codeception/console/_output
|
||||
- ./..:/var/www/html
|
||||
environment:
|
||||
- YII_DEBUG=true
|
||||
- YII_ENV=test
|
||||
YII_DEBUG: "true"
|
||||
YII_ENV: "test"
|
||||
# DB config
|
||||
DB_HOST: "testdb"
|
||||
DB_DATABASE: "ely_accounts_test"
|
||||
DB_USER: "ely_accounts_tester"
|
||||
DB_PASSWORD: "ely_accounts_tester_password"
|
||||
# Redis config
|
||||
REDIS_HOST: "testredis"
|
||||
# Это я потом, когда-нибудь, уберу
|
||||
- XDEBUG_CONFIG=remote_host=10.254.254.254
|
||||
- PHP_IDE_CONFIG=serverName=docker
|
||||
XDEBUG_CONFIG: "remote_host=10.254.254.254"
|
||||
PHP_IDE_CONFIG: "serverName=docker"
|
||||
|
||||
testdb:
|
||||
container_name: accountelyby_testdb
|
||||
@ -36,11 +39,3 @@ services:
|
||||
testredis:
|
||||
container_name: accountelyby_testredis
|
||||
image: redis:3.0-alpine
|
||||
|
||||
testrabbit:
|
||||
container_name: accountelyby_testrabbit
|
||||
image: rabbitmq:3.6
|
||||
environment:
|
||||
RABBITMQ_DEFAULT_USER: "ely-accounts-tester"
|
||||
RABBITMQ_DEFAULT_PASS: "tester-password"
|
||||
RABBITMQ_DEFAULT_VHOST: "/account.ely.by/tests"
|
||||
|
Loading…
Reference in New Issue
Block a user