From e1ddf7f0127e9745f94e5ff9f76ea828e9058720 Mon Sep 17 00:00:00 2001 From: Frédéric Guillot Date: Mon, 15 Sep 2014 22:35:56 +0200 Subject: Run unit tests across different database backends + fix bugs --- .travis.yml | 2 +- README.markdown | 4 +- app/Core/Loader.php | 33 ++++++- app/Model/Project.php | 31 +++++-- app/Model/Task.php | 38 ++++++-- app/check_setup.php | 5 -- app/common.php | 179 +++----------------------------------- app/constants.php | 70 +++++++++++++++ app/functions.php | 131 ++++++++++++++++++++++++++++ app/translator.php | 43 --------- docs/api-json-rpc.markdown | 6 +- docs/centos-installation.markdown | 5 ++ docs/secure-connections.markdown | 59 ------------- jsonrpc.php | 3 +- phpunit.xml | 7 -- tests/functionals.mysql.xml | 16 ++++ tests/functionals.postgres.xml | 16 ++++ tests/functionals.sqlite.xml | 13 +++ tests/functionals/ApiTest.php | 99 +++++++++++++-------- tests/units.mysql.xml | 11 +++ tests/units.postgres.xml | 12 +++ tests/units.sqlite.xml | 11 +++ tests/units/ActionTest.php | 30 +++---- tests/units/Base.php | 100 +++++++-------------- tests/units/TaskHistoryTest.php | 4 +- tests/units/TaskTest.php | 37 +++++--- vendor/PicoDb/Database.php | 6 ++ vendor/PicoDb/Table.php | 8 +- 28 files changed, 537 insertions(+), 442 deletions(-) create mode 100644 app/constants.php create mode 100644 app/functions.php delete mode 100644 app/translator.php delete mode 100644 docs/secure-connections.markdown delete mode 100644 phpunit.xml create mode 100644 tests/functionals.mysql.xml create mode 100644 tests/functionals.postgres.xml create mode 100644 tests/functionals.sqlite.xml create mode 100644 tests/units.mysql.xml create mode 100644 tests/units.postgres.xml create mode 100644 tests/units.sqlite.xml diff --git a/.travis.yml b/.travis.yml index edd10551..66f9c288 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,4 +7,4 @@ php: - "5.3" before_script: wget https://phar.phpunit.de/phpunit.phar -script: php phpunit.phar \ No newline at end of file +script: php phpunit.phar -c tests/units.sqlite.xml \ No newline at end of file diff --git a/README.markdown b/README.markdown index efb002ed..bbf81456 100644 --- a/README.markdown +++ b/README.markdown @@ -58,12 +58,12 @@ Documentation #### Installation - [Installation instructions](docs/installation.markdown) +- [Upgrade Kanboard to a new version](docs/update.markdown) - [Installation on Ubuntu](docs/ubuntu-installation.markdown) - [Installation on Debian](docs/debian-installation.markdown) - [Installation on Centos](docs/centos-installation.markdown) - [Installation on Windows Server with IIS](docs/windows-iis-installation.markdown) -- [Upgrade Kanboard to a new version](docs/update.markdown) -- [Secure connections (HTTPS)](docs/secure-connections.markdown) +- [Example with Nginx + HTTPS + SPDY + PHP-FPM](docs/secure-connections.markdown) #### Database diff --git a/app/Core/Loader.php b/app/Core/Loader.php index 7c437654..151081c1 100644 --- a/app/Core/Loader.php +++ b/app/Core/Loader.php @@ -10,18 +10,30 @@ namespace Core; */ class Loader { + /** + * List of paths + * + * @access private + * @var array + */ + private $paths = array(); + /** * Load the missing class * * @access public - * @param string $class Class name + * @param string $class Class name with namespace */ public function load($class) { - $filename = __DIR__.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.str_replace('\\', DIRECTORY_SEPARATOR, $class).'.php'; + foreach ($this->paths as $path) { + + $filename = $path.DIRECTORY_SEPARATOR.str_replace('\\', DIRECTORY_SEPARATOR, $class).'.php'; - if (file_exists($filename)) { - require $filename; + if (file_exists($filename)) { + require $filename; + break; + } } } @@ -34,4 +46,17 @@ class Loader { spl_autoload_register(array($this, 'load')); } + + /** + * Register a new path + * + * @access public + * @param string $path Path + * @return Core\Loader + */ + public function setPath($path) + { + $this->paths[] = $path; + return $this; + } } diff --git a/app/Model/Project.php b/app/Model/Project.php index 0ba18498..f8df1ae1 100644 --- a/app/Model/Project.php +++ b/app/Model/Project.php @@ -553,7 +553,8 @@ class Project extends Base */ public function update(array $values) { - return $this->db->table(self::TABLE)->eq('id', $values['id'])->save($values); + return $this->exists($values['id']) && + $this->db->table(self::TABLE)->eq('id', $values['id'])->save($values); } /** @@ -568,6 +569,18 @@ class Project extends Base return $this->db->table(self::TABLE)->eq('id', $project_id)->remove(); } + /** + * Return true if the project exists + * + * @access public + * @param integer $project_id Project id + * @return boolean + */ + public function exists($project_id) + { + return $this->db->table(self::TABLE)->eq('id', $project_id)->count() === 1; + } + /** * Enable a project * @@ -577,10 +590,11 @@ class Project extends Base */ public function enable($project_id) { - return $this->db + return $this->exists($project_id) && + $this->db ->table(self::TABLE) ->eq('id', $project_id) - ->save(array('is_active' => 1)); + ->update(array('is_active' => 1)); } /** @@ -592,10 +606,11 @@ class Project extends Base */ public function disable($project_id) { - return $this->db + return $this->exists($project_id) && + $this->db ->table(self::TABLE) ->eq('id', $project_id) - ->save(array('is_active' => 0)); + ->update(array('is_active' => 0)); } /** @@ -607,7 +622,8 @@ class Project extends Base */ public function enablePublicAccess($project_id) { - return $this->db + return $this->exists($project_id) && + $this->db ->table(self::TABLE) ->eq('id', $project_id) ->save(array('is_public' => 1, 'token' => Security::generateToken())); @@ -622,7 +638,8 @@ class Project extends Base */ public function disablePublicAccess($project_id) { - return $this->db + return $this->exists($project_id) && + $this->db ->table(self::TABLE) ->eq('id', $project_id) ->save(array('is_public' => 0, 'token' => '')); diff --git a/app/Model/Task.php b/app/Model/Task.php index 6f62c3d2..fcee67f7 100644 --- a/app/Model/Task.php +++ b/app/Model/Task.php @@ -150,16 +150,16 @@ class Task extends Base * Count all tasks for a given project and status * * @access public - * @param integer $project_id Project id - * @param array $status List of status id + * @param integer $project_id Project id + * @param integer $status_id Status id * @return array */ - public function getAll($project_id, array $status = array(self::STATUS_OPEN, self::STATUS_CLOSED)) + public function getAll($project_id, $status_id = self::STATUS_OPEN) { return $this->db ->table(self::TABLE) ->eq('project_id', $project_id) - ->in('is_active', $status) + ->eq('is_active', $status_id) ->findAll(); } @@ -382,6 +382,10 @@ class Task extends Base if (isset($values['score']) && empty($values['score'])) { $values['score'] = 0; } + + if (isset($values['is_active'])) { + $values['is_active'] = (int) $values['is_active']; + } } /** @@ -487,6 +491,18 @@ class Task extends Base } } + /** + * Return true if the project exists + * + * @access public + * @param integer $task_id Task id + * @return boolean + */ + public function exists($task_id) + { + return $this->db->table(self::TABLE)->eq('id', $task_id)->count() === 1; + } + /** * Mark a task closed * @@ -496,6 +512,10 @@ class Task extends Base */ public function close($task_id) { + if (! $this->exists($task_id)) { + return false; + } + $result = $this->db ->table(self::TABLE) ->eq('id', $task_id) @@ -520,12 +540,16 @@ class Task extends Base */ public function open($task_id) { + if (! $this->exists($task_id)) { + return false; + } + $result = $this->db ->table(self::TABLE) ->eq('id', $task_id) ->update(array( 'is_active' => 1, - 'date_completed' => '' + 'date_completed' => 0 )); if ($result) { @@ -544,6 +568,10 @@ class Task extends Base */ public function remove($task_id) { + if (! $this->exists($task_id)) { + return false; + } + $this->file->removeAll($task_id); return $this->db->table(self::TABLE)->eq('id', $task_id)->remove(); diff --git a/app/check_setup.php b/app/check_setup.php index 9ed16967..c4359d7a 100644 --- a/app/check_setup.php +++ b/app/check_setup.php @@ -33,8 +33,3 @@ if (! extension_loaded('mbstring')) { if (! is_writable('data')) { die('The directory "data" must be writeable by your web server user'); } - -// Include password_compat for PHP < 5.5 -if (version_compare(PHP_VERSION, '5.5.0', '<')) { - require __DIR__.'/../vendor/password.php'; -} diff --git a/app/common.php b/app/common.php index f46e3c6b..0ba7df9d 100644 --- a/app/common.php +++ b/app/common.php @@ -1,183 +1,32 @@ setPath('app'); +$loader->setPath('vendor'); $loader->execute(); $registry = new Registry; - -$registry->db = function() use ($registry) { - require __DIR__.'/../vendor/PicoDb/Database.php'; - - switch (DB_DRIVER) { - case 'sqlite': - require __DIR__.'/Schema/Sqlite.php'; - - $params = array( - 'driver' => 'sqlite', - 'filename' => DB_FILENAME - ); - - break; - - case 'mysql': - require __DIR__.'/Schema/Mysql.php'; - - $params = array( - 'driver' => 'mysql', - 'hostname' => DB_HOSTNAME, - 'username' => DB_USERNAME, - 'password' => DB_PASSWORD, - 'database' => DB_NAME, - 'charset' => 'utf8', - ); - - break; - - case 'postgres': - require __DIR__.'/Schema/Postgres.php'; - - $params = array( - 'driver' => 'postgres', - 'hostname' => DB_HOSTNAME, - 'username' => DB_USERNAME, - 'password' => DB_PASSWORD, - 'database' => DB_NAME, - ); - - break; - - default: - die('Database driver not supported'); - } - - $db = new \PicoDb\Database($params); - - if ($db->schema()->check(Schema\VERSION)) { - return $db; - } - else { - $errors = $db->getLogMessages(); - die('Unable to migrate database schema:

'.(isset($errors[0]) ? $errors[0] : 'Unknown error').''); - } -}; - -$registry->event = function() use ($registry) { - return new Event; -}; - -$registry->mailer = function() use ($registry) { - - require_once 'vendor/swiftmailer/swift_required.php'; - - switch (MAIL_TRANSPORT) { - case 'smtp': - $transport = Swift_SmtpTransport::newInstance(MAIL_SMTP_HOSTNAME, MAIL_SMTP_PORT); - $transport->setUsername(MAIL_SMTP_USERNAME); - $transport->setPassword(MAIL_SMTP_PASSWORD); - $transport->setEncryption(MAIL_SMTP_ENCRYPTION); - break; - case 'sendmail': - $transport = Swift_SendmailTransport::newInstance(MAIL_SENDMAIL_COMMAND); - break; - default: - $transport = Swift_MailTransport::newInstance(); - } - - return $transport; -}; +$registry->db = setup_db(); +$registry->event = setup_events(); +$registry->mailer = setup_mailer(); diff --git a/app/constants.php b/app/constants.php new file mode 100644 index 00000000..d52997d7 --- /dev/null +++ b/app/constants.php @@ -0,0 +1,70 @@ +setUsername(MAIL_SMTP_USERNAME); + $transport->setPassword(MAIL_SMTP_PASSWORD); + $transport->setEncryption(MAIL_SMTP_ENCRYPTION); + break; + case 'sendmail': + $transport = Swift_SendmailTransport::newInstance(MAIL_SENDMAIL_COMMAND); + break; + default: + $transport = Swift_MailTransport::newInstance(); + } + + return $transport; +} + +function setup_db() +{ + switch (DB_DRIVER) { + case 'sqlite': + require_once __DIR__.'/Schema/Sqlite.php'; + + $params = array( + 'driver' => 'sqlite', + 'filename' => DB_FILENAME + ); + + break; + + case 'mysql': + require_once __DIR__.'/Schema/Mysql.php'; + + $params = array( + 'driver' => 'mysql', + 'hostname' => DB_HOSTNAME, + 'username' => DB_USERNAME, + 'password' => DB_PASSWORD, + 'database' => DB_NAME, + 'charset' => 'utf8', + ); + + break; + + case 'postgres': + require_once __DIR__.'/Schema/Postgres.php'; + + $params = array( + 'driver' => 'postgres', + 'hostname' => DB_HOSTNAME, + 'username' => DB_USERNAME, + 'password' => DB_PASSWORD, + 'database' => DB_NAME, + ); + + break; + + default: + die('Database driver not supported'); + } + + $db = new Database($params); + + if ($db->schema()->check(Schema\VERSION)) { + return $db; + } + else { + $errors = $db->getLogMessages(); + die('Unable to migrate database schema:

'.(isset($errors[0]) ? $errors[0] : 'Unknown error').''); + } +} + +// Get a translation +function t() +{ + $t = new Translator; + return call_user_func_array(array($t, 'translate'), func_get_args()); +} + +// translate with no html escaping +function e() +{ + $t = new Translator; + return call_user_func_array(array($t, 'translateNoEscaping'), func_get_args()); +} + +// Get a locale currency +function c($value) +{ + $t = new Translator; + return $t->currency($value); +} + +// Get a formatted number +function n($value) +{ + $t = new Translator; + return $t->number($value); +} + +// Get a locale date +function dt($format, $timestamp) +{ + $t = new Translator; + return $t->datetime($format, $timestamp); +} + +// Plurals, return $t2 if $value > 1 +function p($value, $t1, $t2) { + return $value > 1 ? $t2 : $t1; +} diff --git a/app/translator.php b/app/translator.php deleted file mode 100644 index ac4d72e2..00000000 --- a/app/translator.php +++ /dev/null @@ -1,43 +0,0 @@ -currency($value); -} - -// Get a formatted number -function n($value) -{ - $t = new Translator; - return $t->number($value); -} - -// Get a locale date -function dt($format, $timestamp) -{ - $t = new Translator; - return $t->datetime($format, $timestamp); -} - -// Plurals, return $t2 if $value > 1 -function p($value, $t1, $t2) { - return $value > 1 ? $t2 : $t1; -} diff --git a/docs/api-json-rpc.markdown b/docs/api-json-rpc.markdown index fa9fec85..a6420149 100644 --- a/docs/api-json-rpc.markdown +++ b/docs/api-json-rpc.markdown @@ -608,7 +608,7 @@ Response example: - Purpose: **Get all available tasks** - Parameters: - **project_id** (integer, required) - - **status**: List of status id, the value 1 for active tasks and 0 for inactive (list, required) + - **status**: The value 1 for active tasks and 0 for inactive (integer, required) - Result on success: **List of tasks** - Result on failure: **false** @@ -621,9 +621,7 @@ Request example to fetch all tasks on the board: "id": 133280317, "params": { "project_id": 1, - "status": [ - 1 - ] + "status": 1 } } ``` diff --git a/docs/centos-installation.markdown b/docs/centos-installation.markdown index f8963ecd..f5a31043 100644 --- a/docs/centos-installation.markdown +++ b/docs/centos-installation.markdown @@ -1,6 +1,11 @@ Centos Installation =================== +Centos 7 +-------- + + + Centos 6.5 ---------- diff --git a/docs/secure-connections.markdown b/docs/secure-connections.markdown deleted file mode 100644 index 109574ae..00000000 --- a/docs/secure-connections.markdown +++ /dev/null @@ -1,59 +0,0 @@ -How to Enable Secure Connections -================================ - -If you are hosting Kanboard on a public server, and plan on accessing it via the internet, it is a good idea to enable SSL connections to encrypt your data. This is very simple to do with a self-signed certificate. The following instructions were created and tested on a server running Debian 7 (Wheezy) but they should work for any other Linux distribution. - -OpenSSL Installation and Configuration --------------------------------------- -Install OpenSSL: - -```bash -apt-get update -apt-get install openssl -``` -Enable OpenSSL: - -```bash -a2enmod ssl -``` - -Create a self-signed certificate: - -```bash -mkdir /etc/apache2/ssl -openssl req -new -x509 -days 365 -nodes -out /etc/apache2/ssl/kanboard.pem -keyout /etc/apache2/ssl/kanboard.key -``` - -Apache Configuration --------------------- -Create an apache configuration file: - -```bash -nano /etc/apache2/conf.d/kanboard.conf -``` - -The contents of this file should look like this: - -```bash - - SSLEngine on - SSLCertificateFile /etc/apache2/ssl/kanboard.pem - SSLCertificateKeyFile /etc/apache2/ssl/kanboard.key - DocumentRoot /var/www - - AllowOverride All - order allow, deny - Allow from all - - -``` - -Be sure to replace 127.0.0.1 with the IP address of your server. If you are hosting kanboard in a location other than /var/www , be sure to update the DocumentRoot to match the location where you are hosting your Kanboard site. - -Restart Apache: - -```bash -service apache2 restart -``` - -You will now be able to access your Kanboard site securely by navigating to `https://www.example.com/kanboard`. Your browser will indicate that the certificate is not trusted. This is due to the fact that it is self signed. You can safely ignore this warning, although the certificate is not trusted, your data is still encrypted. diff --git a/jsonrpc.php b/jsonrpc.php index f6a2da45..71795a60 100644 --- a/jsonrpc.php +++ b/jsonrpc.php @@ -1,7 +1,6 @@ register('getTask', function($task_id) use ($task) { return $task->getById($task_id); }); -$server->register('getAllTasks', function($project_id, array $status) use ($task) { +$server->register('getAllTasks', function($project_id, $status) use ($task) { return $task->getAll($project_id, $status); }); diff --git a/phpunit.xml b/phpunit.xml deleted file mode 100644 index 5c4ce58c..00000000 --- a/phpunit.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - tests/units - - - \ No newline at end of file diff --git a/tests/functionals.mysql.xml b/tests/functionals.mysql.xml new file mode 100644 index 00000000..f667cafa --- /dev/null +++ b/tests/functionals.mysql.xml @@ -0,0 +1,16 @@ + + + + functionals + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/functionals.postgres.xml b/tests/functionals.postgres.xml new file mode 100644 index 00000000..38904d1a --- /dev/null +++ b/tests/functionals.postgres.xml @@ -0,0 +1,16 @@ + + + + functionals + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/functionals.sqlite.xml b/tests/functionals.sqlite.xml new file mode 100644 index 00000000..bf5d4117 --- /dev/null +++ b/tests/functionals.sqlite.xml @@ -0,0 +1,13 @@ + + + + functionals + + + + + + + + + \ No newline at end of file diff --git a/tests/functionals/ApiTest.php b/tests/functionals/ApiTest.php index 9a03c891..0960eba7 100644 --- a/tests/functionals/ApiTest.php +++ b/tests/functionals/ApiTest.php @@ -1,21 +1,52 @@ exec('DROP DATABASE '.DB_NAME); + $pdo->exec('CREATE DATABASE '.DB_NAME); + $pdo = new PDO('mysql:host='.DB_HOSTNAME.';dbname='.DB_NAME, DB_USERNAME, DB_PASSWORD); + } + else if (DB_DRIVER === 'postgres') { + $pdo = new PDO('pgsql:host='.DB_HOSTNAME, DB_USERNAME, DB_PASSWORD); + $pdo->exec('DROP DATABASE '.DB_NAME); + $pdo->exec('CREATE DATABASE '.DB_NAME.' WITH OWNER '.DB_USERNAME); + $pdo = new PDO('pgsql:host='.DB_HOSTNAME.';dbname='.DB_NAME, DB_USERNAME, DB_PASSWORD); + } + + setup_db(); + + $pdo->exec("UPDATE config SET api_token='".API_KEY."'"); + $pdo = null; + } + public function setUp() { - $this->client = new JsonRPC\Client(self::URL); - $this->client->authentication('jsonrpc', self::KEY); + $this->client = new JsonRPC\Client(API_URL); + $this->client->authentication('jsonrpc', API_KEY); + } + + private function getTaskId() + { + $tasks = $this->client->getAllTasks(1, 1); + $this->assertNotEmpty($tasks); + $this->assertEquals(1, count($tasks)); - $pdo = new PDO('sqlite:data/db.sqlite'); - $pdo->exec('UPDATE config SET api_token="'.self::KEY.'"'); + return $tasks[0]['id']; } public function testRemoveAll() @@ -154,13 +185,13 @@ class Api extends PHPUnit_Framework_TestCase public function testGetAllTasks() { - $tasks = $this->client->getAllTasks(1, array(1)); + $tasks = $this->client->getAllTasks(1, 1); $this->assertNotFalse($tasks); $this->assertTrue(is_array($tasks)); $this->assertEquals('Task #1', $tasks[0]['title']); - $tasks = $this->client->getAllTasks(2, array(1, 2)); + $tasks = $this->client->getAllTasks(2, 0); $this->assertNotFalse($tasks); $this->assertTrue(is_array($tasks)); @@ -228,10 +259,10 @@ class Api extends PHPUnit_Framework_TestCase public function testUpdateUser() { - $user = $this->client->getUser(2); + $user = array(); + $user['id'] = 2; $user['username'] = 'titi'; $user['name'] = 'Titi'; - unset($user['password']); $this->assertTrue($this->client->updateUser($user)); @@ -280,8 +311,12 @@ class Api extends PHPUnit_Framework_TestCase $this->assertTrue($this->client->execute('createTask', $task)); + $tasks = $this->client->getAllTasks(1, 1); + $this->assertNotEmpty($tasks); + $this->assertEquals(1, count($tasks)); + $comment = array( - 'task_id' => 1, + 'task_id' => $tasks[0]['id'], 'user_id' => 2, 'comment' => 'boo', ); @@ -294,7 +329,6 @@ class Api extends PHPUnit_Framework_TestCase $comment = $this->client->getComment(1); $this->assertNotFalse($comment); $this->assertNotEmpty($comment); - $this->assertEquals(1, $comment['task_id']); $this->assertEquals(2, $comment['user_id']); $this->assertEquals('boo', $comment['comment']); } @@ -312,15 +346,17 @@ class Api extends PHPUnit_Framework_TestCase public function testGetAllComments() { + $task_id = $this->getTaskId(); + $comment = array( - 'task_id' => 1, + 'task_id' => $task_id, 'user_id' => 1, 'comment' => 'blabla', ); $this->assertTrue($this->client->createComment($comment)); - $comments = $this->client->getAllComments(1); + $comments = $this->client->getAllComments($task_id); $this->assertNotFalse($comments); $this->assertNotEmpty($comments); $this->assertTrue(is_array($comments)); @@ -329,9 +365,10 @@ class Api extends PHPUnit_Framework_TestCase public function testRemoveComment() { - $this->assertTrue($this->client->removeComment(1)); + $task_id = $this->getTaskId(); + $this->assertTrue($this->client->removeComment($task_id)); - $comments = $this->client->getAllComments(1); + $comments = $this->client->getAllComments($task_id); $this->assertNotFalse($comments); $this->assertNotEmpty($comments); $this->assertTrue(is_array($comments)); @@ -341,7 +378,7 @@ class Api extends PHPUnit_Framework_TestCase public function testCreateSubtask() { $subtask = array( - 'task_id' => 1, + 'task_id' => $this->getTaskId(), 'title' => 'subtask #1', ); @@ -353,7 +390,7 @@ class Api extends PHPUnit_Framework_TestCase $subtask = $this->client->getSubtask(1); $this->assertNotFalse($subtask); $this->assertNotEmpty($subtask); - $this->assertEquals(1, $subtask['task_id']); + $this->assertEquals($this->getTaskId(), $subtask['task_id']); $this->assertEquals(0, $subtask['user_id']); $this->assertEquals('subtask #1', $subtask['title']); } @@ -362,7 +399,7 @@ class Api extends PHPUnit_Framework_TestCase { $subtask = array(); $subtask['id'] = 1; - $subtask['task_id'] = 1; + $subtask['task_id'] = $this->getTaskId(); $subtask['title'] = 'test'; $this->assertTrue($this->client->execute('updateSubtask', $subtask)); @@ -374,14 +411,14 @@ class Api extends PHPUnit_Framework_TestCase public function testGetAllSubtasks() { $subtask = array( - 'task_id' => 1, + 'task_id' => $this->getTaskId(), 'user_id' => 2, 'title' => 'Subtask #2', ); $this->assertTrue($this->client->execute('createSubtask', $subtask)); - $subtasks = $this->client->getAllSubtasks(1); + $subtasks = $this->client->getAllSubtasks($this->getTaskId()); $this->assertNotFalse($subtasks); $this->assertNotEmpty($subtasks); $this->assertTrue(is_array($subtasks)); @@ -392,7 +429,7 @@ class Api extends PHPUnit_Framework_TestCase { $this->assertTrue($this->client->removeSubtask(1)); - $subtasks = $this->client->getAllSubtasks(1); + $subtasks = $this->client->getAllSubtasks($this->getTaskId()); $this->assertNotFalse($subtasks); $this->assertNotEmpty($subtasks); $this->assertTrue(is_array($subtasks)); @@ -401,20 +438,10 @@ class Api extends PHPUnit_Framework_TestCase public function testMoveTaskPosition() { - $task = array( - 'title' => 'Task to move', - 'color_id' => 'blue', - 'owner_id' => 1, - 'project_id' => 1, - 'column_id' => 1, - ); - - $this->assertTrue($this->client->execute('createTask', $task)); - - $this->assertTrue($this->client->moveTaskPosition(1, 1, 3, 1)); - - $task = $this->client->getTask(1); + $task_id = $this->getTaskId(); + $this->assertTrue($this->client->moveTaskPosition(1, $task_id, 3, 1)); + $task = $this->client->getTask($task_id); $this->assertNotFalse($task); $this->assertTrue(is_array($task)); $this->assertEquals(1, $task['position']); diff --git a/tests/units.mysql.xml b/tests/units.mysql.xml new file mode 100644 index 00000000..0e308a05 --- /dev/null +++ b/tests/units.mysql.xml @@ -0,0 +1,11 @@ + + + + units + + + + + + + \ No newline at end of file diff --git a/tests/units.postgres.xml b/tests/units.postgres.xml new file mode 100644 index 00000000..0583c7f8 --- /dev/null +++ b/tests/units.postgres.xml @@ -0,0 +1,12 @@ + + + + units + + + + + + + + \ No newline at end of file diff --git a/tests/units.sqlite.xml b/tests/units.sqlite.xml new file mode 100644 index 00000000..9771a2a2 --- /dev/null +++ b/tests/units.sqlite.xml @@ -0,0 +1,11 @@ + + + + units + + + + + + + \ No newline at end of file diff --git a/tests/units/ActionTest.php b/tests/units/ActionTest.php index b07af992..23148c44 100644 --- a/tests/units/ActionTest.php +++ b/tests/units/ActionTest.php @@ -9,7 +9,7 @@ use Model\Task; use Model\Category; class ActionTest extends Base -{/* +{ public function testFetchActions() { $action = new Action($this->registry); @@ -86,15 +86,15 @@ class ActionTest extends Base // We move our task $task->movePosition(1, 1, 4, 1); - $this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_MOVE_COLUMN)); - $this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_UPDATE)); + $this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_MOVE_COLUMN)); + $this->assertFalse($this->registry->shared('event')->isEventTriggered(Task::EVENT_UPDATE)); // Our task should be closed $t1 = $task->getById(1); $this->assertEquals(4, $t1['column_id']); $this->assertEquals(0, $t1['is_active']); } -*/ + public function testEventMovePosition() { $task = new Task($this->registry); @@ -138,7 +138,7 @@ class ActionTest extends Base // We bind events $action->attachEvents(); - $this->assertTrue($this->registry->event->hasListener(Task::EVENT_MOVE_POSITION, 'Action\TaskAssignColorCategory')); + $this->assertTrue($this->registry->shared('event')->hasListener(Task::EVENT_MOVE_POSITION, 'Action\TaskAssignColorCategory')); // Our task should have the color red and position=1 $t1 = $task->getById(1); @@ -153,7 +153,7 @@ class ActionTest extends Base // We move our tasks $this->assertTrue($task->movePosition(1, 1, 1, 10)); // task #1 to the end of the column - $this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_MOVE_POSITION)); + $this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_MOVE_POSITION)); $t1 = $task->getById(1); $this->assertEquals(2, $t1['position']); @@ -165,10 +165,10 @@ class ActionTest extends Base $this->assertEquals(1, $t1['is_active']); $this->assertEquals('yellow', $t1['color_id']); - $this->registry->event->clearTriggeredEvents(); + $this->registry->shared('event')->clearTriggeredEvents(); $this->assertTrue($task->movePosition(1, 2, 1, 44)); // task #2 to position 1 - $this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_MOVE_POSITION)); - $this->assertEquals('Action\TaskAssignColorCategory', $this->registry->event->getLastListenerExecuted()); + $this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_MOVE_POSITION)); + $this->assertEquals('Action\TaskAssignColorCategory', $this->registry->shared('event')->getLastListenerExecuted()); $t1 = $task->getById(1); $this->assertEquals(1, $t1['position']); @@ -180,7 +180,7 @@ class ActionTest extends Base $this->assertEquals(1, $t1['is_active']); $this->assertEquals('green', $t1['color_id']); } -/* + public function testExecuteMultipleActions() { $task = new Task($this->registry); @@ -225,8 +225,8 @@ class ActionTest extends Base $action->attachEvents(); // Events should be attached - $this->assertTrue($this->registry->event->hasListener(Task::EVENT_CLOSE, 'Action\TaskDuplicateAnotherProject')); - $this->assertTrue($this->registry->event->hasListener(Task::EVENT_MOVE_COLUMN, 'Action\TaskClose')); + $this->assertTrue($this->registry->shared('event')->hasListener(Task::EVENT_CLOSE, 'Action\TaskDuplicateAnotherProject')); + $this->assertTrue($this->registry->shared('event')->hasListener(Task::EVENT_MOVE_COLUMN, 'Action\TaskClose')); // Our task should be open, linked to the first project and in the first column $t1 = $task->getById(1); @@ -237,8 +237,8 @@ class ActionTest extends Base // We move our task $task->movePosition(1, 1, 4, 1); - $this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_CLOSE)); - $this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_MOVE_COLUMN)); + $this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_CLOSE)); + $this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_MOVE_COLUMN)); // Our task should be closed $t1 = $task->getById(1); @@ -252,5 +252,5 @@ class ActionTest extends Base $this->assertEquals(1, $t2['is_active']); $this->assertEquals(2, $t2['project_id']); $this->assertEquals('unit_test', $t2['title']); - }*/ + } } diff --git a/tests/units/Base.php b/tests/units/Base.php index cea9764c..3a46a4ae 100644 --- a/tests/units/Base.php +++ b/tests/units/Base.php @@ -1,86 +1,48 @@ setPath('app'); +$loader->setPath('vendor'); +$loader->execute(); abstract class Base extends PHPUnit_Framework_TestCase { public function setUp() { - date_default_timezone_set('UTC'); - - $this->registry = new \Core\Registry; - $this->registry->db = $this->getDbConnection(); - $this->registry->event = new \Core\Event; + $this->registry = new Registry; + $this->registry->db = function() { return setup_db(); }; + $this->registry->event = function() { return setup_events(); }; + + if (DB_DRIVER === 'mysql') { + $pdo = new PDO('mysql:host='.DB_HOSTNAME, DB_USERNAME, DB_PASSWORD); + $pdo->exec('DROP DATABASE '.DB_NAME); + $pdo->exec('CREATE DATABASE '.DB_NAME); + $pdo = null; + } + else if (DB_DRIVER === 'postgres') { + $pdo = new PDO('pgsql:host='.DB_HOSTNAME, DB_USERNAME, DB_PASSWORD); + $pdo->exec('DROP DATABASE '.DB_NAME); + $pdo->exec('CREATE DATABASE '.DB_NAME.' WITH OWNER '.DB_USERNAME); + $pdo = null; + } } - public function getDbConnection() + public function tearDown() { - $db = new \PicoDb\Database(array( - 'driver' => 'sqlite', - 'filename' => ':memory:' - )); - - if ($db->schema()->check(\Schema\VERSION)) { - return $db; - } - else { - die('Unable to migrate database schema!'); - } + $this->registry->shared('db')->closeConnection(); } } diff --git a/tests/units/TaskHistoryTest.php b/tests/units/TaskHistoryTest.php index 0d24be58..085162ea 100644 --- a/tests/units/TaskHistoryTest.php +++ b/tests/units/TaskHistoryTest.php @@ -73,7 +73,7 @@ class TaskHistoryTest extends Base $this->assertTrue($e->create(1, 1, 1, Task::EVENT_CLOSE)); } - $this->assertEquals($nb_events, $this->registry->db->table('task_has_events')->count()); + $this->assertEquals($nb_events, $this->registry->shared('db')->table('task_has_events')->count()); $e->cleanup($max); $events = $e->getAllByProjectId(1); @@ -93,6 +93,6 @@ class TaskHistoryTest extends Base $this->assertTrue($e->create(1, 1, 1, Task::EVENT_CLOSE)); } - $this->assertEquals(TaskHistory::MAX_EVENTS, $this->registry->db->table('task_has_events')->count()); + $this->assertEquals(TaskHistory::MAX_EVENTS, $this->registry->shared('db')->table('task_has_events')->count()); } } diff --git a/tests/units/TaskTest.php b/tests/units/TaskTest.php index c9468efd..b876f7e4 100644 --- a/tests/units/TaskTest.php +++ b/tests/units/TaskTest.php @@ -33,6 +33,15 @@ class TaskTest extends Base $this->assertEquals(2, $task['position']); $this->assertEquals(time(), $task['date_creation']); $this->assertEquals(time(), $task['date_modification']); + + $tasks = $t->getAll(1, 1); + $this->assertNotEmpty($tasks); + $this->assertTrue(is_array($tasks)); + $this->assertEquals(1, $tasks[0]['id']); + $this->assertEquals(2, $tasks[1]['id']); + + $tasks = $t->getAll(1, 0); + $this->assertEmpty($tasks); } public function testRemove() @@ -53,11 +62,11 @@ class TaskTest extends Base $p = new Project($this->registry); $this->assertEquals(1, $p->create(array('name' => 'Project #1'))); - $this->assertEquals(1, $this->registry->db->table('tasks')->insert(array('title' => 'A', 'column_id' => 1, 'project_id' => 1, 'position' => 1))); + $this->assertEquals(1, $this->registry->shared('db')->table('tasks')->insert(array('title' => 'A', 'column_id' => 1, 'project_id' => 1, 'position' => 1))); // Both tasks have the same position - $this->assertEquals(2, $this->registry->db->table('tasks')->insert(array('title' => 'B', 'column_id' => 2, 'project_id' => 1, 'position' => 1))); - $this->assertEquals(3, $this->registry->db->table('tasks')->insert(array('title' => 'C', 'column_id' => 2, 'project_id' => 1, 'position' => 1))); + $this->assertEquals(2, $this->registry->shared('db')->table('tasks')->insert(array('title' => 'B', 'column_id' => 2, 'project_id' => 1, 'position' => 1))); + $this->assertEquals(3, $this->registry->shared('db')->table('tasks')->insert(array('title' => 'C', 'column_id' => 2, 'project_id' => 1, 'position' => 1))); // Move the first column to the last position of the 2nd column $this->assertTrue($t->movePosition(1, 1, 2, 3)); @@ -451,7 +460,7 @@ class TaskTest extends Base // We duplicate our task $this->assertEquals(2, $t->duplicateSameProject($task)); - $this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_CREATE)); + $this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_CREATE)); // Check the values of the duplicated task $task = $t->getById(2); @@ -483,7 +492,7 @@ class TaskTest extends Base // We duplicate our task to the 2nd project $this->assertEquals(2, $t->duplicateToAnotherProject(2, $task)); - $this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_CREATE)); + $this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_CREATE)); // Check the values of the duplicated task $task = $t->getById(2); @@ -517,7 +526,7 @@ class TaskTest extends Base // We duplicate our task to the 2nd project $task = $t->getById(1); $this->assertEquals(1, $t->moveToAnotherProject(2, $task)); - //$this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_CREATE)); + //$this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_CREATE)); // Check the values of the duplicated task $task = $t->getById(1); @@ -551,32 +560,32 @@ class TaskTest extends Base // We create task $this->assertEquals(1, $t->create(array('title' => 'test', 'project_id' => 1, 'column_id' => 1))); - $this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_CREATE)); + $this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_CREATE)); // We update a task $this->assertTrue($t->update(array('title' => 'test2', 'id' => 1))); - $this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_UPDATE)); - $this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_CREATE_UPDATE)); + $this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_UPDATE)); + $this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_CREATE_UPDATE)); // We close our task $this->assertTrue($t->close(1)); - $this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_CLOSE)); + $this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_CLOSE)); // We open our task $this->assertTrue($t->open(1)); - $this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_OPEN)); + $this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_OPEN)); // We change the column of our task $this->assertTrue($t->movePosition(1, 1, 2, 1)); - $this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_MOVE_COLUMN)); + $this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_MOVE_COLUMN)); // We change the position of our task $this->assertEquals(2, $t->create(array('title' => 'test 2', 'project_id' => 1, 'column_id' => 2))); $this->assertTrue($t->movePosition(1, 1, 2, 2)); - $this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_MOVE_POSITION)); + $this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_MOVE_POSITION)); // We change the column and the position of our task $this->assertTrue($t->movePosition(1, 1, 1, 1)); - $this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_MOVE_COLUMN)); + $this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_MOVE_COLUMN)); } } diff --git a/vendor/PicoDb/Database.php b/vendor/PicoDb/Database.php index 4d7b7031..5d0beb8a 100644 --- a/vendor/PicoDb/Database.php +++ b/vendor/PicoDb/Database.php @@ -78,6 +78,12 @@ class Database } + public function closeConnection() + { + $this->pdo = null; + } + + public function escapeIdentifier($value) { return $this->pdo->escapeIdentifier($value); diff --git a/vendor/PicoDb/Table.php b/vendor/PicoDb/Table.php index b333feb4..cc637434 100644 --- a/vendor/PicoDb/Table.php +++ b/vendor/PicoDb/Table.php @@ -44,7 +44,11 @@ class Table } } - + /** + * Update + * + * Note: Do not use `rowCount()` the behaviour is different across drivers + */ public function update(array $data) { $columns = array(); @@ -70,7 +74,7 @@ class Table $result = $this->db->execute($sql, $values); - return $result !== false && $result->rowCount() > 0; + return $result !== false; } -- cgit v1.2.3