diff --git a/bt5/erp5_search_rank_catalog/TestTemplateItem/portal_components/test.erp5.testSearchRank.py b/bt5/erp5_search_rank_catalog/TestTemplateItem/portal_components/test.erp5.testSearchRank.py
new file mode 100644
index 0000000000000000000000000000000000000000..0e66c3158bc63e69a6d569808b542816e52ba6f4
--- /dev/null
+++ b/bt5/erp5_search_rank_catalog/TestTemplateItem/portal_components/test.erp5.testSearchRank.py
@@ -0,0 +1,138 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2002-2015 Nexedi SA and Contributors. All Rights Reserved.
+import transaction
+from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
+from decimal import Decimal
+
+def wipeFolder(folder, commit=True):
+  folder.deleteContent(list(folder.objectIds()))
+  if commit:
+    transaction.commit()
+
+class TestSearchRank(ERP5TypeTestCase):
+  def afterSetUp(self):
+    self.login()
+    wipeFolder(self.portal.foo_module, commit=False)
+
+  def beforeTearDown(self):
+    transaction.abort()
+
+  def generateNewId(self):
+    return "%sö" % self.portal.portal_ids.generateNewId(
+                                     id_group=('erp5_search_rank_test'))
+
+  def _makeDocument(self):
+    new_id = self.generateNewId()
+    foo = self.portal.foo_module.newContent(portal_type="Foo")
+    foo.edit(
+      title="live_test_%s" % new_id,
+      reference="live_test_%s" % new_id
+    )
+    return foo
+
+  def assertIndexedDocumentSearchRankEqual(self, document, string_rank):
+    sql_result_list = self.portal.portal_catalog(
+      uid=document.getUid(),
+      select_list=['search_rank'],
+      limit=1
+    )
+    self.assertEqual(
+      sql_result_list[0].search_rank,
+      Decimal(string_rank)
+    )
+
+  def test_rank_value(self):
+    # Newly created document without rank calculated yet
+    document = self._makeDocument()
+    self.tic()
+    self.assertIndexedDocumentSearchRankEqual(document, '0')
+
+    # reindexation does not recalculate the search rank
+    document.reindexObject()
+    self.tic()
+    self.assertIndexedDocumentSearchRankEqual(document, '0')
+
+    # calculate search rank for document without any (related) relation
+    document.Base_updateSearchRank()
+    self.assertIndexedDocumentSearchRankEqual(document, '15000')
+
+    # search rank calculation is stable
+    document.Base_updateSearchRank()
+    self.assertIndexedDocumentSearchRankEqual(document, '15000')
+
+    # reindexation does not modify the search rank
+    document.reindexObject()
+    self.tic()
+    self.assertIndexedDocumentSearchRankEqual(document, '15000')
+
+    # Create document to link to
+    linked_document_1 = self._makeDocument()
+    linked_document_2 = self._makeDocument()
+    self.tic()
+    linked_document_1.Base_updateSearchRank()
+    linked_document_2.Base_updateSearchRank()
+    self.assertIndexedDocumentSearchRankEqual(linked_document_1, '15000')
+    self.assertIndexedDocumentSearchRankEqual(linked_document_2, '15000')
+
+    # Linked from one document only
+    linked_document_1.setFooCategoryValue(document)
+    self.tic()
+    document.Base_updateSearchRank()
+    linked_document_1.Base_updateSearchRank()
+    self.assertIndexedDocumentSearchRankEqual(document, '27750')
+    self.assertIndexedDocumentSearchRankEqual(linked_document_1, '15000')
+    self.assertIndexedDocumentSearchRankEqual(linked_document_2, '15000')
+
+    # Linked from 2 documents (rank is higher than one doc only)
+    linked_document_1.setFooCategoryValue(document)
+    linked_document_2.setFooCategoryValue(document)
+    self.tic()
+    document.Base_updateSearchRank()
+    linked_document_1.Base_updateSearchRank()
+    linked_document_2.Base_updateSearchRank()
+    self.assertIndexedDocumentSearchRankEqual(document, '40500')
+    self.assertIndexedDocumentSearchRankEqual(linked_document_1, '15000')
+    self.assertIndexedDocumentSearchRankEqual(linked_document_2, '15000')
+
+    # reset ranks
+    linked_document_1.setFooCategoryValue(None)
+    linked_document_2.setFooCategoryValue(None)
+    self.tic()
+    document.Base_updateSearchRank()
+    linked_document_1.Base_updateSearchRank()
+    linked_document_2.Base_updateSearchRank()
+    self.assertIndexedDocumentSearchRankEqual(document, '15000')
+    self.assertIndexedDocumentSearchRankEqual(linked_document_1, '15000')
+    self.assertIndexedDocumentSearchRankEqual(linked_document_2, '15000')
+
+    # Linked from 1 document with a higher rank
+    linked_document_1.setFooCategoryValue(document)
+    linked_document_2.setFooCategoryValue(linked_document_1)
+    self.tic()
+    linked_document_2.Base_updateSearchRank()
+    linked_document_1.Base_updateSearchRank()
+    document.Base_updateSearchRank()
+    self.assertIndexedDocumentSearchRankEqual(document, '38587')
+    self.assertIndexedDocumentSearchRankEqual(linked_document_1, '27750')
+    self.assertIndexedDocumentSearchRankEqual(linked_document_2, '15000')
+
+    # reset ranks
+    linked_document_1.setFooCategoryValue(None)
+    linked_document_2.setFooCategoryValue(None)
+    self.tic()
+    document.Base_updateSearchRank()
+    linked_document_1.Base_updateSearchRank()
+    linked_document_2.Base_updateSearchRank()
+    self.assertIndexedDocumentSearchRankEqual(document, '15000')
+    self.assertIndexedDocumentSearchRankEqual(linked_document_1, '15000')
+    self.assertIndexedDocumentSearchRankEqual(linked_document_2, '15000')
+
+    # Linked from 1 document with many categories
+    linked_document_1.setFooCategoryValueList([document, linked_document_2])
+    self.tic()
+    linked_document_2.Base_updateSearchRank()
+    linked_document_1.Base_updateSearchRank()
+    document.Base_updateSearchRank()
+    self.assertIndexedDocumentSearchRankEqual(document, '21375')
+    self.assertIndexedDocumentSearchRankEqual(linked_document_1, '15000')
+    self.assertIndexedDocumentSearchRankEqual(linked_document_2, '21375')
diff --git a/bt5/erp5_search_rank_catalog/TestTemplateItem/portal_components/test.erp5.testSearchRank.xml b/bt5/erp5_search_rank_catalog/TestTemplateItem/portal_components/test.erp5.testSearchRank.xml
new file mode 100644
index 0000000000000000000000000000000000000000..93a904501f6d07c53e44c1bf10e2d2e57d76bb3e
--- /dev/null
+++ b/bt5/erp5_search_rank_catalog/TestTemplateItem/portal_components/test.erp5.testSearchRank.xml
@@ -0,0 +1,133 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="Test Component" module="erp5.portal_type"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_recorded_property_dict</string> </key>
+            <value>
+              <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
+            </value>
+        </item>
+        <item>
+            <key> <string>default_reference</string> </key>
+            <value> <string>testSearchRank</string> </value>
+        </item>
+        <item>
+            <key> <string>default_source_reference</string> </key>
+            <value>
+              <none/>
+            </value>
+        </item>
+        <item>
+            <key> <string>description</string> </key>
+            <value>
+              <none/>
+            </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>test.erp5.testSearchRank</string> </value>
+        </item>
+        <item>
+            <key> <string>portal_type</string> </key>
+            <value> <string>Test Component</string> </value>
+        </item>
+        <item>
+            <key> <string>sid</string> </key>
+            <value>
+              <none/>
+            </value>
+        </item>
+        <item>
+            <key> <string>text_content_error_message</string> </key>
+            <value>
+              <tuple/>
+            </value>
+        </item>
+        <item>
+            <key> <string>text_content_warning_message</string> </key>
+            <value>
+              <tuple/>
+            </value>
+        </item>
+        <item>
+            <key> <string>version</string> </key>
+            <value> <string>erp5</string> </value>
+        </item>
+        <item>
+            <key> <string>workflow_history</string> </key>
+            <value>
+              <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
+            </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+  <record id="2" aka="AAAAAAAAAAI=">
+    <pickle>
+      <global name="PersistentMapping" module="Persistence.mapping"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>data</string> </key>
+            <value>
+              <dictionary/>
+            </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+  <record id="3" aka="AAAAAAAAAAM=">
+    <pickle>
+      <global name="PersistentMapping" module="Persistence.mapping"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>data</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>component_validation_workflow</string> </key>
+                    <value>
+                      <persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
+                    </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+  <record id="4" aka="AAAAAAAAAAQ=">
+    <pickle>
+      <global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_log</string> </key>
+            <value>
+              <list>
+                <dictionary>
+                  <item>
+                      <key> <string>action</string> </key>
+                      <value> <string>validate</string> </value>
+                  </item>
+                  <item>
+                      <key> <string>validation_state</string> </key>
+                      <value> <string>validated</string> </value>
+                  </item>
+                </dictionary>
+              </list>
+            </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_search_rank_catalog/bt/template_test_id_list b/bt5/erp5_search_rank_catalog/bt/template_test_id_list
new file mode 100644
index 0000000000000000000000000000000000000000..f0865ff8047ab9e3a7271f103442f9cb569bae1c
--- /dev/null
+++ b/bt5/erp5_search_rank_catalog/bt/template_test_id_list
@@ -0,0 +1 @@
+test.erp5.testSearchRank
\ No newline at end of file
diff --git a/bt5/erp5_search_rank_catalog/bt/test_dependency_list b/bt5/erp5_search_rank_catalog/bt/test_dependency_list
new file mode 100644
index 0000000000000000000000000000000000000000..2ada34172e5d3525bbe8c046774d92c8c9d2d574
--- /dev/null
+++ b/bt5/erp5_search_rank_catalog/bt/test_dependency_list
@@ -0,0 +1,2 @@
+erp5_ui_test
+erp5_full_text_mroonga_catalog
\ No newline at end of file