Return-Path: X-Original-To: apmail-incubator-bloodhound-commits-archive@minotaur.apache.org Delivered-To: apmail-incubator-bloodhound-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 99637DB94 for ; Mon, 18 Mar 2013 15:10:20 +0000 (UTC) Received: (qmail 94841 invoked by uid 500); 18 Mar 2013 15:10:20 -0000 Delivered-To: apmail-incubator-bloodhound-commits-archive@incubator.apache.org Received: (qmail 94822 invoked by uid 500); 18 Mar 2013 15:10:20 -0000 Mailing-List: contact bloodhound-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: bloodhound-dev@incubator.apache.org Delivered-To: mailing list bloodhound-commits@incubator.apache.org Received: (qmail 94815 invoked by uid 99); 18 Mar 2013 15:10:20 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 18 Mar 2013 15:10:20 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 18 Mar 2013 15:10:19 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id D37A82388A91; Mon, 18 Mar 2013 15:09:47 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1457798 - in /incubator/bloodhound/trunk/bloodhound_search/bhsearch: ./ search_resources/ tests/ tests/search_resources/ Date: Mon, 18 Mar 2013 15:09:47 -0000 To: bloodhound-commits@incubator.apache.org From: andrej@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20130318150947.D37A82388A91@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: andrej Date: Mon Mar 18 15:09:47 2013 New Revision: 1457798 URL: http://svn.apache.org/r1457798 Log: adding updating of bhsearch index after Component renaming - towards #411 Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/milestone_search.py incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/index_with_whoosh.py incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/milestone_search.py incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/ticket_search.py Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py?rev=1457798&r1=1457797&r2=1457798&view=diff ============================================================================== --- incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py (original) +++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py Mon Mar 18 15:09:47 2013 @@ -89,7 +89,6 @@ class ISearchBackend(Interface): """Extension point interface for search backend systems. """ -# def add_doc(self, doc, **kwargs): def add_doc(doc, operation_context): """ Called when new document instance must be added Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/milestone_search.py URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/milestone_search.py?rev=1457798&r1=1457797&r2=1457798&view=diff ============================================================================== --- incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/milestone_search.py (original) +++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/milestone_search.py Mon Mar 18 15:09:47 2013 @@ -24,9 +24,10 @@ from bhsearch.api import (IIndexParticip ISearchParticipant) from bhsearch.search_resources.base import BaseIndexer, BaseSearchParticipant from bhsearch.search_resources.ticket_search import TicketIndexer -from trac.ticket import IMilestoneChangeListener, Milestone +from trac.ticket import Milestone from trac.config import ListOption, Option from trac.core import implements +from trac.resource import IResourceChangeListener MILESTONE_TYPE = u"milestone" @@ -35,7 +36,7 @@ class MilestoneFields(IndexFields): COMPLETED = "completed" class MilestoneIndexer(BaseIndexer): - implements(IMilestoneChangeListener, IIndexParticipant) + implements(IResourceChangeListener, IIndexParticipant) optional_fields = { 'description': MilestoneFields.CONTENT, @@ -43,20 +44,28 @@ class MilestoneIndexer(BaseIndexer): 'completed': MilestoneFields.COMPLETED, } - # IMilestoneChangeListener methods - def milestone_created(self, milestone): - self._index_milestone(milestone) + # IResourceChangeListener methods + def match_resource(self, resource): + if isinstance(resource, Milestone): + return True + return False + + def resource_created(self, resource, context): + # pylint: disable=unused-argument + self._index_milestone(resource) - def milestone_changed(self, milestone, old_values): + def resource_changed(self, resource, old_values, context): + # pylint: disable=unused-argument if "name" in old_values: - self._rename_milestone(milestone, old_values["name"]) + self._rename_milestone(resource, old_values["name"]) else: - self._index_milestone(milestone) + self._index_milestone(resource) - def milestone_deleted(self, milestone): + def resource_deleted(self, resource, context): + # pylint: disable=unused-argument try: search_api = BloodhoundSearchApi(self.env) - search_api.delete_doc(MILESTONE_TYPE, milestone.name) + search_api.delete_doc(MILESTONE_TYPE, resource.name) except Exception, e: if self.silence_on_error: self.log.error("Error occurs during milestone indexing. \ Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py?rev=1457798&r1=1457797&r2=1457798&view=diff ============================================================================== --- incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py (original) +++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py Mon Mar 18 15:09:47 2013 @@ -20,15 +20,16 @@ r"""Ticket specifics for Bloodhound Search plugin.""" from bhsearch import BHSEARCH_CONFIG_SECTION -from bhsearch.api import ISearchParticipant, BloodhoundSearchApi, \ - IIndexParticipant, IndexFields +from bhsearch.api import (ISearchParticipant, BloodhoundSearchApi, + IIndexParticipant, IndexFields) from bhsearch.search_resources.base import BaseIndexer, BaseSearchParticipant from genshi.builder import tag -from trac.ticket.api import ITicketChangeListener, TicketSystem +from trac.ticket.api import TicketSystem from trac.ticket import Ticket -from trac.ticket.query import Query from trac.config import ListOption, Option from trac.core import implements +from trac.resource import IResourceChangeListener +from trac.ticket.model import Component TICKET_TYPE = u"ticket" @@ -42,7 +43,7 @@ class TicketFields(IndexFields): OWNER = 'owner' class TicketIndexer(BaseIndexer): - implements(ITicketChangeListener, IIndexParticipant) + implements(IResourceChangeListener, IIndexParticipant) optional_fields = { 'component': TicketFields.COMPONENT, @@ -61,17 +62,53 @@ class TicketIndexer(BaseIndexer): self.text_area_fields = set( f['name'] for f in self.fields if f['type'] =='textarea') - #ITicketChangeListener methods - def ticket_created(self, ticket): - """Index a recently created ticket.""" - self._index_ticket(ticket) + #IResourceChangeListener methods + def match_resource(self, resource): + if isinstance(resource, (Component, Ticket)): + return True + return False - def ticket_changed(self, ticket, comment, author, old_values): - """Reindex a recently modified ticket.""" + def resource_created(self, resource, context): # pylint: disable=unused-argument - self._index_ticket(ticket) + if isinstance(resource, Ticket): + self._index_ticket(resource) - def ticket_deleted(self, ticket): + def resource_changed(self, resource, old_values, context): + # pylint: disable=unused-argument + if isinstance(resource, Ticket): + self._index_ticket(resource) + elif isinstance(resource, Component): + self._component_changed(resource, old_values) + + def resource_deleted(self, resource, context): + # pylint: disable=unused-argument + if isinstance(resource, Ticket): + self._ticket_deleted(resource) + + def resource_version_deleted(self, resource, context): + pass + + def _component_changed(self, component, old_values): + if "name" in old_values: + old_name = old_values["name"] + try: + search_api = BloodhoundSearchApi(self.env) + with search_api.start_operation() as operation_context: + TicketIndexer(self.env).reindex_tickets( + search_api, + operation_context, + component=component.name) + except Exception, e: + if self.silence_on_error: + self.log.error("Error occurs during renaming Component \ + from %s to %s. The error will not be propagated. \ + Exception: %s", + old_name, component.name, e) + else: + raise + + + def _ticket_deleted(self, ticket): """Called when a ticket is deleted.""" try: search_api = BloodhoundSearchApi(self.env) @@ -83,28 +120,29 @@ class TicketIndexer(BaseIndexer): else: raise - def reindex_tickets(self, search_api, operation_context, milestone=None): - for ticket in self._fetch_tickets(milestone): + def reindex_tickets(self, + search_api, + operation_context, + **kwargs): + for ticket in self._fetch_tickets(**kwargs): self._index_ticket(ticket, search_api, operation_context) - def _fetch_tickets(self, milestone = None): -# with self.env.db_transaction as db: - for ticket_id in self._fetch_ids(milestone): + def _fetch_tickets(self, **kwargs): + for ticket_id in self._fetch_ids(**kwargs): yield Ticket(self.env, ticket_id) - def _fetch_ids(self, milestone): + def _fetch_ids(self, **kwargs): sql = "SELECT id FROM ticket" args = [] conditions = [] - if milestone: - args.append(milestone) - conditions.append("milestone=%s") + for key, value in kwargs.iteritems(): + args.append(value) + conditions.append(key + "=%s") if conditions: sql = sql + " WHERE " + " AND ".join(conditions) for row in self.env.db_query(sql, args): yield int(row[0]) - def _index_ticket( self, ticket, search_api = None, operation_context = None): try: @@ -144,11 +182,6 @@ class TicketIndexer(BaseIndexer): for ticket in self._fetch_tickets(): yield self.build_doc(ticket) - def _load_ticket_ids(self): - query = Query(self.env, cols=['id'], order='id') - return query.execute() - - class TicketSearchParticipant(BaseSearchParticipant): implements(ISearchParticipant) Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/index_with_whoosh.py URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/index_with_whoosh.py?rev=1457798&r1=1457797&r2=1457798&view=diff ============================================================================== --- incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/index_with_whoosh.py (original) +++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/index_with_whoosh.py Mon Mar 18 15:09:47 2013 @@ -39,8 +39,7 @@ class IndexWhooshTestCase(BaseBloodhound def test_can_index_ticket(self): ticket = self.create_dummy_ticket() - ticket.id = "1" - TicketIndexer(self.env).ticket_created(ticket) + TicketIndexer(self.env).resource_created(ticket, None) results = self.search_api.query("*:*") self.print_result(results) Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/milestone_search.py URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/milestone_search.py?rev=1457798&r1=1457797&r2=1457798&view=diff ============================================================================== --- incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/milestone_search.py (original) +++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/milestone_search.py Mon Mar 18 15:09:47 2013 @@ -100,10 +100,12 @@ class MilestoneIndexerEventsTestCase(Bas def test_can_index_delete(self): #arrange self.insert_milestone(self.DUMMY_MILESTONE_NAME) - Milestone(self.env, self.DUMMY_MILESTONE_NAME).delete() + results = self.search_api.query("*") + self.assertEqual(1, results.hits) #act - results = self.search_api.query("*.*") + Milestone(self.env, self.DUMMY_MILESTONE_NAME).delete() #assert + results = self.search_api.query("*") self.print_result(results) self.assertEqual(0, results.hits) Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/ticket_search.py URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/ticket_search.py?rev=1457798&r1=1457797&r2=1457798&view=diff ============================================================================== --- incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/ticket_search.py (original) +++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/ticket_search.py Mon Mar 18 15:09:47 2013 @@ -22,6 +22,7 @@ from bhsearch.api import BloodhoundSearc from bhsearch.tests.base import BaseBloodhoundSearchTest from bhsearch.search_resources.ticket_search import TicketIndexer +from trac.ticket.model import Component, Ticket class TicketIndexerTestCase(BaseBloodhoundSearchTest): def setUp(self): @@ -35,13 +36,13 @@ class TicketIndexerTestCase(BaseBloodhou def test_does_not_raise_exception_by_default(self): self.env.config.set('bhsearch', 'silence_on_error', "True") - self.ticket_indexer.ticket_created(None) + self.ticket_indexer.resource_created(None, None) def test_raise_exception_if_configured(self): self.env.config.set('bhsearch', 'silence_on_error', "False") self.assertRaises( Exception, - self.ticket_indexer.ticket_created, + self.ticket_indexer.resource_created, None) def test_can_strip_wiki_syntax(self): @@ -53,6 +54,40 @@ class TicketIndexerTestCase(BaseBloodhou self.assertEqual(1, results.hits) self.assertEqual("Header", results.docs[0]["content"]) + def test_that_tickets_updated_after_component_renaming(self): + #arrange + INITIAL_COMPONENT = "initial_name" + RENAMED_COMPONENT = "renamed_name" + component = self._insert_component(INITIAL_COMPONENT) + self.insert_ticket("T1", component=INITIAL_COMPONENT) + self.insert_ticket("T2", component=INITIAL_COMPONENT) + #act + component.name = RENAMED_COMPONENT + component.update() + #arrange + results = self.search_api.query("*") + self.print_result(results) + for doc in results.docs: + self.assertEqual(RENAMED_COMPONENT, doc["component"]) + + def test_that_ticket_updated_after_changing(self): + #arrange + ticket = self.insert_ticket("T1", description="some text") + #act + CHANGED_SUMMARY = "T1 changed" + ticket["summary"] = CHANGED_SUMMARY + ticket.save_changes() + #arrange + results = self.search_api.query("*") + self.print_result(results) + self.assertEqual(CHANGED_SUMMARY, results.docs[0]["summary"]) + + def _insert_component(self, name): + component = Component(self.env) + component.name = name + component.insert() + return component + def suite(): return unittest.makeSuite(TicketIndexerTestCase, 'test')