From 44ed771a1cc48a6ad196412f88697132d5f669c7 Mon Sep 17 00:00:00 2001
From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org>
Date: Thu, 19 Dec 2013 17:54:14 +0000
Subject: [PATCH] Issue #1976172 by chx, andypost: Comment entity acquired and
 releases the different locks.

---
 .../comment/CommentStorageController.php      |  5 -
 .../lib/Drupal/comment/Entity/Comment.php     | 14 ++-
 .../comment/Tests/Entity/CommentLockTest.php  | 95 +++++++++++++++++++
 3 files changed, 105 insertions(+), 9 deletions(-)
 create mode 100644 core/modules/comment/tests/Drupal/comment/Tests/Entity/CommentLockTest.php

diff --git a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php
index e23af78c7dfa..d8c0cfe4b20e 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php
@@ -19,11 +19,6 @@
  */
 class CommentStorageController extends FieldableDatabaseStorageController implements CommentStorageControllerInterface {
 
-  /**
-   * The thread for which a lock was acquired.
-   */
-  protected $threadLock = '';
-
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/comment/lib/Drupal/comment/Entity/Comment.php b/core/modules/comment/lib/Drupal/comment/Entity/Comment.php
index d2c79bdc338a..ddedfb042be0 100644
--- a/core/modules/comment/lib/Drupal/comment/Entity/Comment.php
+++ b/core/modules/comment/lib/Drupal/comment/Entity/Comment.php
@@ -56,6 +56,11 @@
  */
 class Comment extends ContentEntityBase implements CommentInterface {
 
+  /**
+   * The thread for which a lock was acquired.
+   */
+  protected $threadLock = '';
+
   /**
    * The comment ID.
    *
@@ -273,12 +278,13 @@ public function preSave(EntityStorageControllerInterface $storage_controller) {
           }
         }
         // Finally, build the thread field for this new comment. To avoid
-        // race conditions, get a lock on the thread. If aother process already
+        // race conditions, get a lock on the thread. If another process already
         // has the lock, just move to the next integer.
         do {
           $thread = $prefix . comment_int_to_alphadecimal(++$n) . '/';
-        } while (!lock()->acquire("comment:{$this->entity_id->value}:$thread"));
-        $this->threadLock = $thread;
+          $lock_name = "comment:{$this->entity_id->value}:$thread";
+        } while (!\Drupal::lock()->acquire($lock_name));
+        $this->threadLock = $lock_name;
       }
       if (empty($this->created->value)) {
         $this->created->value = REQUEST_TIME;
@@ -316,7 +322,7 @@ public function postSave(EntityStorageControllerInterface $storage_controller, $
    */
   protected function releaseThreadLock() {
     if ($this->threadLock) {
-      lock()->release($this->threadLock);
+      \Drupal::lock()->release($this->threadLock);
       $this->threadLock = '';
     }
   }
diff --git a/core/modules/comment/tests/Drupal/comment/Tests/Entity/CommentLockTest.php b/core/modules/comment/tests/Drupal/comment/Tests/Entity/CommentLockTest.php
new file mode 100644
index 000000000000..307a9b54bd70
--- /dev/null
+++ b/core/modules/comment/tests/Drupal/comment/Tests/Entity/CommentLockTest.php
@@ -0,0 +1,95 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\comment\Tests\Entity\CommentTest
+ */
+
+namespace Drupal\comment\Tests\Entity {
+
+use Drupal\comment\Entity\Comment;
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * Unit tests for the comment entity lock behavior.
+ *
+ * @group Drupal
+ */
+class CommentLockTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Comment locks',
+      'description' => 'Test comment acquires and releases the right lock.',
+      'group' => 'Comment',
+    );
+  }
+
+  /**
+   * Test the lock behavior.
+   */
+  public function testLocks() {
+    $container = new ContainerBuilder();
+    $container->set('current_user', $this->getMock('Drupal\Core\Session\AccountInterface'));
+    $container->register('request', 'Symfony\Component\HttpFoundation\Request');
+    $lock = $this->getMock('Drupal\Core\Lock\LockBackendInterface');
+    $cid = 2;
+    $lock_name = "comment:$cid:./";
+    $lock->expects($this->at(0))
+      ->method('acquire')
+      ->with($lock_name, 30)
+      ->will($this->returnValue(TRUE));
+    $lock->expects($this->at(1))
+      ->method('release')
+      ->with($lock_name);
+    $lock->expects($this->exactly(2))
+      ->method($this->anything());
+    $container->set('lock', $lock);
+    \Drupal::setContainer($container);
+    $methods = get_class_methods('Drupal\comment\Entity\Comment');
+    unset($methods[array_search('preSave', $methods)]);
+    unset($methods[array_search('postSave', $methods)]);
+    $comment = $this->getMockBuilder('Drupal\comment\Entity\Comment')
+      ->disableOriginalConstructor()
+      ->setMethods($methods)
+      ->getMock();
+    $comment->expects($this->once())
+      ->method('isNew')
+      ->will($this->returnValue(TRUE));
+    foreach (array('status', 'pid', 'created', 'changed', 'entity_id', 'uid', 'thread', 'hostname') as $property) {
+      $comment->$property = new \stdClass();
+    }
+    $comment->status->value = 1;
+    $comment->entity_id->value = $cid;
+    $comment->uid->target_id = 3;
+    $comment->pid->target_id = 42;
+    $comment->pid->entity = new \stdClass();
+    $comment->pid->entity->thread = (object) array('value' => '');
+    $storage_controller = $this->getMock('Drupal\comment\CommentStorageControllerInterface');
+    $comment->preSave($storage_controller);
+    $comment->postSave($storage_controller);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function tearDown() {
+    parent::tearDown();
+    $container = new ContainerBuilder();
+    \Drupal::setContainer($container);
+  }
+
+}
+}
+namespace {
+if (!function_exists('comment_int_to_alphadecimal')) {
+  function comment_int_to_alphadecimal() {}
+}
+if (!function_exists('module_invoke_all')) {
+  function module_invoke_all() {}
+}
+}
+
-- 
GitLab