Skip to content

Commit

Permalink
Merge pull request #41 from gregorg/feature/handle_slave_delay
Browse files Browse the repository at this point in the history
Feature: handle slave delay + fix master/slave distribution + fix unit tests
  • Loading branch information
gregorg authored Dec 14, 2017
2 parents 865ebe4 + e059c51 commit c763ac2
Show file tree
Hide file tree
Showing 14 changed files with 349 additions and 48 deletions.
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ php:
- "7.1"

addons:
postgresql: "9.4"
postgresql: "9.6"

before_script:
- phpenv config-add config/docker/php/behat/apc.ini
- composer install
- psql -c "create role admin login createdb password 'adminpassword' superuser ;" -U postgres
- psql -c "create role behat login createdb password 'behatpassword';" -U postgres
Expand Down
4 changes: 4 additions & 0 deletions behat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ default:
contexts: [ PdoPgsqlContext ]
filters:
tags: ~@skip-pdo-pgsql
mysqlreplic:
contexts: [ MysqlReplicContext ]
filters:
tags: ~@skip-mysql-replic
9 changes: 7 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
{
"name": "Mathieu Rochette",
"email": "[email protected]"
},
{
"name": "Grégory Duchatelet",
"email": "[email protected]"
}
],
"autoload": {
Expand All @@ -13,9 +17,10 @@
}
},
"require": {
"php": "^7.1",
"php": "^7",
"doctrine/dbal": "^2.5.2",
"psr/cache": "^1.0.0"
"psr/cache": "^1.0",
"cache/apcu-adapter": "^1.0"
},
"require-dev": {
"behat/behat": "~3.0"
Expand Down
12 changes: 6 additions & 6 deletions config/docker/php/behat/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
FROM php:7.1
FROM isanosyan/php:7.1-cli-base

RUN apt-get update
RUN apt-get install -y git file libpq-dev
RUN apt-get install -y git file libpq-dev php-apcu php7.1-dev php7.1-mbstring php7.1-mysql php7.1-pgsql
RUN cd /tmp/ && git clone git://github.com/xdebug/xdebug.git
RUN cd /tmp/xdebug && git checkout XDEBUG_2_5_5 && phpize && ./configure --enable-xdebug && make && cp modules/xdebug.so /usr/local/lib/php/extensions/
RUN cd /tmp/xdebug && git checkout XDEBUG_2_5_5 && phpize && ./configure --enable-xdebug && make && make install

COPY apc.ini /etc/php/7.1/mods-available/apcu.ini
RUN phpenmod -v ALL -s ALL apcu

RUN docker-php-ext-install mbstring
RUN docker-php-ext-install pdo_mysql pdo_pgsql mysqli
RUN docker-php-ext-install pcntl

ENTRYPOINT ["php", "/scripts/vendor/bin/behat"]

Expand Down
33 changes: 33 additions & 0 deletions config/docker/php/behat/apc.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
extension=apcu.so
zend.assertions = On

[Assertion]
; Assert(expr); active by default.
; http://php.net/assert.active
assert.active = On

; Issue a PHP warning for each failed assertion.
; http://php.net/assert.warning
assert.warning = On
assert.exception = On

; Don't bail out by default.
; http://php.net/assert.bail
;assert.bail = Off

; User-function to be called if an assertion fails.
; http://php.net/assert.callback
;assert.callback = 0

; Eval the expression with current error_reporting(). Set to true if you want
; error_reporting(0) around the eval().
; http://php.net/assert.quiet-eval
;assert.quiet_eval = 0

[apc]
apc.enabled=1
apc.shm_size=4M
apc.ttl=60
apc.user_ttl=60
apc.enable_cli=1
apc.gc_ttl=600
29 changes: 27 additions & 2 deletions features/bootstrap/FeatureContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,10 @@ public function aRetryMasterSlavesConnectionWithSlavesLimitedToRetriesWithuserna

$slaveCount = (int) $slaveCount;
$slaves = [];
$master['weight'] = 1;
while ($slaveCount--) {
$master['weight'] = 1;
$slaves[] = $master;
$master['weight']++;
}

$params = [
Expand Down Expand Up @@ -138,7 +139,7 @@ public function requestsAreForcedOnMasterFor($connectionName)
if ($connection instanceof Ez\DbLinker\Driver\Connection\RetryConnection) {
$connection = $connection->wrappedConnection();
}
$connection->connectToMaster();
$connection->connectToMaster(true);
}

/**
Expand Down Expand Up @@ -518,5 +519,29 @@ public function tableCanBeCreatedAutomaticallyOn($tableName, $connectionName)
});
}

/**
* @Given the cache is disable on :connectionName
*/
public function theCacheIsDisable($connectionName)
{
$connection = $this->getWrappedConnection($connectionName);
$connection->disableCache();
}

/**
* @Given slave replication is stopped on :connectionName
*/
public function slaveReplicationIsStopped($connectionName)
{
$connection = $this->getWrappedConnection($connectionName);
if ($connection instanceof Ez\DbLinker\Driver\Connection\RetryConnection) {
$connection = $connection->wrappedConnection();
}
$connection->connectToSlave();
$connection->setSlaveStatus(false, 120);
$connection->isSlaveOk();
}


abstract protected function retryStrategy($n);
}
48 changes: 48 additions & 0 deletions features/bootstrap/MysqlReplicContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

use Behat\Behat\Context\Context;
use Behat\Behat\Context\SnippetAcceptingContext;

class MysqlReplicContext implements Context, SnippetAcceptingContext
{
use FeatureContext;
use MySQLContext;

private function masterParams($username = null, $password = '') {
$params = [
'host' => '192.168.0.8',
'user' => $username === null ? 'mcm' : $username,
'password' => 'uvieng7c',
'dbname' => 'mcm',
];
return $this->params($params);
}
/**
* @BeforeScenario
*/
public function clearConnections() {
}

/**
* @BeforeScenario
*/
public function clearDatabase() {
}

/**
* @BeforeScenario
*/
public function assertNoActiveConnection() {
}

private function params(Array $params)
{
$params['driver'] = 'mysqli';
return $params;
}

private function defaultDatabaseName()
{
return 'mcm';
}
}
11 changes: 9 additions & 2 deletions features/master-slave.feature
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Feature: Master / Slaves
When I exec "SET @var = 1" on "conn"
And I query "SELECT 1" on "conn"
Then the last query succeeded on "conn"
And "conn" is on master
And "conn" is on slave

Scenario: Connect on master when there is no slaves
Given a master/slaves connection "connMaster" with no slaves
Expand All @@ -44,4 +44,11 @@ Feature: Master / Slaves
And "conn" is on master

Scenario: Get database
Then I can get the database name on "conn"
Then I can get the database name on "conn"

Scenario: Disable cache
Given the cache is disable on "conn"
When I query "SELECT 1" on "conn"
Then the last query succeeded on "conn"
And "conn" is on slave

43 changes: 29 additions & 14 deletions features/retry-master-slave.feature
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,25 @@ Feature: Retry Master/Slaves
And "conn" retry limit should be 0
And "conn" should have 1 slave

@skip-mysql-replic
Scenario: ER_BAD_DB_ERROR restart on another slave
Given a retry master/slaves connection "conn" with 2 slaves limited to 1 retry with db "unknown_db"
When I query "SELECT 1" on "conn"
Then the last query failed on "conn"
And the last error should be "DBACCESS_DENIED" on "conn"
And "conn" retry limit should be 0
And "conn" should have 1 slave
@skip-pdo-pgsql
Scenario: database has Gone Away
Given a retry master/slaves connection "conn" with 2 slaves limited to 1 retry
And requests are forced on master for "conn"
And database has Gone Away on "conn"
When I query "SELECT 1" on "conn"
Then the last query succeeded on "conn"
And the last error should be "GONE_AWAY" on "conn"
And "conn" retry limit should be 0
And "conn" should have 2 slaves

Scenario: ACCESS_DENIED_ERROR does not restart on master
Given a retry master/slaves connection "conn" with 2 slaves limited to 1 retry with username "nobody"
And requests are forced on master for "conn"
Expand All @@ -22,14 +41,7 @@ Feature: Retry Master/Slaves
And "conn" retry limit should be 1
And "conn" should have 2 slaves

Scenario: ER_BAD_DB_ERROR restart on another slave
Given a retry master/slaves connection "conn" with 2 slaves limited to 1 retry with db "unknown_db" and username "root"
When I query "SELECT 1" on "conn"
Then the last query failed on "conn"
And the last error should be "BAD_DB" on "conn"
And "conn" retry limit should be 0
And "conn" should have 1 slave

@skip-mysql-replic
Scenario: ER_BAD_DB_ERROR does not restart on master
Given a retry master/slaves connection "conn" with 2 slaves limited to 1 retry with db "unknown_db" and username "root"
And requests are forced on master for "conn"
Expand All @@ -38,12 +50,15 @@ Feature: Retry Master/Slaves
And the last error should be "BAD_DB" on "conn"
And "conn" retry limit should be 1
And "conn" should have 2 slaves
@skip-pdo-pgsql
Scenario: database has Gone Away

@skip-travis @skip-mysqli @skip-pdo-pgsql
Scenario: Replication is stopped on slave and query restart on another slave
Given a retry master/slaves connection "conn" with 2 slaves limited to 1 retry
And database has Gone Away on "conn"
And slave replication is stopped on "conn"
When I query "SELECT 1" on "conn"
Then the last query succeeded on "conn"
And the last error should be "GONE_AWAY" on "conn"
And "conn" retry limit should be 0
And "conn" should have 2 slaves
And "conn" retry limit should be 1
And "conn" should have 1 slaves



15 changes: 9 additions & 6 deletions features/retry.feature
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ Feature: Retry
Then the last query succeeded on "conn"
And the last error should be "GONE_AWAY" on "conn"
And "conn" retry limit should be 0
@skip-pdo-pgsql
@skip-pdo-pgsql @skip-mysql-replic
Scenario: Lock wait timeout exceeded
Given a retry connection "once" limited to 1 retry
And a retry connection "@master" limited to 1 retry
And I exec "SET SESSION innodb_lock_wait_timeout = 1" on "@master"
And I exec "SET SESSION innodb_lock_wait_timeout = 1" on "once"
And there is a table "test_lock" on "@master"
Expand All @@ -24,13 +25,13 @@ Feature: Retry
Then the last query failed on "conn"
And the last error should be "LOCK_WAIT_TIMEOUT" on "once"
And "once" retry limit should be 0
@skip-travis @skip-mysqli @skip-pdo-pgsql
@skip-travis @skip-mysqli @skip-pdo-pgsql @skip-mysql-replic
Scenario: Deadlock found when trying to get lock
Given a retry connection "@master" limited to 1 retry
When I create a deadlock on "conn" with "@master"
Then the last query succeeded on "conn"
And the last error should be "DEADLOCK" on "conn"
Then the last error should be "DEADLOCK" on "conn"
And "conn" retry limit should be 0
@skip-travis-pdo-pgsql
@skip-travis-pdo-pgsql @skip-mysql-replic
Scenario: ER_DBACCESS_DENIED_ERROR don't restart
Given a retry connection "conn" limited to 1 retry with db "forbidden_db"
When I query "SELECT 1" on "conn"
Expand All @@ -45,6 +46,7 @@ Feature: Retry
And the last error should be "ACCESS_DENIED" on "conn"
And "conn" retry limit should be 1

@skip-mysql-replic
Scenario: ER_BAD_DB_ERROR don't restart
Given a retry connection "conn" limited to 1 retry with db "unknown_db" and username "root"
When I query "SELECT 1" on "conn"
Expand All @@ -67,7 +69,7 @@ Feature: Retry
And I query "SELECT 1" on "conn"
Then the last query succeeded on "conn"
And "conn" retry limit should be 0
@skip-pdo-pgsql
@skip-pdo-pgsql @skip-mysql-replic
Scenario: Too many connections
Given the server accept 1 more connections
And a retry connection "conn1" limited to 1 retry
Expand All @@ -81,6 +83,7 @@ Feature: Retry
Scenario: Get database
Then I can get the database name on "conn"

@skip-mysql-replic
Scenario: No such table
Given table "not_here_yet" can be created automatically on "conn"
When I prepare a statement "SELECT * FROM not_here_yet" on "conn"
Expand Down
Loading

0 comments on commit c763ac2

Please sign in to comment.