Skip to content

Commit

Permalink
feat: migrate docs related functions into own module
Browse files Browse the repository at this point in the history
  • Loading branch information
gcharest authored Aug 7, 2024
1 parent 57eae30 commit bfd559f
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 38 deletions.
43 changes: 43 additions & 0 deletions app/modules/incident/incident_document.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Module to manage the incident document used to track the details."""

from integrations.google_workspace import google_docs


def update_incident_document_status(document_id, new_status="Closed"):
"""Update the status of the incident document.
Args:
document_id (str): The ID of the document to update.
new_status (str, optional): The new status to set. Defaults to "Closed".
Returns:
bool: True if the status was updated, False otherwise.
"""
# List of possible statuses to be replaced
possible_statuses = [
"In Progress",
"Open",
"Ready to be Reviewed",
"Reviewed",
"Closed",
]

if new_status not in possible_statuses:
raise ValueError(f"Invalid status: {new_status}")

# Replace all possible statuses with the new status
changes = [
{
"replaceAllText": {
"containsText": {"text": f"Status: {status}", "matchCase": "false"},
"replaceText": f"Status: {new_status}",
}
}
for status in possible_statuses
if status != new_status
]
replies = google_docs.batch_update(document_id, changes)["replies"]
return any(
reply.get("replaceAllText", {}).get("occurrencesChanged", 0) > 0
for reply in replies
)
21 changes: 2 additions & 19 deletions app/modules/incident/incident_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from integrations.google_workspace import google_docs, google_drive
from integrations.slack import channels as slack_channels
from integrations.sentinel import log_to_sentinel
from . import incident_folder, incident_roles, schedule_retro
from . import incident_folder, incident_roles, incident_document, schedule_retro

INCIDENT_CHANNELS_PATTERN = r"^incident-\d{4}-"
SRE_DRIVE_ID = os.environ.get("SRE_DRIVE_ID")
Expand Down Expand Up @@ -155,7 +155,7 @@ def close_incident(client: WebClient, body, ack, respond):

# Update the document status to "Closed" if we can get the document
if document_id != "":
close_incident_document(document_id)
incident_document.update_incident_document_status(document_id)
else:
warning_message = (
"Could not close the incident document - the document was not found."
Expand Down Expand Up @@ -194,23 +194,6 @@ def close_incident(client: WebClient, body, ack, respond):
)


def close_incident_document(document_id):
# List of possible statuses to be replaced
possible_statuses = ["In Progress", "Open", "Ready to be Reviewed", "Reviewed"]

# Replace all possible statuses with "Closed"
changes = [
{
"replaceAllText": {
"containsText": {"text": f"Status: {status}", "matchCase": "false"},
"replaceText": "Status: Closed",
}
}
for status in possible_statuses
]
return google_docs.batch_update(document_id, changes)


def stale_incidents(client, body, ack):
ack()

Expand Down
114 changes: 114 additions & 0 deletions app/tests/modules/incident/test_incident_document.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
from unittest.mock import patch

import pytest
from modules.incident import incident_document


@patch("modules.incident.incident_document.google_docs")
def test_update_incident_document_status_changes_occurred(google_docs_mock):
document_id = "test_document_id"
new_status = "In Progress"
google_docs_mock.batch_update.return_value = {
"replies": [
{"replaceAllText": {"occurrencesChanged": 1}},
{"replaceAllText": {}},
{"replaceAllText": {}},
{"replaceAllText": {}},
]
}

response = incident_document.update_incident_document_status(
document_id, new_status
)
assert response is True

expected_changes = [
{
"replaceAllText": {
"containsText": {"text": "Status: Open", "matchCase": "false"},
"replaceText": f"Status: {new_status}",
}
},
{
"replaceAllText": {
"containsText": {
"text": "Status: Ready to be Reviewed",
"matchCase": "false",
},
"replaceText": f"Status: {new_status}",
}
},
{
"replaceAllText": {
"containsText": {"text": "Status: Reviewed", "matchCase": "false"},
"replaceText": f"Status: {new_status}",
}
},
{
"replaceAllText": {
"containsText": {"text": "Status: Closed", "matchCase": "false"},
"replaceText": f"Status: {new_status}",
}
},
]

google_docs_mock.batch_update.assert_called_once_with(document_id, expected_changes)


@patch("modules.incident.incident_document.google_docs")
def test_update_incident_document_status_no_changes_occurred(google_docs_mock):
document_id = "test_document_id"
new_status = "In Progress"
google_docs_mock.batch_update.return_value = {
"replies": [
{"replaceAllText": {}},
{"replaceAllText": {}},
{"replaceAllText": {}},
{"replaceAllText": {}},
]
}

response = incident_document.update_incident_document_status(
document_id, new_status
)
assert response is False

expected_changes = [
{
"replaceAllText": {
"containsText": {"text": "Status: Open", "matchCase": "false"},
"replaceText": f"Status: {new_status}",
}
},
{
"replaceAllText": {
"containsText": {
"text": "Status: Ready to be Reviewed",
"matchCase": "false",
},
"replaceText": f"Status: {new_status}",
}
},
{
"replaceAllText": {
"containsText": {"text": "Status: Reviewed", "matchCase": "false"},
"replaceText": f"Status: {new_status}",
}
},
{
"replaceAllText": {
"containsText": {"text": "Status: Closed", "matchCase": "false"},
"replaceText": f"Status: {new_status}",
}
},
]

google_docs_mock.batch_update.assert_called_once_with(document_id, expected_changes)


def test_update_incident_document_status_invalid_status():
document_id = "test_document_id"
invalid_status = "Invalid Status"

with pytest.raises(ValueError, match=f"Invalid status: {invalid_status}"):
incident_document.update_incident_document_status(document_id, invalid_status)
38 changes: 19 additions & 19 deletions app/tests/modules/incident/test_incident_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def test_archive_channel_action_ignore(mock_log_to_sentinel):
)


@patch("modules.incident.incident_helper.close_incident_document")
@patch("modules.incident.incident_helper.incident_document.update_incident_document_status")
@patch(
"modules.incident.incident_helper.incident_folder.update_spreadsheet_incident_status"
)
Expand All @@ -124,7 +124,7 @@ def test_archive_channel_action_ignore(mock_log_to_sentinel):
)
@patch("modules.incident.incident_helper.log_to_sentinel")
def test_archive_channel_action_archive(
mock_log_to_sentinel, mock_extract_id, mock_update_spreadsheet, mock_close_document
mock_log_to_sentinel, mock_extract_id, mock_update_spreadsheet, mock_update_document_status
):
client = MagicMock()
body = {
Expand Down Expand Up @@ -193,15 +193,15 @@ def test_channel_item():
]


@patch("modules.incident.incident_helper.close_incident_document")
@patch("modules.incident.incident_helper.incident_document.update_incident_document_status")
@patch(
"modules.incident.incident_helper.incident_folder.update_spreadsheet_incident_status"
)
@patch(
"integrations.google_workspace.google_docs.extract_google_doc_id",
return_value="dummy_document_id",
)
def test_close_incident(mock_extract_id, mock_update_spreadsheet, mock_close_document):
def test_close_incident(mock_extract_id, mock_update_spreadsheet, mock_update_document_status):
mock_client = MagicMock()
mock_ack = MagicMock()
mock_respond = MagicMock()
Expand Down Expand Up @@ -241,22 +241,22 @@ def test_close_incident(mock_extract_id, mock_update_spreadsheet, mock_close_doc
)

# Assert that the Google Drive document and spreadsheet update methods were called
mock_close_document.assert_called_once_with("dummy_document_id")
mock_update_document_status.assert_called_once_with("dummy_document_id")
mock_update_spreadsheet.assert_called_once_with("#2024-01-12-test", "Closed")

# Assert that the Slack client's conversations_archive method was called with the correct channel ID
mock_client.conversations_archive.assert_called_once_with(channel="C12345")


@patch("modules.incident.incident_helper.close_incident_document")
@patch("modules.incident.incident_helper.incident_document.update_incident_document_status")
@patch(
"modules.incident.incident_helper.incident_folder.update_spreadsheet_incident_status"
)
@patch(
"integrations.google_workspace.google_docs.extract_google_doc_id", return_value=None
)
def test_close_incident_no_bookmarks(
mock_extract_id, mock_update_spreadsheet, mock_close_document
mock_extract_id, mock_update_spreadsheet, mock_update_document_status
):
mock_client = MagicMock()
mock_ack = MagicMock()
Expand All @@ -279,19 +279,19 @@ def test_close_incident_no_bookmarks(

# Assertions to ensure that document update functions are not called as there are no bookmarks
mock_extract_id.assert_not_called()
mock_close_document.assert_not_called()
mock_update_document_status.assert_not_called()
mock_update_spreadsheet.assert_called_once_with("#2024-01-12-test", "Closed")


@patch("modules.incident.incident_helper.close_incident_document")
@patch("modules.incident.incident_helper.incident_document.update_incident_document_status")
@patch(
"modules.incident.incident_helper.incident_folder.update_spreadsheet_incident_status"
)
@patch(
"integrations.google_workspace.google_docs.extract_google_doc_id", return_value=None
)
def test_close_incident_no_bookmarks_error(
mock_extract_id, mock_update_spreadsheet, mock_close_document
mock_extract_id, mock_update_spreadsheet, mock_update_document_status
):
mock_client = MagicMock()
mock_ack = MagicMock()
Expand All @@ -314,7 +314,7 @@ def test_close_incident_no_bookmarks_error(

# Assertions to ensure that document update functions are not called as there are no bookmarks
mock_extract_id.assert_not_called()
mock_close_document.assert_not_called()
mock_update_document_status.assert_not_called()
mock_update_spreadsheet.assert_called_once_with("#2024-01-12-test", "Closed")


Expand Down Expand Up @@ -393,7 +393,7 @@ def test_close_incident_cant_send_private_message(caplog):
), "Expected error message not found in log records"


@patch("modules.incident.incident_helper.close_incident_document")
@patch("modules.incident.incident_helper.incident_document.update_incident_document_status")
@patch(
"modules.incident.incident_helper.incident_folder.update_spreadsheet_incident_status"
)
Expand All @@ -402,7 +402,7 @@ def test_close_incident_cant_send_private_message(caplog):
return_value="dummy_document_id",
)
def test_conversations_archive_fail(
mock_extract_id, mock_update_spreadsheet, mock_close_document
mock_extract_id, mock_update_spreadsheet, mock_update_document_status
):
mock_client = MagicMock()
mock_ack = MagicMock()
Expand Down Expand Up @@ -439,14 +439,14 @@ def test_conversations_archive_fail(

# Assertions
# Ensure that the Google Drive document update method was called even if archiving fails
mock_close_document.assert_called_once_with("dummy_document_id")
mock_update_document_status.assert_called_once_with("dummy_document_id")
mock_update_spreadsheet.assert_called_once_with("#2024-01-12-test", "Closed")

# Ensure that the client's conversations_archive method was called
mock_client.conversations_archive.assert_called_once_with(channel="C12345")


@patch("modules.incident.incident_helper.close_incident_document")
@patch("modules.incident.incident_helper.incident_document.update_incident_document_status")
@patch(
"modules.incident.incident_helper.incident_folder.update_spreadsheet_incident_status"
)
Expand All @@ -455,7 +455,7 @@ def test_conversations_archive_fail(
return_value="dummy_document_id",
)
def test_conversations_archive_fail_error_message(
mock_extract_id, mock_update_spreadsheet, mock_close_document, caplog
mock_extract_id, mock_update_spreadsheet, mock_update_document_status, caplog
):
mock_client = MagicMock()
mock_ack = MagicMock()
Expand Down Expand Up @@ -492,7 +492,7 @@ def test_conversations_archive_fail_error_message(

# Assertions
# Ensure that the Google Drive document update method was called even if archiving fails
mock_close_document.assert_called_once_with("dummy_document_id")
mock_update_document_status.assert_called_once_with("dummy_document_id")
mock_update_spreadsheet.assert_called_once_with("#2024-01-12-test", "Closed")

# Ensure that the client's conversations_archive method was called
Expand All @@ -504,7 +504,7 @@ def test_conversations_archive_fail_error_message(
)


@patch("modules.incident.incident_helper.close_incident_document")
@patch("modules.incident.incident_helper.incident_document.update_incident_document_status")
@patch(
"modules.incident.incident_helper.incident_folder.update_spreadsheet_incident_status"
)
Expand All @@ -513,7 +513,7 @@ def test_conversations_archive_fail_error_message(
return_value="dummy_document_id",
)
def test_conversations_archive_succeeds_post_message_who_archived(
mock_extract_id, mock_update_spreadsheet, mock_close_document, caplog
mock_extract_id, mock_update_spreadsheet, mock_update_document_status, caplog
):
mock_client = MagicMock()
mock_ack = MagicMock()
Expand Down

0 comments on commit bfd559f

Please sign in to comment.