Skip to content

Commit 55990f7

Browse files
Merge pull request #4 from matthew-on-git/add_test
feat: add tests made with cursor
2 parents e4d0d7c + cc5dae7 commit 55990f7

File tree

7 files changed

+394
-0
lines changed

7 files changed

+394
-0
lines changed

.github/workflows/test.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: Test
2+
3+
on: [push, pull_request]
4+
5+
jobs:
6+
test:
7+
runs-on: ubuntu-latest
8+
strategy:
9+
matrix:
10+
python-version: ["3.9", "3.10"]
11+
steps:
12+
- uses: actions/checkout@v4
13+
- name: Set up Python ${{ matrix.python-version }}
14+
uses: actions/setup-python@v3
15+
with:
16+
python-version: ${{ matrix.python-version }}
17+
- name: Install dependencies
18+
run: |
19+
python -m pip install --upgrade pip
20+
pip install -r requirements.txt
21+
- name: Run unittests
22+
run: |
23+
python -m unittest discover

tests/__init__.py

Whitespace-only changes.

tests/test_api.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
"""Unit tests for Bitbucket API logic in manage_bitbucket_env.py."""
2+
import unittest
3+
from unittest.mock import patch, Mock
4+
from typing import Optional
5+
6+
from manage_bitbucket_env import get_environment_uuid, get_variables
7+
8+
class TestAPI(unittest.TestCase):
9+
"""Test API-related functions."""
10+
# pylint: disable=attribute-defined-outside-init
11+
logger: Optional[Mock] = None
12+
auth: Optional[Mock] = None
13+
workspace: Optional[str] = None
14+
repo_slug: Optional[str] = None
15+
deployment_name: Optional[str] = None
16+
env_uuid: Optional[str] = None
17+
18+
def setUp(self):
19+
"""Set up test fixtures."""
20+
self.logger: Mock = Mock()
21+
self.auth: Mock = Mock()
22+
self.workspace: str = 'ws'
23+
self.repo_slug: str = 'repo'
24+
self.deployment_name: str = 'env'
25+
self.env_uuid: str = 'uuid-123'
26+
27+
@patch('manage_bitbucket_env.requests.get')
28+
def test_get_environment_uuid_found(self, mock_get):
29+
"""Test successful environment UUID retrieval."""
30+
mock_resp = Mock()
31+
mock_resp.json.return_value = {
32+
"values": [{"name": "env", "uuid": "uuid-123"}]
33+
}
34+
mock_resp.raise_for_status.return_value = None
35+
mock_get.return_value = mock_resp
36+
uuid = get_environment_uuid(
37+
self.workspace, self.repo_slug, self.deployment_name,
38+
self.auth, self.logger
39+
)
40+
self.assertEqual(uuid, 'uuid-123')
41+
mock_get.assert_called_once()
42+
43+
@patch('manage_bitbucket_env.requests.get')
44+
def test_get_environment_uuid_not_found(self, mock_get):
45+
"""Test environment UUID retrieval when environment not found."""
46+
mock_resp = Mock()
47+
mock_resp.json.return_value = {
48+
"values": [{"name": "other", "uuid": "uuid-999"}]
49+
}
50+
mock_resp.raise_for_status.return_value = None
51+
mock_get.return_value = mock_resp
52+
with self.assertRaises(ValueError):
53+
get_environment_uuid(
54+
self.workspace, self.repo_slug, self.deployment_name,
55+
self.auth, self.logger
56+
)
57+
58+
@patch('manage_bitbucket_env.requests.get')
59+
def test_get_variables(self, mock_get):
60+
"""Test successful variable retrieval."""
61+
mock_resp = Mock()
62+
mock_resp.json.return_value = {
63+
"values": [{"key": "A", "value": "1", "secured": False}]
64+
}
65+
mock_resp.raise_for_status.return_value = None
66+
mock_get.return_value = mock_resp
67+
result_vars = get_variables(
68+
self.workspace, self.repo_slug, self.env_uuid,
69+
self.auth, self.logger
70+
)
71+
self.assertEqual(result_vars[0]["key"], "A")
72+
73+
if __name__ == '__main__':
74+
unittest.main()

tests/test_arg_parser.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"""Unit tests for argument parsing in manage_bitbucket_env.py."""
2+
import unittest
3+
from unittest.mock import patch
4+
import sys
5+
6+
from manage_bitbucket_env import arg_parser
7+
8+
class TestArgParser(unittest.TestCase):
9+
"""Test argument parsing functionality."""
10+
11+
def test_export_args(self):
12+
"""Test parsing arguments for exporting variables."""
13+
test_args = [
14+
'prog', '-w', 'ws', '-r', 'repo', '-d', 'env', '-o', 'out.json'
15+
]
16+
with patch.object(sys, 'argv', test_args):
17+
args = arg_parser()
18+
self.assertEqual(args.workspace, 'ws')
19+
self.assertEqual(args.repo_slug, 'repo')
20+
self.assertEqual(args.deployment_name, 'env')
21+
self.assertEqual(args.output, 'out.json')
22+
23+
def test_import_args(self):
24+
"""Test parsing arguments for importing variables."""
25+
test_args = [
26+
'prog', '-w', 'ws', '-r', 'repo', '-d', 'env', '-i', 'in.json'
27+
]
28+
with patch.object(sys, 'argv', test_args):
29+
args = arg_parser()
30+
self.assertEqual(args.import_file, 'in.json')
31+
32+
def test_mutually_exclusive(self):
33+
"""Test that mutually exclusive arguments raise an error."""
34+
test_args = [
35+
'prog', '-w', 'ws', '-r', 'repo', '-d', 'env'
36+
]
37+
with patch.object(sys, 'argv', test_args):
38+
with self.assertRaises(SystemExit):
39+
arg_parser()
40+
41+
if __name__ == '__main__':
42+
unittest.main()

tests/test_export_import.py

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
"""Unit tests for export/import logic in manage_bitbucket_env.py."""
2+
# pylint: disable=duplicate-code
3+
import unittest
4+
from unittest.mock import patch, Mock
5+
import os
6+
import tempfile
7+
import json
8+
from typing import Optional
9+
10+
from manage_bitbucket_env import (
11+
export_variables, export_all_variables, export_secure_keys, import_variables
12+
)
13+
14+
class TestExportImport(unittest.TestCase):
15+
"""Test export and import functionality."""
16+
# pylint: disable=attribute-defined-outside-init
17+
logger: Optional[Mock] = None
18+
auth: Optional[Mock] = None
19+
workspace: Optional[str] = None
20+
repo_slug: Optional[str] = None
21+
deployment_name: Optional[str] = None
22+
env_uuid: Optional[str] = None
23+
24+
def setUp(self):
25+
"""Set up test fixtures."""
26+
self.logger: Mock = Mock()
27+
self.auth: Mock = Mock()
28+
self.workspace: str = 'ws'
29+
self.repo_slug: str = 'repo'
30+
self.deployment_name: str = 'env'
31+
self.env_uuid: str = 'uuid-123'
32+
33+
@patch('manage_bitbucket_env.get_environment_uuid')
34+
@patch('manage_bitbucket_env.get_variables')
35+
def test_export_variables(self, mock_get_vars, mock_get_uuid):
36+
"""Test successful export of non-secured variables."""
37+
mock_get_uuid.return_value = self.env_uuid
38+
mock_get_vars.return_value = [
39+
{"key": "A", "value": "1", "secured": False},
40+
{"key": "B", "value": "2", "secured": True}
41+
]
42+
with tempfile.NamedTemporaryFile(delete=False) as tf:
43+
fname = tf.name
44+
try:
45+
export_variables(
46+
self.workspace, self.repo_slug, self.deployment_name,
47+
fname, self.auth, self.logger
48+
)
49+
with open(fname, encoding="utf-8") as f:
50+
data = json.load(f)
51+
self.assertEqual(len(data), 1)
52+
self.assertEqual(data[0]["key"], "A")
53+
finally:
54+
os.unlink(fname)
55+
56+
@patch('manage_bitbucket_env.get_environment_uuid')
57+
@patch('manage_bitbucket_env.get_variables')
58+
def test_export_all_variables(self, mock_get_vars, mock_get_uuid):
59+
"""Test successful export of all variables."""
60+
mock_get_uuid.return_value = self.env_uuid
61+
mock_get_vars.return_value = [
62+
{"key": "A", "value": "1", "secured": False},
63+
{"key": "B", "value": "2", "secured": True}
64+
]
65+
with tempfile.NamedTemporaryFile(delete=False) as tf:
66+
fname = tf.name
67+
try:
68+
export_all_variables(
69+
self.workspace, self.repo_slug, self.deployment_name,
70+
fname, self.auth, self.logger
71+
)
72+
with open(fname, encoding="utf-8") as f:
73+
data = json.load(f)
74+
self.assertEqual(len(data), 2)
75+
test_var = next(v for v in data if v["key"] == "A")
76+
self.assertEqual(test_var["value"], "1")
77+
self.assertFalse(test_var["secured"])
78+
secure_var = next(v for v in data if v["key"] == "B")
79+
self.assertEqual(secure_var["value"], "")
80+
self.assertTrue(secure_var["secured"])
81+
finally:
82+
os.unlink(fname)
83+
84+
@patch('manage_bitbucket_env.get_environment_uuid')
85+
@patch('manage_bitbucket_env.get_variables')
86+
def test_export_secure_keys(self, mock_get_vars, mock_get_uuid):
87+
"""Test successful export of secure keys."""
88+
mock_get_uuid.return_value = self.env_uuid
89+
mock_get_vars.return_value = [
90+
{"key": "A", "secured": False},
91+
{"key": "B", "secured": True},
92+
{"key": "C", "secured": True}
93+
]
94+
with tempfile.NamedTemporaryFile(delete=False) as tf:
95+
fname = tf.name
96+
try:
97+
export_secure_keys(
98+
self.workspace, self.repo_slug, self.deployment_name,
99+
fname, self.auth, self.logger
100+
)
101+
with open(fname, encoding="utf-8") as f:
102+
data = json.load(f)
103+
self.assertIn("B", data)
104+
self.assertIn("C", data)
105+
self.assertNotIn("A", data)
106+
finally:
107+
os.unlink(fname)
108+
109+
@patch('manage_bitbucket_env.get_environment_uuid')
110+
@patch('manage_bitbucket_env.get_variables')
111+
@patch('manage_bitbucket_env.update_vars')
112+
def test_import_variables(self, mock_update, mock_get_vars, mock_get_uuid):
113+
"""Test successful import of variables."""
114+
mock_get_uuid.return_value = self.env_uuid
115+
mock_get_vars.return_value = []
116+
test_vars = [
117+
{"key": "A", "value": "1", "secured": False},
118+
{"key": "B", "value": "2", "secured": True}
119+
]
120+
with tempfile.NamedTemporaryFile(delete=False, mode='w', encoding="utf-8") as tf:
121+
json.dump(test_vars, tf)
122+
fname = tf.name
123+
try:
124+
import_variables(
125+
self.workspace, self.repo_slug, self.deployment_name,
126+
fname, False, self.auth, self.logger
127+
)
128+
self.assertEqual(mock_update.call_count, 1)
129+
call_args = mock_update.call_args[1]
130+
self.assertEqual(call_args['var']["key"], "A")
131+
finally:
132+
os.unlink(fname)
133+
134+
if __name__ == '__main__':
135+
unittest.main()

tests/test_main.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
"""Unit tests for main function integration in manage_bitbucket_env.py."""
2+
# pylint: disable=unused-argument
3+
import unittest
4+
from unittest.mock import patch, Mock
5+
from typing import Optional
6+
7+
from manage_bitbucket_env import main
8+
9+
class TestMainFunction(unittest.TestCase):
10+
"""Test main function integration."""
11+
# pylint: disable=attribute-defined-outside-init
12+
mock_logger: Optional[Mock] = None
13+
14+
def setUp(self):
15+
"""Set up test fixtures."""
16+
self.mock_logger = Mock()
17+
18+
@patch('manage_bitbucket_env.arg_parser')
19+
@patch('manage_bitbucket_env.load_dotenv')
20+
@patch('os.environ.get')
21+
@patch('manage_bitbucket_env.HTTPBasicAuth')
22+
@patch('manage_bitbucket_env.export_variables')
23+
# pylint: disable=too-many-arguments, too-many-positional-arguments
24+
def test_main_export_variables(self, mock_export, mock_auth, mock_env_get,
25+
mock_load_dotenv, mock_arg_parser):
26+
"""Test main function with export variables."""
27+
mock_args = Mock()
28+
mock_args.output = 'test_output.json'
29+
mock_args.workspace = 'test-workspace'
30+
mock_args.repo_slug = 'test-repo'
31+
mock_args.deployment_name = 'test-deployment'
32+
mock_arg_parser.return_value = mock_args
33+
env_dict = {
34+
'BITBUCKET_USERNAME': 'test_user',
35+
'BITBUCKET_APP_PASSWORD': 'test_password'
36+
}
37+
mock_env_get.side_effect = env_dict.get
38+
mock_auth_instance = Mock()
39+
mock_auth.return_value = mock_auth_instance
40+
main(self.mock_logger)
41+
mock_export.assert_called_once_with(
42+
workspace='test-workspace',
43+
repo_slug='test-repo',
44+
deployment_name='test-deployment',
45+
output_file='test_output.json',
46+
auth=mock_auth_instance,
47+
logger=self.mock_logger
48+
)
49+
50+
@patch('manage_bitbucket_env.arg_parser')
51+
@patch('manage_bitbucket_env.load_dotenv')
52+
@patch('os.environ.get')
53+
def test_main_missing_credentials(self, mock_env_get, mock_load_dotenv, mock_arg_parser):
54+
"""Test main function with missing credentials."""
55+
mock_args = Mock()
56+
mock_args.output = 'test_output.json'
57+
mock_arg_parser.return_value = mock_args
58+
mock_env_get.return_value = None
59+
with self.assertRaises(SystemExit):
60+
main(self.mock_logger)
61+
62+
if __name__ == '__main__':
63+
unittest.main()

0 commit comments

Comments
 (0)