Esempio n. 1
0
def getFieldsForGradingRecord(project, survey_group, record_entity=None):
    """Returns the fields for a GradingRecord.

  See GradingRecord model for description of the grade_decision value.

  Args:
    project: Project entity
    survey_group: a GradingSurveyGroup entity
    record_entity: an optional GradingRecord entity

  Returns:
    Dict containing the fields that should be set on a GradingRecord for this
    GradingSurveyGroup and StudentProject
  """

    # retrieve the two Surveys, student_survey might be None
    grading_survey = survey_group.grading_survey
    student_survey = survey_group.student_survey

    # retrieve a GradingSurveyRecord
    q = GSoCGradingProjectSurveyRecord.all()
    q.filter('project', project)
    q.filter('survey', grading_survey)
    grading_survey_record = q.get()

    if student_survey:
        # retrieve ProjectSurveyRecord
        q = GSoCProjectSurveyRecord.all()
        q.filter('project', project)
        q.filter('survey', student_survey)
        project_survey_record = q.get()
    else:
        project_survey_record = None

    # set the required fields
    fields = {
        'grading_survey_group': survey_group,
        'mentor_record': grading_survey_record,
        'student_record': project_survey_record
    }

    if not record_entity or not record_entity.locked:
        # find grading decision for new or unlocked records

        if not grading_survey_record:
            # no record found, return undecided
            grade_decision = 'undecided'
        elif not student_survey or project_survey_record:
            # if the grade is True then pass else fail
            grade_decision = 'pass' if grading_survey_record.grade else 'fail'
        else:
            # no ProjectSurveyRecord on file while there is a survey to be taken
            grade_decision = 'fail'

        fields['grade_decision'] = grade_decision

    # return the fields that should be set for a GradingRecord
    return fields
  def createSurveys(self):
    """Creates the surveys and records required for the tests.
    """
    survey_values = {
        'author': self.founder,
        'title': 'Title',
        'modified_by': self.founder,
        'link_id': 'link_id',
        'scope': self.gsoc,
        'scope_path': self.gsoc.key().id_or_name()}

    self.project_survey = ProjectSurvey(key_name='key_name',
                                        **survey_values)
    self.project_survey.put()

    self.grading_survey = GradingProjectSurvey(key_name='key_name',
                                               **survey_values)
    self.grading_survey.put()

    record_values = {
        'user': self.student.user,
        'org': self.org,
        'project': self.project,
        'survey': self.project_survey}
    self.project_survey_record = GSoCProjectSurveyRecord(**record_values)
    self.project_survey_record.put()

    self.grading_survey = GradingProjectSurvey(**survey_values)
    self.grading_survey.put()

    record_values = {
        'user': self.student.user,
        'org': self.org,
        'project': self.project,
        'survey': self.grading_survey,
        'grade': True}
    self.grading_survey_record = GSoCGradingProjectSurveyRecord(
        **record_values)
    self.grading_survey_record.put()

    group_values = {
        'name': 'Survey Group Name',
        'grading_survey': self.grading_survey,
        'student_survey': self.project_survey,
        'program': self.gsoc}
    self.survey_group = GSoCGradingSurveyGroup(**group_values)
    self.survey_group.put()

    record_values = {
        'grading_survey_group': self.survey_group,
        'mentor_record': self.grading_survey_record,
        'student_record': self.project_survey_record,
        'grade_decision': 'pass'}
    self.grading_record = GSoCGradingRecord(parent=self.project,
                                            **record_values)
    self.grading_record.put()
Esempio n. 3
0
def getFieldsForGradingRecord(project, survey_group, record_entity=None):
  """Returns the fields for a GradingRecord.

  See GradingRecord model for description of the grade_decision value.

  Args:
    project: Project entity
    survey_group: a GradingSurveyGroup entity
    record_entity: an optional GradingRecord entity

  Returns:
    Dict containing the fields that should be set on a GradingRecord for this
    GradingSurveyGroup and StudentProject
  """

  # retrieve the two Surveys, student_survey might be None
  grading_survey = survey_group.grading_survey
  student_survey = survey_group.student_survey

  # retrieve a GradingSurveyRecord
  q = GSoCGradingProjectSurveyRecord.all()
  q.filter('project', project)
  q.filter('survey', grading_survey)
  grading_survey_record = q.get()

  if student_survey:
    # retrieve ProjectSurveyRecord
    q = GSoCProjectSurveyRecord.all()
    q.filter('project', project)
    q.filter('survey', student_survey)
    project_survey_record = q.get()
  else:
    project_survey_record = None

  # set the required fields
  fields = {'grading_survey_group': survey_group,
            'mentor_record': grading_survey_record,
            'student_record': project_survey_record}

  if not record_entity or not record_entity.locked:
    # find grading decision for new or unlocked records

    if not grading_survey_record:
      # no record found, return undecided
      grade_decision = 'undecided'
    elif not student_survey or project_survey_record:
      # if the grade is True then pass else fail
      grade_decision = 'pass' if grading_survey_record.grade else 'fail'
    else:
      # no ProjectSurveyRecord on file while there is a survey to be taken
      grade_decision = 'fail'

    fields['grade_decision'] = grade_decision

  # return the fields that should be set for a GradingRecord
  return fields
Esempio n. 4
0
  def studentEvaluationRecordFromKwargs(self):
    """Sets the student evaluation record in RequestData object.
    """
    assert access_checker.isSet(self.data.student_evaluation)
    assert access_checker.isSet(self.data.project)

    self.data.organization = self.data.project.org

    q = GSoCProjectSurveyRecord.all()
    q.filter('project', self.data.project)
    q.filter('survey', self.data.student_evaluation)
    self.data.student_evaluation_record = q.get()
Esempio n. 5
0
  def studentEvaluationRecordFromKwargs(self):
    """Sets the student evaluation record in RequestData object.
    """
    assert access_checker.isSet(self.data.student_evaluation)

    # TODO(daniel): get rid of this ugly mutation!
    org_key = project_model.GSoCProject.org.get_value_for_datastore(
        self.data.url_project)
    self.data.organization = ndb.Key.from_old_key(org_key).get()

    q = GSoCProjectSurveyRecord.all()
    q.filter('project', self.data.url_project)
    q.filter('survey', self.data.student_evaluation)
    self.data.student_evaluation_record = q.get()
Esempio n. 6
0
    def studentEvaluationRecordFromKwargs(self):
        """Sets the student evaluation record in RequestData object.
    """
        assert access_checker.isSet(self.data.student_evaluation)

        # TODO(daniel): get rid of this ugly mutation!
        org_key = project_model.GSoCProject.org.get_value_for_datastore(
            self.data.url_project)
        self.data.organization = ndb.Key.from_old_key(org_key).get()

        q = GSoCProjectSurveyRecord.all()
        q.filter('project', self.data.url_project)
        q.filter('survey', self.data.student_evaluation)
        self.data.student_evaluation_record = q.get()
Esempio n. 7
0
def convertGSoCProfileDBEntityGroup(profile_key):
  """Converts DB based part of entity group associated with the specified
  profile.

  Args:
    profile_key: db.Key of the profile to process
  """
  # map that associate old keys with new ones which are created during
  # the conversion
  conversion_map = {}
  to_delete = []
  do_put = True

  proposals = GSoCProposal.all().ancestor(profile_key).fetch(1000)
  for proposal in proposals:
    # update GSoCProposal.parent
    new_proposal = _convertParent(proposal)

    # update GSoCProposal.possible_mentors
    new_proposal.possible_mentors = _convertListProperty(
        GSoCProposal.possible_mentors, new_proposal)

    # update GSoCProposal.mentor
    new_proposal.mentor = _convertReferenceProperty(
        GSoCProposal.mentor, new_proposal)
    to_delete.append(proposal)
    if do_put:
      new_proposal.put()
      conversion_map[proposal.key()] = new_proposal.key()

    comments = GSoCComment.all().ancestor(proposal).fetch(1000)
    for comment in comments:
      # update GSoCComment.parent
      new_comment = _convertParent(comment, parent=new_proposal.key())

      # update GSoCComment.author
      new_comment.author = _convertReferenceProperty(
          GSoCComment.author, new_comment)
      if do_put:
        new_comment.put()
      to_delete.append(comment)

    scores = GSoCScore.all().ancestor(proposal).fetch(1000)
    for score in scores:
      # update GSoCScore.parent
      new_score = _convertParent(score, parent=new_proposal.key())

      # update GSoCScore.author
      new_score.author = _convertReferenceProperty(GSoCScore.author, new_score)
      if do_put:
        new_score.put()
      to_delete.append(score)

  projects = GSoCProject.all().ancestor(profile_key).fetch(1000)
  for project in projects:
    # update GSoCProject.parent
    new_project = _convertParent(project)

    # update GSoCProject.mentors
    new_project.mentors = _convertListProperty(GSoCProject.mentors, new_project)

    # update GSoCProject.proposal
    proposal_key = GSoCProject.proposal.get_value_for_datastore(project)
    if proposal_key:
      new_project.proposal = conversion_map.get(
          GSoCProject.proposal.get_value_for_datastore(project))

    if do_put:
      new_project.put()
      conversion_map[project.key()] = new_project.key()
    to_delete.append(project)

    grading_records = GSoCGradingRecord.all().ancestor(project.key())
    for grading_record in grading_records:
      # update GSoCGradingProjectSurveyRecord.project
      # this is another entity group, but XG transaction does the thing
      grading_project_survey_record_key = (
          GSoCGradingRecord.mentor_record.get_value_for_datastore(
              grading_record))
      if grading_project_survey_record_key:
        grading_project_survey_record = GSoCGradingProjectSurveyRecord.get(
            grading_project_survey_record_key)
        if grading_project_survey_record:
          grading_project_survey_record.project = new_project.key()
          if do_put:
            grading_project_survey_record.put()

      # update GSoCProjectSurveyRecord.project
      # this is another entity group, but XG transaction does the thing
      project_survey_record_key = (
          GSoCGradingRecord.student_record.get_value_for_datastore(
              grading_record))
      if project_survey_record_key:
        project_survey_record = GSoCProjectSurveyRecord.get(
            project_survey_record_key)
        if project_survey_record:
          project_survey_record.project = new_project.key()
          if do_put:
            project_survey_record.put()

      # update GSoCGradingRecord.parent
      new_grading_record = _convertParent(
          grading_record, parent=new_project.key())
      if do_put:
        new_grading_record.put()

    code_samples = GSoCCodeSample.all().ancestor(project.key())
    for code_sample in code_samples:
      # update GSoCCodeSample.parent
      new_code_sample = _convertParent(code_sample, parent=new_project.key())
      if do_put:
        new_code_sample.put()
      to_delete.append(code_sample)

  db.delete(to_delete)
Esempio n. 8
0
def convertGSoCProfileDBEntityGroup(profile_key):
    """Converts DB based part of entity group associated with the specified
  profile.

  Args:
    profile_key: db.Key of the profile to process
  """
    # map that associate old keys with new ones which are created during
    # the conversion
    conversion_map = {}
    to_delete = []
    do_put = True

    proposals = GSoCProposal.all().ancestor(profile_key).fetch(1000)
    for proposal in proposals:
        # update GSoCProposal.parent
        new_proposal = _convertParent(proposal)

        # update GSoCProposal.possible_mentors
        new_proposal.possible_mentors = _convertListProperty(
            GSoCProposal.possible_mentors, new_proposal)

        # update GSoCProposal.mentor
        new_proposal.mentor = _convertReferenceProperty(
            GSoCProposal.mentor, new_proposal)
        to_delete.append(proposal)
        if do_put:
            new_proposal.put()
            conversion_map[proposal.key()] = new_proposal.key()

        comments = GSoCComment.all().ancestor(proposal).fetch(1000)
        for comment in comments:
            # update GSoCComment.parent
            new_comment = _convertParent(comment, parent=new_proposal.key())

            # update GSoCComment.author
            new_comment.author = _convertReferenceProperty(
                GSoCComment.author, new_comment)
            if do_put:
                new_comment.put()
            to_delete.append(comment)

        scores = GSoCScore.all().ancestor(proposal).fetch(1000)
        for score in scores:
            # update GSoCScore.parent
            new_score = _convertParent(score, parent=new_proposal.key())

            # update GSoCScore.author
            new_score.author = _convertReferenceProperty(
                GSoCScore.author, new_score)
            if do_put:
                new_score.put()
            to_delete.append(score)

    projects = GSoCProject.all().ancestor(profile_key).fetch(1000)
    for project in projects:
        # update GSoCProject.parent
        new_project = _convertParent(project)

        # update GSoCProject.mentors
        new_project.mentors = _convertListProperty(GSoCProject.mentors,
                                                   new_project)

        # update GSoCProject.proposal
        proposal_key = GSoCProject.proposal.get_value_for_datastore(project)
        if proposal_key:
            new_project.proposal = conversion_map.get(
                GSoCProject.proposal.get_value_for_datastore(project))

        if do_put:
            new_project.put()
            conversion_map[project.key()] = new_project.key()
        to_delete.append(project)

        grading_records = GSoCGradingRecord.all().ancestor(project.key())
        for grading_record in grading_records:
            # update GSoCGradingProjectSurveyRecord.project
            # this is another entity group, but XG transaction does the thing
            grading_project_survey_record_key = (
                GSoCGradingRecord.mentor_record.get_value_for_datastore(
                    grading_record))
            if grading_project_survey_record_key:
                grading_project_survey_record = GSoCGradingProjectSurveyRecord.get(
                    grading_project_survey_record_key)
                if grading_project_survey_record:
                    grading_project_survey_record.project = new_project.key()
                    if do_put:
                        grading_project_survey_record.put()

            # update GSoCProjectSurveyRecord.project
            # this is another entity group, but XG transaction does the thing
            project_survey_record_key = (
                GSoCGradingRecord.student_record.get_value_for_datastore(
                    grading_record))
            if project_survey_record_key:
                project_survey_record = GSoCProjectSurveyRecord.get(
                    project_survey_record_key)
                if project_survey_record:
                    project_survey_record.project = new_project.key()
                    if do_put:
                        project_survey_record.put()

            # update GSoCGradingRecord.parent
            new_grading_record = _convertParent(grading_record,
                                                parent=new_project.key())
            if do_put:
                new_grading_record.put()

        code_samples = GSoCCodeSample.all().ancestor(project.key())
        for code_sample in code_samples:
            # update GSoCCodeSample.parent
            new_code_sample = _convertParent(code_sample,
                                             parent=new_project.key())
            if do_put:
                new_code_sample.put()
            to_delete.append(code_sample)

    db.delete(to_delete)
    def createSurveys(self):
        """Creates the surveys and records required for the tests.
    """
        survey_values = {
            'author': self.founder,
            'title': 'Title',
            'modified_by': self.founder,
            'link_id': 'link_id',
            'scope': self.gsoc,
            'scope_path': self.gsoc.key().id_or_name()
        }

        self.project_survey = ProjectSurvey(key_name='key_name',
                                            **survey_values)
        self.project_survey.put()

        self.grading_survey = GradingProjectSurvey(key_name='key_name',
                                                   **survey_values)
        self.grading_survey.put()

        record_values = {
            'user': self.student.user,
            'org': self.org,
            'project': self.project,
            'survey': self.project_survey
        }
        self.project_survey_record = GSoCProjectSurveyRecord(**record_values)
        self.project_survey_record.put()

        self.grading_survey = GradingProjectSurvey(**survey_values)
        self.grading_survey.put()

        record_values = {
            'user': self.student.user,
            'org': self.org,
            'project': self.project,
            'survey': self.grading_survey,
            'grade': True
        }
        self.grading_survey_record = GSoCGradingProjectSurveyRecord(
            **record_values)
        self.grading_survey_record.put()

        group_values = {
            'name': 'Survey Group Name',
            'grading_survey': self.grading_survey,
            'student_survey': self.project_survey,
            'program': self.gsoc
        }
        self.survey_group = GSoCGradingSurveyGroup(**group_values)
        self.survey_group.put()

        record_values = {
            'grading_survey_group': self.survey_group,
            'mentor_record': self.grading_survey_record,
            'student_record': self.project_survey_record,
            'grade_decision': 'pass'
        }
        self.grading_record = GSoCGradingRecord(parent=self.project,
                                                **record_values)
        self.grading_record.put()
class GradingSurveyGroupTest(MailTestCase, GSoCDjangoTestCase,
                             TaskQueueTestCase):
    """Tests for accept_proposals task.
  """

    UPDATE_RECORDS_URL = '/tasks/gsoc/grading_record/update_records'
    UPDATE_PROJECTS_URL = '/tasks/gsoc/grading_record/update_projects'
    SEND_URL = '/tasks/gsoc/grading_record/mail_result'

    def setUp(self):
        super(GradingSurveyGroupTest, self).setUp()
        self.init()
        self.createMentor()
        self.createStudent()
        self.createSurveys()

    def createMentor(self):
        """Creates a new mentor.
    """
        profile_helper = GSoCProfileHelper(self.gsoc, self.dev_test)
        profile_helper.createOtherUser('*****@*****.**')
        self.mentor = profile_helper.createMentor(self.org)

    def createStudent(self):
        """Creates a Student with a project.
    """
        profile_helper = GSoCProfileHelper(self.gsoc, self.dev_test)
        profile_helper.createOtherUser('*****@*****.**')
        self.student = profile_helper.createStudentWithProject(
            self.org, self.mentor)
        self.project = GSoCProject.all().ancestor(self.student).get()

    def createSurveys(self):
        """Creates the surveys and records required for the tests.
    """
        survey_values = {
            'author': self.founder,
            'title': 'Title',
            'modified_by': self.founder,
            'link_id': 'link_id',
            'scope': self.gsoc,
            'scope_path': self.gsoc.key().id_or_name()
        }

        self.project_survey = ProjectSurvey(key_name='key_name',
                                            **survey_values)
        self.project_survey.put()

        self.grading_survey = GradingProjectSurvey(key_name='key_name',
                                                   **survey_values)
        self.grading_survey.put()

        record_values = {
            'user': self.student.user,
            'org': self.org,
            'project': self.project,
            'survey': self.project_survey
        }
        self.project_survey_record = GSoCProjectSurveyRecord(**record_values)
        self.project_survey_record.put()

        self.grading_survey = GradingProjectSurvey(**survey_values)
        self.grading_survey.put()

        record_values = {
            'user': self.student.user,
            'org': self.org,
            'project': self.project,
            'survey': self.grading_survey,
            'grade': True
        }
        self.grading_survey_record = GSoCGradingProjectSurveyRecord(
            **record_values)
        self.grading_survey_record.put()

        group_values = {
            'name': 'Survey Group Name',
            'grading_survey': self.grading_survey,
            'student_survey': self.project_survey,
            'program': self.gsoc
        }
        self.survey_group = GSoCGradingSurveyGroup(**group_values)
        self.survey_group.put()

        record_values = {
            'grading_survey_group': self.survey_group,
            'mentor_record': self.grading_survey_record,
            'student_record': self.project_survey_record,
            'grade_decision': 'pass'
        }
        self.grading_record = GSoCGradingRecord(parent=self.project,
                                                **record_values)
        self.grading_record.put()

    def testCreateGradingRecord(self):
        """Test creating a GradingRecord.
    """
        self.grading_record.delete()

        post_data = {'group_key': self.survey_group.key().id_or_name()}

        response = self.post(self.UPDATE_RECORDS_URL, post_data)

        self.assertEqual(response.status_code, httplib.OK)
        self.assertTasksInQueue(n=1, url=self.UPDATE_RECORDS_URL)

        record = GSoCGradingRecord.all().get()
        self.assertFalse(record is None)
        self.assertEqual(record.grade_decision, 'pass')

    def testUpdateGradingRecord(self):
        """Test updating a GradingRecord.
    """
        self.grading_record.grade_decision = 'undecided'
        self.grading_record.put()

        post_data = {'group_key': self.survey_group.key().id_or_name()}

        response = self.post(self.UPDATE_RECORDS_URL, post_data)

        self.assertEqual(response.status_code, httplib.OK)
        self.assertTasksInQueue(n=1, url=self.UPDATE_RECORDS_URL)

        record = GSoCGradingRecord.all().get()
        self.assertFalse(record is None)
        self.assertEqual(record.grade_decision, 'pass')

    def testUpdateProject(self):
        """Test updating a Project with a GradingRecord's result.
    """
        post_data = {
            'group_key': self.survey_group.key().id_or_name(),
        }

        response = self.post(self.UPDATE_PROJECTS_URL, post_data)

        self.assertEqual(response.status_code, httplib.OK)
        self.assertTasksInQueue(n=1, url=self.UPDATE_PROJECTS_URL)

        project = GSoCProject.all().get()
        self.assertFalse(project is None)
        self.assertEqual(project.passed_evaluations,
                         [self.grading_record.key()])
        self.assertEqual(1, project.parent().student_info.passed_evaluations)

    def testUpdateProjectWithSendMail(self):
        """Test updating a Project with a GradingRecord's result and sending mail.
    """
        post_data = {
            'group_key': self.survey_group.key().id_or_name(),
            'send_mail': True,
        }

        response = self.post(self.UPDATE_PROJECTS_URL, post_data)

        self.assertEqual(response.status_code, httplib.OK)
        self.assertTasksInQueue(n=1, url=self.UPDATE_PROJECTS_URL)
        self.assertTasksInQueue(n=1, url=self.SEND_URL)

        project = GSoCProject.all().get()
        self.assertFalse(project is None)
        self.assertEqual(project.passed_evaluations,
                         [self.grading_record.key()])
        self.assertEqual(1, project.parent().student_info.passed_evaluations)

    def testSendMail(self):
        """Test sending mail about a GradingRecord's result.
    """
        post_data = {'record_key': str(self.grading_record.key())}

        response = self.post(self.SEND_URL, post_data)

        self.assertEqual(response.status_code, httplib.OK)
        # URL explicitly added since the email task is in there
        self.assertTasksInQueue(n=0, url=self.SEND_URL)
        self.assertEmailSent(to=self.student.email)
Esempio n. 11
0
class GradingSurveyGroupTest(MailTestCase, GSoCDjangoTestCase, TaskQueueTestCase):
  """Tests for accept_proposals task.
  """

  UPDATE_RECORDS_URL = '/tasks/gsoc/grading_record/update_records'
  UPDATE_PROJECTS_URL = '/tasks/gsoc/grading_record/update_projects'
  SEND_URL = '/tasks/gsoc/grading_record/mail_result'

  def setUp(self):
    super(GradingSurveyGroupTest, self).setUp()
    self.init()
    self.createMentor()
    self.createStudent()
    self.createSurveys()

  def createMentor(self):
    """Creates a new mentor.
    """
    profile_helper = GSoCProfileHelper(self.gsoc, self.dev_test)
    profile_helper.createOtherUser('*****@*****.**')
    self.mentor = profile_helper.createMentor(self.org)

  def createStudent(self):
    """Creates a Student with a project.
    """
    profile_helper = GSoCProfileHelper(self.gsoc, self.dev_test)
    profile_helper.createOtherUser('*****@*****.**')
    self.student = profile_helper.createStudentWithProject(self.org,
                                                           self.mentor)
    self.project = GSoCProject.all().ancestor(self.student).get()

  def createSurveys(self):
    """Creates the surveys and records required for the tests.
    """
    survey_values = {
        'author': self.founder,
        'title': 'Title',
        'modified_by': self.founder,
        'link_id': 'link_id',
        'scope': self.gsoc,
        'scope_path': self.gsoc.key().id_or_name()}

    self.project_survey = ProjectSurvey(key_name='key_name',
                                        **survey_values)
    self.project_survey.put()

    self.grading_survey = GradingProjectSurvey(key_name='key_name',
                                               **survey_values)
    self.grading_survey.put()

    record_values = {
        'user': self.student.user,
        'org': self.org,
        'project': self.project,
        'survey': self.project_survey}
    self.project_survey_record = GSoCProjectSurveyRecord(**record_values)
    self.project_survey_record.put()

    self.grading_survey = GradingProjectSurvey(**survey_values)
    self.grading_survey.put()

    record_values = {
        'user': self.student.user,
        'org': self.org,
        'project': self.project,
        'survey': self.grading_survey,
        'grade': True}
    self.grading_survey_record = GSoCGradingProjectSurveyRecord(
        **record_values)
    self.grading_survey_record.put()

    group_values = {
        'name': 'Survey Group Name',
        'grading_survey': self.grading_survey,
        'student_survey': self.project_survey,
        'program': self.gsoc}
    self.survey_group = GSoCGradingSurveyGroup(**group_values)
    self.survey_group.put()

    record_values = {
        'grading_survey_group': self.survey_group,
        'mentor_record': self.grading_survey_record,
        'student_record': self.project_survey_record,
        'grade_decision': 'pass'}
    self.grading_record = GSoCGradingRecord(parent=self.project,
                                            **record_values)
    self.grading_record.put()

  def testCreateGradingRecord(self):
    """Test creating a GradingRecord.
    """
    self.grading_record.delete()

    post_data = {
        'group_key': self.survey_group.key().id_or_name()
        }

    response = self.post(self.UPDATE_RECORDS_URL, post_data)

    self.assertEqual(response.status_code, httplib.OK)
    self.assertTasksInQueue(n=1, url=self.UPDATE_RECORDS_URL)

    record = GSoCGradingRecord.all().get()
    self.assertFalse(record is None)
    self.assertEqual(record.grade_decision, 'pass')

  def testUpdateGradingRecord(self):
    """Test updating a GradingRecord.
    """
    self.grading_record.grade_decision = 'undecided'
    self.grading_record.put()

    post_data = {
        'group_key': self.survey_group.key().id_or_name()
        }

    response = self.post(self.UPDATE_RECORDS_URL, post_data)

    self.assertEqual(response.status_code, httplib.OK)
    self.assertTasksInQueue(n=1, url=self.UPDATE_RECORDS_URL)

    record = GSoCGradingRecord.all().get()
    self.assertFalse(record is None)
    self.assertEqual(record.grade_decision, 'pass')

  def testUpdateProject(self):
    """Test updating a Project with a GradingRecord's result.
    """
    post_data = {
        'group_key': self.survey_group.key().id_or_name(),
        }

    response = self.post(self.UPDATE_PROJECTS_URL, post_data)

    self.assertEqual(response.status_code, httplib.OK)
    self.assertTasksInQueue(n=1, url=self.UPDATE_PROJECTS_URL)

    project = GSoCProject.all().get()
    self.assertFalse(project is None)
    self.assertEqual(project.passed_evaluations, [self.grading_record.key()])
    self.assertEqual(1, project.parent().student_info.passed_evaluations)

  def testUpdateProjectWithSendMail(self):
    """Test updating a Project with a GradingRecord's result and sending mail.
    """
    post_data = {
        'group_key': self.survey_group.key().id_or_name(),
        'send_mail': True,
        }

    response = self.post(self.UPDATE_PROJECTS_URL, post_data)

    self.assertEqual(response.status_code, httplib.OK)
    self.assertTasksInQueue(n=1, url=self.UPDATE_PROJECTS_URL)
    self.assertTasksInQueue(n=1, url=self.SEND_URL)

    project = GSoCProject.all().get()
    self.assertFalse(project is None)
    self.assertEqual(project.passed_evaluations, [self.grading_record.key()])
    self.assertEqual(1, project.parent().student_info.passed_evaluations)

  def testSendMail(self):
    """Test sending mail about a GradingRecord's result.
    """
    post_data = {
        'record_key': str(self.grading_record.key())
        }

    response = self.post(self.SEND_URL, post_data)

    self.assertEqual(response.status_code, httplib.OK)
    # URL explicitly added since the email task is in there
    self.assertTasksInQueue(n=0, url=self.SEND_URL)
    self.assertEmailSent(to=self.student.email)