Skip to content

Commit e586280

Browse files
committed
Updare upon review
Signed-off-by: Alina Buzachis <[email protected]>
1 parent d723e7a commit e586280

File tree

13 files changed

+221
-248
lines changed

13 files changed

+221
-248
lines changed

core/controller_client.py

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,24 @@
66
from requests import Session
77
from requests.auth import HTTPBasicAuth
88

9-
from pattern_service.settings.aap import get_aap_settings
9+
from pattern_service.settings.aap import AAP_PASSWORD
10+
from pattern_service.settings.aap import AAP_USERNAME
11+
from pattern_service.settings.aap import AAP_VALIDATE_CERTS
1012

1113
logger = logging.getLogger(__name__)
1214

13-
settings = get_aap_settings()
1415

15-
_aap_session: Optional[Session] = None
16+
def get_http_session() -> Session:
17+
"""Creates and returns a new Session instance with AAP credentials."""
18+
session = Session()
19+
session.auth = HTTPBasicAuth(AAP_USERNAME, AAP_PASSWORD)
20+
session.verify = AAP_VALIDATE_CERTS
21+
session.headers.update({"Content-Type": "application/json"})
22+
return session
1623

1724

18-
def get_http_session(force_refresh: bool = False) -> Session:
19-
"""Returns a cached Session instance with AAP credentials."""
20-
global _aap_session
21-
if _aap_session is None or force_refresh:
22-
session = Session()
23-
session.auth = HTTPBasicAuth(settings.username, settings.password)
24-
session.verify = settings.verify_ssl
25-
session.headers.update({"Content-Type": "application/json"})
26-
_aap_session = session
27-
28-
return _aap_session
29-
30-
31-
def get(path: str, *, params: Optional[Dict] = None) -> requests.Response:
32-
session = get_http_session()
33-
url = f"{settings.url}{path}"
34-
response = session.get(url, params=params, stream=True)
35-
response.raise_for_status()
36-
37-
return response
38-
39-
40-
def build_collection_uri(collection: str, version: str) -> str:
41-
"""Builds the URI for a given collection and version."""
42-
base_url = settings.url
43-
path = "/api/galaxy/v3/plugin/ansible/content/published/collections/artifacts"
44-
filename = f"{collection}-{version}.tar.gz"
45-
46-
return f"{base_url}{path}/{filename}"
25+
def get(url: str, *, params: Optional[Dict] = None) -> requests.Response:
26+
with get_http_session() as session:
27+
response = session.get(url, params=params, stream=True)
28+
response.raise_for_status()
29+
return response

core/models.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,8 @@ class Meta:
9494

9595
status: models.CharField = models.CharField(max_length=20, choices=status_choices)
9696
details: models.JSONField = models.JSONField(null=True, blank=True)
97+
98+
def update_task_status(self, status_: str, details: dict) -> None:
99+
self.status = status_
100+
self.details = details
101+
self.save()

core/services.py

Lines changed: 0 additions & 94 deletions
This file was deleted.

core/tasks.py

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,46 @@
1-
from core.services import pattern_task
1+
import json
2+
import logging
3+
import os
4+
5+
from .models import Pattern
6+
from .models import Task
7+
from .utils import build_collection_uri
8+
from .utils import download_collection
9+
10+
logger = logging.getLogger(__name__)
211

312

413
def run_pattern_task(pattern_id: int, task_id: int) -> None:
5-
pattern_task(pattern_id, task_id)
14+
"""
15+
Orchestrates downloading a collection and saving a pattern definition.
16+
"""
17+
task = Task.objects.get(id=task_id)
18+
try:
19+
pattern = Pattern.objects.get(id=pattern_id)
20+
task.update_task_status("Running", {"info": "Processing pattern"})
21+
with download_collection(
22+
pattern.collection_name, pattern.collection_version
23+
) as collection_path:
24+
path_to_definition = os.path.join(
25+
collection_path,
26+
"extensions",
27+
"patterns",
28+
pattern.pattern_name,
29+
"meta",
30+
"pattern.json",
31+
)
32+
with open(path_to_definition, "r") as file:
33+
definition = json.load(file)
34+
35+
pattern.pattern_definition = definition
36+
pattern.collection_version_uri = build_collection_uri(
37+
pattern.collection_name, pattern.collection_version
38+
)
39+
pattern.save(update_fields=["pattern_definition", "collection_version_uri"])
40+
task.update_task_status("Completed", {"info": "Pattern processed successfully"})
41+
except FileNotFoundError:
42+
logger.error(f"Could not find pattern definition for task {task_id}")
43+
task.update_task_status("Failed", {"error": "Pattern definition not found."})
44+
except Exception as e:
45+
logger.error(f"Task {task_id} failed: {e}")
46+
task.update_task_status("Failed", {"error": str(e)})
Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
import core.controller_client as cc
22

33

4-
def test_get_http_session_caches():
4+
def test_get_http_session():
55
"""Subsequent calls without force_refresh must return the *same* object."""
66
s1 = cc.get_http_session()
77
s2 = cc.get_http_session()
8-
assert s1 is s2
9-
10-
s3 = cc.get_http_session(force_refresh=True)
11-
assert s3 is not s1 and s3 is cc._aap_session
8+
assert s1 is not s2

core/tests/test_services.py renamed to core/tests/test_tasks.py

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from core.models import Pattern
1313
from core.models import PatternInstance
1414
from core.models import Task
15-
from core.services import pattern_task
15+
from core.tasks import run_pattern_task
1616

1717

1818
class SharedDataMixin:
@@ -78,12 +78,9 @@ def tearDown(self):
7878

7979

8080
class PatternTaskTest(SharedDataMixin, TestCase):
81-
@patch(
82-
"core.services.update_task_status",
83-
wraps=pattern_task.__globals__["update_task_status"],
84-
)
85-
@patch("core.services.open", new_callable=mock_open, read_data='{"name": "test"}')
86-
@patch("core.services.download_collection")
81+
@patch("core.models.Task.update_task_status", autospec=True)
82+
@patch("core.tasks.open", new_callable=mock_open, read_data='{"name": "test"}')
83+
@patch("core.tasks.download_collection")
8784
def test_run_pattern_task_success(
8885
self, mock_download, mock_open_fn, mock_update_status
8986
):
@@ -112,7 +109,7 @@ def test_run_pattern_task_success(
112109
) as f:
113110
f.write(json.dumps({"name": "test"}))
114111

115-
pattern_task(pattern.id, task.id)
112+
run_pattern_task(pattern.id, task.id)
116113

117114
mock_update_status.assert_any_call(
118115
task, "Running", {"info": "Processing pattern"}
@@ -121,11 +118,8 @@ def test_run_pattern_task_success(
121118
task, "Completed", {"info": "Pattern processed successfully"}
122119
)
123120

124-
@patch(
125-
"core.services.update_task_status",
126-
wraps=pattern_task.__globals__["update_task_status"],
127-
)
128-
@patch("core.services.download_collection", side_effect=FileNotFoundError)
121+
@patch("core.models.Task.update_task_status", autospec=True)
122+
@patch("core.tasks.download_collection", side_effect=FileNotFoundError)
129123
def test_run_pattern_task_file_not_found(self, mock_download, mock_update_status):
130124
pattern = Pattern.objects.create(
131125
collection_name="demo.collection",
@@ -134,49 +128,55 @@ def test_run_pattern_task_file_not_found(self, mock_download, mock_update_status
134128
)
135129
task = Task.objects.create(status="Initiated", details={})
136130

137-
pattern_task(pattern.id, task.id)
131+
run_pattern_task(pattern.id, task.id)
138132

139133
mock_update_status.assert_called_with(
140134
task, "Failed", {"error": "Pattern definition not found."}
141135
)
142136

143-
@patch(
144-
"core.services.download_collection", side_effect=Exception("Download failed")
145-
)
137+
@patch("core.tasks.download_collection", side_effect=Exception("Download failed"))
146138
def test_run_pattern_task_handles_download_failure(self, mock_download):
147-
pattern_task(self.pattern.id, self.task.id)
139+
run_pattern_task(self.pattern.id, self.task.id)
148140
self.task.refresh_from_db()
149141
self.assertEqual(self.task.status, "Failed")
150142
self.assertIn("Download failed", self.task.details.get("error", ""))
151143

152-
@patch(
153-
"core.services.update_task_status",
154-
wraps=pattern_task.__globals__["update_task_status"],
155-
)
156-
@patch("core.services.download_collection")
144+
@patch("core.models.Task.update_task_status", autospec=True)
145+
@patch("core.tasks.download_collection")
157146
def test_full_status_update_flow(self, mock_download, mock_update_status):
158147
temp_dir_path = self.create_temp_collection_dir()
159148
mock_download.return_value.__enter__.return_value = temp_dir_path
160149

161-
# Run the task
162-
pattern_task(self.pattern.id, self.task.id)
150+
def _side_effect(self_task, status_, details):
151+
self_task.status = status_
152+
self_task.details = details
153+
self_task.save()
154+
155+
mock_update_status.side_effect = _side_effect
156+
157+
run_pattern_task(self.pattern.id, self.task.id)
163158

164-
# Verify calls to update_task_status
165159
expected_calls = [
166160
(self.task, "Running", {"info": "Processing pattern"}),
167161
(self.task, "Completed", {"info": "Pattern processed successfully"}),
168162
]
169-
actual_calls = [tuple(call.args) for call in mock_update_status.call_args_list]
163+
164+
actual_calls = [
165+
(call_args[0][0], call_args[0][1], call_args[0][2])
166+
for call_args in mock_update_status.call_args_list
167+
]
168+
169+
# Assert update_task_status calls
170170
for expected in expected_calls:
171171
self.assertIn(expected, actual_calls)
172172

173-
# Verify final DB state
173+
# Assert final DB state
174174
self.task.refresh_from_db()
175175
self.assertEqual(self.task.status, "Completed")
176176
self.assertEqual(
177177
self.task.details.get("info"), "Pattern processed successfully"
178178
)
179179

180-
# Verify pattern_definition was updated and saved
180+
# Assert pattern definition was updated
181181
self.pattern.refresh_from_db()
182182
self.assertEqual(self.pattern.pattern_definition, {"mock_key": "mock_value"})

core/tests/test_views.py

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
import json
2-
import os
3-
import shutil
4-
import tempfile
5-
from unittest.mock import patch
6-
71
from django.urls import reverse
82
from rest_framework import status
93
from rest_framework.test import APITestCase
@@ -53,20 +47,6 @@ def setUpTestData(cls):
5347

5448

5549
class PatternViewSetTest(SharedDataMixin, APITestCase):
56-
def create_temp_collection_dir(self):
57-
temp_dir = tempfile.mkdtemp()
58-
os.makedirs(
59-
os.path.join(temp_dir, "extensions", "patterns", "new_pattern", "meta"),
60-
exist_ok=True,
61-
)
62-
pattern_json_path = os.path.join(
63-
temp_dir, "extensions", "patterns", "new_pattern", "meta", "pattern.json"
64-
)
65-
with open(pattern_json_path, "w") as f:
66-
json.dump({"mock_key": "mock_value"}, f)
67-
self.addCleanup(lambda: shutil.rmtree(temp_dir, ignore_errors=True))
68-
return temp_dir
69-
7050
def test_pattern_list_view(self):
7151
url = reverse("pattern-list")
7252
response = self.client.get(url)
@@ -80,11 +60,7 @@ def test_pattern_detail_view(self):
8060
self.assertEqual(response.status_code, status.HTTP_200_OK)
8161
self.assertEqual(response.data["collection_name"], "mynamespace.mycollection")
8262

83-
@patch("core.services.download_collection")
84-
def test_pattern_create_view(self, mock_download_collection):
85-
temp_dir = self.create_temp_collection_dir() # Simulate a valid pattern.json
86-
mock_download_collection.return_value.__enter__.return_value = temp_dir
87-
63+
def test_pattern_create_view(self):
8864
url = reverse("pattern-list")
8965
data = {
9066
"collection_name": "new.namespace.collection",
@@ -106,8 +82,9 @@ def test_pattern_create_view(self, mock_download_collection):
10682

10783
# Task exists
10884
task = Task.objects.get(id=task_id)
109-
self.assertEqual(task.status, "Completed")
110-
self.assertEqual(task.details.get("info"), "Pattern processed successfully")
85+
self.assertEqual(task.status, "Initiated")
86+
self.assertEqual(task.details.get("model"), "Pattern")
87+
self.assertEqual(task.details.get("id"), pattern.id)
11188

11289
def test_pattern_delete_view(self):
11390
# Create a separate pattern for deletion

0 commit comments

Comments
 (0)