Repository: oppia/oppia

Issue:
Explorations search is not updating after changing the category.
<!--
  - Thanks for taking the time to report a bug in the Oppia project.
  - Before filing a new issue, please do a quick search to check that it hasn't
  - already been filed on the [issue tracker](https://github.com/oppia/oppia/issues)._
  -->

**Describe the bug**
Search results in the library for the explorations is not displaying the correct results after the category of the exploration is changed. Even though the picture of the exploration changes it does not filter properly. 

**To Reproduce**
Steps to reproduce the behavior:
 1. Create an exploration with algorithm(for eg).
 2. Change the category of the exploration to art(for eg).
 3. Go to Library page.
 4. Search for the exploration by name.(It is found , the pic denoting the category of the exploration changes)
 5. Search it by Category. (The exploration is not found)

**Expected behavior**
Display the correct results when queried based on category.

**Screenshots**
Search based on name.
![Screenshot from 2019-10-19 14-36-35](https://user-images.githubusercontent.com/42460632/67141109-e9de3b00-f27d-11e9-9699-5db9b4c209d7.png)
Search based on category.
![Screenshot from 2019-10-19 14-23-10](https://user-images.githubusercontent.com/42460632/67141039-7a684b80-f27d-11e9-9567-76d25c36da0a.png)


**Desktop**
 - OS: Ubuntu
 - Browser: Chrome

**Additional context**
This issue occurs only if the category is changed. The exploration is listed correctly based on category before the change of category.

Explorations search is not updating after changing the category.
<!--
  - Thanks for taking the time to report a bug in the Oppia project.
  - Before filing a new issue, please do a quick search to check that it hasn't
  - already been filed on the [issue tracker](https://github.com/oppia/oppia/issues)._
  -->

**Describe the bug**
Search results in the library for the explorations is not displaying the correct results after the category of the exploration is changed. Even though the picture of the exploration changes it does not filter properly. 

**To Reproduce**
Steps to reproduce the behavior:
 1. Create an exploration with algorithm(for eg).
 2. Change the category of the exploration to art(for eg).
 3. Go to Library page.
 4. Search for the exploration by name.(It is found , the pic denoting the category of the exploration changes)
 5. Search it by Category. (The exploration is not found)

**Expected behavior**
Display the correct results when queried based on category.

**Screenshots**
Search based on name.
![Screenshot from 2019-10-19 14-36-35](https://user-images.githubusercontent.com/42460632/67141109-e9de3b00-f27d-11e9-9699-5db9b4c209d7.png)
Search based on category.
![Screenshot from 2019-10-19 14-23-10](https://user-images.githubusercontent.com/42460632/67141039-7a684b80-f27d-11e9-9567-76d25c36da0a.png)


**Desktop**
 - OS: Ubuntu
 - Browser: Chrome

**Additional context**
This issue occurs only if the category is changed. The exploration is listed correctly based on category before the change of category.



Discussion:
@rohitkatlaa, Thanks for reporting the issue! :)

In between steps 1 and 2 you have changed the exploration category from X --> Art? If so can you please update the issue thread so that it's clear? 
I have made the changes.
This same issue happens if we change the name instead of category.
@rohitkatlaa, Thanks for reporting the issue! :)

In between steps 1 and 2 you have changed the exploration category from X --> Art? If so can you please update the issue thread so that it's clear? 
I have made the changes.
This same issue happens if we change the name instead of category.

Resolving patch:
diff --git a/core/domain/exp_services.py b/core/domain/exp_services.py
--- a/core/domain/exp_services.py
+++ b/core/domain/exp_services.py
@@ -521,7 +521,6 @@ def _save_exploration(committer_id, exploration, commit_message, change_list):
     exploration_model.commit(committer_id, commit_message, change_list_dict)
     exp_memcache_key = exp_fetchers.get_exploration_memcache_key(exploration.id)
     memcache_services.delete(exp_memcache_key)
-    index_explorations_given_ids([exploration.id])
 
     exploration.version += 1
 
@@ -1042,6 +1041,12 @@ def save_exploration_summary(exp_summary):
 
     exp_summary_model.put()
 
+    # The index should be updated after saving the exploration
+    # summary instead of after saving the exploration since the
+    # index contains documents computed on basis of exploration
+    # summary.
+    index_explorations_given_ids([exp_summary.id])
+
 
 def delete_exploration_summary(exploration_id):
     """Delete an exploration summary model.


Test patch:
diff --git a/core/controllers/editor_test.py b/core/controllers/editor_test.py
--- a/core/controllers/editor_test.py
+++ b/core/controllers/editor_test.py
@@ -1053,18 +1053,24 @@ def mock_logging_function(msg, *_):
             self.delete_json(
                 '/createhandler/data/%s' % exp_id)
 
-            # Observed_log_messages[1] is 'Attempting to delete documents
+            # Observed_log_messaged[0] is 'adding the following docs to
+            # index %s: %s' % (index.name, documents). It is logged from the
+            # function add_documents_to_index in
+            # oppia/core/platform/search/gae_search_services.py,
+            # not to be checked here (same for admin and moderator). The
+            # function is called when an exploration is saved.
+            # Observed_log_messages[2] is 'Attempting to delete documents
             # from index %s, ids: %s' % (index.name, ', '.join(doc_ids)). It
             # is logged by function delete_documents_from_index in
             # oppia/core/platform/search/gae_search_services.py,
             # not to be checked here (same for admin and moderator).
-            self.assertEqual(len(observed_log_messages), 3)
+            self.assertEqual(len(observed_log_messages), 4)
             self.assertEqual(
-                observed_log_messages[0],
+                observed_log_messages[1],
                 '(%s) %s tried to delete exploration %s' %
                 (feconf.ROLE_ID_EXPLORATION_EDITOR, self.owner_id, exp_id))
             self.assertEqual(
-                observed_log_messages[2],
+                observed_log_messages[3],
                 '(%s) %s deleted exploration %s' %
                 (feconf.ROLE_ID_EXPLORATION_EDITOR, self.owner_id, exp_id))
             self.logout()
@@ -1078,13 +1084,13 @@ def mock_logging_function(msg, *_):
 
             self.login(self.ADMIN_EMAIL)
             self.delete_json('/createhandler/data/%s' % exp_id)
-            self.assertEqual(len(observed_log_messages), 3)
+            self.assertEqual(len(observed_log_messages), 4)
             self.assertEqual(
-                observed_log_messages[0],
+                observed_log_messages[1],
                 '(%s) %s tried to delete exploration %s' %
                 (feconf.ROLE_ID_ADMIN, self.admin_id, exp_id))
             self.assertEqual(
-                observed_log_messages[2],
+                observed_log_messages[3],
                 '(%s) %s deleted exploration %s' %
                 (feconf.ROLE_ID_ADMIN, self.admin_id, exp_id))
             self.logout()
@@ -1098,13 +1104,13 @@ def mock_logging_function(msg, *_):
 
             self.login(self.MODERATOR_EMAIL)
             self.delete_json('/createhandler/data/%s' % exp_id)
-            self.assertEqual(len(observed_log_messages), 3)
+            self.assertEqual(len(observed_log_messages), 4)
             self.assertEqual(
-                observed_log_messages[0],
+                observed_log_messages[1],
                 '(%s) %s tried to delete exploration %s' %
                 (feconf.ROLE_ID_MODERATOR, self.moderator_id, exp_id))
             self.assertEqual(
-                observed_log_messages[2],
+                observed_log_messages[3],
                 '(%s) %s deleted exploration %s' %
                 (feconf.ROLE_ID_MODERATOR, self.moderator_id, exp_id))
             self.logout()
diff --git a/core/domain/exp_services_test.py b/core/domain/exp_services_test.py
--- a/core/domain/exp_services_test.py
+++ b/core/domain/exp_services_test.py
@@ -3062,6 +3062,59 @@ def mock_add_documents_to_index(docs, index):
 
         self.assertEqual(add_docs_counter.times_called, 1)
 
+    def test_updated_exploration_is_added_correctly_to_index(self):
+        exp_id = 'id0'
+        exp_title = 'title 0'
+        exp_category = 'cat0'
+        actual_docs = []
+        initial_exp_doc = {
+            'category': 'cat0',
+            'id': 'id0',
+            'language_code': 'en',
+            'objective': 'An objective',
+            'rank': 20,
+            'tags': [],
+            'title': 'title 0'}
+        updated_exp_doc = {
+            'category': 'cat1',
+            'id': 'id0',
+            'language_code': 'en',
+            'objective': 'An objective',
+            'rank': 20,
+            'tags': [],
+            'title': 'title 0'
+        }
+
+        def mock_add_documents_to_index(docs, index):
+            self.assertEqual(index, exp_services.SEARCH_INDEX_EXPLORATIONS)
+            actual_docs.extend(docs)
+
+        add_docs_counter = test_utils.CallCounter(mock_add_documents_to_index)
+        add_docs_swap = self.swap(
+            search_services,
+            'add_documents_to_index',
+            add_docs_counter)
+
+        with add_docs_swap:
+            self.save_new_valid_exploration(
+                exp_id, self.owner_id, title=exp_title, category=exp_category,
+                end_state_name='End')
+
+            rights_manager.publish_exploration(self.owner, exp_id)
+            self.assertEqual(actual_docs, [initial_exp_doc])
+            self.assertEqual(add_docs_counter.times_called, 2)
+
+            actual_docs = []
+            exp_services.update_exploration(
+                self.owner_id, exp_id, [
+                    exp_domain.ExplorationChange({
+                        'cmd': exp_domain.CMD_EDIT_EXPLORATION_PROPERTY,
+                        'property_name': 'category',
+                        'new_value': 'cat1'})], 'update category')
+            self.assertEqual(actual_docs, [updated_exp_doc])
+            self.assertEqual(add_docs_counter.times_called, 3)
+
+
     def test_get_number_of_ratings(self):
         self.save_new_valid_exploration(self.EXP_ID, self.owner_id)
         exp = exp_fetchers.get_exploration_summary_by_id(self.EXP_ID)