Browse Source

Add some more transaction tests

And remove 2 else clauses.
chinpei215 11 years ago
parent
commit
cb376bf420
2 changed files with 171 additions and 4 deletions
  1. 2 4
      lib/Cake/Model/Model.php
  2. 169 0
      lib/Cake/Test/Case/Model/ModelWriteTest.php

+ 2 - 4
lib/Cake/Model/Model.php

@@ -2243,11 +2243,10 @@ class Model extends Object implements CakeEventListener {
 			$options['validate'] = false;
 		}
 
+		$transactionBegun = false;
 		if ($options['atomic']) {
 			$db = $this->getDataSource();
 			$transactionBegun = $db->begin();
-		} else {
-			$transactionBegun = false;
 		}
 
 		try {
@@ -2378,11 +2377,10 @@ class Model extends Object implements CakeEventListener {
 			$options['validate'] = false;
 		}
 
+		$transactionBegun = false;
 		if ($options['atomic']) {
 			$db = $this->getDataSource();
 			$transactionBegun = $db->begin();
-		} else {
-			$transactionBegun = false;
 		}
 
 		try {

+ 169 - 0
lib/Cake/Test/Case/Model/ModelWriteTest.php

@@ -36,6 +36,8 @@ class TestAuthor extends Author {
 
 	protected $_dataSourceObject;
 
+	public $dataForAfterSave;
+
 /**
  * Helper method to set a datasource object
  *
@@ -74,6 +76,8 @@ class TestPost extends Post {
 
 	protected $_dataSourceObject;
 
+	public $dataForAfterSave;
+
 /**
  * Helper method to set a datasource object
  *
@@ -7499,4 +7503,169 @@ class ModelWriteTest extends BaseModelTest {
 
 		return $db;
 	}
+
+/**
+ * Test that transactions behave correctly on nested saveMany calls.
+ *
+ * @return void
+ */
+	public function testTransactionOnNestedSaveMany() {
+		$this->loadFixtures('Post');
+		$Post = new TestPost();
+		$Post->getEventManager()->attach(array($this, 'nestedSaveMany'), 'Model.afterSave');
+
+		// begin -> [ begin -> commit ] -> commit
+		$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
+		$db->expects($this->exactly(2))->method('begin')->will($this->returnValue(true));
+		$db->expects($this->exactly(2))->method('commit');
+		$db->expects($this->never())->method('rollback');
+		$Post->setDataSourceObject($db);
+
+		$data = array(
+			array('author_id' => 1, 'title' => 'Outer Post'),
+		);
+		$Post->dataForAfterSave = array(
+			array('author_id' => 1, 'title' => 'Inner Post'),
+		);
+		$this->assertTrue($Post->saveMany($data));
+
+		// begin -> [  begin(false) ] -> commit
+		$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
+		$db->expects($this->at(0))->method('begin')->will($this->returnValue(true));
+		$db->expects($this->at(1))->method('begin')->will($this->returnValue(false));
+		$db->expects($this->once())->method('commit');
+		$db->expects($this->never())->method('rollback');
+		$Post->setDataSourceObject($db);
+
+		$data = array(
+			array('author_id' => 1, 'title' => 'Outer Post'),
+		);
+		$Post->dataForAfterSave = array(
+			array('author_id' => 1, 'title' => 'Inner Post'),
+		);
+		$this->assertTrue($Post->saveMany($data));
+
+		// begin -> [ begin -> rollback ] -> rollback
+		$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
+		$db->expects($this->exactly(2))->method('begin')->will($this->returnValue(true));
+		$db->expects($this->never())->method('commit');
+		$db->expects($this->exactly(2))->method('rollback');
+		$Post->setDataSourceObject($db);
+		$data = array(
+			array('author_id' => 1, 'title' => 'Outer Post'),
+		);
+		$Post->dataForAfterSave = array(
+			array('author_id' => 1, 'title' => 'Inner Post', 'body' => $db->expression('PDO_EXCEPTION()')),
+		);
+
+		try {
+			$Post->saveMany($data);
+			$this->fail('No exception thrown');
+		} catch(Exception $e) {
+		}
+	}
+
+/**
+ * Test that transaction behaves correctly on nested saveAssociated calls.
+ *
+ * @return void
+ */
+	public function testTransactionOnNestedSaveAssociated() {
+		$this->loadFixtures('Author', 'Post');
+
+		$Author = new TestAuthor();
+		$Author->getEventManager()->attach(array($this, 'nestedSaveAssociated'), 'Model.afterSave');
+
+		// begin -> [ begin -> commit ] -> commit
+		$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
+		$db->expects($this->exactly(2))->method('begin')->will($this->returnValue(true));
+		$db->expects($this->exactly(2))->method('commit');
+		$db->expects($this->never())->method('rollback');
+		$Author->setDataSourceObject($db);
+		$Author->Post->setDataSourceObject($db);
+
+		$data = array(
+			'Author' => array('user' => 'outer'),
+			'Post' => array(
+				array('title' => 'Outer Post'),
+			)
+		);
+		$Author->dataForAfterSave = array(
+			'Author' => array('user' => 'inner'),
+			'Post' => array(
+				array('title' => 'Inner Post'),
+			)
+		);
+		$this->assertTrue($Author->saveAssociated($data));
+
+		// begin -> [  begin(false) ] -> commit
+		$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
+		$db->expects($this->at(0))->method('begin')->will($this->returnValue(true));
+		$db->expects($this->at(1))->method('begin')->will($this->returnValue(false));
+		$db->expects($this->once())->method('commit');
+		$db->expects($this->never())->method('rollback');
+		$Author->setDataSourceObject($db);
+		$Author->Post->setDataSourceObject($db);
+		$data = array(
+			'Author' => array('user' => 'outer'),
+			'Post' => array(
+				array('title' => 'Outer Post'),
+			)
+		);
+		$Author->dataForAfterSave = array(
+			'Author' => array('user' => 'inner'),
+			'Post' => array(
+				array('title' => 'Inner Post'),
+			)
+		);
+		$this->assertTrue($Author->saveAssociated($data));
+
+		// begin -> [ begin -> rollback ] -> rollback
+		$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
+		$db->expects($this->exactly(2))->method('begin')->will($this->returnValue(true));
+		$db->expects($this->never())->method('commit');
+		$db->expects($this->exactly(2))->method('rollback');
+		$Author->setDataSourceObject($db);
+		$Author->Post->setDataSourceObject($db);
+		$data = array(
+			'Author' => array('user' => 'outer'),
+			'Post' => array(
+				array('title' => 'Outer Post'),
+			)
+		);
+		$Author->dataForAfterSave = array(
+			'Author' => array('user' => 'inner', 'password' => $db->expression('PDO_EXCEPTION()')),
+			'Post' => array(
+				array('title' => 'Inner Post'),
+			)
+		);
+
+		try {
+			$Author->saveAssociated($data);
+			$this->fail('No exception thrown');
+		} catch(Exception $e) {
+		}
+	}
+
+/**
+ * A callback for testing nested saveMany.
+ *
+ * @param CakeEvent $event containing the Model
+ * @return void
+ */
+	public function nestedSaveMany($event) {
+		$Model = $event->subject;
+		$Model->saveMany($Model->dataForAfterSave, array('callbacks' => false));
+	}
+
+/**
+ * A callback for testing nested saveAssociated.
+ *
+ * @param CakeEvent $event containing the Model
+ * @return void
+ */
+	public function nestedSaveAssociated($event) {
+		$Model = $event->subject;
+		$Model->saveAssociated($Model->dataForAfterSave, array('callbacks' => false));
+	}
 }