Example #1
0
  def __init__(self, data):
    """Initializes the dashboard.

    Args:
      data: The RequestData object
    """
    # TODO(nathaniel): Eliminate this state-setting call.
    data.redirect.program()

    subpages = [
        {
            'name': 'edit_evaluation_group',
            'description': ugettext('Create evaluation group'),
            'title': 'Create',
            'link': data.redirect.urlOf('gsoc_grading_group')
        },
    ]

    q = GSoCGradingSurveyGroup.all()
    q.filter('program', data.program)

    for group in q:
      data.redirect.id(group.key().id())
      subpages.append(
        {
            'name': 'view_evaluation_group_%s' % group.key().id(),
            'description': ugettext('View this group'),
            'title': 'View %s' % group.name,
            'link': data.redirect.urlOf('gsoc_grading_record_overview')
        }
      )

    super(EvaluationGroupDashboard, self).__init__(data, subpages)
Example #2
0
    def __init__(self, data):
        """Initializes the dashboard.

    Args:
      data: The RequestData object
    """
        # TODO(nathaniel): Eliminate this state-setting call.
        data.redirect.program()

        subpages = [
            {
                'name': 'edit_evaluation_group',
                'description': ugettext('Create evaluation group'),
                'title': 'Create',
                'link': data.redirect.urlOf('gsoc_grading_group')
            },
        ]

        q = GSoCGradingSurveyGroup.all()
        q.filter('program', data.program)

        for group in q:
            data.redirect.id(group.key().id())
            subpages.append({
                'name':
                'view_evaluation_group_%s' % group.key().id(),
                'description':
                ugettext('View this group'),
                'title':
                'View %s' % group.name,
                'link':
                data.redirect.urlOf('gsoc_grading_record_overview')
            })

        super(EvaluationGroupDashboard, self).__init__(data, subpages)
Example #3
0
    def __init__(self, data):
        """Initializes the dashboard.

    Args:
      data: The RequestData object
    """
        # TODO(nathaniel): Eliminate this state-setting call.
        data.redirect.program()

        subpages = [
            {
                "name": "edit_evaluation_group",
                "description": ugettext("Create evaluation group"),
                "title": "Create",
                "link": data.redirect.urlOf("gsoc_grading_group"),
            }
        ]

        q = GSoCGradingSurveyGroup.all()
        q.filter("program", data.program)

        for group in q:
            data.redirect.id(group.key().id())
            subpages.append(
                {
                    "name": "view_evaluation_group_%s" % group.key().id(),
                    "description": ugettext("View this group"),
                    "title": "View %s" % group.name,
                    "link": data.redirect.urlOf("gsoc_grading_record_overview"),
                }
            )

        super(EvaluationGroupDashboard, self).__init__(data, subpages)
  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 post(self, data, check, mutator):
    """Handles the POST request when creating a Grading Group"""
    student_survey = None
    grading_survey = None
    survey_type = None

    if 'midterm' in data.POST:
      student_survey = survey.getMidtermProjectSurveyForProgram(data.program)
      grading_survey = survey.getMidtermGradingProjectSurveyForProgram(
          data.program)
      survey_type = 'Midterm'
    elif 'final' in data.POST:
      student_survey = survey.getFinalProjectSurveyForProgram(data.program)
      grading_survey = survey.getFinalGradingProjectSurveyForProgram(
          data.program)
      survey_type = 'Final'
    else:
      raise exception.BadRequest('No valid evaluation type present')

    if not student_survey or not grading_survey:
      data.redirect.program()
      return data.redirect.to('gsoc_grading_group', extra=['err=1'])

    q = GSoCGradingSurveyGroup.all()
    q.filter('student_survey', student_survey)
    q.filter('grading_survey', grading_survey)

    existing_group = q.get()

    if existing_group:
      data.redirect.id(existing_group.key().id())
    else:
      props = {
          'name': '%s - %s Evaluation' %(data.program.name, survey_type),
          'program': data.program,
          'grading_survey': grading_survey,
          'student_survey': student_survey,
      }
      new_group = GSoCGradingSurveyGroup(**props)
      new_group.put()
      data.redirect.id(new_group.key().id())

    return data.redirect.to('gsoc_grading_record_overview')
Example #6
0
  def updateRecordsForSurveyGroup(self, request, *args, **kwargs):
    """Updates or creates GradingRecords for the given GradingSurveyGroup.

    Expects the following to be present in the POST dict:
      group_key: Specifies the GradingSurveyGroup key name.
      cursor: optional to specify where the query should continue from.

    Args:
      request: Django Request object
    """
    post_dict = request.POST

    group_key = post_dict.get('group_key')

    if not group_key:
      # invalid task data, log and return OK
      return error_handler.logErrorAndReturnOK(
          'Invalid updateRecordForSurveyGroup data: %s' % post_dict)

    # get the GradingSurveyGroup for the given key
    survey_group = GSoCGradingSurveyGroup.get_by_id(int(group_key))

    if not survey_group:
      # invalid GradingSurveyGroup specified, log and return OK
      return error_handler.logErrorAndReturnOK(
          'Invalid GradingSurveyGroup specified: %s' % group_key)

    q = GSoCProject.all()
    q.filter('program', survey_group.program)
    q.filter('status', 'accepted')

    if 'cursor' in post_dict:
      q.with_cursor(post_dict['cursor'])

    # get the first batch_size number of StudentProjects
    projects = q.fetch(self.DEF_BATCH_SIZE)

    if not projects:
      # task completed, update timestamp for last update complete
      survey_group.last_update_complete = datetime.datetime.now()
      survey_group.put()
      return http.HttpResponse()

    # update/create and batch put the new GradingRecords
    grading_record.updateOrCreateRecordsFor(survey_group, projects)

    # pass along these params as POST to the new task
    task_params = {'group_key': group_key,
                   'cursor': q.cursor()}

    new_task = taskqueue.Task(params=task_params, url=request.path)
    new_task.add()

    # task completed, return OK
    return http.HttpResponse('OK')
Example #7
0
  def surveyGroupFromKwargs(self):
    """Sets the GradingSurveyGroup from kwargs.
    """
    assert access_checker.isSet(self.data.program)

    survey_group = GSoCGradingSurveyGroup.get_by_id(int(self.data.kwargs['id']))

    if not survey_group:
      raise NotFound('Requested GSoCGradingSurveyGroup does not exist')

    if survey_group.program.key() != self.data.program.key():
      raise NotFound(
          'Requested GSoCGradingSurveyGroup does not exist in this program')

    self.data.survey_group = survey_group
Example #8
0
    def surveyGroupFromKwargs(self):
        """Sets the GradingSurveyGroup from kwargs.
    """
        assert access_checker.isSet(self.data.program)

        survey_group = GSoCGradingSurveyGroup.get_by_id(
            int(self.data.kwargs['id']))

        if not survey_group:
            raise exception.NotFound(
                message='Requested GSoCGradingSurveyGroup does not exist')

        if survey_group.program.key() != self.data.program.key():
            raise exception.NotFound(
                message=('Requested GSoCGradingSurveyGroup '
                         'does not exist in this program'))

        self.data.survey_group = survey_group
    def post(self, data, check, mutator):
        """Handles the POST request when creating a Grading Group"""
        student_survey = None
        grading_survey = None
        survey_type = None

        if 'midterm' in data.POST:
            student_survey = survey.getMidtermProjectSurveyForProgram(
                data.program)
            grading_survey = survey.getMidtermGradingProjectSurveyForProgram(
                data.program)
            survey_type = 'Midterm'
        elif 'final' in data.POST:
            student_survey = survey.getFinalProjectSurveyForProgram(
                data.program)
            grading_survey = survey.getFinalGradingProjectSurveyForProgram(
                data.program)
            survey_type = 'Final'
        else:
            raise exception.BadRequest('No valid evaluation type present')

        if not student_survey or not grading_survey:
            data.redirect.program()
            return data.redirect.to('gsoc_grading_group', extra=['err=1'])

        q = GSoCGradingSurveyGroup.all()
        q.filter('student_survey', student_survey)
        q.filter('grading_survey', grading_survey)

        existing_group = q.get()

        if existing_group:
            data.redirect.id(existing_group.key().id())
        else:
            props = {
                'name':
                '%s - %s Evaluation' % (data.program.name, survey_type),
                'program': data.program,
                'grading_survey': grading_survey,
                'student_survey': student_survey,
            }
            new_group = GSoCGradingSurveyGroup(**props)
            new_group.put()
            data.redirect.id(new_group.key().id())

        return data.redirect.to('gsoc_grading_record_overview')
Example #10
0
  def updateProjectsForSurveyGroup(self, request, *args, **kwargs):
    """Updates each StudentProject for which a GradingRecord is found.

    Expects the following to be present in the POST dict:
      group_key: Specifies the GradingSurveyGroup key name.
      cursor: Optional, specifies the cursor for the GadingRecord query.
      send_mail: Optional, if this string evaluates to True mail will be send
                 for each GradingRecord that's processed.

    Args:
      request: Django Request object
    """
    post_dict = request.POST

    group_key = post_dict.get('group_key')
    if not group_key:
      # invalid task data, log and return OK
      return error_handler.logErrorAndReturnOK(
          'Invalid updateRecordForSurveyGroup data: %s' % post_dict)

    # get the GradingSurveyGroup for the given keyname
    survey_group = GSoCGradingSurveyGroup.get_by_id(int(group_key))

    if not survey_group:
      # invalid GradingSurveyGroup specified, log and return OK
      return error_handler.logErrorAndReturnOK(
          'Invalid GradingSurveyGroup specified: %s' % group_key)

    q = GSoCGradingRecord.all()
    q.filter('grading_survey_group', survey_group)

    if 'cursor' in post_dict:
      q.with_cursor(post_dict['cursor'])

    # get the first batch_size number of GradingRecords
    records = q.fetch(self.DEF_BATCH_SIZE)

    if not records:
      # we are done
      return http.HttpResponse()

    grading_record.updateProjectsForGradingRecords(records)

    # check if we need to send an email for each GradingRecord
    send_mail = post_dict.get('send_mail', '')

    if send_mail:
      # enqueue a task to send mail for each GradingRecord
      for record in records:
        # pass along these params as POST to the new task
        task_params = {'record_key': str(record.key())}
        task_url = '/tasks/gsoc/grading_record/mail_result'

        mail_task = taskqueue.Task(params=task_params, url=task_url)
        mail_task.add('mail')

    # pass along these params as POST to the new task
    task_params = {'group_key': group_key,
                   'cursor': q.cursor(),
                   'send_mail': send_mail}

    new_task = taskqueue.Task(params=task_params, url=request.path)
    new_task.add()

    # task completed, return OK
    return http.HttpResponse('OK')
    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)
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)