Source

trac-mq / t11148 / t11148_r11784_IEntityListener_compat_attachment.diff

Full commit
# HG changeset patch
# Parent e01d7454b5fe56724d7abd0c80143e78aa8deb77
Trac #11148 : 'IAttachmentListener' notifications powered by 'ListenerNotifier.notify'

diff -r e01d7454b5fe trac/attachment.py
--- a/trac/attachment.py	Fri Apr 26 00:27:27 2013 -0500
+++ b/trac/attachment.py	Fri Apr 26 00:59:58 2013 -0500
@@ -34,6 +34,7 @@
                        console_datetime_format, get_dir_list
 from trac.config import BoolOption, IntOption
 from trac.core import *
+from trac.core import ListenerNotifier
 from trac.mimeview import *
 from trac.perm import PermissionError, IPermissionPolicy
 from trac.resource import *
@@ -235,8 +236,8 @@
 
         self.env.log.info("Attachment removed: %s" % self.title)
 
-        for listener in AttachmentModule(self.env).change_listeners:
-            listener.attachment_deleted(self)
+        ListenerNotifier(self.env).notify(
+                     IAttachmentChangeListener.attachment_deleted, entity=self)
 
     def reparent(self, new_realm, new_id):
         assert self.filename, "Cannot reparent non-existent attachment"
@@ -284,9 +285,10 @@
 
         self.env.log.info("Attachment reparented: %s" % self.title)
 
-        for listener in AttachmentModule(self.env).change_listeners:
-            if hasattr(listener, 'attachment_reparented'):
-                listener.attachment_reparented(self, old_realm, old_id)
+        ListenerNotifier(self.env).notify(
+                     IAttachmentChangeListener.attachment_reparented,
+                     entity=self, old_parent_realm=old_realm,
+                     old_parent_id=old_id)
 
     def insert(self, filename, fileobj, size, t=None, db=None):
         """Create a new Attachment record and save the file content.
@@ -330,8 +332,8 @@
                 self.env.log.info("New attachment: %s by %s", self.title,
                                   self.author)
 
-        for listener in AttachmentModule(self.env).change_listeners:
-            listener.attachment_added(self)
+        ListenerNotifier(self.env).notify(
+                     IAttachmentChangeListener.attachment_added, entity=self)
 
 
     @classmethod
diff -r e01d7454b5fe trac/tests/attachment.py
--- a/trac/tests/attachment.py	Fri Apr 26 00:27:27 2013 -0500
+++ b/trac/tests/attachment.py	Fri Apr 26 00:59:58 2013 -0500
@@ -6,11 +6,13 @@
 import tempfile
 import unittest
 
-from trac.attachment import Attachment, AttachmentModule
+from trac.attachment import Attachment, AttachmentModule, \
+                            IAttachmentChangeListener
 from trac.core import Component, implements, TracError
 from trac.perm import IPermissionPolicy, PermissionCache
 from trac.resource import Resource, resource_exists
 from trac.test import EnvironmentStub
+from trac.tests.core import GenericEntitiesChangeListenerMock 
 
 
 hashes = {
@@ -39,6 +41,26 @@
             return None
 
 
+class TestAttachmentListener(Component):
+    implements(IAttachmentChangeListener)
+
+    def __init__(self):
+        self.details = []
+
+    def attachment_added(self, attachment):
+        self.details.append(dict(action='added', entity=attachment))
+
+    def attachment_deleted(self, attachment):
+        self.details.append(dict(action='deleted', entity=attachment))
+
+    def attachment_reparented(self, attachment, old_parent_realm, old_parent_id):
+        kwargs = locals()
+        kwargs.pop('self')
+        kwargs['entity'] = kwargs.pop('attachment')
+        kwargs['action'] = 'reparented'
+        self.details.append(kwargs)
+
+
 class AttachmentTestCase(unittest.TestCase):
 
     def setUp(self):
@@ -52,6 +74,8 @@
         self.env.config.set('attachment', 'max_size', 512)
 
         self.perm = PermissionCache(self.env)
+        self.attachment_listener = TestAttachmentListener(self.env)
+        self.entity_listener = GenericEntitiesChangeListenerMock(self.env)
 
     def tearDown(self):
         shutil.rmtree(self.env.path)
@@ -122,28 +146,42 @@
                           Attachment.select(self.env, 'wiki', 'SomePage').next)
 
     def test_insert(self):
-        attachment = Attachment(self.env, 'ticket', 42)
-        attachment.insert('foo.txt', StringIO(''), 0, 1)
-        attachment = Attachment(self.env, 'ticket', 42)
-        attachment.insert('bar.jpg', StringIO(''), 0, 2)
+        attachment1 = Attachment(self.env, 'ticket', 42)
+        attachment1.insert('foo.txt', StringIO(''), 0, 1)
+        attachment2 = Attachment(self.env, 'ticket', 42)
+        attachment2.insert('bar.jpg', StringIO(''), 0, 2)
 
         attachments = Attachment.select(self.env, 'ticket', 42)
         self.assertEqual('foo.txt', attachments.next().filename)
         self.assertEqual('bar.jpg', attachments.next().filename)
         self.assertRaises(StopIteration, attachments.next)
 
+        expected_events = [{'action' : 'added', 'entity' : attachment1},
+                           {'action' : 'added', 'entity' : attachment2}]
+        self.assertEquals(expected_events, self.attachment_listener.details,
+                          "IAttachmentChangeListener event sequence")
+        self.assertEquals(expected_events, self.entity_listener.details,
+                          "IEntityChangeListener event sequence")
+
     def test_insert_unique(self):
-        attachment = Attachment(self.env, 'ticket', 42)
-        attachment.insert('foo.txt', StringIO(''), 0)
-        self.assertEqual('foo.txt', attachment.filename)
-        attachment = Attachment(self.env, 'ticket', 42)
-        attachment.insert('foo.txt', StringIO(''), 0)
-        self.assertEqual('foo.2.txt', attachment.filename)
+        attachment1 = Attachment(self.env, 'ticket', 42)
+        attachment1.insert('foo.txt', StringIO(''), 0)
+        self.assertEqual('foo.txt', attachment1.filename)
+        attachment2 = Attachment(self.env, 'ticket', 42)
+        attachment2.insert('foo.txt', StringIO(''), 0)
+        self.assertEqual('foo.2.txt', attachment2.filename)
         self.assertEqual(os.path.join(self.attachments_dir, 'ticket',
                                       hashes['42'][0:3], hashes['42'],
                                       hashes['foo.2.txt'] + '.txt'),
-                         attachment.path)
-        self.assert_(os.path.exists(attachment.path))
+                         attachment2.path)
+        self.assert_(os.path.exists(attachment2.path))
+
+        expected_events = [{'action' : 'added', 'entity' : attachment1},
+                           {'action' : 'added', 'entity' : attachment2}]
+        self.assertEquals(expected_events, self.attachment_listener.details,
+                          "IAttachmentChangeListener event sequence")
+        self.assertEquals(expected_events, self.entity_listener.details,
+                          "IEntityChangeListener event sequence")
 
     def test_insert_outside_attachments_dir(self):
         attachment = Attachment(self.env, '../../../../../sth/private', 42)
@@ -168,6 +206,15 @@
         attachments = Attachment.select(self.env, 'wiki', 'SomePage')
         self.assertEqual(0, len(list(attachments)))
 
+        expected_events = [{'action' : 'added', 'entity' : attachment1},
+                           {'action' : 'added', 'entity' : attachment2},
+                           {'action' : 'deleted', 'entity' : attachment1},
+                           {'action' : 'deleted', 'entity' : attachment2}]
+        self.assertEquals(expected_events, self.attachment_listener.details,
+                          "IAttachmentChangeListener event sequence")
+        self.assertEquals(expected_events, self.entity_listener.details,
+                          "IEntityChangeListener event sequence")
+
     def test_delete_file_gone(self):
         """
         Verify that deleting an attachment works even if the referenced file
@@ -179,6 +226,13 @@
 
         attachment.delete()
 
+        expected_events = [{'action' : 'added', 'entity' : attachment},
+                           {'action' : 'deleted', 'entity' : attachment}]
+        self.assertEquals(expected_events, self.attachment_listener.details,
+                          "IAttachmentChangeListener event sequence")
+        self.assertEquals(expected_events, self.entity_listener.details,
+                          "IEntityChangeListener event sequence")
+
     def test_reparent(self):
         attachment1 = Attachment(self.env, 'wiki', 'SomePage')
         attachment1.insert('foo.txt', StringIO(''), 0)
@@ -205,6 +259,17 @@
         assert not os.path.exists(path1) and os.path.exists(attachment1.path)
         assert os.path.exists(attachment2.path)
 
+        expected_events = [{'action' : 'added', 'entity' : attachment1},
+                           {'action' : 'added', 'entity' : attachment2},
+                           {'action' : 'reparented', 'entity' : attachment1,
+                            'old_parent_realm' : 'wiki', 
+                            'old_parent_id' : 'SomePage'}]
+        self.assertEquals(expected_events, self.attachment_listener.details,
+                          "IAttachmentChangeListener event sequence")
+        self.assertEquals(expected_events, self.entity_listener.details,
+                          "IEntityChangeListener event sequence")
+
+
     def test_legacy_permission_on_parent(self):
         """Ensure that legacy action tests are done on parent.  As
         `ATTACHMENT_VIEW` maps to `TICKET_VIEW`, the `TICKET_VIEW` is tested
@@ -221,6 +286,12 @@
         att.insert('file.txt', StringIO(''), 1)
         self.assertTrue(resource_exists(self.env, att.resource))
 
+        expected_events = [{'action' : 'added', 'entity' : att}]
+        self.assertEquals(expected_events, self.attachment_listener.details,
+                          "IAttachmentChangeListener event sequence")
+        self.assertEquals(expected_events, self.entity_listener.details,
+                          "IEntityChangeListener event sequence")
+
 
 def suite():
     suite = unittest.TestSuite()