Exemple #1
0
    def test_reload_collection(self):
        observed_log_messages = []

        def _mock_logging_function(msg, *args):
            """Mocks logging.info()."""
            observed_log_messages.append(msg % args)

        self.login(self.ADMIN_EMAIL, is_super_admin=True)
        csrf_token = self.get_new_csrf_token()

        collection_services.load_demo('0')
        collection_rights = rights_manager.get_collection_rights('0')

        self.assertFalse(collection_rights.community_owned)

        with self.swap(logging, 'info', _mock_logging_function):
            self.post_json('/adminhandler', {
                'action': 'reload_collection',
                'collection_id': '0'
            },
                           csrf_token=csrf_token)

        collection_rights = rights_manager.get_collection_rights('0')

        self.assertTrue(collection_rights.community_owned)
        self.assertEqual(observed_log_messages, [
            '[ADMIN] %s reloaded collection 0' % self.admin_id,
            'Collection with id 0 was loaded.'
        ])

        self.logout()
    def setUp(self):
        super(CollectionEditorTests, self).setUp()
        system_user = user_services.get_system_user()

        collection_services.load_demo(self.COLLECTION_ID)
        rights_manager.release_ownership_of_collection(
            system_user, self.COLLECTION_ID)
Exemple #3
0
    def test_access_collection(self):
        response_dict = self.get_json(
            feconf.COLLECTION_SUMMARIES_DATA_URL,
            params={'stringified_collection_ids': json.dumps('0')})
        self.assertDictContainsSubset({
            'summaries': [],
        }, response_dict)

        # Load a collection.
        collection_services.load_demo('0')
        response_dict = self.get_json(
            feconf.COLLECTION_SUMMARIES_DATA_URL,
            params={'stringified_collection_ids': json.dumps('0')})
        self.assertEqual(len(response_dict['summaries']), 1)
        self.assertDictContainsSubset(
            {
                'id': '0',
                'title': 'Introduction to Collections in Oppia',
                'category': 'Welcome',
                'objective':
                'To introduce collections using demo explorations.',
                'language_code': 'en',
                'tags': [],
                'node_count': 4,
            }, response_dict['summaries'][0])
 def test_clear_collection_search_index(self):
     collection_services.load_demo('0')
     result = search_services.search_collections('Welcome', [], [], 2)[0]
     self.assertEqual(result, ['0'])
     search_services.clear_collection_search_index()
     result = search_services.search_collections('Welcome', [], [], 2)[0]
     self.assertEqual(result, [])
Exemple #5
0
    def test_demo_collection(self):
        collection_services.load_demo('0')
        rights_manager.release_ownership_of_collection(
            self.system_user, '0')
        collection_rights = rights_manager.get_collection_rights('0')

        self.assertTrue(rights_manager.check_can_access_activity(
            self.user_a, collection_rights))
        self.assertTrue(rights_manager.check_can_edit_activity(
            self.user_a, collection_rights))
        self.assertFalse(rights_manager.check_can_delete_activity(
            self.user_a, collection_rights))

        self.assertTrue(rights_manager.check_can_access_activity(
            self.user_admin, collection_rights))
        self.assertTrue(rights_manager.check_can_edit_activity(
            self.user_admin, collection_rights))
        self.assertTrue(rights_manager.check_can_delete_activity(
            self.user_admin, collection_rights))

        self.assertTrue(rights_manager.check_can_access_activity(
            self.user_moderator, collection_rights))
        self.assertTrue(rights_manager.check_can_edit_activity(
            self.user_moderator, collection_rights))
        self.assertTrue(rights_manager.check_can_delete_activity(
            self.user_moderator, collection_rights))
    def test_demo_collections_are_added_to_search_index(self):
        results = search_services.search_collections('Welcome', [], [], 2)[0]
        self.assertEqual(results, [])

        collection_services.load_demo('0')
        results = search_services.search_collections('Welcome', [], [], 2)[0]
        self.assertEqual(results, ['0'])
Exemple #7
0
    def test_demo_collection(self):
        collection_services.load_demo('0')
        rights_manager.release_ownership_of_collection(
            feconf.SYSTEM_COMMITTER_ID, '0')

        self.assertTrue(
            rights_manager.Actor(self.user_id_a).can_play(
                rights_manager.ACTIVITY_TYPE_COLLECTION, '0'))
        self.assertTrue(
            rights_manager.Actor(self.user_id_a).can_view(
                rights_manager.ACTIVITY_TYPE_COLLECTION, '0'))
        self.assertTrue(
            rights_manager.Actor(self.user_id_a).can_edit(
                rights_manager.ACTIVITY_TYPE_COLLECTION, '0'))
        self.assertFalse(
            rights_manager.Actor(self.user_id_a).can_delete(
                rights_manager.ACTIVITY_TYPE_COLLECTION, '0'))

        self.assertTrue(
            rights_manager.Actor(self.user_id_admin).can_play(
                rights_manager.ACTIVITY_TYPE_COLLECTION, '0'))
        self.assertTrue(
            rights_manager.Actor(self.user_id_admin).can_view(
                rights_manager.ACTIVITY_TYPE_COLLECTION, '0'))
        self.assertTrue(
            rights_manager.Actor(self.user_id_admin).can_edit(
                rights_manager.ACTIVITY_TYPE_COLLECTION, '0'))
        self.assertTrue(
            rights_manager.Actor(self.user_id_admin).can_delete(
                rights_manager.ACTIVITY_TYPE_COLLECTION, '0'))
    def test_demo_collection(self):
        collection_services.load_demo('0')
        rights_manager.release_ownership_of_collection(
            feconf.SYSTEM_COMMITTER_ID, '0')

        self.assertTrue(
            rights_manager.Actor(self.user_id_a).can_play(
                rights_manager.ACTIVITY_TYPE_COLLECTION, '0'))
        self.assertTrue(
            rights_manager.Actor(self.user_id_a).can_view(
                rights_manager.ACTIVITY_TYPE_COLLECTION, '0'))
        self.assertTrue(
            rights_manager.Actor(self.user_id_a).can_edit(
                rights_manager.ACTIVITY_TYPE_COLLECTION, '0'))
        self.assertFalse(
            rights_manager.Actor(self.user_id_a).can_delete(
                rights_manager.ACTIVITY_TYPE_COLLECTION, '0'))

        self.assertTrue(
            rights_manager.Actor(self.user_id_admin).can_play(
                rights_manager.ACTIVITY_TYPE_COLLECTION, '0'))
        self.assertTrue(
            rights_manager.Actor(self.user_id_admin).can_view(
                rights_manager.ACTIVITY_TYPE_COLLECTION, '0'))
        self.assertTrue(
            rights_manager.Actor(self.user_id_admin).can_edit(
                rights_manager.ACTIVITY_TYPE_COLLECTION, '0'))
        self.assertTrue(
            rights_manager.Actor(self.user_id_admin).can_delete(
                rights_manager.ACTIVITY_TYPE_COLLECTION, '0'))
Exemple #9
0
 def _reload_collection(self, collection_id):
     if constants.DEV_MODE:
         logging.info('[ADMIN] %s reloaded collection %s' %
                      (self.user_id, collection_id))
         collection_services.load_demo(unicode(collection_id))
         rights_manager.release_ownership_of_collection(
             user_services.get_system_user(), unicode(collection_id))
     else:
         raise Exception('Cannot reload a collection in production.')
Exemple #10
0
 def _reload_collection(self, collection_id):
     if feconf.DEV_MODE:
         logging.info('[ADMIN] %s reloaded collection %s' %
                      (self.user_id, collection_id))
         collection_services.load_demo(unicode(collection_id))
         rights_manager.release_ownership_of_collection(
             feconf.SYSTEM_COMMITTER_ID, unicode(collection_id))
     else:
         raise Exception('Cannot reload a collection in production.')
Exemple #11
0
 def _reload_collection(self, collection_id):
     if feconf.DEV_MODE:
         logging.info(
             '[ADMIN] %s reloaded collection %s' %
             (self.user_id, collection_id))
         collection_services.load_demo(unicode(collection_id))
         rights_manager.release_ownership_of_collection(
             feconf.SYSTEM_COMMITTER_ID, unicode(collection_id))
     else:
         raise Exception('Cannot reload a collection in production.')
Exemple #12
0
    def _reload_collection(self, collection_id):
        """Reloads the collection in dev_mode corresponding to the given
        collection id.

        Args:
            collection_id: str. The collection id.

        Raises:
            Exception: Cannot reload a collection in production.
        """
        if constants.DEV_MODE:
            logging.info('[ADMIN] %s reloaded collection %s' %
                         (self.user_id, collection_id))
            collection_services.load_demo(unicode(collection_id))
            rights_manager.release_ownership_of_collection(
                user_services.get_system_user(), unicode(collection_id))
        else:
            raise Exception('Cannot reload a collection in production.')
Exemple #13
0
 def test_clear_search_index(self):
     exp_services.load_demo('0')
     result_explorations = search_services.search_explorations(
         'Welcome', 2)[0]
     self.assertEqual(result_explorations, ['0'])
     collection_services.load_demo('0')
     result_collections = search_services.search_collections('Welcome',
                                                             2)[0]
     self.assertEqual(result_collections, ['0'])
     self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME)
     self.login(self.ADMIN_EMAIL, is_super_admin=True)
     csrf_token = self.get_new_csrf_token()
     generated_exps_response = self.post_json(
         '/adminhandler', {'action': 'clear_search_index'},
         csrf_token=csrf_token)
     self.assertEqual(generated_exps_response, {})
     result_explorations = search_services.search_explorations(
         'Welcome', 2)[0]
     self.assertEqual(result_explorations, [])
     result_collections = search_services.search_collections('Welcome',
                                                             2)[0]
     self.assertEqual(result_collections, [])
Exemple #14
0
    def test_welcome_collection(self):
        """Test a learner's progression through the default collection."""
        collection_services.load_demo('0')

        # Login as the user who will play the collection.
        self.login(self.VIEWER_EMAIL)

        # Request the collection from the data handler.
        response_dict = self.get_json(
            '%s/0' % feconf.COLLECTION_DATA_URL_PREFIX)
        collection_dict = response_dict['collection']

        # Verify the collection was properly loaded.
        self.assertEqual(
            collection_dict['objective'],
            'To introduce collections using demo explorations.')
        self.assertEqual(collection_dict['category'], 'Welcome')
        self.assertEqual(
            collection_dict['title'], 'Introduction to Collections in Oppia')

        # Verify there are 5 explorations in this collection, the initial
        # explorations to be completed, and that there are no explorations
        # currently completed within the context of this collection.
        self.assertEqual(len(collection_dict['nodes']), 5)
        self.assertEqual(collection_dict['next_exploration_ids'], ['0'])
        self.assertEqual(collection_dict['completed_exploration_ids'], [])

        # 'Complete' the first exploration. This should lead to 3 more being
        # suggested to the learner.
        collection_services.record_played_exploration_in_collection_context(
            self.VIEWER_ID, '0', '0')
        response_dict = self.get_json(
            '%s/0' % feconf.COLLECTION_DATA_URL_PREFIX)
        collection_dict = response_dict['collection']

        self.assertEqual(
            collection_dict['next_exploration_ids'], ['13', '4', '14'])
        self.assertEqual(collection_dict['completed_exploration_ids'], ['0'])

        # Completing the 'Solar System' exploration results in no branching.
        collection_services.record_played_exploration_in_collection_context(
            self.VIEWER_ID, '0', '13')
        response_dict = self.get_json(
            '%s/0' % feconf.COLLECTION_DATA_URL_PREFIX)
        collection_dict = response_dict['collection']

        self.assertEqual(
            collection_dict['next_exploration_ids'], ['4', '14'])
        self.assertEqual(
            collection_dict['completed_exploration_ids'], ['0', '13'])

        # Completing the 'About Oppia' exploration results in another
        # exploration being suggested.
        collection_services.record_played_exploration_in_collection_context(
            self.VIEWER_ID, '0', '14')
        response_dict = self.get_json(
            '%s/0' % feconf.COLLECTION_DATA_URL_PREFIX)
        collection_dict = response_dict['collection']

        self.assertEqual(
            collection_dict['next_exploration_ids'], ['4', '15'])
        self.assertEqual(
            collection_dict['completed_exploration_ids'], ['0', '13', '14'])

        # Completing all explorations should lead to no other suggestions.
        collection_services.record_played_exploration_in_collection_context(
            self.VIEWER_ID, '0', '15')
        collection_services.record_played_exploration_in_collection_context(
            self.VIEWER_ID, '0', '4')
        response_dict = self.get_json(
            '%s/0' % feconf.COLLECTION_DATA_URL_PREFIX)
        collection_dict = response_dict['collection']

        self.assertEqual(collection_dict['next_exploration_ids'], [])
        self.assertEqual(
            collection_dict['completed_exploration_ids'],
            ['0', '13', '14', '15', '4'])
Exemple #15
0
    def post(self):
        """Handles POST requests."""
        try:
            if self.payload.get('action') == 'reload_exploration':
                exploration_id = self.payload.get('exploration_id')
                logging.info(
                    '[ADMIN] %s reloaded exploration %s' %
                    (self.user_id, exploration_id))
                exp_services.load_demo(unicode(exploration_id))
                rights_manager.release_ownership_of_exploration(
                    feconf.SYSTEM_COMMITTER_ID, unicode(exploration_id))
            elif self.payload.get('action') == 'reload_collection':
                collection_id = self.payload.get('collection_id')
                logging.info(
                    '[ADMIN] %s reloaded collection %s' %
                    (self.user_id, collection_id))
                collection_services.load_demo(unicode(collection_id))
                rights_manager.release_ownership_of_collection(
                    feconf.SYSTEM_COMMITTER_ID, unicode(collection_id))
            elif self.payload.get('action') == 'clear_search_index':
                exp_services.clear_search_index()
            elif self.payload.get('action') == 'save_config_properties':
                new_config_property_values = self.payload.get(
                    'new_config_property_values')
                logging.info('[ADMIN] %s saved config property values: %s' %
                             (self.user_id, new_config_property_values))
                for (name, value) in new_config_property_values.iteritems():
                    config_services.set_property(self.user_id, name, value)
            elif self.payload.get('action') == 'revert_config_property':
                config_property_id = self.payload.get('config_property_id')
                logging.info('[ADMIN] %s reverted config property: %s' %
                             (self.user_id, config_property_id))
                config_services.revert_property(
                    self.user_id, config_property_id)
            elif self.payload.get('action') == 'refresh_computed_property':
                computed_property_name = self.payload.get(
                    'computed_property_name')
                config_domain.Registry.get_config_property(
                    computed_property_name).refresh_default_value()
            elif self.payload.get('action') == 'start_new_job':
                for klass in jobs_registry.ONE_OFF_JOB_MANAGERS:
                    if klass.__name__ == self.payload.get('job_type'):
                        klass.enqueue(klass.create_new())
                        break
            elif self.payload.get('action') == 'cancel_job':
                job_id = self.payload.get('job_id')
                job_type = self.payload.get('job_type')
                for klass in jobs_registry.ONE_OFF_JOB_MANAGERS:
                    if klass.__name__ == job_type:
                        klass.cancel(job_id, self.user_id)
                        break
            elif self.payload.get('action') == 'start_computation':
                computation_type = self.payload.get('computation_type')
                for klass in jobs_registry.ALL_CONTINUOUS_COMPUTATION_MANAGERS:
                    if klass.__name__ == computation_type:
                        klass.start_computation()
                        break
            elif self.payload.get('action') == 'stop_computation':
                computation_type = self.payload.get('computation_type')
                for klass in jobs_registry.ALL_CONTINUOUS_COMPUTATION_MANAGERS:
                    if klass.__name__ == computation_type:
                        klass.stop_computation(self.user_id)
                        break
            elif self.payload.get('action') == 'upload_topic_similarities':
                data = self.payload.get('data')
                recommendations_services.update_topic_similarities(data)

            self.render_json({})
        except Exception as e:
            self.render_json({'error': unicode(e)})
            raise
Exemple #16
0
    def post(self):
        """Handles POST requests."""
        try:
            if self.payload.get('action') == 'reload_exploration':
                exploration_id = self.payload.get('exploration_id')
                logging.info(
                    '[ADMIN] %s reloaded exploration %s' %
                    (self.user_id, exploration_id))
                exp_services.load_demo(unicode(exploration_id))
                rights_manager.release_ownership_of_exploration(
                    feconf.SYSTEM_COMMITTER_ID, unicode(exploration_id))
            elif self.payload.get('action') == 'reload_collection':
                collection_id = self.payload.get('collection_id')
                logging.info(
                    '[ADMIN] %s reloaded collection %s' %
                    (self.user_id, collection_id))
                collection_services.load_demo(unicode(collection_id))
                rights_manager.release_ownership_of_collection(
                    feconf.SYSTEM_COMMITTER_ID, unicode(collection_id))
            elif self.payload.get('action') == 'clear_search_index':
                exp_services.clear_search_index()
            elif self.payload.get('action') == 'save_config_properties':
                new_config_property_values = self.payload.get(
                    'new_config_property_values')
                logging.info('[ADMIN] %s saved config property values: %s' %
                             (self.user_id, new_config_property_values))
                for (name, value) in new_config_property_values.iteritems():
                    config_services.set_property(self.user_id, name, value)
            elif self.payload.get('action') == 'revert_config_property':
                config_property_id = self.payload.get('config_property_id')
                logging.info('[ADMIN] %s reverted config property: %s' %
                             (self.user_id, config_property_id))
                config_services.revert_property(
                    self.user_id, config_property_id)
            elif self.payload.get('action') == 'start_new_job':
                for klass in jobs_registry.ONE_OFF_JOB_MANAGERS:
                    if klass.__name__ == self.payload.get('job_type'):
                        klass.enqueue(klass.create_new())
                        break
            elif self.payload.get('action') == 'cancel_job':
                job_id = self.payload.get('job_id')
                job_type = self.payload.get('job_type')
                for klass in jobs_registry.ONE_OFF_JOB_MANAGERS:
                    if klass.__name__ == job_type:
                        klass.cancel(job_id, self.user_id)
                        break
            elif self.payload.get('action') == 'start_computation':
                computation_type = self.payload.get('computation_type')
                for klass in jobs_registry.ALL_CONTINUOUS_COMPUTATION_MANAGERS:
                    if klass.__name__ == computation_type:
                        klass.start_computation()
                        break
            elif self.payload.get('action') == 'stop_computation':
                computation_type = self.payload.get('computation_type')
                for klass in jobs_registry.ALL_CONTINUOUS_COMPUTATION_MANAGERS:
                    if klass.__name__ == computation_type:
                        klass.stop_computation(self.user_id)
                        break
            elif self.payload.get('action') == 'upload_topic_similarities':
                data = self.payload.get('data')
                recommendations_services.update_topic_similarities(data)

            self.render_json({})
        except Exception as e:
            self.render_json({'error': unicode(e)})
            raise
    def test_welcome_collection(self):
        """Test a learner's progression through the default collection."""
        collection_services.load_demo('0')

        # Login as the user who will play the collection.
        self.login(self.VIEWER_EMAIL)

        # Request the collection from the data handler.
        response_dict = self.get_json(
            '%s/0' % feconf.COLLECTION_DATA_URL_PREFIX)
        collection_dict = response_dict['collection']

        # Verify the collection was properly loaded.
        self.assertEqual(
            collection_dict['objective'],
            'To introduce collections using demo explorations.')
        self.assertEqual(collection_dict['category'], 'Welcome')
        self.assertEqual(
            collection_dict['title'], 'Introduction to Collections in Oppia')

        # Verify there are 5 explorations in this collection, the initial
        # explorations to be completed, and that there are no explorations
        # currently completed within the context of this collection.
        self.assertEqual(len(collection_dict['nodes']), 5)

        playthrough_dict = collection_dict['playthrough_dict']
        self.assertEqual(playthrough_dict['next_exploration_ids'], ['0'])
        self.assertEqual(playthrough_dict['completed_exploration_ids'], [])

        # 'Complete' the first exploration. This should lead to 3 more being
        # suggested to the learner.
        collection_services.record_played_exploration_in_collection_context(
            self.viewer_id, '0', '0')
        response_dict = self.get_json(
            '%s/0' % feconf.COLLECTION_DATA_URL_PREFIX)
        collection_dict = response_dict['collection']

        playthrough_dict = collection_dict['playthrough_dict']
        self.assertEqual(
            playthrough_dict['next_exploration_ids'], ['13', '4', '14'])
        self.assertEqual(playthrough_dict['completed_exploration_ids'], ['0'])

        # Completing the 'Solar System' exploration results in no branching.
        collection_services.record_played_exploration_in_collection_context(
            self.viewer_id, '0', '13')
        response_dict = self.get_json(
            '%s/0' % feconf.COLLECTION_DATA_URL_PREFIX)
        collection_dict = response_dict['collection']

        playthrough_dict = collection_dict['playthrough_dict']
        self.assertEqual(
            playthrough_dict['next_exploration_ids'], ['4', '14'])
        self.assertEqual(
            playthrough_dict['completed_exploration_ids'], ['0', '13'])

        # Completing the 'About Oppia' exploration results in another
        # exploration being suggested.
        collection_services.record_played_exploration_in_collection_context(
            self.viewer_id, '0', '14')
        response_dict = self.get_json(
            '%s/0' % feconf.COLLECTION_DATA_URL_PREFIX)
        collection_dict = response_dict['collection']

        playthrough_dict = collection_dict['playthrough_dict']
        self.assertEqual(
            playthrough_dict['next_exploration_ids'], ['4', '15'])
        self.assertEqual(
            playthrough_dict['completed_exploration_ids'], ['0', '13', '14'])

        # Completing all explorations should lead to no other suggestions.
        collection_services.record_played_exploration_in_collection_context(
            self.viewer_id, '0', '15')
        collection_services.record_played_exploration_in_collection_context(
            self.viewer_id, '0', '4')
        response_dict = self.get_json(
            '%s/0' % feconf.COLLECTION_DATA_URL_PREFIX)
        collection_dict = response_dict['collection']

        playthrough_dict = collection_dict['playthrough_dict']
        self.assertEqual(playthrough_dict['next_exploration_ids'], [])
        self.assertEqual(
            playthrough_dict['completed_exploration_ids'],
            ['0', '13', '14', '15', '4'])
    def setUp(self):
        super(CollectionEditorTest, self).setUp()

        collection_services.load_demo(self.COLLECTION_ID)
        rights_manager.release_ownership_of_collection(
            feconf.SYSTEM_COMMITTER_ID, self.COLLECTION_ID)
Exemple #19
0
    def test_welcome_collection(self):
        """Test a learner's progression through the default collection."""
        collection_services.load_demo('0')

        # Login as the user who will play the collection.
        self.login(self.VIEWER_EMAIL)

        # Request the collection from the data handler.
        response_dict = self.get_json('%s/0' %
                                      feconf.COLLECTION_DATA_URL_PREFIX)
        collection_dict = response_dict['collection']

        # Verify the collection was properly loaded.
        self.assertEqual(collection_dict['objective'],
                         'To introduce collections using demo explorations.')
        self.assertEqual(collection_dict['category'], 'Welcome')
        self.assertEqual(collection_dict['title'],
                         'Introduction to Collections in Oppia')

        # Verify there are 4 explorations in this collection, the initial
        # explorations to be completed, and that there are no explorations
        # currently completed within the context of this collection.
        self.assertEqual(len(collection_dict['nodes']), 4)

        playthrough_dict = collection_dict['playthrough_dict']
        self.assertEqual(playthrough_dict['next_exploration_ids'], ['19'])
        self.assertEqual(playthrough_dict['completed_exploration_ids'], [])

        # 'Complete' the first exploration. This should lead to 1 new one being
        # suggested to the learner.
        collection_services.record_played_exploration_in_collection_context(
            self.viewer_id, '0', '19')
        response_dict = self.get_json('%s/0' %
                                      feconf.COLLECTION_DATA_URL_PREFIX)
        collection_dict = response_dict['collection']

        playthrough_dict = collection_dict['playthrough_dict']
        self.assertEqual(playthrough_dict['next_exploration_ids'], ['20'])
        self.assertEqual(playthrough_dict['completed_exploration_ids'], ['19'])

        # Completing the next exploration results in a third suggested exp.
        collection_services.record_played_exploration_in_collection_context(
            self.viewer_id, '0', '20')
        response_dict = self.get_json('%s/0' %
                                      feconf.COLLECTION_DATA_URL_PREFIX)
        collection_dict = response_dict['collection']

        playthrough_dict = collection_dict['playthrough_dict']
        self.assertEqual(playthrough_dict['next_exploration_ids'], ['21'])
        self.assertEqual(playthrough_dict['completed_exploration_ids'],
                         ['19', '20'])

        # Completing the next exploration results in a fourth and final
        # suggested exp.
        collection_services.record_played_exploration_in_collection_context(
            self.viewer_id, '0', '21')
        response_dict = self.get_json('%s/0' %
                                      feconf.COLLECTION_DATA_URL_PREFIX)
        collection_dict = response_dict['collection']

        playthrough_dict = collection_dict['playthrough_dict']
        self.assertEqual(playthrough_dict['next_exploration_ids'], ['0'])
        self.assertEqual(playthrough_dict['completed_exploration_ids'],
                         ['19', '20', '21'])

        # Completing the final exploration should result in no new suggestions.
        collection_services.record_played_exploration_in_collection_context(
            self.viewer_id, '0', '0')
        response_dict = self.get_json('%s/0' %
                                      feconf.COLLECTION_DATA_URL_PREFIX)
        collection_dict = response_dict['collection']

        playthrough_dict = collection_dict['playthrough_dict']
        self.assertEqual(playthrough_dict['next_exploration_ids'], [])
        self.assertEqual(playthrough_dict['completed_exploration_ids'],
                         ['19', '20', '21', '0'])
    def setUp(self):
        super(CollectionEditorTest, self).setUp()

        collection_services.load_demo(self.COLLECTION_ID)
        rights_manager.release_ownership_of_collection(
            feconf.SYSTEM_COMMITTER_ID, self.COLLECTION_ID)
    def test_welcome_collection(self):
        """Test a learner's progression through the default collection."""
        collection_services.load_demo("0")

        # Login as the user who will play the collection.
        self.login(self.VIEWER_EMAIL)

        # Request the collection from the data handler.
        response_dict = self.get_json("%s/0" % feconf.COLLECTION_DATA_URL_PREFIX)
        collection_dict = response_dict["collection"]

        # Verify the collection was properly loaded.
        self.assertEqual(collection_dict["objective"], "To introduce collections using demo explorations.")
        self.assertEqual(collection_dict["category"], "Welcome")
        self.assertEqual(collection_dict["title"], "Introduction to Collections in Oppia")

        # Verify there are 5 explorations in this collection, the initial
        # explorations to be completed, and that there are no explorations
        # currently completed within the context of this collection.
        self.assertEqual(len(collection_dict["nodes"]), 5)

        playthrough_dict = collection_dict["playthrough_dict"]
        self.assertEqual(playthrough_dict["next_exploration_ids"], ["0"])
        self.assertEqual(playthrough_dict["completed_exploration_ids"], [])

        # 'Complete' the first exploration. This should lead to 3 more being
        # suggested to the learner.
        collection_services.record_played_exploration_in_collection_context(self.viewer_id, "0", "0")
        response_dict = self.get_json("%s/0" % feconf.COLLECTION_DATA_URL_PREFIX)
        collection_dict = response_dict["collection"]

        playthrough_dict = collection_dict["playthrough_dict"]
        self.assertEqual(playthrough_dict["next_exploration_ids"], ["13"])
        self.assertEqual(playthrough_dict["completed_exploration_ids"], ["0"])

        # Completing the 'Solar System' exploration results in no branching.
        collection_services.record_played_exploration_in_collection_context(self.viewer_id, "0", "13")
        response_dict = self.get_json("%s/0" % feconf.COLLECTION_DATA_URL_PREFIX)
        collection_dict = response_dict["collection"]

        playthrough_dict = collection_dict["playthrough_dict"]
        self.assertEqual(playthrough_dict["next_exploration_ids"], ["4"])
        self.assertEqual(playthrough_dict["completed_exploration_ids"], ["0", "13"])

        # Completing the 'About Oppia' exploration results in another
        # exploration being suggested.
        collection_services.record_played_exploration_in_collection_context(self.viewer_id, "0", "14")
        response_dict = self.get_json("%s/0" % feconf.COLLECTION_DATA_URL_PREFIX)
        collection_dict = response_dict["collection"]

        playthrough_dict = collection_dict["playthrough_dict"]
        self.assertEqual(playthrough_dict["next_exploration_ids"], ["4"])
        self.assertEqual(playthrough_dict["completed_exploration_ids"], ["0", "13", "14"])

        # Completing all explorations should lead to no other suggestions.
        collection_services.record_played_exploration_in_collection_context(self.viewer_id, "0", "15")
        collection_services.record_played_exploration_in_collection_context(self.viewer_id, "0", "4")
        response_dict = self.get_json("%s/0" % feconf.COLLECTION_DATA_URL_PREFIX)
        collection_dict = response_dict["collection"]

        playthrough_dict = collection_dict["playthrough_dict"]
        self.assertEqual(playthrough_dict["next_exploration_ids"], [])
        self.assertEqual(playthrough_dict["completed_exploration_ids"], ["0", "13", "14", "15", "4"])