From c269e7fb60f832342f3aa638bc95e2c9fa0452fb Mon Sep 17 00:00:00 2001 From: Jefersson Nathan Date: Thu, 8 Sep 2016 14:48:04 -0300 Subject: [PATCH 1/7] Introduce EventStore#transaction(callable $callable) API --- src/EventStore.php | 16 ++++++++++++++++ tests/EventStoreTest.php | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/src/EventStore.php b/src/EventStore.php index 68e08e9c..fcf2df5e 100644 --- a/src/EventStore.php +++ b/src/EventStore.php @@ -295,6 +295,22 @@ public function replay(array $streamNames, DateTimeInterface $since = null, arra }); } + /** + * @param callable $callable + * + * @return mixed + */ + public function transaction(callable $callable) + { + $this->beginTransaction(); + + $result = $callable($this); + + $this->commit(); + + return $result; + } + /** * Begin transaction * diff --git a/tests/EventStoreTest.php b/tests/EventStoreTest.php index e3279da5..3fd8a520 100644 --- a/tests/EventStoreTest.php +++ b/tests/EventStoreTest.php @@ -586,6 +586,46 @@ public function it_makes_rollback_when_event_is_stopped_during_commit() $this->eventStore->load($stream->streamName()); } + /** + * @test + */ + public function it_wrap_up_code_in_transaction_properly() + { + $recordedEvents = []; + + $this->eventStore->getActionEventEmitter()->attachListener('commit.post', function (ActionEvent $event) use (&$recordedEvents) { + foreach ($event->getParam('recordedEvents', new \ArrayIterator()) as $recordedEvent) { + $recordedEvents[] = $recordedEvent; + } + }); + + $transactionResult = $this->eventStore->transaction(function (EventStore $eventStore) { + $this->eventStore->create($this->getTestStream()); + + $this->assertSame($this->eventStore, $eventStore); + + return 'Result'; + }); + + $this->assertSame('Result', $transactionResult); + + $secondStreamEvent = UsernameChanged::with( + ['new_name' => 'John Doe'], + 2 + ); + + $transactionResult = $this->eventStore->transaction(function (EventStore $eventStore) use ($secondStreamEvent) { + $this->eventStore->appendTo(new StreamName('user'), new ArrayIterator([$secondStreamEvent])); + + $this->assertSame($this->eventStore, $eventStore); + + return 'Second Result'; + }); + + $this->assertSame('Second Result', $transactionResult); + $this->assertEquals(2, count($recordedEvents)); + } + /** * @test */ From 6c34243e5703a12f7a4fa9b1a53a68fec1b39605 Mon Sep 17 00:00:00 2001 From: Jefersson Nathan Date: Fri, 9 Sep 2016 10:01:32 -0300 Subject: [PATCH 2/7] s/transaction/transactional Signed-off-by: Jefersson Nathan --- src/EventStore.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EventStore.php b/src/EventStore.php index fcf2df5e..00229640 100644 --- a/src/EventStore.php +++ b/src/EventStore.php @@ -300,7 +300,7 @@ public function replay(array $streamNames, DateTimeInterface $since = null, arra * * @return mixed */ - public function transaction(callable $callable) + public function transactional(callable $callable) { $this->beginTransaction(); From 969590577b3c4bd46785782a6ea95ff3eac6d588 Mon Sep 17 00:00:00 2001 From: Jefersson Nathan Date: Fri, 9 Sep 2016 10:03:47 -0300 Subject: [PATCH 3/7] Rollback and boolean returns Signed-off-by: Jefersson Nathan --- src/EventStore.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/EventStore.php b/src/EventStore.php index 00229640..222450cf 100644 --- a/src/EventStore.php +++ b/src/EventStore.php @@ -298,17 +298,24 @@ public function replay(array $streamNames, DateTimeInterface $since = null, arra /** * @param callable $callable * + * @throws \Exception + * * @return mixed */ public function transactional(callable $callable) { $this->beginTransaction(); - $result = $callable($this); + try { + $result = $callable($this); + $this->commit(); + } catch (\Exception $e) { + $this->rollback(); - $this->commit(); + throw $e; + } - return $result; + return $result ?: true; } /** From b8e61128b38e34fca11f03a837a1283402794c9f Mon Sep 17 00:00:00 2001 From: Jefersson Nathan Date: Fri, 9 Sep 2016 10:04:23 -0300 Subject: [PATCH 4/7] Use new api on unit tests Signed-off-by: Jefersson Nathan --- tests/EventStoreTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/EventStoreTest.php b/tests/EventStoreTest.php index 3fd8a520..c09397ce 100644 --- a/tests/EventStoreTest.php +++ b/tests/EventStoreTest.php @@ -599,7 +599,7 @@ public function it_wrap_up_code_in_transaction_properly() } }); - $transactionResult = $this->eventStore->transaction(function (EventStore $eventStore) { + $transactionResult = $this->eventStore->transactional(function (EventStore $eventStore) { $this->eventStore->create($this->getTestStream()); $this->assertSame($this->eventStore, $eventStore); @@ -614,7 +614,7 @@ public function it_wrap_up_code_in_transaction_properly() 2 ); - $transactionResult = $this->eventStore->transaction(function (EventStore $eventStore) use ($secondStreamEvent) { + $transactionResult = $this->eventStore->transactional(function (EventStore $eventStore) use ($secondStreamEvent) { $this->eventStore->appendTo(new StreamName('user'), new ArrayIterator([$secondStreamEvent])); $this->assertSame($this->eventStore, $eventStore); From 91201173edd160bc5ecf4510b85e3df3094e9817 Mon Sep 17 00:00:00 2001 From: Jefersson Nathan Date: Tue, 13 Sep 2016 17:44:44 -0300 Subject: [PATCH 5/7] Added missing test cases Signed-off-by: Jefersson Nathan --- tests/EventStoreTest.php | 58 +++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/tests/EventStoreTest.php b/tests/EventStoreTest.php index c09397ce..9e749dcb 100644 --- a/tests/EventStoreTest.php +++ b/tests/EventStoreTest.php @@ -15,6 +15,7 @@ use Prooph\Common\Event\ProophActionEventEmitter; use Prooph\EventStore\Adapter\Adapter; use Prooph\EventStore\Adapter\Feature\CanHandleTransaction; +use Prooph\EventStore\Adapter\InMemoryAdapter; use Prooph\EventStore\EventStore; use Prooph\EventStore\Stream\Stream; use Prooph\EventStore\Stream\StreamName; @@ -589,7 +590,52 @@ public function it_makes_rollback_when_event_is_stopped_during_commit() /** * @test */ - public function it_wrap_up_code_in_transaction_properly() + public function it_should_rollback_and_throw_exception_in_case_of_transaction_fail() + { + + $adapter = new class () extends InMemoryAdapter implements CanHandleTransaction { + public function beginTransaction() + { + } + + public function commit() + { + } + + public function rollback() + { + } + }; + + $eventStore = new EventStore($adapter, new ProophActionEventEmitter()); + + $this->setExpectedException(\Exception::class, 'Transaction failed'); + + $eventStore->transactional(function (EventStore $es) use ($eventStore) { + self::assertSame($es, $eventStore); + + throw new \Exception('Transaction failed'); + }); + } + + /** + * @test + */ + public function it_should_return_true_by_default_if_transaction_is_used() + { + $transactionResult = $this->eventStore->transactional(function (EventStore $eventStore) { + $this->eventStore->create($this->getTestStream()); + + self::assertSame($this->eventStore, $eventStore); + }); + + self::assertTrue($transactionResult); + } + + /** + * @test + */ + public function it_wraps_up_code_in_transaction_properly() { $recordedEvents = []; @@ -602,12 +648,12 @@ public function it_wrap_up_code_in_transaction_properly() $transactionResult = $this->eventStore->transactional(function (EventStore $eventStore) { $this->eventStore->create($this->getTestStream()); - $this->assertSame($this->eventStore, $eventStore); + self::assertSame($this->eventStore, $eventStore); return 'Result'; }); - $this->assertSame('Result', $transactionResult); + self::assertSame('Result', $transactionResult); $secondStreamEvent = UsernameChanged::with( ['new_name' => 'John Doe'], @@ -617,13 +663,13 @@ public function it_wrap_up_code_in_transaction_properly() $transactionResult = $this->eventStore->transactional(function (EventStore $eventStore) use ($secondStreamEvent) { $this->eventStore->appendTo(new StreamName('user'), new ArrayIterator([$secondStreamEvent])); - $this->assertSame($this->eventStore, $eventStore); + self::assertSame($this->eventStore, $eventStore); return 'Second Result'; }); - $this->assertSame('Second Result', $transactionResult); - $this->assertEquals(2, count($recordedEvents)); + self::assertSame('Second Result', $transactionResult); + self::assertCount(2, $recordedEvents); } /** From aba1aed5dafb9449bdfdf5b1b33c9c2fc79614ca Mon Sep 17 00:00:00 2001 From: Jefersson Nathan Date: Tue, 13 Sep 2016 17:53:54 -0300 Subject: [PATCH 6/7] Introduce AdapterCanHandlerMock Signed-off-by: Jefersson Nathan --- tests/EventStoreTest.php | 19 ++---------- tests/Mock/AdapterCanHandlerMock.php | 44 ++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 17 deletions(-) create mode 100644 tests/Mock/AdapterCanHandlerMock.php diff --git a/tests/EventStoreTest.php b/tests/EventStoreTest.php index 9e749dcb..5f9d9bbe 100644 --- a/tests/EventStoreTest.php +++ b/tests/EventStoreTest.php @@ -15,10 +15,10 @@ use Prooph\Common\Event\ProophActionEventEmitter; use Prooph\EventStore\Adapter\Adapter; use Prooph\EventStore\Adapter\Feature\CanHandleTransaction; -use Prooph\EventStore\Adapter\InMemoryAdapter; use Prooph\EventStore\EventStore; use Prooph\EventStore\Stream\Stream; use Prooph\EventStore\Stream\StreamName; +use ProophTest\EventStore\Mock\AdapterCanHandlerMock; use ProophTest\EventStore\Mock\PostCreated; use ProophTest\EventStore\Mock\TestDomainEvent; use ProophTest\EventStore\Mock\UserCreated; @@ -592,22 +592,7 @@ public function it_makes_rollback_when_event_is_stopped_during_commit() */ public function it_should_rollback_and_throw_exception_in_case_of_transaction_fail() { - - $adapter = new class () extends InMemoryAdapter implements CanHandleTransaction { - public function beginTransaction() - { - } - - public function commit() - { - } - - public function rollback() - { - } - }; - - $eventStore = new EventStore($adapter, new ProophActionEventEmitter()); + $eventStore = new EventStore(new AdapterCanHandlerMock(), new ProophActionEventEmitter()); $this->setExpectedException(\Exception::class, 'Transaction failed'); diff --git a/tests/Mock/AdapterCanHandlerMock.php b/tests/Mock/AdapterCanHandlerMock.php new file mode 100644 index 00000000..df30b8b9 --- /dev/null +++ b/tests/Mock/AdapterCanHandlerMock.php @@ -0,0 +1,44 @@ + + * (c) 2015-2016 Sascha-Oliver Prolic + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ProophTest\EventStore\Mock; + +use Prooph\EventStore\Adapter\Feature\CanHandleTransaction; +use Prooph\EventStore\Adapter\InMemoryAdapter; + +/** + * Class AdapterCanHandlerMock + * + * @package ProophTest\EventStore + * @author Jefersson Nathan + */ +final class AdapterCanHandlerMock extends InMemoryAdapter implements CanHandleTransaction +{ + /** + * {@inheritDoc} + */ + public function beginTransaction() + { + } + + /** + * {@inheritDoc} + */ + public function commit() + { + } + + /** + * {@inheritDoc} + */ + public function rollback() + { + } +} From 6013fbd6ab3643e904bee156e089c08050534740 Mon Sep 17 00:00:00 2001 From: Jefersson Nathan Date: Wed, 14 Sep 2016 02:05:56 -0300 Subject: [PATCH 7/7] rename AdapterCanHandlerMock to TransactionalInMemoryAdapterMock as per @prolic suggestion Signed-off-by: Jefersson Nathan --- tests/EventStoreTest.php | 4 ++-- ...anHandlerMock.php => TransactionalInMemoryAdapterMock.php} | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename tests/Mock/{AdapterCanHandlerMock.php => TransactionalInMemoryAdapterMock.php} (85%) diff --git a/tests/EventStoreTest.php b/tests/EventStoreTest.php index 5f9d9bbe..d577f62d 100644 --- a/tests/EventStoreTest.php +++ b/tests/EventStoreTest.php @@ -18,7 +18,7 @@ use Prooph\EventStore\EventStore; use Prooph\EventStore\Stream\Stream; use Prooph\EventStore\Stream\StreamName; -use ProophTest\EventStore\Mock\AdapterCanHandlerMock; +use ProophTest\EventStore\Mock\TransactionalInMemoryAdapterMock; use ProophTest\EventStore\Mock\PostCreated; use ProophTest\EventStore\Mock\TestDomainEvent; use ProophTest\EventStore\Mock\UserCreated; @@ -592,7 +592,7 @@ public function it_makes_rollback_when_event_is_stopped_during_commit() */ public function it_should_rollback_and_throw_exception_in_case_of_transaction_fail() { - $eventStore = new EventStore(new AdapterCanHandlerMock(), new ProophActionEventEmitter()); + $eventStore = new EventStore(new TransactionalInMemoryAdapterMock(), new ProophActionEventEmitter()); $this->setExpectedException(\Exception::class, 'Transaction failed'); diff --git a/tests/Mock/AdapterCanHandlerMock.php b/tests/Mock/TransactionalInMemoryAdapterMock.php similarity index 85% rename from tests/Mock/AdapterCanHandlerMock.php rename to tests/Mock/TransactionalInMemoryAdapterMock.php index df30b8b9..3b342cfa 100644 --- a/tests/Mock/AdapterCanHandlerMock.php +++ b/tests/Mock/TransactionalInMemoryAdapterMock.php @@ -14,12 +14,12 @@ use Prooph\EventStore\Adapter\InMemoryAdapter; /** - * Class AdapterCanHandlerMock + * Class TransactionalInMemoryAdapterMock * * @package ProophTest\EventStore * @author Jefersson Nathan */ -final class AdapterCanHandlerMock extends InMemoryAdapter implements CanHandleTransaction +final class TransactionalInMemoryAdapterMock extends InMemoryAdapter implements CanHandleTransaction { /** * {@inheritDoc}