def test_not_acked(self): incident_acked = StatefulIncidentFactory() user = PersonUserFactory() # Create an expired ack incident_acked.create_ack(user, expiration=self.timestamp) result = Incident.objects.not_acked() self.assertEqual(set(result), set(Incident.objects.all()))
def test_update_expired_ack_should_fail(self): incident = StatefulIncidentFactory() timestamp_in_the_past = timezone.now() - datetime.timedelta(days=30) ack = incident.create_ack(self.user, expiration=timestamp_in_the_past) validated_data = {"expiration": None} serializer = UpdateAcknowledgementSerializer() with self.assertRaises(serializers.ValidationError) as e: updated_ack = serializer.update(ack, validated_data)
def test_update_golden_path(self): incident = StatefulIncidentFactory() ack = incident.create_ack(self.user, expiration=None) self.assertFalse(ack.expiration) validated_data = {"expiration": timezone.now()} serializer = UpdateAcknowledgementSerializer() updated_ack = serializer.update(ack, validated_data) self.assertEqual(ack, updated_ack) self.assertTrue(updated_ack.expiration)
def setUp(self): disconnect_signals() super().init_test_objects() self.stateful_incident1 = StatefulIncidentFactory( start_time=make_aware(datetime(2000, 1, 1)), end_time=timezone.now() + timedelta(weeks=1), source=self.source1, source_incident_id="1", ) self.stateless_incident1 = duplicate(self.stateful_incident1, end_time=None, source_incident_id="2") self.events_url = lambda incident: reverse("v1:incident:incident-events", args=[incident.pk])
def setUp(self): disconnect_signals() # Lock in timestamps self.timestamp = timezone.now() # We don't care about source but let's ensure it is unique source = SourceSystemFactory() self.incident1 = StatelessIncidentFactory(source=source, start_time=self.timestamp, ticket_url="") self.incident2 = StatefulIncidentFactory(source=source, start_time=self.timestamp, ticket_url="") self.incident3 = StatefulIncidentFactory(source=source, start_time=self.timestamp, ticket_url="") self.incident4 = StatefulIncidentFactory(source=source, start_time=self.timestamp) self.incident4.end_time = self.timestamp self.incident4.save()
def test_validate_event_type_for_incident_acknowledge_raises_validation_error( self): incident = StatefulIncidentFactory(source=self.source) viewfactory = RequestFactory() request = viewfactory.get(f"/api/v1/incidents/{incident.pk}/events/") request.versioning_scheme = versioning.NamespaceVersioning() request.version = "v1" view = EventViewSet() view.request = request with self.assertRaises(serializers.ValidationError): view.validate_event_type_for_incident(Event.Type.ACKNOWLEDGE, incident)
def test_create_golden_path(self): request = self.request_factory.post("/") request.user = self.user incident = StatefulIncidentFactory() timestamp = timezone.now() data = { "event": { "actor": {}, # Forced to request.user "timestamp": timestamp.isoformat(), "type": "STA", # Forced to ACK "description": "string", }, "expiration": None, } serializer = AcknowledgementSerializer(data=data, context={"request": request}) serializer.is_valid() validated_data = serializer.validated_data validated_data["actor"] = self.user validated_data["incident"] = incident ack = serializer.create(validated_data) self.assertEqual(ack.event.incident, incident) self.assertEqual(ack.event.type, "ACK")
class IncidentQuerySetTestCase(TestCase): def setUp(self): disconnect_signals() # Lock in timestamps self.timestamp = timezone.now() # We don't care about source but let's ensure it is unique source = SourceSystemFactory() self.incident1 = StatelessIncidentFactory(source=source, start_time=self.timestamp, ticket_url="") self.incident2 = StatefulIncidentFactory(source=source, start_time=self.timestamp, ticket_url="") self.incident3 = StatefulIncidentFactory(source=source, start_time=self.timestamp, ticket_url="") self.incident4 = StatefulIncidentFactory(source=source, start_time=self.timestamp) self.incident4.end_time = self.timestamp self.incident4.save() def tearDown(self): connect_signals() def test_stateful(self): result = Incident.objects.stateful() self.assertNotIn(self.incident1, result) def test_stateless(self): result = Incident.objects.stateless() self.assertEqual(result.get(), self.incident1) def test_open(self): result = Incident.objects.open() self.assertEqual(set(result), set((self.incident2, self.incident3))) def test_closed(self): result = Incident.objects.closed() self.assertEqual(result.get(), self.incident4) def test_acked(self): incident_acked = StatefulIncidentFactory() user = PersonUserFactory() incident_acked.create_ack(user) result = Incident.objects.acked() self.assertEqual(result.get(), incident_acked) def test_not_acked(self): incident_acked = StatefulIncidentFactory() user = PersonUserFactory() # Create an expired ack incident_acked.create_ack(user, expiration=self.timestamp) result = Incident.objects.not_acked() self.assertEqual(set(result), set(Incident.objects.all())) def test_has_ticket(self): result = Incident.objects.has_ticket() self.assertEqual(result.get(), self.incident4) def test_lacks_ticket(self): result = Incident.objects.lacks_ticket() self.assertEqual(set(result), set((self.incident1, self.incident2, self.incident3)))
def test_acked(self): incident_acked = StatefulIncidentFactory() user = PersonUserFactory() incident_acked.create_ack(user) result = Incident.objects.acked() self.assertEqual(result.get(), incident_acked)
class EventAPITests(APITestCase, IncidentBasedAPITestCaseHelper): def setUp(self): disconnect_signals() super().init_test_objects() self.stateful_incident1 = StatefulIncidentFactory( start_time=make_aware(datetime(2000, 1, 1)), end_time=timezone.now() + timedelta(weeks=1), source=self.source1, source_incident_id="1", ) self.stateless_incident1 = duplicate(self.stateful_incident1, end_time=None, source_incident_id="2") self.events_url = lambda incident: reverse("v1:incident:incident-events", args=[incident.pk]) def tearDown(self): connect_signals() @staticmethod def _create_event_dict(event_type: str): return { "timestamp": timezone.now(), "type": event_type, } def _assert_response_field_invalid(self, response, field_name: str): self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertIn(field_name, response.data) self.assertEqual(response.data[field_name].code, "invalid") def _assert_posting_event_is_rejected_and_does_not_change_end_time( self, post_data: dict, original_end_time: datetime, client: Client ): event_count = Event.objects.count() response = client.post(self.events_url(self.stateful_incident1), post_data) self._assert_response_field_invalid(response, "type") self.assertEqual(Event.objects.count(), event_count) self.stateful_incident1.refresh_from_db() self.assertEqual(self.stateful_incident1.end_time, original_end_time) def _assert_posting_event_succeeds(self, post_data: dict, client: Client): event_count = self.stateful_incident1.events.count() response = client.post(self.events_url(self.stateful_incident1), post_data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(self.stateful_incident1.events.count(), event_count + 1) self.assertTrue(self.stateful_incident1.events.filter(pk=response.data["pk"]).exists()) self.assertEqual(response.data["incident"], self.stateful_incident1.pk) def test_posting_close_and_reopen_events_properly_changes_stateful_incidents(self): self.assertTrue(self.stateful_incident1.stateful) self.assertTrue(self.stateful_incident1.open) # Test closing incident close_event_dict = self._create_event_dict(Event.Type.CLOSE) event_timestamp = close_event_dict["timestamp"] response = self.user1_rest_client.post(self.events_url(self.stateful_incident1), close_event_dict) self.assertEqual(parse_datetime(response.data["timestamp"]), event_timestamp) self.stateful_incident1.refresh_from_db() self.assertFalse(self.stateful_incident1.open) set_end_time = self.stateful_incident1.end_time self.assertEqual(set_end_time, event_timestamp) # It's illegal to close an already closed incident self._assert_posting_event_is_rejected_and_does_not_change_end_time( close_event_dict, set_end_time, self.user1_rest_client ) # Test reopening incident reopen_event_dict = self._create_event_dict(Event.Type.REOPEN) response = self.user1_rest_client.post(self.events_url(self.stateful_incident1), reopen_event_dict) self.assertEqual(parse_datetime(response.data["timestamp"]), reopen_event_dict["timestamp"]) self.stateful_incident1.refresh_from_db() self.assertTrue(self.stateful_incident1.open) set_end_time = self.stateful_incident1.end_time self.assertEqual(datetime_utils.make_naive(set_end_time), datetime.max) # It's illegal to reopen an already opened incident self._assert_posting_event_is_rejected_and_does_not_change_end_time( reopen_event_dict, set_end_time, self.user1_rest_client ) def test_posting_close_and_reopen_events_does_not_change_stateless_incidents(self): def assert_incident_stateless(): self.stateless_incident1.refresh_from_db() self.assertFalse(self.stateless_incident1.stateful) self.assertFalse(self.stateless_incident1.open) assert_incident_stateless() response = self.user1_rest_client.post( self.events_url(self.stateless_incident1), self._create_event_dict(Event.Type.CLOSE) ) self._assert_response_field_invalid(response, "type") assert_incident_stateless() response = self.user1_rest_client.post( self.events_url(self.stateless_incident1), self._create_event_dict(Event.Type.REOPEN) ) self._assert_response_field_invalid(response, "type") assert_incident_stateless() def test_posting_allowed_event_types_for_source_system_is_valid(self): def delete_start_event(incident: Incident): incident.start_event.delete() source_system_allowed_types_and_preconditions = { Event.Type.INCIDENT_START: delete_start_event, Event.Type.INCIDENT_END: lambda incident: None, Event.Type.OTHER: lambda incident: None, } for event_type, ensure_precondition in source_system_allowed_types_and_preconditions.items(): with self.subTest(event_type=event_type): ensure_precondition(self.stateful_incident1) self._assert_posting_event_succeeds(self._create_event_dict(event_type), self.source1_rest_client) def test_posting_allowed_event_types_for_end_user_is_valid(self): def set_end_time_to(end_time): def set_end_time(incident: Incident): incident.end_time = end_time incident.save() return set_end_time end_user_allowed_types_and_preconditions = { Event.Type.CLOSE: set_end_time_to("infinity"), Event.Type.REOPEN: set_end_time_to(timezone.now()), Event.Type.OTHER: lambda incident: None, } for event_type, ensure_precondition in end_user_allowed_types_and_preconditions.items(): with self.subTest(event_type=event_type): ensure_precondition(self.stateful_incident1) self._assert_posting_event_succeeds(self._create_event_dict(event_type), self.user1_rest_client) def test_posting_disallowed_event_types_for_source_system_is_invalid(self): original_end_time = self.stateful_incident1.end_time source_system_disallowed_types = set(Event.Type.values) - Event.ALLOWED_TYPES_FOR_SOURCE_SYSTEMS for event_type in source_system_disallowed_types: with self.subTest(event_type=event_type): self._assert_posting_event_is_rejected_and_does_not_change_end_time( self._create_event_dict(event_type), original_end_time, self.source1_rest_client ) def test_posting_disallowed_event_types_for_end_user_is_invalid(self): original_end_time = self.stateful_incident1.end_time end_user_disallowed_types = set(Event.Type.values) - Event.ALLOWED_TYPES_FOR_END_USERS for event_type in end_user_disallowed_types: with self.subTest(event_type=event_type): self._assert_posting_event_is_rejected_and_does_not_change_end_time( self._create_event_dict(event_type), original_end_time, self.user1_rest_client )
def test_get_details_url_is_link_if_base_url_and_details_url(self): detail_url = "foo" incident = StatefulIncidentFactory.build(source=self.source_has_base_url, details_url=detail_url) incident_admin = IncidentAdmin(incident._meta.model, AdminSite()) result = incident_admin.get_details_url(incident) self.assertTrue(result.startswith(f'<a href="{self.base_url}'))
def test_pp_details_url_has_base_url_absolute_url(self): detail_url = "foo" incident = StatefulIncidentFactory.build(source=self.source_has_base_url, details_url=detail_url) self.assertTrue(incident.pp_details_url().startswith(self.base_url)) self.assertTrue(incident.pp_details_url().endswith(detail_url))
def test_pp_details_url_has_base_url_empty_string(self): detail_url = "" incident = StatefulIncidentFactory.build(source=self.source_has_base_url, details_url=detail_url) self.assertEqual(incident.pp_details_url(), detail_url)
def test_pp_details_url_relative_url(self): detail_url = "foo" incident = StatefulIncidentFactory.build(source=self.source_no_base_url, details_url=detail_url) self.assertEqual(incident.pp_details_url(), detail_url)