|
1 | 1 | import unittest
|
2 |
| -from unittest.mock import MagicMock |
| 2 | +from unittest.mock import MagicMock, patch |
3 | 3 |
|
4 | 4 | from johen import generate
|
5 | 5 |
|
6 | 6 | from seer.automation.autofix.autofix_context import AutofixContext
|
7 |
| -from seer.automation.autofix.models import AutofixContinuation, AutofixRequest |
8 |
| -from seer.automation.codebase.models import QueryResultDocumentChunk |
9 |
| -from seer.automation.models import ( |
10 |
| - EventDetails, |
11 |
| - ExceptionDetails, |
12 |
| - IssueDetails, |
13 |
| - SentryEventData, |
14 |
| - Stacktrace, |
15 |
| - StacktraceFrame, |
| 7 | +from seer.automation.autofix.models import ( |
| 8 | + AutofixContinuation, |
| 9 | + AutofixRequest, |
| 10 | + AutofixStatus, |
| 11 | + ChangesStep, |
| 12 | + CodebaseChange, |
| 13 | + CodebaseState, |
| 14 | + StepType, |
16 | 15 | )
|
17 |
| -from seer.automation.state import LocalMemoryState |
| 16 | +from seer.automation.autofix.state import ContinuationState |
| 17 | +from seer.automation.codebase.models import QueryResultDocumentChunk, RepositoryInfo |
| 18 | +from seer.automation.models import FileChange, IssueDetails, SentryEventData |
| 19 | +from seer.automation.state import DbState, LocalMemoryState |
| 20 | +from seer.db import DbPrIdToAutofixRunIdMapping, Session |
18 | 21 |
|
19 | 22 |
|
20 | 23 | class TestAutofixContext(unittest.TestCase):
|
@@ -56,5 +59,94 @@ def test_multi_codebase_query(self):
|
56 | 59 | self.assertEqual(result_chunks, sorted_chunks)
|
57 | 60 |
|
58 | 61 |
|
| 62 | +class TestAutofixContextPrCommit(unittest.TestCase): |
| 63 | + def setUp(self): |
| 64 | + error_event = next(generate(SentryEventData)) |
| 65 | + self.state = ContinuationState.new( |
| 66 | + AutofixContinuation( |
| 67 | + request=AutofixRequest( |
| 68 | + organization_id=1, |
| 69 | + project_id=1, |
| 70 | + repos=[], |
| 71 | + issue=IssueDetails(id=0, title="", events=[error_event], short_id="ISSUE_1"), |
| 72 | + ), |
| 73 | + ) |
| 74 | + ) |
| 75 | + self.autofix_context = AutofixContext( |
| 76 | + self.state, MagicMock(), MagicMock(), skip_loading_codebase=True |
| 77 | + ) |
| 78 | + self.autofix_context._get_org_slug = MagicMock(return_value="slug") |
| 79 | + |
| 80 | + @patch( |
| 81 | + "seer.automation.autofix.autofix_context.CodebaseIndex.get_repo_info_from_db", |
| 82 | + return_value=RepositoryInfo( |
| 83 | + id=1, |
| 84 | + organization=1, |
| 85 | + project=1, |
| 86 | + provider="github", |
| 87 | + external_slug="getsentry/slug", |
| 88 | + external_id="1", |
| 89 | + ), |
| 90 | + ) |
| 91 | + @patch("seer.automation.autofix.autofix_context.RepoClient") |
| 92 | + def test_commit_changes(self, mock_RepoClient, mock_get_repo_info_from_db): |
| 93 | + mock_repo_client = MagicMock() |
| 94 | + mock_repo_client.create_branch_from_changes.return_value = "test_branch" |
| 95 | + mock_pr = MagicMock(number=1, html_url="http://test.com", id=123) |
| 96 | + mock_repo_client.create_pr_from_branch.return_value = mock_pr |
| 97 | + |
| 98 | + mock_RepoClient.from_repo_info.return_value = mock_repo_client |
| 99 | + |
| 100 | + with self.state.update() as cur: |
| 101 | + cur.codebases = { |
| 102 | + 1: CodebaseState( |
| 103 | + repo_id=1, |
| 104 | + namespace_id=1, |
| 105 | + file_changes=[ |
| 106 | + FileChange( |
| 107 | + path="test.py", |
| 108 | + reference_snippet="test", |
| 109 | + change_type="edit", |
| 110 | + new_snippet="test2", |
| 111 | + description="test", |
| 112 | + ) |
| 113 | + ], |
| 114 | + ) |
| 115 | + } |
| 116 | + cur.steps = [ |
| 117 | + ChangesStep( |
| 118 | + id="changes", |
| 119 | + title="changes_title", |
| 120 | + type=StepType.CHANGES, |
| 121 | + status=AutofixStatus.PENDING, |
| 122 | + index=0, |
| 123 | + changes=[ |
| 124 | + CodebaseChange( |
| 125 | + repo_id=1, |
| 126 | + repo_name="test", |
| 127 | + title="This is the title", |
| 128 | + description="This is the description", |
| 129 | + ) |
| 130 | + ], |
| 131 | + ) |
| 132 | + ] |
| 133 | + |
| 134 | + self.autofix_context.commit_changes() |
| 135 | + |
| 136 | + mock_repo_client.create_pr_from_branch.assert_called_once_with( |
| 137 | + "test_branch", |
| 138 | + "🤖 This is the title", |
| 139 | + "👋 Hi there! This PR was automatically generated 🤖\n\n\nFixes [ISSUE_1](https://sentry.io/organizations/slug/issues/0/)\n\nThis is the description\n\n### 📣 Instructions for the reviewer which is you, yes **you**:\n- **If these changes were incorrect, please close this PR and comment explaining why.**\n- **If these changes were incomplete, please continue working on this PR then merge it.**\n- **If you are feeling confident in my changes, please merge this PR.**\n\nThis will greatly help us improve the autofix system. Thank you! 🙏\n\nIf there are any questions, please reach out to the [AI/ML Team](https://github.com/orgs/getsentry/teams/machine-learning-ai) on [#proj-autofix](https://sentry.slack.com/archives/C06904P7Z6E)\n\n### 🤓 Stats for the nerds:\nPrompt tokens: **0**\nCompletion tokens: **0**\nTotal tokens: **0**", |
| 140 | + ) |
| 141 | + |
| 142 | + with Session() as session: |
| 143 | + pr_mapping = session.query(DbPrIdToAutofixRunIdMapping).filter_by(pr_id=123).first() |
| 144 | + self.assertIsNotNone(pr_mapping) |
| 145 | + |
| 146 | + if pr_mapping: |
| 147 | + cur = self.state.get() |
| 148 | + self.assertEqual(pr_mapping.run_id, cur.run_id) |
| 149 | + |
| 150 | + |
59 | 151 | if __name__ == "__main__":
|
60 | 152 | unittest.main()
|
0 commit comments