Пример #1
0
    def test_record_and_retrieve_single_answer(self):
        state_answers = stats_services.get_state_answers(
            self.EXP_ID, self.exploration.version,
            self.exploration.init_state_name)
        self.assertIsNone(state_answers)

        stats_services.record_answer(
            self.EXP_ID, self.exploration.version,
            self.exploration.init_state_name, 'TextInput',
            stats_domain.SubmittedAnswer(
                'some text', 'TextInput', 0,
                1, exp_domain.EXPLICIT_CLASSIFICATION, {},
                'a_session_id_val', 10.0))

        state_answers = stats_services.get_state_answers(
            self.EXP_ID, self.exploration.version,
            self.exploration.init_state_name)
        self.assertEqual(state_answers.exploration_id, 'exp_id0')
        self.assertEqual(state_answers.exploration_version, 1)
        self.assertEqual(
            state_answers.state_name, feconf.DEFAULT_INIT_STATE_NAME)
        self.assertEqual(state_answers.interaction_id, 'TextInput')
        self.assertEqual(state_answers.get_submitted_answer_dict_list(), [{
            'answer': 'some text',
            'time_spent_in_sec': 10.0,
            'answer_group_index': 0,
            'rule_spec_index': 1,
            'classification_categorization': 'explicit',
            'session_id': 'a_session_id_val',
            'interaction_id': 'TextInput',
            'params': {}
        }])
Пример #2
0
    def test_record_many_answers(self):
        state_answers = stats_services.get_state_answers(
            self.EXP_ID, self.exploration.version,
            self.exploration.init_state_name)
        self.assertIsNone(state_answers)

        submitted_answer_list = [
            stats_domain.SubmittedAnswer(
                'answer a', 'TextInput', 0, 1,
                exp_domain.EXPLICIT_CLASSIFICATION, {}, 'session_id_v', 10.0),
            stats_domain.SubmittedAnswer(
                'answer ccc', 'TextInput', 1, 1,
                exp_domain.EXPLICIT_CLASSIFICATION, {}, 'session_id_v', 3.0),
            stats_domain.SubmittedAnswer(
                'answer bbbbb', 'TextInput', 1, 0,
                exp_domain.EXPLICIT_CLASSIFICATION, {}, 'session_id_v', 7.5),
        ]
        stats_services.record_answers(
            self.EXP_ID, self.exploration.version,
            self.exploration.init_state_name, 'TextInput',
            submitted_answer_list)

        # The order of the answers returned depends on the size of the answers.
        state_answers = stats_services.get_state_answers(
            self.EXP_ID, self.exploration.version,
            self.exploration.init_state_name)
        self.assertEqual(state_answers.exploration_id, 'exp_id0')
        self.assertEqual(state_answers.exploration_version, 1)
        self.assertEqual(
            state_answers.state_name, feconf.DEFAULT_INIT_STATE_NAME)
        self.assertEqual(state_answers.interaction_id, 'TextInput')
        self.assertEqual(state_answers.get_submitted_answer_dict_list(), [{
            'answer': 'answer a',
            'time_spent_in_sec': 10.0,
            'answer_group_index': 0,
            'rule_spec_index': 1,
            'classification_categorization': 'explicit',
            'session_id': 'session_id_v',
            'interaction_id': 'TextInput',
            'params': {}
        }, {
            'answer': 'answer ccc',
            'time_spent_in_sec': 3.0,
            'answer_group_index': 1,
            'rule_spec_index': 1,
            'classification_categorization': 'explicit',
            'session_id': 'session_id_v',
            'interaction_id': 'TextInput',
            'params': {}
        }, {
            'answer': 'answer bbbbb',
            'time_spent_in_sec': 7.5,
            'answer_group_index': 1,
            'rule_spec_index': 0,
            'classification_categorization': 'explicit',
            'session_id': 'session_id_v',
            'interaction_id': 'TextInput',
            'params': {}
        }])
Пример #3
0
    def test_record_answers_exceeding_one_shard(self):
        # Use a smaller max answer list size so less answers are needed to
        # exceed a shard.
        with self.swap(
            stats_models.StateAnswersModel, '_MAX_ANSWER_LIST_BYTE_SIZE',
            100000):
            state_answers = stats_services.get_state_answers(
                self.EXP_ID, self.exploration.version,
                self.exploration.init_state_name)
            self.assertIsNone(state_answers)

            submitted_answer_list = [
                stats_domain.SubmittedAnswer(
                    'answer a', 'TextInput', 0, 1,
                    exp_domain.EXPLICIT_CLASSIFICATION, {}, 'session_id_v',
                    10.0),
                stats_domain.SubmittedAnswer(
                    'answer ccc', 'TextInput', 1, 1,
                    exp_domain.EXPLICIT_CLASSIFICATION, {}, 'session_id_v',
                    3.0),
                stats_domain.SubmittedAnswer(
                    'answer bbbbb', 'TextInput', 1, 0,
                    exp_domain.EXPLICIT_CLASSIFICATION, {}, 'session_id_v',
                    7.5),
            ]
            stats_services.record_answers(
                self.EXP_ID, self.exploration.version,
                self.exploration.init_state_name, 'TextInput',
                submitted_answer_list * 200)

            # Verify more than 1 shard was stored. The index shard (shard_id 0)
            # is not included in the shard count.
            model = stats_models.StateAnswersModel.get('%s:%s:%s:%s' % (
                self.exploration.id, str(self.exploration.version),
                self.exploration.init_state_name, '0'))
            self.assertEqual(model.shard_count, 1)

            # The order of the answers returned depends on the size of the
            # answers.
            state_answers = stats_services.get_state_answers(
                self.EXP_ID, self.exploration.version,
                self.exploration.init_state_name)
            self.assertEqual(state_answers.exploration_id, 'exp_id0')
            self.assertEqual(state_answers.exploration_version, 1)
            self.assertEqual(
                state_answers.state_name, feconf.DEFAULT_INIT_STATE_NAME)
            self.assertEqual(state_answers.interaction_id, 'TextInput')
            self.assertEqual(
                len(state_answers.get_submitted_answer_dict_list()), 600)
Пример #4
0
    def get(self):
        exp_id = self.normalized_request.get('exp_id')
        exp_version = self.normalized_request.get('exp_version')

        exploration = exp_fetchers.get_exploration_by_id(
            exp_id, strict=False, version=exp_version)
        if exploration is None:
            raise self.InvalidInputException(
                'Entity for exploration with id %s and version %s not found.'
                % (exp_id, exp_version))

        state_name = self.normalized_request.get('state_name')
        num_answers = self.normalized_request.get('num_answers')

        if state_name not in exploration.states:
            raise self.InvalidInputException(
                'Exploration \'%s\' does not have \'%s\' state.'
                % (exp_id, state_name))

        state_answers = stats_services.get_state_answers(
            exp_id, exp_version, state_name)
        extracted_answers = state_answers.get_submitted_answer_dict_list()

        if num_answers > 0:
            extracted_answers = extracted_answers[:num_answers]

        response = {
            'data': extracted_answers
        }
        self.render_json(response)
Пример #5
0
    def get(self):
        exp_id = self.request.get('exp_id')
        exp_version = int(self.request.get('exp_version'))
        state_name = self.request.get('state_name')
        num_answers = int(self.request.get('num_answers'))

        exploration = exp_services.get_exploration_by_id(
            exp_id, strict=False, version=exp_version)

        if exploration is None:
            raise self.InvalidInputException(
                'No exploration with ID \'%s\' exists.' % exp_id)

        if state_name not in exploration.states:
            raise self.InvalidInputException(
                'Exploration \'%s\' does not have \'%s\' state.'
                % (exp_id, state_name))

        state_answers = stats_services.get_state_answers(
            exp_id, exp_version, state_name)
        extracted_answers = state_answers.get_submitted_answer_dict_list()

        if num_answers > 0:
            extracted_answers = extracted_answers[:num_answers]

        response = {
            'data': extracted_answers
        }
        self.render_json(response)
Пример #6
0
    def test_answer_submission(self):
        all_models = (stats_models.AnswerSubmittedEventLogEntryModel.get_all())
        self.assertEqual(all_models.count(), 0)

        exp_id = 'eid1'
        session_id = 'sid1'
        category = exp_domain.DEFAULT_OUTCOME_CLASSIFICATION
        self.save_new_valid_exploration(exp_id, self.OWNER_EMAIL)
        exploration = exp_fetchers.get_exploration_by_id(exp_id)

        event_services.AnswerSubmissionEventHandler.record(
            exp_id,
            exploration.version,
            state_name=feconf.DEFAULT_INIT_STATE_NAME,
            interaction_id='TextInput',
            answer_group_index=1,
            rule_spec_index=1,
            classification_categorization=category,
            session_id=session_id,
            time_spent_in_secs=2,
            params={},
            normalized_answer='answer_submitted')

        state_answers = stats_services.get_state_answers(
            exp_id, exploration.version, exploration.init_state_name)

        self.assertEqual(state_answers.get_submitted_answer_dict_list(),
                         [{
                             'answer': 'answer_submitted',
                             'time_spent_in_sec': 2.0,
                             'answer_group_index': 1,
                             'rule_spec_index': 1,
                             'classification_categorization': category,
                             'session_id': session_id,
                             'interaction_id': 'TextInput',
                             'params': {},
                             'rule_spec_str': None,
                             'answer_str': None,
                         }])

        all_models = (stats_models.AnswerSubmittedEventLogEntryModel.get_all())
        self.assertEqual(all_models.count(), 1)

        model = all_models.get()

        self.assertEqual(model.exp_id, exp_id)
        self.assertEqual(model.exp_version, exploration.version)
Пример #7
0
    def test_record_answer_without_retrieving_it_first(self):
        stats_services.record_answer(
            self.EXP_ID, self.exploration.version,
            self.exploration.init_state_name, 'TextInput',
            stats_domain.SubmittedAnswer('first answer', 'TextInput', 0, 0,
                                         exp_domain.EXPLICIT_CLASSIFICATION,
                                         {}, 'a_session_id_val', 1.0))

        state_answers = stats_services.get_state_answers(
            self.EXP_ID, self.exploration.version,
            self.exploration.init_state_name)
        self.assertEqual(state_answers.get_submitted_answer_dict_list(),
                         [{
                             'answer': 'first answer',
                             'time_spent_in_sec': 1.0,
                             'answer_group_index': 0,
                             'rule_spec_index': 0,
                             'classification_categorization': 'explicit',
                             'session_id': 'a_session_id_val',
                             'interaction_id': 'TextInput',
                             'params': {}
                         }])
Пример #8
0
    def test_record_answer_without_retrieving_it_first(self):
        stats_services.record_answer(
            self.EXP_ID, self.exploration.version,
            self.exploration.init_state_name, 'TextInput',
            stats_domain.SubmittedAnswer(
                'first answer', 'TextInput', 0,
                0, exp_domain.EXPLICIT_CLASSIFICATION, {},
                'a_session_id_val', 1.0))

        state_answers = stats_services.get_state_answers(
            self.EXP_ID, self.exploration.version,
            self.exploration.init_state_name)
        self.assertEqual(state_answers.get_submitted_answer_dict_list(), [{
            'answer': 'first answer',
            'time_spent_in_sec': 1.0,
            'answer_group_index': 0,
            'rule_spec_index': 0,
            'classification_categorization': 'explicit',
            'session_id': 'a_session_id_val',
            'interaction_id': 'TextInput',
            'params': {}
        }])
Пример #9
0
    def test_only_sample_answers_in_main_shard_returned(self):
        # Use a smaller max answer list size so fewer answers are needed to
        # exceed a shard.
        with self.swap(stats_models.StateAnswersModel,
                       '_MAX_ANSWER_LIST_BYTE_SIZE', 15000):
            state_answers = stats_services.get_state_answers(
                self.EXP_ID, self.exploration.version,
                self.exploration.init_state_name)
            self.assertIsNone(state_answers)

            submitted_answer_list = [
                stats_domain.SubmittedAnswer(
                    'answer ccc', 'TextInput', 1, 1,
                    exp_domain.EXPLICIT_CLASSIFICATION, {}, 'session_id_v',
                    3.0),
            ]
            stats_services.record_answers(self.EXP_ID,
                                          self.exploration.version,
                                          self.exploration.init_state_name,
                                          'TextInput',
                                          submitted_answer_list * 100)

        # Verify more than 1 shard was stored. The index shard (shard_id 0)
        # is not included in the shard count. Since a total of 100 answers were
        # submitted, there must therefore be fewer than 100 answers in the
        # index shard.
        model = stats_models.StateAnswersModel.get(
            '%s:%s:%s:%s' %
            (self.exploration.id, str(self.exploration.version),
             self.exploration.init_state_name, '0'))
        self.assertEqual(model.shard_count, 1)

        # Verify that the list of sample answers returned contains fewer than
        # 100 answers, although a total of 100 answers were submitted.
        sample_answers = stats_services.get_sample_answers(
            self.EXP_ID, self.exploration.version,
            self.exploration.init_state_name)
        self.assertLess(len(sample_answers), 100)
Пример #10
0
    def test_record_answer(self):
        self.save_new_default_exploration('eid', '*****@*****.**')
        exp = exp_services.get_exploration_by_id('eid')

        first_state_name = exp.init_state_name
        second_state_name = 'State 2'
        third_state_name = 'State 3'
        exp_services.update_exploration(
            '*****@*****.**', 'eid', [{
                'cmd': exp_domain.CMD_EDIT_STATE_PROPERTY,
                'state_name': first_state_name,
                'property_name': exp_domain.STATE_PROPERTY_INTERACTION_ID,
                'new_value': 'TextInput',
            }, {
                'cmd': exp_domain.CMD_ADD_STATE,
                'state_name': second_state_name,
            }, {
                'cmd': exp_domain.CMD_ADD_STATE,
                'state_name': third_state_name,
            }, {
                'cmd': exp_domain.CMD_EDIT_STATE_PROPERTY,
                'state_name': second_state_name,
                'property_name': exp_domain.STATE_PROPERTY_INTERACTION_ID,
                'new_value': 'TextInput',
            }, {
                'cmd': exp_domain.CMD_EDIT_STATE_PROPERTY,
                'state_name': third_state_name,
                'property_name': exp_domain.STATE_PROPERTY_INTERACTION_ID,
                'new_value': 'Continue',
            }], 'Add new state')
        exp = exp_services.get_exploration_by_id('eid')

        exp_version = exp.version

        for state_name in [first_state_name, second_state_name]:
            state_answers = stats_services.get_state_answers(
                'eid', exp_version, state_name)
            self.assertEqual(state_answers, None)

        # answer is a string
        event_services.AnswerSubmissionEventHandler.record(
            'eid', exp_version, first_state_name, 'TextInput', 0, 0,
            exp_domain.EXPLICIT_CLASSIFICATION, 'sid1', self.TIME_SPENT,
            self.PARAMS, 'answer1')
        event_services.AnswerSubmissionEventHandler.record(
            'eid', exp_version, first_state_name, 'TextInput', 0, 1,
            exp_domain.EXPLICIT_CLASSIFICATION, 'sid2', self.TIME_SPENT,
            self.PARAMS, 'answer1')
        # answer is a dict
        event_services.AnswerSubmissionEventHandler.record(
            'eid', exp_version, first_state_name, 'TextInput', 1, 0,
            exp_domain.EXPLICIT_CLASSIFICATION, 'sid1', self.TIME_SPENT,
            self.PARAMS, {
                'x': 1.0,
                'y': 5.0
            })
        # answer is a number
        event_services.AnswerSubmissionEventHandler.record(
            'eid', exp_version, first_state_name, 'TextInput', 2, 0,
            exp_domain.EXPLICIT_CLASSIFICATION, 'sid1', self.TIME_SPENT,
            self.PARAMS, 10)
        # answer is a list of dicts
        event_services.AnswerSubmissionEventHandler.record(
            'eid', exp_version, first_state_name, 'TextInput', 3, 0,
            exp_domain.EXPLICIT_CLASSIFICATION, 'sid1', self.TIME_SPENT,
            self.PARAMS, [{
                'a': 'some',
                'b': 'text'
            }, {
                'a': 1.0,
                'c': 2.0
            }])
        # answer is a list
        event_services.AnswerSubmissionEventHandler.record(
            'eid', exp_version, second_state_name, 'TextInput', 2, 0,
            exp_domain.EXPLICIT_CLASSIFICATION, 'sid3', self.TIME_SPENT,
            self.PARAMS, [2, 4, 8])
        # answer is a unicode string
        event_services.AnswerSubmissionEventHandler.record(
            'eid', exp_version, second_state_name, 'TextInput', 1, 1,
            exp_domain.EXPLICIT_CLASSIFICATION, 'sid4', self.TIME_SPENT,
            self.PARAMS, self.UNICODE_TEST_STRING)
        # answer is None (such as for Continue)
        event_services.AnswerSubmissionEventHandler.record(
            'eid', exp_version, third_state_name, 'Continue', 1, 1,
            exp_domain.EXPLICIT_CLASSIFICATION, 'sid5', self.TIME_SPENT,
            self.PARAMS, None)

        expected_submitted_answer_list1 = [{
            'answer': 'answer1',
            'time_spent_in_sec': 5.0,
            'answer_group_index': 0,
            'rule_spec_index': 0,
            'classification_categorization': 'explicit',
            'session_id': 'sid1',
            'interaction_id': 'TextInput',
            'params': {}
        }, {
            'answer': 'answer1',
            'time_spent_in_sec': 5.0,
            'answer_group_index': 0,
            'rule_spec_index': 1,
            'classification_categorization': 'explicit',
            'session_id': 'sid2',
            'interaction_id': 'TextInput',
            'params': {}
        }, {
            'answer': {
                'x': 1.0,
                'y': 5.0
            },
            'time_spent_in_sec': 5.0,
            'answer_group_index': 1,
            'rule_spec_index': 0,
            'classification_categorization': 'explicit',
            'session_id': 'sid1',
            'interaction_id': 'TextInput',
            'params': {}
        }, {
            'answer': 10,
            'time_spent_in_sec': 5.0,
            'answer_group_index': 2,
            'rule_spec_index': 0,
            'classification_categorization': 'explicit',
            'session_id': 'sid1',
            'interaction_id': 'TextInput',
            'params': {}
        }, {
            'answer': [{
                'a': 'some',
                'b': 'text'
            }, {
                'a': 1.0,
                'c': 2.0
            }],
            'time_spent_in_sec':
            5.0,
            'answer_group_index':
            3,
            'rule_spec_index':
            0,
            'classification_categorization':
            'explicit',
            'session_id':
            'sid1',
            'interaction_id':
            'TextInput',
            'params': {}
        }]
        expected_submitted_answer_list2 = [{
            'answer': [2, 4, 8],
            'time_spent_in_sec': 5.0,
            'answer_group_index': 2,
            'rule_spec_index': 0,
            'classification_categorization': 'explicit',
            'session_id': 'sid3',
            'interaction_id': 'TextInput',
            'params': {}
        }, {
            'answer': self.UNICODE_TEST_STRING,
            'time_spent_in_sec': 5.0,
            'answer_group_index': 1,
            'rule_spec_index': 1,
            'classification_categorization': 'explicit',
            'session_id': 'sid4',
            'interaction_id': 'TextInput',
            'params': {}
        }]
        expected_submitted_answer_list3 = [{
            'answer': None,
            'time_spent_in_sec': 5.0,
            'answer_group_index': 1,
            'rule_spec_index': 1,
            'classification_categorization': 'explicit',
            'session_id': 'sid5',
            'interaction_id': 'Continue',
            'params': {}
        }]

        state_answers = stats_services.get_state_answers(
            'eid', exp_version, first_state_name)
        self.assertEqual(state_answers.get_submitted_answer_dict_list(),
                         expected_submitted_answer_list1)

        state_answers = stats_services.get_state_answers(
            'eid', exp_version, second_state_name)
        self.assertEqual(state_answers.get_submitted_answer_dict_list(),
                         expected_submitted_answer_list2)

        state_answers = stats_services.get_state_answers(
            'eid', exp_version, third_state_name)
        self.assertEqual(state_answers.get_submitted_answer_dict_list(),
                         expected_submitted_answer_list3)
Пример #11
0
    def test_record_many_answers_with_preexisting_entry(self):
        stats_services.record_answer(
            self.EXP_ID, self.exploration.version,
            self.exploration.init_state_name, 'TextInput',
            stats_domain.SubmittedAnswer('1 answer', 'TextInput', 0, 0,
                                         exp_domain.EXPLICIT_CLASSIFICATION,
                                         {}, 'a_session_id_val', 1.0))

        state_answers = stats_services.get_state_answers(
            self.EXP_ID, self.exploration.version,
            self.exploration.init_state_name)
        self.assertEqual(state_answers.get_submitted_answer_dict_list(),
                         [{
                             'answer': '1 answer',
                             'time_spent_in_sec': 1.0,
                             'answer_group_index': 0,
                             'rule_spec_index': 0,
                             'classification_categorization': 'explicit',
                             'session_id': 'a_session_id_val',
                             'interaction_id': 'TextInput',
                             'params': {}
                         }])

        submitted_answer_list = [
            stats_domain.SubmittedAnswer('answer aaa', 'TextInput', 0, 1,
                                         exp_domain.EXPLICIT_CLASSIFICATION,
                                         {}, 'session_id_v', 10.0),
            stats_domain.SubmittedAnswer('answer ccccc', 'TextInput', 1, 1,
                                         exp_domain.EXPLICIT_CLASSIFICATION,
                                         {}, 'session_id_v', 3.0),
            stats_domain.SubmittedAnswer('answer bbbbbbb', 'TextInput', 1, 0,
                                         exp_domain.EXPLICIT_CLASSIFICATION,
                                         {}, 'session_id_v', 7.5),
        ]
        stats_services.record_answers(self.EXP_ID, self.exploration.version,
                                      self.exploration.init_state_name,
                                      'TextInput', submitted_answer_list)

        # The order of the answers returned depends on the size of the answers.
        state_answers = stats_services.get_state_answers(
            self.EXP_ID, self.exploration.version,
            self.exploration.init_state_name)
        self.assertEqual(state_answers.exploration_id, 'exp_id0')
        self.assertEqual(state_answers.exploration_version, 1)
        self.assertEqual(state_answers.state_name,
                         feconf.DEFAULT_INIT_STATE_NAME)
        self.assertEqual(state_answers.interaction_id, 'TextInput')
        self.assertEqual(state_answers.get_submitted_answer_dict_list(),
                         [{
                             'answer': '1 answer',
                             'time_spent_in_sec': 1.0,
                             'answer_group_index': 0,
                             'rule_spec_index': 0,
                             'classification_categorization': 'explicit',
                             'session_id': 'a_session_id_val',
                             'interaction_id': 'TextInput',
                             'params': {}
                         }, {
                             'answer': 'answer aaa',
                             'time_spent_in_sec': 10.0,
                             'answer_group_index': 0,
                             'rule_spec_index': 1,
                             'classification_categorization': 'explicit',
                             'session_id': 'session_id_v',
                             'interaction_id': 'TextInput',
                             'params': {}
                         }, {
                             'answer': 'answer ccccc',
                             'time_spent_in_sec': 3.0,
                             'answer_group_index': 1,
                             'rule_spec_index': 1,
                             'classification_categorization': 'explicit',
                             'session_id': 'session_id_v',
                             'interaction_id': 'TextInput',
                             'params': {}
                         }, {
                             'answer': 'answer bbbbbbb',
                             'time_spent_in_sec': 7.5,
                             'answer_group_index': 1,
                             'rule_spec_index': 0,
                             'classification_categorization': 'explicit',
                             'session_id': 'session_id_v',
                             'interaction_id': 'TextInput',
                             'params': {}
                         }])
Пример #12
0
    def test_record_answer(self):
        self.save_new_default_exploration('eid', '*****@*****.**')
        exp = exp_services.get_exploration_by_id('eid')

        first_state_name = exp.init_state_name
        second_state_name = 'State 2'
        third_state_name = 'State 3'
        exp_services.update_exploration('*****@*****.**', 'eid', [{
            'cmd': exp_domain.CMD_EDIT_STATE_PROPERTY,
            'state_name': first_state_name,
            'property_name': exp_domain.STATE_PROPERTY_INTERACTION_ID,
            'new_value': 'TextInput',
        }, {
            'cmd': exp_domain.CMD_ADD_STATE,
            'state_name': second_state_name,
        }, {
            'cmd': exp_domain.CMD_ADD_STATE,
            'state_name': third_state_name,
        }, {
            'cmd': exp_domain.CMD_EDIT_STATE_PROPERTY,
            'state_name': second_state_name,
            'property_name': exp_domain.STATE_PROPERTY_INTERACTION_ID,
            'new_value': 'TextInput',
        }, {
            'cmd': exp_domain.CMD_EDIT_STATE_PROPERTY,
            'state_name': third_state_name,
            'property_name': exp_domain.STATE_PROPERTY_INTERACTION_ID,
            'new_value': 'Continue',
        }], 'Add new state')
        exp = exp_services.get_exploration_by_id('eid')

        exp_version = exp.version

        for state_name in [first_state_name, second_state_name]:
            state_answers = stats_services.get_state_answers(
                'eid', exp_version, state_name)
            self.assertEqual(state_answers, None)

        # answer is a string
        event_services.AnswerSubmissionEventHandler.record(
            'eid', exp_version, first_state_name, 'TextInput', 0, 0,
            exp_domain.EXPLICIT_CLASSIFICATION, 'sid1', self.TIME_SPENT,
            self.PARAMS, 'answer1')
        event_services.AnswerSubmissionEventHandler.record(
            'eid', exp_version, first_state_name, 'TextInput', 0, 1,
            exp_domain.EXPLICIT_CLASSIFICATION, 'sid2', self.TIME_SPENT,
            self.PARAMS, 'answer1')
        # answer is a dict
        event_services.AnswerSubmissionEventHandler.record(
            'eid', exp_version, first_state_name, 'TextInput', 1, 0,
            exp_domain.EXPLICIT_CLASSIFICATION, 'sid1', self.TIME_SPENT,
            self.PARAMS, {'x': 1.0, 'y': 5.0})
        # answer is a number
        event_services.AnswerSubmissionEventHandler.record(
            'eid', exp_version, first_state_name, 'TextInput', 2, 0,
            exp_domain.EXPLICIT_CLASSIFICATION, 'sid1', self.TIME_SPENT,
            self.PARAMS, 10)
        # answer is a list of dicts
        event_services.AnswerSubmissionEventHandler.record(
            'eid', exp_version, first_state_name, 'TextInput', 3, 0,
            exp_domain.EXPLICIT_CLASSIFICATION, 'sid1', self.TIME_SPENT,
            self.PARAMS, [{'a': 'some', 'b': 'text'}, {'a': 1.0, 'c': 2.0}])
        # answer is a list
        event_services.AnswerSubmissionEventHandler.record(
            'eid', exp_version, second_state_name, 'TextInput', 2, 0,
            exp_domain.EXPLICIT_CLASSIFICATION, 'sid3', self.TIME_SPENT,
            self.PARAMS, [2, 4, 8])
        # answer is a unicode string
        event_services.AnswerSubmissionEventHandler.record(
            'eid', exp_version, second_state_name, 'TextInput', 1, 1,
            exp_domain.EXPLICIT_CLASSIFICATION, 'sid4', self.TIME_SPENT,
            self.PARAMS, self.UNICODE_TEST_STRING)
        # answer is None (such as for Continue)
        event_services.AnswerSubmissionEventHandler.record(
            'eid', exp_version, third_state_name, 'Continue', 1, 1,
            exp_domain.EXPLICIT_CLASSIFICATION, 'sid5', self.TIME_SPENT,
            self.PARAMS, None)

        expected_submitted_answer_list1 = [{
            'answer': 'answer1', 'time_spent_in_sec': 5.0,
            'answer_group_index': 0, 'rule_spec_index': 0,
            'classification_categorization': 'explicit', 'session_id': 'sid1',
            'interaction_id': 'TextInput', 'params': {}
        }, {
            'answer': 'answer1', 'time_spent_in_sec': 5.0,
            'answer_group_index': 0, 'rule_spec_index': 1,
            'classification_categorization': 'explicit', 'session_id': 'sid2',
            'interaction_id': 'TextInput', 'params': {}
        }, {
            'answer': {'x': 1.0, 'y': 5.0}, 'time_spent_in_sec': 5.0,
            'answer_group_index': 1, 'rule_spec_index': 0,
            'classification_categorization': 'explicit', 'session_id': 'sid1',
            'interaction_id': 'TextInput', 'params': {}
        }, {
            'answer': 10, 'time_spent_in_sec': 5.0, 'answer_group_index': 2,
            'rule_spec_index': 0, 'classification_categorization': 'explicit',
            'session_id': 'sid1', 'interaction_id': 'TextInput', 'params': {}
        }, {
            'answer': [{'a': 'some', 'b': 'text'}, {'a': 1.0, 'c': 2.0}],
            'time_spent_in_sec': 5.0, 'answer_group_index': 3,
            'rule_spec_index': 0, 'classification_categorization': 'explicit',
            'session_id': 'sid1', 'interaction_id': 'TextInput', 'params': {}
        }]
        expected_submitted_answer_list2 = [{
            'answer': [2, 4, 8], 'time_spent_in_sec': 5.0,
            'answer_group_index': 2, 'rule_spec_index': 0,
            'classification_categorization': 'explicit', 'session_id': 'sid3',
            'interaction_id': 'TextInput', 'params': {}
        }, {
            'answer': self.UNICODE_TEST_STRING, 'time_spent_in_sec': 5.0,
            'answer_group_index': 1, 'rule_spec_index': 1,
            'classification_categorization': 'explicit', 'session_id': 'sid4',
            'interaction_id': 'TextInput', 'params': {}
        }]
        expected_submitted_answer_list3 = [{
            'answer': None, 'time_spent_in_sec': 5.0, 'answer_group_index': 1,
            'rule_spec_index': 1, 'classification_categorization': 'explicit',
            'session_id': 'sid5', 'interaction_id': 'Continue', 'params': {}
        }]

        state_answers = stats_services.get_state_answers(
            'eid', exp_version, first_state_name)
        self.assertEqual(
            state_answers.get_submitted_answer_dict_list(),
            expected_submitted_answer_list1)

        state_answers = stats_services.get_state_answers(
            'eid', exp_version, second_state_name)
        self.assertEqual(
            state_answers.get_submitted_answer_dict_list(),
            expected_submitted_answer_list2)

        state_answers = stats_services.get_state_answers(
            'eid', exp_version, third_state_name)
        self.assertEqual(
            state_answers.get_submitted_answer_dict_list(),
            expected_submitted_answer_list3)