Esempio n. 1
0
    def test_preassign_workers(self, mock_mail, mock_slack):
        request_cause = StaffBotRequest.RequestCause.AUTOSTAFF.value
        staffing_request_count = StaffingRequestInquiry.objects.filter(
            request__request_cause=request_cause).count()
        project = self.projects['staffbot_assignment_policy']

        # Create first task in test project
        create_subsequent_tasks(project)
        send_staffing_requests()
        self.assertEqual(project.tasks.count(), 1)
        # Assign initial task to worker 0
        initial_task = assign_task(self.workers[0].id,
                                   project.tasks.first().id)
        # Submit task; next task should be created
        with patch('orchestra.utils.task_lifecycle._is_review_needed',
                   return_value=False):
            initial_task = submit_task(initial_task.id, {},
                                       Iteration.Status.REQUESTED_REVIEW,
                                       self.workers[0])

        # Mock mail should be called if we autostaff
        self.assertTrue(mock_mail.called)
        self.assertTrue(mock_slack.called)
        # Assert we created new StaffingRequestInquirys because of autostaff
        new_staffing_request_count = StaffingRequestInquiry.objects.filter(
            request__request_cause=request_cause).count()
        self.assertTrue(staffing_request_count < new_staffing_request_count)
        self.assertEqual(project.tasks.count(), 2)
        related_task = project.tasks.exclude(id=initial_task.id).first()
        # Worker 0 not certified for related tasks, so should not have been
        # auto-assigned
        self.assertEqual(related_task.assignments.count(), 0)
        self.assertEqual(related_task.status, Task.Status.AWAITING_PROCESSING)
Esempio n. 2
0
    def test_send_staffing_request_priorities(self, mock_slack):

        worker2 = WorkerFactory(staffing_priority=-1)
        CommunicationPreferenceFactory(
            worker=worker2,
            communication_type=(
                CommunicationPreference.CommunicationType
                .NEW_TASK_AVAILABLE.value))

        worker3 = WorkerFactory(staffing_priority=1)
        CommunicationPreferenceFactory(
            worker=worker3,
            communication_type=(
                CommunicationPreference.CommunicationType
                .NEW_TASK_AVAILABLE.value))

        request = StaffBotRequestFactory()
        self.assertEquals(request.status,
                          StaffBotRequest.Status.PROCESSING.value)

        # Workers should be contacted in priority order.
        excluded = []
        for worker in (worker3, self.worker, worker2):
            send_staffing_requests(worker_batch_size=1,
                                   frequency=timedelta(minutes=0))
            inquiries = (
                StaffingRequestInquiry.objects
                .filter(request=request)
                .exclude(communication_preference__worker__in=excluded))
            for inquiry in inquiries:
                self.assertEquals(worker.id,
                                  inquiry.communication_preference.worker.id)
            excluded.append(worker)
Esempio n. 3
0
    def test_send_staffing_request_priorities(self, mock_slack):

        worker2 = WorkerFactory()
        WorkerCertificationFactory(worker=worker2, staffing_priority=-1)

        CommunicationPreferenceFactory(
            worker=worker2,
            communication_type=(CommunicationPreference.CommunicationType.
                                NEW_TASK_AVAILABLE.value))

        worker3 = WorkerFactory()
        WorkerCertificationFactory(worker=worker3, staffing_priority=1)
        CommunicationPreferenceFactory(
            worker=worker3,
            communication_type=(CommunicationPreference.CommunicationType.
                                NEW_TASK_AVAILABLE.value))

        request = StaffBotRequestFactory()
        self.assertEqual(request.status,
                         StaffBotRequest.Status.PROCESSING.value)

        # Workers should be contacted in priority order.
        excluded = []
        for worker in (worker3, self.worker, worker2):
            send_staffing_requests(worker_batch_size=1,
                                   frequency=timedelta(minutes=0))
            inquiries = (StaffingRequestInquiry.objects.filter(
                request=request).exclude(
                    communication_preference__worker__in=excluded))
            for inquiry in inquiries:
                self.assertEqual(worker.id,
                                 inquiry.communication_preference.worker.id)
            excluded.append(worker)
Esempio n. 4
0
 def _test_staffing_requests(self, worker, task, command,
                             can_slack=False, can_mail=False):
     StaffBotRequest.objects.all().delete()
     bot = StaffBot()
     communication_type = (CommunicationPreference.CommunicationType
                           .NEW_TASK_AVAILABLE.value)
     communication_preference = CommunicationPreference.objects.get(
         worker=worker,
         communication_type=communication_type)
     communication_preference.methods.slack = can_slack
     communication_preference.methods.email = can_mail
     communication_preference.save()
     data = get_mock_slack_data(
         text=command,
         user_id=self.worker.slack_user_id)
     bot.dispatch(data)
     send_staffing_requests(worker_batch_size=20)
     self.assertEquals(StaffingRequestInquiry.objects.filter(
         communication_preference__worker_id=worker,
         request__task=task).count(), can_slack + can_mail)
Esempio n. 5
0
 def _test_staffing_requests(self, worker, task, command,
                             can_slack=False, can_mail=False):
     StaffBotRequest.objects.all().delete()
     bot = StaffBot()
     communication_type = (CommunicationPreference.CommunicationType
                           .NEW_TASK_AVAILABLE.value)
     communication_preference = CommunicationPreference.objects.get(
         worker=worker,
         communication_type=communication_type)
     communication_preference.methods.slack = can_slack
     communication_preference.methods.email = can_mail
     communication_preference.save()
     data = get_mock_slack_data(
         text=command,
         user_id=self.worker.slack_user_id)
     bot.dispatch(data)
     send_staffing_requests(worker_batch_size=20,
                            frequency=timedelta(minutes=0))
     self.assertEquals(StaffingRequestInquiry.objects.filter(
         communication_preference__worker_id=worker,
         request__task=task).count(), can_slack + can_mail)
    def test_preassign_workers(self, mock_mail, mock_slack):
        request_cause = StaffBotRequest.RequestCause.AUTOSTAFF.value
        staffing_request_count = StaffingRequestInquiry.objects.filter(
            request__request_cause=request_cause).count()
        project = self.projects['staffbot_assignment_policy']

        # Create first task in test project
        create_subsequent_tasks(project)
        send_staffing_requests()
        self.assertEqual(project.tasks.count(), 1)
        # Assign initial task to worker 0
        initial_task = assign_task(self.workers[0].id,
                                   project.tasks.first().id)
        # Submit task; next task should be created
        with patch('orchestra.utils.task_lifecycle._is_review_needed',
                   return_value=False):
            initial_task = submit_task(initial_task.id, {},
                                       Iteration.Status.REQUESTED_REVIEW,
                                       self.workers[0])

        # Mock mail should be called if we autostaff
        self.assertTrue(mock_mail.called)
        self.assertTrue(mock_slack.called)
        # Assert we created new StaffingRequestInquirys because of autostaff
        new_staffing_request_count = StaffingRequestInquiry.objects.filter(
            request__request_cause=request_cause).count()
        self.assertTrue(staffing_request_count < new_staffing_request_count)
        self.assertEqual(project.tasks.count(), 2)
        related_task = project.tasks.exclude(id=initial_task.id).first()
        # Worker 0 not certified for related tasks, so should not have been
        # auto-assigned
        self.assertEqual(related_task.assignments.count(), 0)
        self.assertEqual(related_task.status, Task.Status.AWAITING_PROCESSING)

        # Reset project
        project.tasks.all().delete()
Esempio n. 7
0
    def test_send_staffing_requests(self, mock_slack):
        worker2 = WorkerFactory()
        CommunicationPreferenceFactory(
            worker=worker2,
            communication_type=(
                CommunicationPreference.CommunicationType
                .NEW_TASK_AVAILABLE.value))
        WorkerCertificationFactory(
            worker=worker2,
            certification=self.certification
        )

        request = StaffBotRequestFactory()
        request.task.step.required_certifications.add(self.certification)

        self.assertEqual(request.status,
                         StaffBotRequest.Status.SENDING_INQUIRIES.value)

        send_staffing_requests(worker_batch_size=1,
                               frequency=timedelta(minutes=0))
        mock_slack.assert_not_called()
        request.refresh_from_db()
        self.assertEqual(request.status,
                         StaffBotRequest.Status.SENDING_INQUIRIES.value)
        # Inquiries increase by two because we send a Slack and an
        # email notification.
        self.assertEqual(
            StaffingRequestInquiry.objects.filter(request=request).count(),
            2)

        send_staffing_requests(worker_batch_size=1,
                               frequency=timedelta(minutes=0))
        self.assertEqual(mock_slack.call_count, 1)
        mock_slack.reset()

        request.refresh_from_db()
        self.assertEqual(request.status,
                         StaffBotRequest.Status.SENDING_INQUIRIES.value)
        self.assertEqual(
            StaffingRequestInquiry.objects.filter(request=request).count(),
            4)

        # marked as closed and no new request inquiries sent.
        send_staffing_requests(worker_batch_size=1,
                               frequency=timedelta(minutes=0))
        self.assertTrue(mock_slack.called)
        request.refresh_from_db()
        self.assertEqual(request.status,
                         StaffBotRequest.Status.DONE_SENDING_INQUIRIES.value)
        self.assertEqual(
            StaffingRequestInquiry.objects.filter(request=request).count(),
            4)
Esempio n. 8
0
    def test_send_staffing_requests(self, mock_slack):

        worker2 = WorkerFactory()
        CommunicationPreferenceFactory(
            worker=worker2,
            communication_type=(
                CommunicationPreference.CommunicationType
                .NEW_TASK_AVAILABLE.value))

        request = StaffBotRequestFactory()
        self.assertEquals(request.status,
                          StaffBotRequest.Status.PROCESSING.value)

        send_staffing_requests(worker_batch_size=1,
                               frequency=timedelta(minutes=0))
        mock_slack.assert_not_called()
        request.refresh_from_db()
        self.assertEquals(request.status,
                          StaffBotRequest.Status.PROCESSING.value)
        # Inquiries increase by two because we send a Slack and an
        # email notification.
        self.assertEquals(
            StaffingRequestInquiry.objects.filter(request=request).count(),
            2)

        send_staffing_requests(worker_batch_size=1,
                               frequency=timedelta(minutes=0))
        mock_slack.assert_not_called()
        request.refresh_from_db()
        self.assertEquals(request.status,
                          StaffBotRequest.Status.PROCESSING.value)
        self.assertEquals(
            StaffingRequestInquiry.objects.filter(request=request).count(),
            4)

        # marked as complete and no new request inquiries sent.
        send_staffing_requests(worker_batch_size=1,
                               frequency=timedelta(minutes=0))
        self.assertTrue(mock_slack.called)
        request.refresh_from_db()
        self.assertEquals(request.status,
                          StaffBotRequest.Status.COMPLETE.value)
        self.assertEquals(
            StaffingRequestInquiry.objects.filter(request=request).count(),
            4)
Esempio n. 9
0
    def test_send_staffing_requests(self, mock_slack):
        worker2 = WorkerFactory()

        StaffingRequestInquiryFactory(
            communication_preference__worker=worker2,
            communication_preference__communication_type=(
                CommunicationPreference.CommunicationType
                .NEW_TASK_AVAILABLE.value),
            request__task__step__is_human=True
        )

        request = StaffBotRequestFactory()
        self.assertEquals(request.status,
                          StaffBotRequest.Status.PROCESSING.value)

        send_staffing_requests(worker_batch_size=1)
        mock_slack.assert_not_called()
        request.refresh_from_db()
        self.assertEquals(request.status,
                          StaffBotRequest.Status.PROCESSING.value)

        self.assertEquals(
            StaffingRequestInquiry.objects.filter(request=request).count(),
            2)

        send_staffing_requests(worker_batch_size=1)
        mock_slack.assert_not_called()
        request.refresh_from_db()
        self.assertEquals(request.status,
                          StaffBotRequest.Status.PROCESSING.value)

        self.assertEquals(
            StaffingRequestInquiry.objects.filter(request=request).count(),
            4)

        # marked as complete and no new request inquiries sent.
        send_staffing_requests(worker_batch_size=1)
        self.assertTrue(mock_slack.called)
        request.refresh_from_db()
        self.assertEquals(request.status,
                          StaffBotRequest.Status.COMPLETE.value)

        self.assertEquals(
            StaffingRequestInquiry.objects.filter(request=request).count(),
            4)
Esempio n. 10
0
    def test_send_staffing_requests_parameters(self, mock_slack):
        for idx in range(5):
            worker = WorkerFactory()
            CommunicationPreferenceFactory(
                worker=worker,
                communication_type=(
                    CommunicationPreference.CommunicationType
                    .NEW_TASK_AVAILABLE.value))
            WorkerCertificationFactory(
                worker=worker,
                certification=self.certification
            )
        # Make a new request and turn off the global request, as the
        # global one has an inquiry on it already.
        request = StaffBotRequestFactory(task__step__is_human=True)
        request.task.step.required_certifications.add(self.certification)

        self.staffing_request_inquiry.request.status = (
            StaffBotRequest.Status.DONE_SENDING_INQUIRIES)

        send_staffing_requests(worker_batch_size=1,
                               frequency=timedelta(minutes=20))
        # Inquiries increase by two because we send a Slack and an
        # email notification.  `last_inquiry_sent` is None on new
        # tasks, so we send this batch regardless of frequency.
        self.assertEqual(
            StaffingRequestInquiry.objects.filter(request=request).count(),
            2)

        send_staffing_requests(worker_batch_size=2,
                               frequency=timedelta(minutes=20))
        # Don't send more inquiries, since it hasn't been 20 minutes.
        self.assertEqual(
            StaffingRequestInquiry.objects.filter(request=request).count(),
            2)

        request.last_inquiry_sent = timezone.now() - timedelta(minutes=21)
        request.save()
        send_staffing_requests(worker_batch_size=2,
                               frequency=timedelta(minutes=20))
        # Send two email and two slack inquiries since it's been 21 minutes.
        self.assertEqual(
            StaffingRequestInquiry.objects.filter(request=request).count(),
            6)

        send_staffing_requests(worker_batch_size=10,
                               frequency=timedelta(minutes=20))
        # Don't send more inquiries, since it hasn't been 20 minutes.
        self.assertEqual(
            StaffingRequestInquiry.objects.filter(request=request).count(),
            6)

        request.last_inquiry_sent = timezone.now() - timedelta(minutes=21)
        request.save()
        send_staffing_requests(worker_batch_size=10,
                               frequency=timedelta(minutes=20))
        # Send remaining inquiries, since enough time has passed.
        self.assertEqual(
            StaffingRequestInquiry.objects.filter(request=request).count(),
            12)

        request.last_inquiry_sent = timezone.now() - timedelta(minutes=21)
        request.save()
        send_staffing_requests(worker_batch_size=10,
                               frequency=timedelta(minutes=20))
        # We're all out of workers to whom we'd like to send inquiries.
        self.assertEqual(
            StaffingRequestInquiry.objects.filter(request=request).count(),
            12)
Esempio n. 11
0
    def test_get_available_request(self, mock_slack):
        # Close all open requests so new worker doesn't receive them.
        send_staffing_requests(worker_batch_size=2,
                               frequency=timedelta(minutes=0))

        self.assertEqual(len(get_available_requests(self.worker)), 1)

        worker2 = WorkerFactory()
        CommunicationPreferenceFactory(
            worker=worker2,
            communication_type=(
                CommunicationPreference.CommunicationType
                .NEW_TASK_AVAILABLE.value))
        WorkerCertificationFactory(
            worker=worker2,
            certification=self.certification
        )

        request1 = StaffBotRequestFactory(task__step__is_human=True)
        request1.task.step.required_certifications.add(self.certification)
        request2 = StaffBotRequestFactory(task__step__is_human=True)
        request2.task.step.required_certifications.add(self.certification)

        send_staffing_requests(worker_batch_size=2,
                               frequency=timedelta(minutes=0))
        inquiry1 = (
            StaffingRequestInquiry.objects
            .filter(communication_preference__worker=self.worker)
            .filter(request=request1).first())
        inquiry2 = (
            StaffingRequestInquiry.objects
            .filter(communication_preference__worker=worker2)
            .filter(request=request2).first())

        # `self.worker` now has three available tasks, whereas `worker2`
        # just has access to the two new tasks.
        available_requests = get_available_requests(self.worker)
        self.assertEqual(len(available_requests), 3)
        self.assertEqual(len(get_available_requests(worker2)), 2)

        # Tasks should be sorted by start_datetime in ascending order.

        first_task, second_task, third_task = (
            available_requests[0]['task'], available_requests[1]['task'],
            available_requests[2]['task'])
        self.assertLess(
            first_task.start_datetime, second_task.start_datetime)
        self.assertLess(
            second_task.start_datetime, third_task.start_datetime)

        # `self.worker` will lose an available task (they accept it),
        # whereas `worker2` is unchanged.
        handle_staffing_response(
            self.worker, self.staffing_request_inquiry.id,
            is_available=True)
        self.assertEqual(len(get_available_requests(self.worker)), 2)
        self.assertEqual(len(get_available_requests(worker2)), 2)

        # `self.worker` will lose an available task (they ignore it),
        # whereas `worker2` is unchanged.
        handle_staffing_response(
            self.worker, inquiry1.id,
            is_available=False)
        self.assertEqual(len(get_available_requests(self.worker)), 1)
        self.assertEqual(len(get_available_requests(worker2)), 2)

        # `worker2` takes a task.
        handle_staffing_response(
            worker2, inquiry2.id,
            is_available=True)
        self.assertEqual(len(get_available_requests(self.worker)), 0)
        self.assertEqual(len(get_available_requests(worker2)), 1)
Esempio n. 12
0
def send_staffing_requests_periodically():
    send_staffing_requests()
Esempio n. 13
0
    def test_send_staffing_requests_parameters(self, mock_slack):
        for idx in range(5):
            CommunicationPreferenceFactory(
                worker=WorkerFactory(),
                communication_type=(
                    CommunicationPreference.CommunicationType
                    .NEW_TASK_AVAILABLE.value))
        # Make a new request and turn off the global request, as the
        # global one has an inquiry on it already.
        request = StaffBotRequestFactory(task__step__is_human=True)
        self.staffing_request_inquiry.request.status = (
            StaffBotRequest.Status.COMPLETE)

        send_staffing_requests(worker_batch_size=1,
                               frequency=timedelta(minutes=20))
        # Inquiries increase by two because we send a Slack and an
        # email notification.  `last_inquiry_sent` is None on new
        # tasks, so we send this batch regardless of frequency.
        self.assertEquals(
            StaffingRequestInquiry.objects.filter(request=request).count(),
            2)

        send_staffing_requests(worker_batch_size=2,
                               frequency=timedelta(minutes=20))
        # Don't send more inquiries, since it hasn't been 20 minutes.
        self.assertEquals(
            StaffingRequestInquiry.objects.filter(request=request).count(),
            2)

        request.last_inquiry_sent = timezone.now() - timedelta(minutes=21)
        request.save()
        send_staffing_requests(worker_batch_size=2,
                               frequency=timedelta(minutes=20))
        # Send two email and two slack inquiries since it's been 21 minutes.
        self.assertEquals(
            StaffingRequestInquiry.objects.filter(request=request).count(),
            6)

        send_staffing_requests(worker_batch_size=10,
                               frequency=timedelta(minutes=20))
        # Don't send more inquiries, since it hasn't been 20 minutes.
        self.assertEquals(
            StaffingRequestInquiry.objects.filter(request=request).count(),
            6)

        request.last_inquiry_sent = timezone.now() - timedelta(minutes=21)
        request.save()
        send_staffing_requests(worker_batch_size=10,
                               frequency=timedelta(minutes=20))
        # Send remaining inquiries, since enough time has passed.
        self.assertEquals(
            StaffingRequestInquiry.objects.filter(request=request).count(),
            12)

        request.last_inquiry_sent = timezone.now() - timedelta(minutes=21)
        request.save()
        send_staffing_requests(worker_batch_size=10,
                               frequency=timedelta(minutes=20))
        # We're all out of workers to whom we'd like to send inquiries.
        self.assertEquals(
            StaffingRequestInquiry.objects.filter(request=request).count(),
            12)
Esempio n. 14
0
    def test_get_available_request(self, mock_slack):
        # Complete all open requests so new worker doesn't receive them.
        send_staffing_requests(worker_batch_size=2,
                               frequency=timedelta(minutes=0))

        self.assertEquals(len(get_available_requests(self.worker)), 1)

        worker2 = WorkerFactory()
        CommunicationPreferenceFactory(
            worker=worker2,
            communication_type=(
                CommunicationPreference.CommunicationType
                .NEW_TASK_AVAILABLE.value))
        request1 = StaffBotRequestFactory(task__step__is_human=True)
        request2 = StaffBotRequestFactory(task__step__is_human=True)

        send_staffing_requests(worker_batch_size=2,
                               frequency=timedelta(minutes=0))
        inquiry1 = (
            StaffingRequestInquiry.objects
            .filter(communication_preference__worker=self.worker)
            .filter(request=request1).first())
        inquiry2 = (
            StaffingRequestInquiry.objects
            .filter(communication_preference__worker=worker2)
            .filter(request=request2).first())

        # `self.worker` now has three available tasks, whereas `worker2`
        # just has access to the two new tasks.
        available_requests = get_available_requests(self.worker)
        self.assertEquals(len(available_requests), 3)
        self.assertEquals(len(get_available_requests(worker2)), 2)

        # Tasks should be sorted by start_datetime in ascending order.

        first_task, second_task, third_task = (
            available_requests[0]['task'], available_requests[1]['task'],
            available_requests[2]['task'])
        self.assertLess(
            first_task.start_datetime, second_task.start_datetime)
        self.assertLess(
            second_task.start_datetime, third_task.start_datetime)

        # `self.worker` will lose an available task (they accept it),
        # whereas `worker2` is unchanged.
        handle_staffing_response(
            self.worker, self.staffing_request_inquiry.id,
            is_available=True)
        self.assertEquals(len(get_available_requests(self.worker)), 2)
        self.assertEquals(len(get_available_requests(worker2)), 2)

        # `self.worker` will lose an available task (they ignore it),
        # whereas `worker2` is unchanged.
        handle_staffing_response(
            self.worker, inquiry1.id,
            is_available=False)
        self.assertEquals(len(get_available_requests(self.worker)), 1)
        self.assertEquals(len(get_available_requests(worker2)), 2)

        # `worker2` takes a task.
        handle_staffing_response(
            worker2, inquiry2.id,
            is_available=True)
        self.assertEquals(len(get_available_requests(self.worker)), 0)
        self.assertEquals(len(get_available_requests(worker2)), 1)