You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by br...@apache.org on 2012/09/19 20:43:27 UTC

[26/50] git commit: [#4713] Added Thread.new() to prevent duplicate _ids

[#4713] Added Thread.new() to prevent duplicate _ids

Signed-off-by: Cory Johns <jo...@geek.net>


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/2b5c68c8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/2b5c68c8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/2b5c68c8

Branch: refs/heads/master
Commit: 2b5c68c894541b7fcef58073ac541a5d1c51a365
Parents: 554f00f
Author: Cory Johns <jo...@geek.net>
Authored: Wed Sep 12 16:50:49 2012 +0000
Committer: Dave Brondsema <db...@geek.net>
Committed: Thu Sep 13 18:09:57 2012 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/repository.py           |    2 +-
 Allura/allura/model/artifact.py                   |    2 +-
 Allura/allura/model/discuss.py                    |   15 +++++++
 Allura/allura/tests/model/test_discussion.py      |   35 ++++++++++++----
 Allura/allura/tests/unit/factories.py             |    2 +-
 ForgeBlog/forgeblog/main.py                       |    2 +-
 ForgeDiscussion/forgediscussion/import_support.py |    2 +-
 ForgeTracker/forgetracker/model/ticket.py         |    2 +-
 ForgeWiki/forgewiki/model/wiki.py                 |    2 +-
 scripts/teamforge-import.py                       |    4 +-
 10 files changed, 50 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2b5c68c8/Allura/allura/controllers/repository.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/repository.py b/Allura/allura/controllers/repository.py
index e04c79c..8dcd78c 100644
--- a/Allura/allura/controllers/repository.py
+++ b/Allura/allura/controllers/repository.py
@@ -139,7 +139,7 @@ class RepoRootController(BaseController):
             M.Notification.post(
                 mr, 'merge_request',
                 subject='Merge request: ' + mr.summary)
-            t = M.Thread(
+            t = M.Thread.new(
                 discussion_id=c.app.config.discussion_id,
                 artifact_reference=mr.index_id(),
                 subject='Discussion for Merge Request #:%s: %s' % (

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2b5c68c8/Allura/allura/model/artifact.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/artifact.py b/Allura/allura/model/artifact.py
index 5f9bb47..fca2219 100644
--- a/Allura/allura/model/artifact.py
+++ b/Allura/allura/model/artifact.py
@@ -262,7 +262,7 @@ class Artifact(MappedClass):
         t = Thread.query.get(ref_id=self.index_id())
         if t is None:
             idx = self.index()
-            t = Thread(
+            t = Thread.new(
                 discussion_id=self.app_config.discussion_id,
                 ref_id=idx['id'],
                 subject='%s discussion' % idx['title_s'])

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2b5c68c8/Allura/allura/model/discuss.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/discuss.py b/Allura/allura/model/discuss.py
index 80f276d..8101495 100644
--- a/Allura/allura/model/discuss.py
+++ b/Allura/allura/model/discuss.py
@@ -2,6 +2,7 @@ import logging
 from datetime import datetime
 
 import pymongo
+from pymongo.errors import OperationFailure
 from pylons import c, g
 
 from ming import schema
@@ -149,6 +150,20 @@ class Thread(Artifact, ActivityObject):
         return self.discussion
 
     @classmethod
+    def new(cls, **props):
+        '''Creates a new Thread instance, ensuring a unique _id.'''
+        while True:
+            try:
+                thread = cls(**props)
+                session(thread).flush(thread)
+                return thread
+            except OperationFailure as err:
+                if 'duplicate' in err.args[0]:
+                    session(thread).expunge(thread)
+                    continue
+                raise
+
+    @classmethod
     def discussion_class(cls):
         return cls.discussion.related
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2b5c68c8/Allura/allura/tests/model/test_discussion.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/model/test_discussion.py b/Allura/allura/tests/model/test_discussion.py
index f80805e..4ccb16b 100644
--- a/Allura/allura/tests/model/test_discussion.py
+++ b/Allura/allura/tests/model/test_discussion.py
@@ -11,7 +11,7 @@ from pylons import c, g, request, response
 from nose.tools import assert_raises, assert_equals, with_setup
 import mock
 
-from ming.orm.ormsession import ThreadLocalORMSession
+from ming.orm import session, ThreadLocalORMSession
 from webob import Request, Response, exc
 
 from allura import model as M
@@ -57,7 +57,7 @@ def test_discussion_methods():
 @with_setup(setUp, tearDown)
 def test_thread_methods():
     d = M.Discussion(shortname='test', name='test')
-    t = M.Thread(discussion_id=d._id, subject='Test Thread')
+    t = M.Thread.new(discussion_id=d._id, subject='Test Thread')
     assert t.discussion_class() == M.Discussion
     assert t.post_class() == M.Post
     assert t.attachment_class() == M.DiscussionAttachment
@@ -101,9 +101,26 @@ def test_thread_methods():
     t.delete()
 
 @with_setup(setUp, tearDown)
+def test_thread_new():
+    with mock.patch('allura.model.discuss.h.nonce') as nonce:
+        nonce.side_effect = ['deadbeef', 'deadbeef', 'beefdead']
+        d = M.Discussion(shortname='test', name='test')
+        t1 = M.Thread.new(discussion_id=d._id, subject='Test Thread One')
+        t2 = M.Thread.new(discussion_id=d._id, subject='Test Thread Two')
+        ThreadLocalORMSession.flush_all()
+        session(t1).expunge(t1)
+        session(t2).expunge(t2)
+        t1_2 = M.Thread.query.get(_id=t1._id)
+        t2_2 = M.Thread.query.get(_id=t2._id)
+        assert_equals(t1._id, 'deadbeef')
+        assert_equals(t2._id, 'beefdead')
+        assert_equals(t1_2.subject, 'Test Thread One')
+        assert_equals(t2_2.subject, 'Test Thread Two')
+
+@with_setup(setUp, tearDown)
 def test_post_methods():
     d = M.Discussion(shortname='test', name='test')
-    t = M.Thread(discussion_id=d._id, subject='Test Thread')
+    t = M.Thread.new(discussion_id=d._id, subject='Test Thread')
     p = t.post('This is a post')
     p2 = t.post('This is another post')
     assert p.discussion_class() == M.Discussion
@@ -137,7 +154,7 @@ def test_post_methods():
 @with_setup(setUp, tearDown)
 def test_attachment_methods():
     d = M.Discussion(shortname='test', name='test')
-    t = M.Thread(discussion_id=d._id, subject='Test Thread')
+    t = M.Thread.new(discussion_id=d._id, subject='Test Thread')
     p = t.post('This is a post')
     p_att = p.attach('foo.text', StringIO('Hello, world!'),
                 discussion_id=d._id,
@@ -158,7 +175,7 @@ def test_attachment_methods():
         assert 'attachment/' in att.url()
 
     # Test notification in mail
-    t = M.Thread(discussion_id=d._id, subject='Test comment notification')
+    t = M.Thread.new(discussion_id=d._id, subject='Test comment notification')
     fs = FieldStorage()
     fs.name='file_info'
     fs.filename='fake.txt'
@@ -172,7 +189,7 @@ def test_attachment_methods():
 @with_setup(setUp, tearDown)
 def test_discussion_delete():
     d = M.Discussion(shortname='test', name='test')
-    t = M.Thread(discussion_id=d._id, subject='Test Thread')
+    t = M.Thread.new(discussion_id=d._id, subject='Test Thread')
     p = t.post('This is a post')
     p.attach('foo.text', StringIO(''),
                 discussion_id=d._id,
@@ -184,7 +201,7 @@ def test_discussion_delete():
 @with_setup(setUp, tearDown)
 def test_thread_delete():
     d = M.Discussion(shortname='test', name='test')
-    t = M.Thread(discussion_id=d._id, subject='Test Thread')
+    t = M.Thread.new(discussion_id=d._id, subject='Test Thread')
     p = t.post('This is a post')
     p.attach('foo.text', StringIO(''),
                 discussion_id=d._id,
@@ -196,7 +213,7 @@ def test_thread_delete():
 @with_setup(setUp, tearDown)
 def test_post_delete():
     d = M.Discussion(shortname='test', name='test')
-    t = M.Thread(discussion_id=d._id, subject='Test Thread')
+    t = M.Thread.new(discussion_id=d._id, subject='Test Thread')
     p = t.post('This is a post')
     p.attach('foo.text', StringIO(''),
                 discussion_id=d._id,
@@ -208,7 +225,7 @@ def test_post_delete():
 @with_setup(setUp, tearDown)
 def test_post_permission_check():
     d = M.Discussion(shortname='test', name='test')
-    t = M.Thread(discussion_id=d._id, subject='Test Thread')
+    t = M.Thread.new(discussion_id=d._id, subject='Test Thread')
     c.user = M.User.anonymous()
     try:
         p1 = t.post('This post will fail the check.')

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2b5c68c8/Allura/allura/tests/unit/factories.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/unit/factories.py b/Allura/allura/tests/unit/factories.py
index 60addb7..519bb0e 100644
--- a/Allura/allura/tests/unit/factories.py
+++ b/Allura/allura/tests/unit/factories.py
@@ -54,7 +54,7 @@ def create_post(slug):
 
 @flush_on_return
 def create_thread(discussion):
-    return Thread(discussion_id=discussion._id)
+    return Thread.new(discussion_id=discussion._id)
 
 
 @flush_on_return

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2b5c68c8/ForgeBlog/forgeblog/main.py
----------------------------------------------------------------------
diff --git a/ForgeBlog/forgeblog/main.py b/ForgeBlog/forgeblog/main.py
index f32e6fe..9dda569 100644
--- a/ForgeBlog/forgeblog/main.py
+++ b/ForgeBlog/forgeblog/main.py
@@ -216,7 +216,7 @@ class RootController(BaseController):
         post.neighborhood_id=c.project.neighborhood_id
         post.make_slug()
         post.commit()
-        M.Thread(discussion_id=post.app_config.discussion_id,
+        M.Thread.new(discussion_id=post.app_config.discussion_id,
                ref_id=post.index_id(),
                subject='%s discussion' % post.title)
         redirect(h.really_unicode(post.url()).encode('utf-8'))

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2b5c68c8/ForgeDiscussion/forgediscussion/import_support.py
----------------------------------------------------------------------
diff --git a/ForgeDiscussion/forgediscussion/import_support.py b/ForgeDiscussion/forgediscussion/import_support.py
index 8e8e34b..6dafaf5 100644
--- a/ForgeDiscussion/forgediscussion/import_support.py
+++ b/ForgeDiscussion/forgediscussion/import_support.py
@@ -46,7 +46,7 @@ def perform_import(json, username_mapping, default_username=None, create_users=F
             description=forum['description'])
         for tid, posts in forum.threads.iteritems():
             rest, head = posts[:-1], posts[-1]
-            t = DM.ForumThread(
+            t = DM.ForumThread.new(
                 _id=tid,
                 discussion_id=f._id,
                 subject=head['subject'])

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2b5c68c8/ForgeTracker/forgetracker/model/ticket.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/model/ticket.py b/ForgeTracker/forgetracker/model/ticket.py
index 1e4e8c9..67ce054 100644
--- a/ForgeTracker/forgetracker/model/ticket.py
+++ b/ForgeTracker/forgetracker/model/ticket.py
@@ -426,7 +426,7 @@ class Ticket(VersionedArtifact, ActivityObject, VotableArtifact):
                 self.subscribe(user=User.query.get(_id=self.assigned_to_id))
             description = ''
             subject = self.email_subject
-            Thread(discussion_id=self.app_config.discussion_id,
+            Thread.new(discussion_id=self.app_config.discussion_id,
                    ref_id=self.index_id())
             n = Notification.post(artifact=self, topic='metadata', text=description, subject=subject)
             if monitoring_email and n:

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2b5c68c8/ForgeWiki/forgewiki/model/wiki.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/model/wiki.py b/ForgeWiki/forgewiki/model/wiki.py
index a903a33..7744b13 100644
--- a/ForgeWiki/forgewiki/model/wiki.py
+++ b/ForgeWiki/forgewiki/model/wiki.py
@@ -155,7 +155,7 @@ class Page(VersionedArtifact, ActivityObject):
                     title=title,
                     app_config_id=context.app.config._id,
                     )
-                Thread(discussion_id=obj.app_config.discussion_id,
+                Thread.new(discussion_id=obj.app_config.discussion_id,
                            ref_id=obj.index_id())
             return obj
         else:

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2b5c68c8/scripts/teamforge-import.py
----------------------------------------------------------------------
diff --git a/scripts/teamforge-import.py b/scripts/teamforge-import.py
index 57430ec..49294f8 100644
--- a/scripts/teamforge-import.py
+++ b/scripts/teamforge-import.py
@@ -486,7 +486,7 @@ def import_discussion(project, pid, frs_mapping, sf_project_shortname, nbhd):
                         thread_query['import_id'] = topic_data.id
                     to = DM.ForumThread.query.get(**thread_query)
                     if not to:
-                        to = DM.ForumThread(
+                        to = DM.ForumThread.new(
                             subject=topic_data.title,
                             discussion_id=fo._id,
                             import_id=topic_data.id,
@@ -566,7 +566,7 @@ def import_news(project, pid, frs_mapping, sf_project_shortname, nbhd):
                 if not p.history().first():
                     p.commit()
                     ThreadLocalORMSession.flush_all()
-                    M.Thread(discussion_id=p.app_config.discussion_id,
+                    M.Thread.new(discussion_id=p.app_config.discussion_id,
                            ref_id=p.index_id(),
                            subject='%s discussion' % p.title)
                 user = get_user(post_data.createdByUsername)