diff --git a/Model/Datasource/CouchdbSource.php b/Model/Datasource/CouchDBSource.php similarity index 68% rename from Model/Datasource/CouchdbSource.php rename to Model/Datasource/CouchDBSource.php index 73f1301..04a735d 100644 --- a/Model/Datasource/CouchdbSource.php +++ b/Model/Datasource/CouchDBSource.php @@ -17,7 +17,8 @@ * @since CakePHP Datasources v 0.3 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'HttpSocket'); +App::uses('HttpSocket', 'Network/Http'); +App::uses('DataSource', 'Model/Datasource'); /** * CouchDB Datasource @@ -25,13 +26,27 @@ * @package datasources * @subpackage datasources.models.datasources */ -class CouchdbSource extends DataSource { +class CouchDBSource extends DataSource { /** - * Constructor + * Start quote + * + * @var string + */ + public $startQuote = null; + +/** + * End quote + * + * @var string + */ + public $endQuote = null; + +/** + * Constructor. * * @param array $config Connection setup for CouchDB. - * @param integer $autoConnect Autoconnect + * @param integer $autoConnect Autoconnect. * @return boolean */ public function __construct($config = null, $autoConnect = true) { @@ -51,10 +66,10 @@ public function __construct($config = null, $autoConnect = true) { } /** - * Reconnects to the database with optional new settings + * Reconnects to the database with optional new settings. * - * @param array $config New settings - * @return boolean Success + * @param array $config New settings. + * @return boolean Success. */ public function reconnect($config = null) { $this->disconnect(); @@ -64,9 +79,9 @@ public function reconnect($config = null) { } /** - * Connects to the database. Options are specified in the $config instance variable + * Connects to the database. Options are specified in the $config instance variable. * - * @return boolean Connected + * @return boolean Connected. */ public function connect() { if ($this->connected !== true) { @@ -76,12 +91,12 @@ public function connect() { if (isset($this->config['password'])) $this->config['request']['uri']['pass'] = $this->config['password']; - $this->Socket = new HttpSocket($this->config); - if (strpos($this->Socket->get(), 'couchdb') !== false) { + try { + $this->Socket = new HttpSocket($this->config); + $this->Socket->get(); $this->connected = true; - } else { - trigger_error(__('CouchDB Error: connection failed ', true), E_USER_WARNING); - return $this->cakeError('missingConnection', array(array('code' => 500, 'className' => 'CouchdbSource'))); + } catch (SocketException $e) { + throw new MissingConnectionException(array('class' => $e->getMessage())); } } return $this->connected; @@ -92,7 +107,7 @@ public function connect() { * connection is closed, and if DEBUG is turned on (equal to 2) displays the * log of stored data. * - * @return boolean Disconnected + * @return boolean Disconnected. */ public function close() { if (Configure::read('debug') > 1) { @@ -102,9 +117,9 @@ public function close() { } /** - * Disconnect from the database + * Disconnect from the database. * - * @return boolean Disconnected + * @return boolean Disconnected. */ public function disconnect() { if (isset($this->results) && is_resource($this->results)) { @@ -115,19 +130,20 @@ public function disconnect() { } /** - * List of databases + * List of databases. * - * @return array Databases + * @return array Databases. */ public function listSources() { - return $this->__decode($this->Socket->get($this->__uri('_all_dbs')), true); + $databases = $this->__decode($this->Socket->get($this->__uri('_all_dbs')), true); + return $databases; } /** * Convenience method for DboSource::listSources(). * Returns the names of databases in lowercase. * - * @return array Lowercase databases + * @return array Lowercase databases. */ public function sources($reset = false) { if ($reset === true) { @@ -137,10 +153,10 @@ public function sources($reset = false) { } /** - * Returns a description of the model (metadata) + * Returns a description of the model (metadata). * * @param Model $model - * @return array + * @return array Schema. */ public function describe($model) { return $model->schema; @@ -149,12 +165,12 @@ public function describe($model) { /** * Creates a new document in the database. * If the primaryKey is declared, creates the document with the specified ID. - * To create a new database: $this->__decode($this->Socket->put($this->__uri('databaseName'))); + * To create a new database: $this->Model->curlPut('databaseName'); * * @param Model $model * @param array $fields An array of field names to insert. If null, $model->data will be used to generate the field names. * @param array $values An array with key values of the fields. If null, $model->data will be used to generate the field names. - * @return boolean Success + * @return boolean Success. */ public function create($model, $fields = null, $values = null) { $data = $model->data; @@ -183,7 +199,7 @@ public function create($model, $fields = null, $values = null) { * Reads data from a document. * * @param Model $model - * @param array $queryData An array of information containing $queryData keys, similar to Model::find() + * @param array $queryData An array of information containing $queryData keys, similar to Model::find(). * @param integer $recursive Level number of associations. * @return mixed False if an error occurred, otherwise an array of results. */ @@ -224,7 +240,7 @@ public function read($model, $queryData = array(), $recursive = null) { * Applies the rules to the document read. * * @param Model $model - * @param array $queryData An array of information containing $queryData keys, similar to Model::find() + * @param array $queryData An array of information containing $queryData keys, similar to Model::find(). * @param array $result Data read from the document. * @return mixed False if an error occurred, otherwise an array of results. */ @@ -269,7 +285,7 @@ private function __readResult($model, $queryData, $result) { * @param array $fields * @param array $values * @param mixed $conditions - * @return boolean Success + * @return boolean Success. */ public function update($model, $fields = null, $values = null, $conditions = null) { $data = $model->data[$model->alias]; @@ -307,21 +323,36 @@ private function __idRevData(&$model, &$data) { unset($data['rev']); } else if ($model->rev) { $data['_rev'] = $model->rev; + } else { + $data['_rev'] = $this->__lastRevision($model, $model->id); } } /** - * Generates and executes a DELETE statement + * The method searches for the latest revision of a document + * + * @param object $model + * @param int $id + * @return string Last revision of the document + */ + private function __lastRevision(&$model, $id) { + $result = $this->__decode($this->Socket->get($this->__uri($model, $id))); + return $result->_rev; + } + +/** + * Generates and executes a DELETE statement. * * @param Model $model * @param mixed $conditions - * @return boolean Success + * @return boolean Success. */ public function delete($model, $conditions = null) { $id = $model->id; $rev = $model->rev; - if (!empty($id) && !empty($rev)) { + if (!empty($id)) { + if (empty($rev)) $rev = $this->__lastRevision($model, $id); $id_rev = $id . '/?rev=' . $rev; $result = $this->__decode($this->Socket->delete($this->__uri($model, $id_rev))); return $this->__checkOk($result); @@ -330,23 +361,37 @@ public function delete($model, $conditions = null) { } /** - * Returns an instruction to count data. (SQL, i.e. COUNT() or MAX()) + * Returns an instruction to count data. (SQL, i.e. COUNT() or MAX()). * * @param model $model - * @param string $func Lowercase name of SQL function, i.e. 'count' or 'max' - * @param array $params Function parameters (any values must be quoted manually) - * @return string An SQL calculation function + * @param string $func Lowercase name of SQL function, i.e. 'count' or 'max'. + * @param array $params Function parameters (any values must be quoted manually). + * @return string An SQL calculation function. */ public function calculate($model, $func, $params = array()) { return true; } /** - * Gets full table name including prefix + * Returns an object to represent a database expression in a query. Expression objects + * are not sanitized or escaped. + * + * @param string $expression An arbitrary expression to be inserted into a query. + * @return stdClass An object representing a database expression to be used in a query + */ + public function expression($expression) { + $obj = new stdClass(); + $obj->type = 'expression'; + $obj->value = $expression; + return $obj; + } + +/** + * Gets full table name including prefix. * * @param mixed $model * @param boolean $quote - * @return string Full name of table + * @return string Full name of table. */ public function fullTableName($model = null, $quote = true) { $table = null; @@ -361,22 +406,75 @@ public function fullTableName($model = null, $quote = true) { } /** - * Perform any function in CouchDB + * Perform any function in CouchDB. + * The first position of the $params array is used to mount the uri. + * The second place in the $params array is used to assemble data from a POST or PUT. + * The third parameter is used to decode the return json. + * The fourth parameter is used to build an associative array. + * + * The method can be performed by a Model of the following ways: + * + * $this->Model->curlGet('_all_dbs'); + * $this->Model->curlPut('document_name'); + * $this->Model->curlPost('document_name', array('field' => 'value')); + * $this->Model->curlDelete('document_name'); + * $this->Model->curlPost('document_name', array('field' => 'value'), false); + * $this->Model->curlPost('document_name', array('field' => 'value'), true , false); * - * @param string $uri - * @param array $post + * @param string $method + * @param array $params ParĂ¢metros aceitos na ordem: uri, data, decode, assoc * @return object */ - public function query($uri, $post) { - return $this->__decode($this->Socket->post($uri, $this->__encode($post))); + public function query($method, $params) { + list($uri, $data, $decode, $assoc) = $this->__queryParams($params); + + $request = array( + 'method' => strtoupper(str_replace('curl', '', $method)) + ); + + if (!empty($uri)) + $request['uri'] = '/' . $uri; + + if (!empty($data)) + $request['body'] = $this->__encode($data); + + $result = $this->Socket->request($request); + + if ($decode === true) { + $result = $this->__decode($result, $assoc); + } + + return $result; } /** - * Get a URI + * Construct the parameter of the query method. + * + * @param array $params + * @return array + */ + private function __queryParams($params) { + if (isset($params[0])) $uri = $params[0]; + else $uri = ''; + + if (isset($params[1])) $data = $params[1]; + else $data = array(); + + if (isset($params[2])) $decode = $params[2]; + else $decode = true; + + if (isset($params[3])) $assoc = $params[3]; + else $assoc = true; + + return array($uri, $data, $decode, $assoc); + } + +/** + * Get a URI. * * @param mixed $model * @param string $params - * @return string URI + * @return string URI. */ private function __uri($model = null, $params = null) { if (!is_null($params)) { @@ -386,17 +484,18 @@ private function __uri($model = null, $params = null) { } /** - * JSON encode + * JSON encode. * * @param string json $data - * @return string JSON + * @return string JSON. */ private function __encode($data) { return json_encode($data); } /** - * JSON decode + * JSON decode. + * * @param string json $data * @param boolean $assoc If true, returns array. If false, returns object. * @return mixed Object or Array. @@ -406,7 +505,7 @@ private function __decode($data, $assoc = false) { } /** - * Checks if the result returned ok = true + * Checks if the result returned ok = true. * * @param object $object * @return boolean @@ -415,3 +514,4 @@ private function __checkOk($object = null) { return isset($object->ok) && $object->ok === true; } } +?> \ No newline at end of file diff --git a/Test/Case/Model/Datasource/CouchDBSourceTest.php b/Test/Case/Model/Datasource/CouchDBSourceTest.php new file mode 100644 index 0000000..52dea3d --- /dev/null +++ b/Test/Case/Model/Datasource/CouchDBSourceTest.php @@ -0,0 +1,618 @@ + array( + 'notempty' => array( + 'rule' => array('notempty'), + //'message' => 'Your custom message here', + //'allowEmpty' => false, + //'required' => false, + //'last' => false, // Stop validation after this rule + //'on' => 'create', // Limit validation to 'create' or 'update' operations + ), + ), + ); + + public $schema = array( + 'id' => array( + 'type' => 'string', + 'null' => true, + 'key' => 'primary', + 'length' => 32, + ), + 'rev' => array( + 'type' => 'string', + 'null' => true, + 'key' => 'primary', + 'length' => 34, + ), + 'title' => array( + 'type' => 'string', + 'null' => true, + 'length' => 255, + ), + 'description' => array( + 'type' => 'text', + 'null' => true, + ) + ); +} + +/** + * CouchDBTestCase + * + * @package datasources + * @subpackage datasources.tests.cases.models.datasources + */ +class CouchDBTestCase extends CakeTestCase { + +/** + * CouchDB Datasource object + * + * @var object + */ + public $CouchDB = null; + +/** + * Configuration + * + * @var array + */ + protected $config = array( + 'datasource' => 'CouchDB.CouchDBSource', + 'persistent' => false, + 'host' => 'localhost', + 'port' => '5984', + 'login' => 'root', + 'password' => 'root', + 'database' => null + ); + +/** + * Start Test + * + * @return void + */ + public function startTest() { + config('database'); + $config = new DATABASE_CONFIG(); + + if (isset($config->couchdb_test)) { + $this->config = $config->couchdb_test; + } + + ConnectionManager::create('couchdb_test', $this->config); + + $this->Post = ClassRegistry::init('Post'); + $this->removeAllDocuments(); + } + +/** + * testConnection + * + * @return void + */ + public function testConnection() { + $this->CouchDB = new CouchDBSource($this->config); + $this->CouchDB =& ConnectionManager::getDataSource($this->Post->useDbConfig); + + $reconnect = $this->CouchDB->reconnect($this->config); + $this->assertIdentical($reconnect, true, __('Not reconnected')); + + $disconnect = $this->CouchDB->disconnect(); + $this->assertIdentical($disconnect, true, __('Not disconnect')); + } + +/** + * testFind + * + * @return void + */ + public function testFind() { + $data = array( + 'title' => 'My first post', + 'description' => 'My first post' + ); + $this->Post->save($data); + + $result = $this->Post->find('all'); + $this->assertEqual(1, count($result)); + + $resultData = $result[0]['Post']; + $this->assertEqual(4, count($resultData)); + $this->assertTrue(!empty($resultData['id'])); + $this->assertEqual($this->Post->id, $resultData['id']); + $this->assertEqual($this->Post->rev, $resultData['rev']); + $this->assertEqual($data['title'], $resultData['title']); + $this->assertEqual($data['description'], $resultData['description']); + } + + +/** + * testFindConditions + * + * @return void + */ + public function testFindConditions() { + $data = array( + 'title' => 'My first post', + 'description' => 'My first post' + ); + $this->Post->save($data); + + $this->Post->create(); + $this->Post->save($data); + + $result = $this->Post->find('all'); + $this->assertEqual(2, count($result)); + + $result = $this->Post->find('all', array('conditions' => array('Post.id' => $this->Post->id))); + $this->assertEqual(1, count($result)); + + $result = $this->Post->find('all', array('conditions' => array('id' => $this->Post->id))); + $this->assertEqual(1, count($result)); + } + +/** + * testFindRevs + * + * @return void + */ + public function testFindRevs() { + $data = array( + 'title' => 'My first post', + 'description' => 'My first post' + ); + $this->Post->save($data); + $this->Post->save($data); + + $this->Post->recursive = 0; + $result = $this->Post->find('all', array('conditions' => array('id' => $this->Post->id))); + $this->assertEqual(2, count($result[0]['Post']['_revs_info'])); + } + +/** + * Tests save method. + * + * @return void + */ + public function testSave() { + $data = array( + 'title' => 'My first post', + 'description' => 'My first post' + ); + + $this->Post->create(); + $saveResult = $this->Post->save($data); + $this->assertIdentical(is_array($saveResult), true); + + $result = $this->Post->find('all'); + $this->assertEqual(1, count($result)); + + $resultData = $result[0]['Post']; + $this->assertEqual(4, count($resultData)); + $this->assertTrue(!empty($resultData['id'])); + $this->assertEqual($this->Post->id, $resultData['id']); + $this->assertEqual($this->Post->rev, $resultData['rev']); + $this->assertEqual($data['title'], $resultData['title']); + $this->assertEqual($data['description'], $resultData['description']); + } + +/** + * Tests save method. + * + * @return void + */ + public function testSaveWithId() { + $data = array( + 'id' => String::uuid(), + 'title' => 'My first post', + 'description' => 'My first post' + ); + + $this->Post->create(); + $saveResult = $this->Post->save($data); + $this->assertIdentical(is_array($saveResult), true); + + $result = $this->Post->find('all'); + $this->assertEqual(1, count($result)); + + $resultData = $result[0]['Post']; + $this->assertEqual(4, count($resultData)); + $this->assertTrue(!empty($resultData['id'])); + $this->assertEqual($resultData['id'], $data['id']); + $this->assertEqual($this->Post->id, $resultData['id']); + $this->assertEqual($this->Post->rev, $resultData['rev']); + $this->assertEqual($data['title'], $resultData['title']); + $this->assertEqual($data['description'], $resultData['description']); + } + +/** + * Tests saveAll method. + * + * @return void + */ + public function testSaveAll() { + $data[0]['Post'] = array( + 'title' => 'My first post', + 'description' => 'My first post' + ); + + $data[1]['Post'] = array( + 'title' => 'My second post', + 'description' => 'My second post' + ); + + $this->Post->create(); + $saveResult = $this->Post->saveAll($data); + + $result = $this->Post->find('all'); + $this->assertEqual(2, count($result)); + + $resultData = $result[0]['Post']; + $this->assertEqual(4, count($resultData)); + $this->assertTrue(!empty($resultData['id'])); + $this->assertEqual($data[0]['Post']['title'], $resultData['title']); + $this->assertEqual($data[0]['Post']['description'], $resultData['description']); + + $resultData = $result[1]['Post']; + $this->assertEqual(4, count($resultData)); + $this->assertTrue(!empty($resultData['id'])); + $this->assertEqual($data[1]['Post']['title'], $resultData['title']); + $this->assertEqual($data[1]['Post']['description'], $resultData['description']); + } + +/** + * Tests update method. + * + * @return void + */ + public function updateTest() { + // Count posts + $uri = '/posts/_temp_view?group=true'; + $post = array( + 'map' => 'function(doc) { emit(doc._id,1); }', + 'reduce' => 'function(keys, values) { return sum(values); }' + ); + + $mapReduce = $this->Post->query($uri, $post); + if(isset($mapReduce->rows[0]->value)) $count0 = $mapReduce->rows[0]->value; + else $count0 = 0; + + $count1 = $this->updateTest1($uri, $post, $count0); + $count2 = $this->updateTest2($uri, $post, $count1); + $count3 = $this->updateTest3($uri, $post, $count2); + $count4 = $this->updateTest4($uri, $post, $count2); + $updateData = $this->updateTest5($uri, $post, $count4); + + // Final test + $result = $this->Post->find('all'); + $this->assertEqual(1, count($result)); + + $resultData = $result[0]['Post']; + $this->assertEqual(4, count($resultData)); + $this->assertTrue(!empty($resultData['id'])); + $this->assertEqual($this->Post->id, $resultData['id']); + $this->assertEqual($this->Post->rev, $resultData['rev']); + $this->assertNotEqual($updateData['title'], $resultData['title']); + $this->assertNotEqual($updateData['description'], $resultData['description']); + + } + +/** + * Tests update1 method. + * + * @param string $uri + * @param array $post + * @param interger $previousCount + * @return void + */ + private function updateTest1($uri, $post, $previousCount) { + $data = array( + 'title' => 'My first post', + 'description' => 'My first post' + ); + + $this->Post->create(); + $saveResult = $this->Post->save($data); + $this->assertIdentical(is_array($saveResult), true); + $this->assertIdentical(!empty($this->Post->id), true); + + $mapReduce = $this->Post->curlPost($uri, $post); + $count1 = $mapReduce['rows'][0]['value']; + + $this->assertIdentical($count1 - $previousCount, 1); + + return $count1; + } + +/** + * Tests update2 method. + * + * @param string $uri + * @param array $post + * @param interger $previousCount + * @return void + */ + private function updateTest2($uri, $post, $previousCount) { + $findResult = $this->Post->find('first'); + $this->assertEqual(4, count($findResult['Post'])); + + $updateData = array( + 'title' => 'My post update', + 'description' => 'My post update' + ); + + $this->Post->id = $findResult['Post']['id']; + $this->Post->rev = $findResult['Post']['rev']; + $saveResult = $this->Post->save($updateData); + $this->assertIdentical(is_array($saveResult), true); + + $mapReduce = $this->Post->curlPost($uri, $post); + $count2 = $mapReduce['rows'][0]['value']; + + $this->assertIdentical($count2 - $previousCount, 0); + + return $count2; + } + +/** + * Tests update3 method. + * + * @param string $uri + * @param array $post + * @param interger $previousCount + * @return void + */ + private function updateTest3($uri, $post, $previousCount) { + $findResult = $this->Post->find('first'); + $this->assertEqual(4, count($findResult['Post'])); + + $updateData = array( + 'id' => $findResult['Post']['id'], + 'title' => 'My post update', + 'description' => 'My post update' + ); + + $this->Post->rev = $findResult['Post']['rev']; + $saveResult = $this->Post->save($updateData); + $this->assertIdentical(is_array($saveResult), true); + $this->assertIdentical($this->Post->id, $findResult['Post']['id']); + + $mapReduce = $this->Post->curlPost($uri, $post); + $count3 = $mapReduce['rows'][0]['value']; + + $this->assertIdentical($count3 - $previousCount, 0); + + return $count3; + } + +/** + * Tests update4 method. + * + * @param string $uri + * @param array $post + * @param interger $previousCount + * @return void + */ + private function updateTest4($uri, $post, $previousCount) { + $findResult = $this->Post->find('first'); + $this->assertEqual(4, count($findResult['Post'])); + + $updateData = array( + 'id' => $findResult['Post']['id'], + 'rev' => $findResult['Post']['rev'], + 'title' => 'My post update', + 'description' => 'My post update' + ); + + $saveResult = $this->Post->save($updateData); + $this->assertIdentical(is_array($saveResult), true); + $this->assertIdentical($this->Post->id, $findResult['Post']['id']); + + $mapReduce = $this->Post->curlPost($uri, $post); + $count4 = $mapReduce['rows'][0]['value']; + + $this->assertIdentical($count4 - $previousCount, 0); + + return $count4; + } + +/** + * Tests update5 method. + * + * @param string $uri + * @param array $post + * @param interger $previousCount + * @return void + */ + private function updateTest5($uri, $post, $previousCount) { + $findResult = $this->Post->find('first'); + $this->assertEqual(4, count($findResult['Post'])); + + $updateData = array( + 'id' => $findResult['Post']['id'], + 'rev' => 'whatever', + 'title' => 'My post fail', + 'description' => 'My post fail' + ); + + $saveResult = $this->Post->save($updateData); + $this->assertFalse($saveResult); + $this->assertIdentical($this->Post->id, $findResult['Post']['id']); + + $mapReduce = $this->Post->curlPost($uri, $post); + $count5 = $mapReduce['rows'][0]['value']; + + $this->assertIdentical($count5 - $previousCount, 0); + + return $updateData; + } + +/** + * Test update without revision + * + * @return void + */ + public function testUpdateWithoutRevision() { + $data = array( + 'title' => 'My first post', + 'description' => 'My first post' + ); + + $this->Post->create(); + $saveResult = $this->Post->save($data); + + $result = $this->Post->find('first'); + + unset($result['Post']['rev']); + unset($this->Post->rev); + + $updateResult = $this->Post->save($result); + + $this->assertIdentical(is_array($updateResult), true); + $this->assertIdentical($this->Post->id, $saveResult['Post']['id']); + } + +/** + * Tests delete method. + * + * @return void + */ + public function testDelete() { + $data = array( + 'title' => 'My first post', + 'description' => 'My first post' + ); + + $this->Post->create(); + $saveResult = $this->Post->save($data); + + $result = $this->Post->find('all'); + $this->assertEqual(1, count($result)); + + $this->Post->id = $result[0]['Post']['id']; + $this->Post->rev = $result[0]['Post']['rev']; + $this->Post->delete(); + + $result = $this->Post->find('all'); + $this->assertEqual(0, count($result)); + } + +/** + * Test delete without revision + * + * @return void + */ + public function testDeleteWithoutRevision() { + $data = array( + 'title' => 'My first post', + 'description' => 'My first post' + ); + + $this->Post->create(); + $saveResult = $this->Post->save($data); + + $result = $this->Post->find('all'); + $this->assertEqual(1, count($result)); + + unset($result['Post']['rev']); + unset($this->Post->rev); + + $this->Post->delete(); + + $result = $this->Post->find('all'); + $this->assertEqual(0, count($result)); + } + +/** + * Tests query method. + * + * @return void + */ + public function testQuery() { + // GET + $result = $this->Post->curlGet('_all_dbs'); + $this->assertIdentical(is_array($result), true); + + // POST + $data = array( + 'title' => 'My first post', + 'description' => 'My first post' + ); + + $result = $this->Post->curlPost('/posts', $data); + $this->assertIdentical($result['ok'], true); + + // PUT + $data = array( + '_rev' => $result['rev'], + 'title' => 'My first update', + 'description' => 'My first update' + ); + + $result = $this->Post->curlPut('/posts/' . $result['id'], $data); + $this->assertIdentical($result['ok'], true); + + // DELETE + $result = $this->Post->curlDelete('/posts/' . $result['id'] . '/?rev=' . $result['rev']); + $this->assertIdentical($result['ok'], true); + } + +/** + * Remove all documents from database + * + * @return void + */ + private function removeAllDocuments() { + $posts = $this->Post->find('list', array('fields' => array('Post.rev'))); + foreach($posts as $id => $post) { + $this->Post->rev = $post; + $this->Post->delete($id); + } + } + +/** + * End Test + * + * @return void + */ + public function endTest() { + $this->removeAllDocuments(); + unset($this->Post); + unset($this->CouchDB); + ClassRegistry::flush(); + } +}