Testing Bitbucket Provider Integration in PR-Agent
This test suite validates the BitbucketProvider and BitbucketServerProvider classes, focusing on URL parsing and diff file handling across different Bitbucket versions. The tests verify proper handling of pull request URLs, file content comparisons, and complex merge scenarios.
Test Coverage Overview
Implementation Analysis
Technical Details
Best Practices Demonstrated
codium-ai/pr-agent
tests/unittest/test_bitbucket_provider.py
from unittest.mock import MagicMock
from atlassian.bitbucket import Bitbucket
from pr_agent.algo.types import EDIT_TYPE, FilePatchInfo
from pr_agent.git_providers import BitbucketServerProvider
from pr_agent.git_providers.bitbucket_provider import BitbucketProvider
class TestBitbucketProvider:
def test_parse_pr_url(self):
url = "https://bitbucket.org/WORKSPACE_XYZ/MY_TEST_REPO/pull-requests/321"
workspace_slug, repo_slug, pr_number = BitbucketProvider._parse_pr_url(url)
assert workspace_slug == "WORKSPACE_XYZ"
assert repo_slug == "MY_TEST_REPO"
assert pr_number == 321
class TestBitbucketServerProvider:
def test_parse_pr_url(self):
url = "https://git.onpreminstance.com/projects/AAA/repos/my-repo/pull-requests/1"
workspace_slug, repo_slug, pr_number = BitbucketServerProvider._parse_pr_url(url)
assert workspace_slug == "AAA"
assert repo_slug == "my-repo"
assert pr_number == 1
def mock_get_content_of_file(self, project_key, repository_slug, filename, at=None, markup=None):
content_map = {
'9c1cffdd9f276074bfb6fb3b70fbee62d298b058': 'file
with
some
lines
to
emulate
a
real
file
',
'2a1165446bdf991caf114d01f7c88d84ae7399cf': 'file
with
multiple
lines
to
emulate
a
fake
file
',
'f617708826cdd0b40abb5245eda71630192a17e3': 'file
with
multiple
lines
to
emulate
a
real
file
',
'cb68a3027d6dda065a7692ebf2c90bed1bcdec28': 'file
with
some
changes
to
emulate
a
real
file
',
'1905dcf16c0aac6ac24f7ab617ad09c73dc1d23b': 'file
with
some
lines
to
emulate
a
fake
test
',
'ae4eca7f222c96d396927d48ab7538e2ee13ca63': 'readme
without
some
lines
to
simulate
a
real
file',
'548f8ba15abc30875a082156314426806c3f4d97': 'file
with
some
lines
to
emulate
a
real
file',
'0e898cb355a5170d8c8771b25d43fcaa1d2d9489': 'file
with
multiple
lines
to
emulate
a
real
file'
}
return content_map.get(at, '')
def mock_get_from_bitbucket_60(self, url):
response_map = {
"rest/api/1.0/application-properties": {
"version": "6.0"
}
}
return response_map.get(url, '')
def mock_get_from_bitbucket_70(self, url):
response_map = {
"rest/api/1.0/application-properties": {
"version": "7.0"
}
}
return response_map.get(url, '')
def mock_get_from_bitbucket_816(self, url):
response_map = {
"rest/api/1.0/application-properties": {
"version": "8.16"
},
"rest/api/latest/projects/AAA/repos/my-repo/pull-requests/1/merge-base": {
'id': '548f8ba15abc30875a082156314426806c3f4d97'
}
}
return response_map.get(url, '')
'''
tests the 2-way diff functionality where the diff should be between the HEAD of branch b and node c
NOT between the HEAD of main and the HEAD of branch b
- o branch b
/
o - o - o main
^ node c
'''
def test_get_diff_files_simple_diverge_70(self):
bitbucket_client = MagicMock(Bitbucket)
bitbucket_client.get_pull_request.return_value = {
'toRef': {'latestCommit': '9c1cffdd9f276074bfb6fb3b70fbee62d298b058'},
'fromRef': {'latestCommit': '2a1165446bdf991caf114d01f7c88d84ae7399cf'}
}
bitbucket_client.get_pull_requests_commits.return_value = [
{'id': '2a1165446bdf991caf114d01f7c88d84ae7399cf',
'parents': [{'id': 'f617708826cdd0b40abb5245eda71630192a17e3'}]}
]
bitbucket_client.get_commits.return_value = [
{'id': '9c1cffdd9f276074bfb6fb3b70fbee62d298b058'},
{'id': 'dbca09554567d2e4bee7f07993390153280ee450'}
]
bitbucket_client.get_pull_requests_changes.return_value = [
{
'path': {'toString': 'Readme.md'},
'type': 'MODIFY',
}
]
bitbucket_client.get.side_effect = self.mock_get_from_bitbucket_70
bitbucket_client.get_content_of_file.side_effect = self.mock_get_content_of_file
provider = BitbucketServerProvider(
"https://git.onpreminstance.com/projects/AAA/repos/my-repo/pull-requests/1",
bitbucket_client=bitbucket_client
)
expected = [
FilePatchInfo(
'file
with
multiple
lines
to
emulate
a
real
file
',
'file
with
multiple
lines
to
emulate
a
fake
file
',
'---
+++
@@ -5,5 +5,5 @@
to
emulate
a
-real
+fake
file
',
'Readme.md',
edit_type=EDIT_TYPE.MODIFIED,
)
]
actual = provider.get_diff_files()
assert actual == expected
'''
tests the 2-way diff functionality where the diff should be between the HEAD of branch b and node c
NOT between the HEAD of main and the HEAD of branch b
- o - o - o branch b
/ /
o - o -- o - o main
^ node c
'''
def test_get_diff_files_diverge_with_merge_commit_70(self):
bitbucket_client = MagicMock(Bitbucket)
bitbucket_client.get_pull_request.return_value = {
'toRef': {'latestCommit': 'cb68a3027d6dda065a7692ebf2c90bed1bcdec28'},
'fromRef': {'latestCommit': '1905dcf16c0aac6ac24f7ab617ad09c73dc1d23b'}
}
bitbucket_client.get_pull_requests_commits.return_value = [
{'id': '1905dcf16c0aac6ac24f7ab617ad09c73dc1d23b',
'parents': [{'id': '692772f456c3db77a90b11ce39ea516f8c2bad93'}]},
{'id': '692772f456c3db77a90b11ce39ea516f8c2bad93', 'parents': [
{'id': '2a1165446bdf991caf114d01f7c88d84ae7399cf'},
{'id': '9c1cffdd9f276074bfb6fb3b70fbee62d298b058'},
]},
{'id': '2a1165446bdf991caf114d01f7c88d84ae7399cf',
'parents': [{'id': 'f617708826cdd0b40abb5245eda71630192a17e3'}]}
]
bitbucket_client.get_commits.return_value = [
{'id': 'cb68a3027d6dda065a7692ebf2c90bed1bcdec28'},
{'id': '9c1cffdd9f276074bfb6fb3b70fbee62d298b058'},
{'id': 'dbca09554567d2e4bee7f07993390153280ee450'}
]
bitbucket_client.get_pull_requests_changes.return_value = [
{
'path': {'toString': 'Readme.md'},
'type': 'MODIFY',
}
]
bitbucket_client.get.side_effect = self.mock_get_from_bitbucket_70
bitbucket_client.get_content_of_file.side_effect = self.mock_get_content_of_file
provider = BitbucketServerProvider(
"https://git.onpreminstance.com/projects/AAA/repos/my-repo/pull-requests/1",
bitbucket_client=bitbucket_client
)
expected = [
FilePatchInfo(
'file
with
some
lines
to
emulate
a
real
file
',
'file
with
some
lines
to
emulate
a
fake
test
',
'---
+++
@@ -5,5 +5,5 @@
to
emulate
a
-real
-file
+fake
+test
',
'Readme.md',
edit_type=EDIT_TYPE.MODIFIED,
)
]
actual = provider.get_diff_files()
assert actual == expected
'''
tests the 2-way diff functionality where the diff should be between the HEAD of branch c and node d
NOT between the HEAD of main and the HEAD of branch c
---- o - o branch c
/ /
---- o branch b
/ /
o - o - o main
^ node d
'''
def get_multi_merge_diverge_mock_client(self, api_version):
bitbucket_client = MagicMock(Bitbucket)
bitbucket_client.get_pull_request.return_value = {
'toRef': {'latestCommit': '9569922b22fe4fd0968be6a50ed99f71efcd0504'},
'fromRef': {'latestCommit': 'ae4eca7f222c96d396927d48ab7538e2ee13ca63'}
}
bitbucket_client.get_pull_requests_commits.return_value = [
{'id': 'ae4eca7f222c96d396927d48ab7538e2ee13ca63',
'parents': [{'id': 'bbf300fb3af5129af8c44659f8cc7a526a6a6f31'}]},
{'id': 'bbf300fb3af5129af8c44659f8cc7a526a6a6f31', 'parents': [
{'id': '10b7b8e41cb370b48ceda8da4e7e6ad033182213'},
{'id': 'd1bb183c706a3ebe4c2b1158c25878201a27ad8c'},
]},
{'id': 'd1bb183c706a3ebe4c2b1158c25878201a27ad8c', 'parents': [
{'id': '5bd76251866cb415fc5ff232f63a581e89223bda'},
{'id': '548f8ba15abc30875a082156314426806c3f4d97'}
]},
{'id': '5bd76251866cb415fc5ff232f63a581e89223bda',
'parents': [{'id': '0e898cb355a5170d8c8771b25d43fcaa1d2d9489'}]},
{'id': '10b7b8e41cb370b48ceda8da4e7e6ad033182213',
'parents': [{'id': '0e898cb355a5170d8c8771b25d43fcaa1d2d9489'}]}
]
bitbucket_client.get_commits.return_value = [
{'id': '9569922b22fe4fd0968be6a50ed99f71efcd0504'},
{'id': '548f8ba15abc30875a082156314426806c3f4d97'}
]
bitbucket_client.get_pull_requests_changes.return_value = [
{
'path': {'toString': 'Readme.md'},
'type': 'MODIFY',
}
]
bitbucket_client.get_content_of_file.side_effect = self.mock_get_content_of_file
if api_version == 60:
bitbucket_client.get.side_effect = self.mock_get_from_bitbucket_60
elif api_version == 70:
bitbucket_client.get.side_effect = self.mock_get_from_bitbucket_70
elif api_version == 816:
bitbucket_client.get.side_effect = self.mock_get_from_bitbucket_816
return bitbucket_client
def test_get_diff_files_multi_merge_diverge_60(self):
bitbucket_client = self.get_multi_merge_diverge_mock_client(60)
provider = BitbucketServerProvider(
"https://git.onpreminstance.com/projects/AAA/repos/my-repo/pull-requests/1",
bitbucket_client=bitbucket_client
)
expected = [
FilePatchInfo(
'file
with
multiple
lines
to
emulate
a
real
file',
'readme
without
some
lines
to
simulate
a
real
file',
'---
+++
@@ -1,9 +1,9 @@
-file
-with
-multiple
+readme
+without
+some
lines
to
-emulate
+simulate
a
real
file',
'Readme.md',
edit_type=EDIT_TYPE.MODIFIED,
)
]
actual = provider.get_diff_files()
assert actual == expected
def test_get_diff_files_multi_merge_diverge_70(self):
bitbucket_client = self.get_multi_merge_diverge_mock_client(70)
provider = BitbucketServerProvider(
"https://git.onpreminstance.com/projects/AAA/repos/my-repo/pull-requests/1",
bitbucket_client=bitbucket_client
)
expected = [
FilePatchInfo(
'file
with
some
lines
to
emulate
a
real
file',
'readme
without
some
lines
to
simulate
a
real
file',
'---
+++
@@ -1,9 +1,9 @@
-file
-with
+readme
+without
some
lines
to
-emulate
+simulate
a
real
file',
'Readme.md',
edit_type=EDIT_TYPE.MODIFIED,
)
]
actual = provider.get_diff_files()
assert actual == expected
def test_get_diff_files_multi_merge_diverge_816(self):
bitbucket_client = self.get_multi_merge_diverge_mock_client(816)
provider = BitbucketServerProvider(
"https://git.onpreminstance.com/projects/AAA/repos/my-repo/pull-requests/1",
bitbucket_client=bitbucket_client
)
expected = [
FilePatchInfo(
'file
with
some
lines
to
emulate
a
real
file',
'readme
without
some
lines
to
simulate
a
real
file',
'---
+++
@@ -1,9 +1,9 @@
-file
-with
+readme
+without
some
lines
to
-emulate
+simulate
a
real
file',
'Readme.md',
edit_type=EDIT_TYPE.MODIFIED,
)
]
actual = provider.get_diff_files()
assert actual == expected