def test_used_types(self):
        # given
        bucharest = GeographicRegion.objects.get(slug='bucharest')
        romania = GeographicRegion.objects.get(slug='romania')
        service_type = ServiceType.objects.first()
        service = ServiceFactory(region=bucharest, status='current')
        service.types.add(service_type)
        service.save()

        # when
        get_used_types_bucharest = self.api_client.get(
            path='/v2/custom-servicetypes/used_types/?geographic_region=' + bucharest.slug,
            format='json')
        self.assertEqual(get_used_types_bucharest.status_code, 200)
        get_used_types_romania = self.api_client.get(
            path='/v2/custom-servicetypes/used_types/?geographic_region=' + romania.slug,
            format='json')
        self.assertEqual(get_used_types_romania.status_code, 200)

        # then
        used_types_bucharest = json.loads(get_used_types_bucharest.content.decode('utf-8'))
        self.assertEqual(len(used_types_bucharest), 1)
        used_types_romania = json.loads(get_used_types_romania.content.decode('utf-8'))
        self.assertEqual(len(used_types_romania), 1)
Пример #2
0
class IndexingTest(TestCase):
    def setUp(self):
        self.service_ar = ServiceFactory(name_ar='Arabic',
                                         name_en='',
                                         name_fr='',
                                         description_ar='language-of-Egypt',
                                         status=Service.STATUS_CURRENT)
        self.service_ar.save()
        self.service_en = ServiceFactory(
            name_en='English',
            name_ar='',
            name_fr='',
            description_en='language-of-Australia',
            status=Service.STATUS_CURRENT)
        self.service_en.save()
        self.service_fr = ServiceFactory(name_fr='French',
                                         name_ar='',
                                         name_en='',
                                         description_fr='language-of-France',
                                         status=Service.STATUS_CURRENT)
        self.service_fr.save()
        self.rejected_service_fr = ServiceFactory(
            name_fr='InactiveParis',
            name_ar='',
            name_en='',
            status=Service.STATUS_REJECTED)
        self.rejected_service_fr.save()

    def test_querysets(self):
        index = ServiceIndex()
        self.assertIn(self.service_ar, index.get_index_queryset('ar'))
        self.assertNotIn(self.service_ar, index.get_index_queryset('en'))

        self.assertIn(self.service_fr, index.get_index_queryset('fr'))
        self.assertNotIn(self.service_fr, index.get_index_queryset('ar'))

        self.assertNotIn(self.rejected_service_fr,
                         index.get_index_queryset('fr'))

    def test_search_data(self):
        index = ServiceIndex()
        ar_data = index.get_search_data(self.service_ar, 'ar', None)
        self.assertIn('Egypt', ar_data)
        en_data = index.get_search_data(self.service_en, 'en', None)
        self.assertIn('Australia', en_data)
Пример #3
0
class IndexingTest(TestCase):

    def setUp(self):
        self.service_ar = ServiceFactory(
            name_ar='Arabic', name_en='', name_fr='',
            description_ar='language-of-Egypt',
            status=Service.STATUS_CURRENT
        )
        self.service_ar.save()
        self.service_en = ServiceFactory(
            name_en='English', name_ar='', name_fr='',
            description_en='language-of-Australia',
            status=Service.STATUS_CURRENT
        )
        self.service_en.save()
        self.service_fr = ServiceFactory(
            name_fr='French', name_ar='', name_en='',
            description_fr='language-of-France',
            status=Service.STATUS_CURRENT
        )
        self.service_fr.save()
        self.rejected_service_fr = ServiceFactory(
            name_fr='InactiveParis', name_ar='', name_en='',
            status=Service.STATUS_REJECTED
        )
        self.rejected_service_fr.save()

    def test_querysets(self):
        index = ServiceIndex()
        self.assertIn(self.service_ar, index.get_index_queryset('ar'))
        self.assertNotIn(self.service_ar, index.get_index_queryset('en'))

        self.assertIn(self.service_fr, index.get_index_queryset('fr'))
        self.assertNotIn(self.service_fr, index.get_index_queryset('ar'))

        self.assertNotIn(self.rejected_service_fr, index.get_index_queryset('fr'))

    def test_search_data(self):
        index = ServiceIndex()
        ar_data = index.get_search_data(self.service_ar, 'ar', None)
        self.assertIn('Egypt', ar_data)
        en_data = index.get_search_data(self.service_en, 'en', None)
        self.assertIn('Australia', en_data)
Пример #4
0
class ServiceAdminTest(TestCase):
    def setUp(self):
        self.service = ServiceFactory(status=Service.STATUS_DRAFT,
                                      location="POINT (33.0000 35.0000)")
        self.password = '******'
        self.user = EmailUserFactory(is_staff=True, password=self.password)
        assert self.user.is_staff
        group = Group.objects.get(name='Staff')
        self.user.groups.add(group)
        assert self.user.has_perm('services.change_service')
        assert self.client.login(email=self.user.email, password=self.password)

    def test_permissions(self):
        # Must have Staff group to access services in the admin
        self.user.groups.remove(Group.objects.get(name='Staff'))
        rsp = self.client.get(
            reverse('admin:services_service_change', args=[self.service.pk]))
        self.assertEqual(403, rsp.status_code)
        rsp = self.save_service_in_form()
        self.assertEqual(403, rsp.status_code)

    def save_service_in_form(self, **kwargs):
        """
        Simulate loading the service in a change form in the admin, updating
        some data from **kwargs, and submitting.
        Returns the response returned by the post.
        """
        data = model_to_dict(self.service)
        data['location'] = str(data['location'])
        # inline data
        data["selection_criteria-TOTAL_FORMS"] = 0
        data["selection_criteria-INITIAL_FORMS"] = 0
        data["selection_criteria-MIN_NUM_FORMS"] = 0
        data["selection_criteria-MAX_NUM_FORMS"] = 0
        # Drop any None values
        data = {k: v for k, v in data.items() if v is not None}
        # Update with caller data
        data.update(**kwargs)
        rsp = self.client.post(reverse('admin:services_service_change',
                                       args=[self.service.pk]),
                               data=data)
        return rsp

    def test_edit_service(self):
        # Make a change to the data
        rsp = self.save_service_in_form(name_en="New service name")
        self.assertEqual(302, rsp.status_code, msg=rsp.content.decode('utf-8'))
        service = Service.objects.get(pk=self.service.pk)
        self.assertEqual("New service name", service.name_en)

    def test_approve_button(self):
        rsp = self.save_service_in_form(
            name_en="New service name",
            _approve=True,  # the button we "clicked"
        )
        self.assertEqual(302, rsp.status_code, msg=rsp.content.decode('utf-8'))
        service = Service.objects.get(pk=self.service.pk)
        self.assertEqual("New service name", service.name_en)
        self.assertEqual(Service.STATUS_CURRENT, service.status)

    def test_approve_button_with_bad_data(self):
        rsp = self.save_service_in_form(
            name_en="New service name",
            location="not a valid location",
            _approve=True,  # the button we "clicked"
        )
        self.assertEqual(200, rsp.status_code, msg=rsp.content.decode('utf-8'))
        self.assertIn(
            '<ul class="errorlist"><li>Invalid geometry value.</li></ul>',
            rsp.context['errors'])
        service = Service.objects.get(pk=self.service.pk)
        self.assertEqual(Service.STATUS_DRAFT, service.status)

    def test_approve_button_with_missing_data(self):
        rsp = self.save_service_in_form(
            name_en="New service name",
            location='',
            _approve=True,  # the button we "clicked"
        )
        self.assertEqual(200, rsp.status_code, msg=rsp.content.decode('utf-8'))
        self.assertIn(
            '<ul class="errorlist"><li>No geometry value provided.</li></ul>',
            rsp.context['errors'])
        service = Service.objects.get(pk=self.service.pk)
        self.assertEqual(Service.STATUS_DRAFT, service.status)

    def test_reject_button(self):
        rsp = self.save_service_in_form(
            name_en="New service name",
            _reject=True,  # the button we "clicked"
        )
        self.assertEqual(302, rsp.status_code, msg=rsp.content.decode('utf-8'))
        service = Service.objects.get(pk=self.service.pk)
        self.assertEqual("New service name", service.name_en)
        self.assertEqual(Service.STATUS_REJECTED, service.status)

    def test_actions_appear(self):
        rsp = self.client.get(reverse('admin:services_service_changelist'))
        self.assertContains(rsp, "Approve new or changed service")
        self.assertContains(rsp, "Reject new or changed service")

    def test_buttons_appear(self):
        rsp = self.client.get(
            reverse('admin:services_service_change', args=[self.service.pk]))
        self.assertContains(rsp, "Save and approve")
        self.assertContains(rsp, "Save and reject")

    def test_approve_action(self):
        self.service.validate_for_approval()
        data = {
            'index': '0',  # "Go" button
            'action': 'approve',  # selected action
            '_selected_action': [
                str(self.service.pk),  # selected checkbox
            ]
        }
        rsp = self.client.post(reverse('admin:services_service_changelist'),
                               data)
        self.assertEqual(302, rsp.status_code, msg=rsp.content.decode('utf-8'))
        new_url = rsp['Location']
        rsp = self.client.get(new_url)
        self.assertEqual(200, rsp.status_code, msg=rsp.content.decode('utf-8'))
        service = Service.objects.get(pk=self.service.pk)
        self.assertEqual(Service.STATUS_CURRENT, service.status)

    def test_reject_action(self):
        data = {
            'index': '0',  # "Go" button
            'action': 'reject',  # selected action
            '_selected_action': [
                str(self.service.pk),  # selected checkbox
            ]
        }
        rsp = self.client.post(reverse('admin:services_service_changelist'),
                               data)
        self.assertEqual(302, rsp.status_code, msg=rsp.content.decode('utf-8'))
        new_url = rsp['Location']
        rsp = self.client.get(new_url)
        self.assertEqual(200, rsp.status_code, msg=rsp.content.decode('utf-8'))
        service = Service.objects.get(pk=self.service.pk)
        self.assertEqual(Service.STATUS_REJECTED, service.status)

    def test_approve_action_wrong_status(self):
        self.service.status = Service.STATUS_CURRENT
        self.service.save()
        data = {
            'index': '0',  # "Go" button
            'action': 'approve',  # selected action
            '_selected_action': [
                str(self.service.pk),  # selected checkbox
            ]
        }
        rsp = self.client.post(reverse('admin:services_service_changelist'),
                               data,
                               follow=True)
        self.assertEqual(200, rsp.status_code)
        self.assertIn('Only services in draft status may be approved',
                      [str(msg) for msg in rsp.context['messages']])

    def test_reject_action_wrong_status(self):
        self.service.status = Service.STATUS_CURRENT
        self.service.save()
        data = {
            'index': '0',  # "Go" button
            'action': 'reject',  # selected action
            '_selected_action': [
                str(self.service.pk),  # selected checkbox
            ]
        }
        rsp = self.client.post(reverse('admin:services_service_changelist'),
                               data,
                               follow=True)
        self.assertEqual(200, rsp.status_code)
        self.assertIn('Only services in draft status may be rejected',
                      [str(msg) for msg in rsp.context['messages']])
Пример #5
0
class ServiceAdminTest(TestCase):
    def setUp(self):
        self.service = ServiceFactory(status=Service.STATUS_DRAFT,
                                      location="POINT (33.0000 35.0000)")
        self.password = '******'
        self.user = EmailUserFactory(is_staff=True, password=self.password)
        assert self.user.is_staff
        group = Group.objects.get(name='Staff')
        self.user.groups.add(group)
        assert self.user.has_perm('services.change_service')
        assert self.client.login(email=self.user.email, password=self.password)

    def test_permissions(self):
        # Must have Staff group to access services in the admin
        self.user.groups.remove(Group.objects.get(name='Staff'))
        rsp = self.client.get(reverse('admin:services_service_change', args=[self.service.pk]))
        self.assertEqual(403, rsp.status_code)
        rsp = self.save_service_in_form()
        self.assertEqual(403, rsp.status_code)

    def save_service_in_form(self, **kwargs):
        """
        Simulate loading the service in a change form in the admin, updating
        some data from **kwargs, and submitting.
        Returns the response returned by the post.
        """
        data = model_to_dict(self.service)
        data['location'] = str(data['location'])
        # inline data
        data["selection_criteria-TOTAL_FORMS"] = 0
        data["selection_criteria-INITIAL_FORMS"] = 0
        data["selection_criteria-MIN_NUM_FORMS"] = 0
        data["selection_criteria-MAX_NUM_FORMS"] = 0
        # Drop any None values
        data = {k: v for k, v in data.items() if v is not None}
        # Update with caller data
        data.update(**kwargs)
        rsp = self.client.post(reverse('admin:services_service_change', args=[self.service.pk]),
                               data=data)
        return rsp

    def test_edit_service(self):
        # Make a change to the data
        rsp = self.save_service_in_form(name_en="New service name")
        self.assertEqual(302, rsp.status_code, msg=rsp.content.decode('utf-8'))
        service = Service.objects.get(pk=self.service.pk)
        self.assertEqual("New service name", service.name_en)

    def test_approve_button(self):
        rsp = self.save_service_in_form(name_en="New service name",
                                        _approve=True,  # the button we "clicked"
                                        )
        self.assertEqual(302, rsp.status_code, msg=rsp.content.decode('utf-8'))
        service = Service.objects.get(pk=self.service.pk)
        self.assertEqual("New service name", service.name_en)
        self.assertEqual(Service.STATUS_CURRENT, service.status)

    def test_approve_button_with_bad_data(self):
        rsp = self.save_service_in_form(name_en="New service name",
                                        location="not a valid location",
                                        _approve=True,  # the button we "clicked"
                                        )
        self.assertEqual(200, rsp.status_code, msg=rsp.content.decode('utf-8'))
        self.assertIn('<ul class="errorlist"><li>Invalid geometry value.</li></ul>',
                      rsp.context['errors'])
        service = Service.objects.get(pk=self.service.pk)
        self.assertEqual(Service.STATUS_DRAFT, service.status)

    def test_approve_button_with_missing_data(self):
        rsp = self.save_service_in_form(name_en="New service name",
                                        location='',
                                        _approve=True,  # the button we "clicked"
                                        )
        self.assertEqual(200, rsp.status_code, msg=rsp.content.decode('utf-8'))
        self.assertIn('<ul class="errorlist"><li>No geometry value provided.</li></ul>',
                      rsp.context['errors'])
        service = Service.objects.get(pk=self.service.pk)
        self.assertEqual(Service.STATUS_DRAFT, service.status)

    def test_reject_button(self):
        rsp = self.save_service_in_form(name_en="New service name",
                                        _reject=True,  # the button we "clicked"
                                        )
        self.assertEqual(302, rsp.status_code, msg=rsp.content.decode('utf-8'))
        service = Service.objects.get(pk=self.service.pk)
        self.assertEqual("New service name", service.name_en)
        self.assertEqual(Service.STATUS_REJECTED, service.status)

    def test_actions_appear(self):
        rsp = self.client.get(reverse('admin:services_service_changelist'))
        self.assertContains(rsp, "Approve new or changed service")
        self.assertContains(rsp, "Reject new or changed service")

    def test_buttons_appear(self):
        rsp = self.client.get(reverse('admin:services_service_change', args=[self.service.pk]))
        self.assertContains(rsp, "Save and approve")
        self.assertContains(rsp, "Save and reject")

    def test_approve_action(self):
        self.service.validate_for_approval()
        data = {
            'index': '0',  # "Go" button
            'action': 'approve',  # selected action
            '_selected_action': [
                str(self.service.pk),  # selected checkbox
            ]
        }
        rsp = self.client.post(reverse('admin:services_service_changelist'), data)
        self.assertEqual(302, rsp.status_code, msg=rsp.content.decode('utf-8'))
        new_url = rsp['Location']
        rsp = self.client.get(new_url)
        self.assertEqual(200, rsp.status_code, msg=rsp.content.decode('utf-8'))
        service = Service.objects.get(pk=self.service.pk)
        self.assertEqual(Service.STATUS_CURRENT, service.status)

    def test_reject_action(self):
        data = {
            'index': '0',  # "Go" button
            'action': 'reject',  # selected action
            '_selected_action': [
                str(self.service.pk),  # selected checkbox
            ]
        }
        rsp = self.client.post(reverse('admin:services_service_changelist'), data)
        self.assertEqual(302, rsp.status_code, msg=rsp.content.decode('utf-8'))
        new_url = rsp['Location']
        rsp = self.client.get(new_url)
        self.assertEqual(200, rsp.status_code, msg=rsp.content.decode('utf-8'))
        service = Service.objects.get(pk=self.service.pk)
        self.assertEqual(Service.STATUS_REJECTED, service.status)

    def test_approve_action_wrong_status(self):
        self.service.status = Service.STATUS_CURRENT
        self.service.save()
        data = {
            'index': '0',  # "Go" button
            'action': 'approve',  # selected action
            '_selected_action': [
                str(self.service.pk),  # selected checkbox
            ]
        }
        rsp = self.client.post(reverse('admin:services_service_changelist'), data, follow=True)
        self.assertEqual(200, rsp.status_code)
        self.assertIn('Only services in draft status may be approved',
                      [str(msg) for msg in rsp.context['messages']])

    def test_reject_action_wrong_status(self):
        self.service.status = Service.STATUS_CURRENT
        self.service.save()
        data = {
            'index': '0',  # "Go" button
            'action': 'reject',  # selected action
            '_selected_action': [
                str(self.service.pk),  # selected checkbox
            ]
        }
        rsp = self.client.post(reverse('admin:services_service_changelist'), data, follow=True)
        self.assertEqual(200, rsp.status_code)
        self.assertIn('Only services in draft status may be rejected',
                      [str(msg) for msg in rsp.context['messages']])

    def test_show_image_in_changelist(self):
        rsp = self.client.get(reverse('admin:services_service_changelist'))
        image_tag = '<img src="%s">' % self.service.get_thumbnail_url()
        self.assertContains(rsp, image_tag, html=True)

    def test_show_no_image_if_not_set(self):
        self.service.image = ''
        self.service.save()
        rsp = self.client.get(reverse('admin:services_service_changelist'))
        self.assertContains(rsp, 'no image')
Пример #6
0
class JiraNewServiceTest(MockJiraTestMixin, TestCase):
    def setUp(self):
        self.test_service = ServiceFactory(location='POINT(5 23)')
        self.jira_record = self.test_service.jira_records.get(
            update_type=JiraUpdateRecord.NEW_SERVICE)
        self.staff_user = EmailUserFactory(is_staff=True)

    def test_create_issue_sets_keyval(self, mock_JIRA):
        self.assertEqual('', self.jira_record.jira_issue_key)
        issue_key = self.setup_issue_key(mock_JIRA)
        self.jira_record.do_jira_work()
        self.assertEqual(issue_key, self.jira_record.jira_issue_key)

    def test_create_issue_kwargs(self, mock_JIRA):
        self.test_service.sunday_open = datetime.time(11, 10)
        self.test_service.sunday_close = datetime.time(12, 10)
        self.test_service.saturday_open = datetime.time(17, 18)
        self.test_service.saturday_close = datetime.time(19, 18)
        self.test_service.save()
        self.test_service.provider.focal_point_phone_number = '12-345678'
        self.test_service.provider.number_of_monthly_beneficiaries = '31415'
        self.test_service.provider.save()
        SelectionCriterionFactory(
            service=self.test_service,
            text_en="Must be 18",
            text_ar="Must have passport",
            text_fr="Must have transportation"
        )
        SelectionCriterionFactory(
            service=self.test_service,
            text_en="Must be 21",
            text_ar="Must have shoes",
            text_fr="Must be citizen"
        )
        self.setup_issue_key(mock_JIRA)
        self.jira_record = JiraUpdateRecord.objects.get(pk=self.jira_record.pk)
        self.jira_record.do_jira_work()
        call_args, call_kwargs = mock_JIRA.return_value.create_issue.call_args
        # Expecting: summary, project, issuetype, description, duedate
        self.assertTrue('summary' in call_kwargs)
        self.assertTrue('new service' in call_kwargs['summary'].lower())
        self.assertTrue(self.test_service.provider.name_en in call_kwargs['summary'])
        self.assertTrue('project' in call_kwargs)
        self.assertEqual({'key': settings.JIRA_SERVICES_PROJECT_KEY}, call_kwargs['project'])
        self.assertTrue('issuetype' in call_kwargs)
        self.assertEqual({'name': 'Task'}, call_kwargs['issuetype'])
        self.assertTrue('description' in call_kwargs)
        admin_url = absolute_url(self.test_service.get_admin_edit_url())
        self.assertTrue(
            admin_url in call_kwargs['description'],
            msg='%s not found in %s' % (admin_url, call_kwargs['description']))
        self.assertIn('11:10', call_kwargs['description'])
        self.assertIn('17:18', call_kwargs['description'])
        self.assertIn('Must be 18', call_kwargs['description'])
        self.assertIn('Must have shoes', call_kwargs['description'])
        self.assertIn('12-345678', call_kwargs['description'])
        self.assertIn('31415', call_kwargs['description'])
        self.assertTrue('duedate' in call_kwargs)
        expected_duedate = datetime.date.today() + datetime.timedelta(days=settings.JIRA_DUEIN_DAYS)
        self.assertEqual(str(expected_duedate), call_kwargs['duedate'])
        # We've tested 5, ensure that is all that were passed
        self.assertEqual(5, len(call_kwargs))
        self.assertEqual((), call_args)

    def test_create_issue_kwargs_for_update(self, mock_JIRA):
        self.test_service.update_of = ServiceFactory()
        self.jira_record.update_type = JiraUpdateRecord.CHANGE_SERVICE
        self.jira_record.save()
        self.setup_issue_key(mock_JIRA)
        self.jira_record.do_jira_work()
        call_args, call_kwargs = mock_JIRA.return_value.create_issue.call_args
        # Only checking summary as that has the essentially different value
        # from what the "new service" case sets.
        self.assertTrue('summary' in call_kwargs)
        self.assertTrue('changed service' in call_kwargs['summary'].lower())
        self.assertTrue(self.test_service.provider.name_en in call_kwargs['summary'])

    def test_new_service_then_approve_before_task(self, mock_JIRA):
        # If a service is approved before we try to do the JIRA work,
        # the JIRA work gracefully works
        self.jira_record.update_type = JiraUpdateRecord.NEW_SERVICE
        self.jira_record.save()
        self.test_service.staff_approve(self.staff_user)
        self.setup_issue_key(mock_JIRA)
        self.jira_record.do_jira_work()

    def test_change_service_then_approve_before_task(self, mock_JIRA):
        # If a service is approved before we try to do the JIRA work,
        # the JIRA work gracefully works
        self.test_service.update_of = ServiceFactory()
        self.jira_record.update_type = JiraUpdateRecord.CHANGE_SERVICE
        self.jira_record.save()
        self.test_service.staff_approve(self.staff_user)
        self.setup_issue_key(mock_JIRA)
        self.jira_record.do_jira_work()

    def test_create_jira_issue_noop_if_already_created(self, mock_JIRA):
        test_key_val = 'ALREADY-SET'
        self.jira_record.jira_issue_key = test_key_val
        self.jira_record.save()
        self.jira_record.do_jira_work()
        self.assertFalse(mock_JIRA.called)
        self.assertEqual(test_key_val, self.jira_record.jira_issue_key)

    def test_create_jira_issue_uses_provided_jira(self, mock_JIRA):
        # This 2nd mock will take precendence by default, we test to
        # ensure that if the original mock is passed in it is called.
        with mock.patch('services.jira_support.JIRA') as JIRA:
            issue_key = self.setup_issue_key(mock_JIRA)
            self.jira_record.do_jira_work(mock_JIRA())
            self.assertFalse(JIRA.called)
            self.assertEqual(issue_key, self.jira_record.jira_issue_key)

    def test_cancel_current_service_creates_jira_issue(self, mock_JIRA):
        service = self.jira_record.service
        service.status = service.STATUS_CURRENT
        service.save()
        service.cancel()
        self.jira_record = \
            service.jira_records.get(update_type=JiraUpdateRecord.CANCEL_CURRENT_SERVICE)
        self.jira_record.save()
        self.setup_issue_key(mock_JIRA)
        self.jira_record.do_jira_work()
        call_args, call_kwargs = mock_JIRA.return_value.create_issue.call_args
        # Only checking summary as that has the essentially different value
        # from what the "new service" case sets.
        self.assertTrue('summary' in call_kwargs)
        self.assertTrue('canceled service' in call_kwargs['summary'].lower())
        self.assertTrue(self.test_service.provider.name_en in call_kwargs['summary'])

    def test_cancel_draft_new_service_comments_on_jira_issue(self, mock_JIRA):
        # If we cancel a pending new service, it adds a comment to the
        # existing JIRA issue.

        # First create a record from when the draft service was started
        issue_key = 'XXX-123'
        self.jira_record.jira_issue_key = issue_key
        self.jira_record.save()

        service = self.jira_record.service
        service.status = service.STATUS_DRAFT
        service.save()

        service.cancel()
        cancel_record = service.jira_records.get(update_type=JiraUpdateRecord.CANCEL_DRAFT_SERVICE)

        cancel_record.do_jira_work()
        call_args, call_kwargs = mock_JIRA.return_value.add_comment.call_args
        # Only checking summary as that has the essentially different value
        # from what the "new service" case sets.
        self.assertEqual(issue_key, call_args[0])
        self.assertIn('change was canceled', call_args[1])
        # We should NOT have created a new JIRA record
        self.assertFalse(mock_JIRA.return_value.create_issue.called)

    def test_cancel_draft_service_change_comments_on_jira_issue(self, mock_JIRA):
        # If we cancel a pending change to a current service, it adds a comment
        # to the existing jira issue.

        # make the service we're canceling look like a change to an existing service
        existing_service = ServiceFactory(status=Service.STATUS_CURRENT)
        draft_service = ServiceFactory(
            update_of=existing_service,
            status=Service.STATUS_DRAFT,
        )
        # Pretend we've created a JIRA issue when the draft was started.
        issue_key = 'XXX-123'
        draft_service.jira_records.update(jira_issue_key=issue_key)

        # Now cancel the draft
        draft_service.cancel()

        # We should get a new jira update record created
        cancel_record = \
            draft_service.jira_records.get(update_type=JiraUpdateRecord.CANCEL_DRAFT_SERVICE)
        # run it:
        cancel_record.do_jira_work()
        call_args, call_kwargs = mock_JIRA.return_value.add_comment.call_args
        # Only checking summary as that has the essentially different value
        # from what the "new service" case sets.
        self.assertEqual(issue_key, call_args[0])
        self.assertIn('change was canceled', call_args[1])
        record = JiraUpdateRecord.objects.get(pk=cancel_record.pk)
        self.assertEqual(issue_key, record.jira_issue_key)
        # We should NOT have created a new JIRA record
        self.assertFalse(mock_JIRA.return_value.create_issue.called)

    def test_replacing_a_draft_comments_on_jira_issue(self, mock_JIRA):
        draft_service = ServiceFactory(status=Service.STATUS_DRAFT)
        # Pretend we've created a JIRA issue when the draft was started.
        issue_key = 'XXX-123'
        draft_service.jira_records.update(jira_issue_key=issue_key)
        mock_JIRA.return_value.create_issue.reset_mock()  # Forget we "created a jira record"
        # Now edit the draft
        new_draft = ServiceFactory(update_of=draft_service, status=Service.STATUS_DRAFT)
        # We should have a new update record
        jira_record = new_draft.jira_records.get(update_type=JiraUpdateRecord.SUPERSEDED_DRAFT)
        jira_record.do_jira_work()
        # We should NOT have created another JIRA record
        self.assertFalse(mock_JIRA.return_value.create_issue.called)
        # We add a comment with links to the old and new data
        call_args, call_kwargs = mock_JIRA.return_value.add_comment.call_args
        self.assertEqual(issue_key, call_args[0])
        self.assertIn(new_draft.get_admin_edit_url(), call_args[1])