Repository: oppia/oppia

Issue:
Load dummy skill with questions
**Is your feature request related to a problem? Please describe.**
Create a button in the admin page to load a skill with dummy questions(at least 15 -20) which could be assigned to a story of a topic.This can be used in the testing of display of pretext questions if the skill is assigned as a prerequisite to a story of a topic.

**Additional context**
Similar button exists for loading dummy topics with few skills and questions in the activities tab of the admin page.

Load dummy skill with questions
**Is your feature request related to a problem? Please describe.**
Create a button in the admin page to load a skill with dummy questions(at least 15 -20) which could be assigned to a story of a topic.This can be used in the testing of display of pretext questions if the skill is assigned as a prerequisite to a story of a topic.

**Additional context**
Similar button exists for loading dummy topics with few skills and questions in the activities tab of the admin page.



Discussion:

Resolving patch:
diff --git a/core/controllers/admin.py b/core/controllers/admin.py
--- a/core/controllers/admin.py
+++ b/core/controllers/admin.py
@@ -179,6 +179,10 @@ def post(self):
                     self.payload.get('action') ==
                     'generate_dummy_new_structures_data'):
                 self._load_dummy_new_structures_data()
+            elif (
+                    self.payload.get('action') ==
+                    'generate_dummy_new_skill_data'):
+                self._generate_dummy_skill_and_questions()
             elif self.payload.get('action') == (
                     'flush_migration_bot_contribution_data'):
                 user_services.flush_migration_bot_contributions_model()
@@ -441,6 +445,39 @@ def _load_dummy_new_structures_data(self):
         else:
             raise Exception('Cannot load new structures data in production.')
 
+    def _generate_dummy_skill_and_questions(self):
+        """Generate and loads the database with a skill and 15 questions
+        linked to the skill.
+
+        Raises:
+            Exception: Cannot load new structures data in production mode.
+            Exception: User does not have enough rights to generate data.
+        """
+        if constants.DEV_MODE:
+            if self.user.role != feconf.ROLE_ID_ADMIN:
+                raise Exception(
+                    'User does not have enough rights to generate data.')
+            skill_id = skill_services.get_new_skill_id()
+            skill_name = 'Dummy Skill %s' % python_utils.UNICODE(
+                random.getrandbits(32))
+            skill = self._create_dummy_skill(
+                skill_id, skill_name, '<p>Dummy Explanation 1</p>')
+            skill_services.save_new_skill(self.user_id, skill)
+            for i in python_utils.RANGE(15):
+                question_id = question_services.get_new_question_id()
+                question_name = 'Question number %s %s' % (
+                    python_utils.UNICODE(i), skill_name)
+                question = self._create_dummy_question(
+                    question_id, question_name, [skill_id])
+                question_services.add_question(self.user_id, question)
+                question_difficulty = [feconf.EASY_SKILL_DIFFICULTY,
+                                       feconf.MEDIUM_SKILL_DIFFICULTY,
+                                       feconf.HARD_SKILL_DIFFICULTY]
+                random_difficulty = random.choice(question_difficulty)
+                question_services.create_new_question_skill_link(
+                    self.user_id, question_id, skill_id, random_difficulty)
+        else:
+            raise Exception('Cannot generate dummy skills in production.')
 
     def _reload_collection(self, collection_id):
         """Reloads the collection in dev_mode corresponding to the given
diff --git a/feconf.py b/feconf.py
--- a/feconf.py
+++ b/feconf.py
@@ -500,8 +500,12 @@ def get_empty_ratings():
 # category.
 MINIMUM_SCORE_REQUIRED_TO_REVIEW = 10
 
-# The number of medium question skill difficulty.
+# The difficulty value of an easy question.
+EASY_SKILL_DIFFICULTY = 0.3
+# The difficulty value of a medium question.
 MEDIUM_SKILL_DIFFICULTY = 0.6
+# The difficulty value of a hard question.
+HARD_SKILL_DIFFICULTY = 0.9
 
 # The maximum number of skills to be requested at one time when fetching
 # questions.


Test patch:
diff --git a/core/controllers/admin_test.py b/core/controllers/admin_test.py
--- a/core/controllers/admin_test.py
+++ b/core/controllers/admin_test.py
@@ -169,6 +169,32 @@ def test_non_admins_cannot_load_new_structures_data(self):
                 }, csrf_token=csrf_token)
         self.logout()
 
+    def test_cannot_generate_dummy_skill_data_in_production_mode(self):
+        self.login(self.ADMIN_EMAIL, is_super_admin=True)
+        csrf_token = self.get_new_csrf_token()
+
+        prod_mode_swap = self.swap(constants, 'DEV_MODE', False)
+        assert_raises_regexp_context_manager = self.assertRaisesRegexp(
+            Exception, 'Cannot generate dummy skills in production.')
+        with assert_raises_regexp_context_manager, prod_mode_swap:
+            self.post_json(
+                '/adminhandler', {
+                    'action': 'generate_dummy_new_skill_data'
+                }, csrf_token=csrf_token)
+        self.logout()
+
+    def test_non_admins_cannot_generate_dummy_skill_data(self):
+        self.login(self.ADMIN_EMAIL, is_super_admin=True)
+        csrf_token = self.get_new_csrf_token()
+        assert_raises_regexp = self.assertRaisesRegexp(
+            Exception, 'User does not have enough rights to generate data.')
+        with assert_raises_regexp:
+            self.post_json(
+                '/adminhandler', {
+                    'action': 'generate_dummy_new_skill_data'
+                }, csrf_token=csrf_token)
+        self.logout()
+
     def test_cannot_reload_collection_in_production_mode(self):
         self.login(self.ADMIN_EMAIL, is_super_admin=True)
         csrf_token = self.get_new_csrf_token()
@@ -249,6 +275,23 @@ def test_load_new_structures_data(self):
         self.assertEqual(len(questions), 3)
         self.logout()
 
+    def test_generate_dummy_skill_and_questions_data(self):
+        self.set_admins([self.ADMIN_USERNAME])
+        self.login(self.ADMIN_EMAIL, is_super_admin=True)
+        csrf_token = self.get_new_csrf_token()
+        self.post_json(
+            '/adminhandler', {
+                'action': 'generate_dummy_new_skill_data'
+            }, csrf_token=csrf_token)
+        skill_summaries = skill_services.get_all_skill_summaries()
+        self.assertEqual(len(skill_summaries), 1)
+        questions, _, _ = (
+            question_fetchers.get_questions_and_skill_descriptions_by_skill_ids(
+                20, [skill_summaries[0].id], '')
+        )
+        self.assertEqual(len(questions), 15)
+        self.logout()
+
     def test_flush_migration_bot_contributions_action(self):
         created_exploration_ids = ['exp_1', 'exp_2']
         edited_exploration_ids = ['exp_3', 'exp_4']