Skip to content

Commit 64f5736

Browse files
Merge pull request #50 from glassflow/remove-status-from-get-pipeline
ETL-376: remove status from get pipeline response
2 parents beeb6a8 + 48c11a4 commit 64f5736

File tree

7 files changed

+138
-105
lines changed

7 files changed

+138
-105
lines changed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.2.0
1+
3.2.1

src/glassflow/etl/pipeline.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def get(self) -> Pipeline:
6868
"GET", f"{self.ENDPOINT}/{self.pipeline_id}", event_name="PipelineGet"
6969
)
7070
self.config = models.PipelineConfig.model_validate(response.json())
71-
self.status = models.PipelineStatus(response.json()["status"])
71+
self.health()
7272
self._dlq = DLQ(pipeline_id=self.pipeline_id, host=self.host)
7373
return self
7474

tests/conftest.py

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,26 @@ def get_pipeline_response(valid_config) -> dict:
2929
return config
3030

3131

32+
@pytest.fixture
33+
def get_health_payload():
34+
"""Factory to create a health endpoint payload for a pipeline id."""
35+
36+
def factory(
37+
pipeline_id: str,
38+
name: str = "Test Pipeline",
39+
status: str = "Running",
40+
) -> dict:
41+
return {
42+
"pipeline_id": pipeline_id,
43+
"pipeline_name": name,
44+
"overall_status": status,
45+
"created_at": "2025-01-01T00:00:00Z",
46+
"updated_at": "2025-01-01T00:00:00Z",
47+
}
48+
49+
return factory
50+
51+
3252
@pytest.fixture
3353
def valid_config_without_joins() -> dict:
3454
"""Fixture for a valid pipeline configuration without joins."""
@@ -96,18 +116,45 @@ def mock_connection_error():
96116

97117

98118
@pytest.fixture
99-
def mock_success_get_pipeline(get_pipeline_response):
100-
"""Fixture for a successful GET pipeline response."""
101-
return mock_responses.create_mock_response_factory()(
102-
status_code=200,
103-
json_data=get_pipeline_response,
104-
)
119+
def mock_success():
120+
"""Factory-context fixture that patches httpx and returns 200 with JSON.
121+
122+
- Accepts either a single dict payload or a list of dict payloads via the
123+
optional argument to the returned context manager. If a list is provided,
124+
they are returned sequentially from response.json() to simulate multiple
125+
HTTP calls within the same test flow.
126+
- If no payload is provided, it defaults to {"message": "Success"}.
127+
128+
Usage:
129+
with mock_success(payload_or_list) as mock_request:
130+
# invoke code under test
131+
assert mock_request.call_args_list == [...]
132+
"""
133+
from contextlib import contextmanager
134+
135+
@contextmanager
136+
def factory(json_payloads=None):
137+
if json_payloads is None:
138+
json_payloads = [{"message": "Success"}]
139+
payload_list = (
140+
list(json_payloads) if isinstance(json_payloads, list) else [json_payloads]
141+
)
142+
response = mock_responses.create_mock_response_factory()(
143+
status_code=200,
144+
json_data=payload_list[0] if payload_list else {},
145+
)
146+
with patch("httpx.Client.request", return_value=response) as mock:
147+
if payload_list:
148+
response.json.side_effect = payload_list
149+
yield mock
150+
151+
return factory
105152

106153

107154
@pytest.fixture
108-
def pipeline_from_id(mock_success_get_pipeline):
155+
def pipeline_from_id(mock_success, get_pipeline_response, get_health_payload):
109156
"""Fixture for a successful GET request."""
110-
with patch("httpx.Client.request", return_value=mock_success_get_pipeline):
157+
with mock_success([get_pipeline_response, get_health_payload("test-pipeline-id")]):
111158
return Pipeline(pipeline_id="test-pipeline-id").get()
112159

113160

tests/data/pipeline_configs.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,3 +272,14 @@ def get_invalid_config() -> dict:
272272
"table_mapping": [], # Empty table mapping should trigger validation error
273273
},
274274
}
275+
276+
277+
def get_health_payload(pipeline_id: str) -> dict:
278+
"""Get a health payload for a pipeline."""
279+
return {
280+
"pipeline_id": pipeline_id,
281+
"pipeline_name": "Test Pipeline",
282+
"overall_status": "Running",
283+
"created_at": "2025-01-01T00:00:00Z",
284+
"updated_at": "2025-01-01T00:00:00Z",
285+
}

tests/test_client.py

Lines changed: 25 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from unittest.mock import patch
1+
from unittest.mock import call, patch
22

33
import pytest
44

@@ -19,21 +19,23 @@ def test_client_init(self):
1919
assert client.http_client.base_url == "https://example.com"
2020

2121
def test_client_get_pipeline_success(
22-
self, get_pipeline_response, mock_success_response
22+
self, mock_success, get_pipeline_response, get_health_payload
2323
):
2424
"""Test successful pipeline retrieval by ID."""
2525
client = Client()
2626
pipeline_id = "test-pipeline-id"
2727

28-
mock_success_response.json.return_value = get_pipeline_response
29-
30-
with patch(
31-
"httpx.Client.request", return_value=mock_success_response
28+
with mock_success(
29+
[
30+
get_pipeline_response,
31+
get_health_payload(pipeline_id),
32+
]
3233
) as mock_request:
3334
pipeline = client.get_pipeline(pipeline_id)
34-
mock_request.assert_called_once_with(
35-
"GET", f"{client.ENDPOINT}/{pipeline_id}"
36-
)
35+
assert mock_request.call_args_list == [
36+
call("GET", f"{client.ENDPOINT}/{pipeline_id}"),
37+
call("GET", f"{client.ENDPOINT}/{pipeline_id}/health"),
38+
]
3739
assert isinstance(pipeline, Pipeline)
3840
assert pipeline.pipeline_id == pipeline_id
3941

@@ -126,13 +128,11 @@ def test_client_list_pipelines_empty(self):
126128
mock_request.assert_called_once_with("GET", client.ENDPOINT)
127129
assert pipelines == []
128130

129-
def test_client_create_pipeline_success(self, valid_config, mock_success_response):
131+
def test_client_create_pipeline_success(self, valid_config, mock_success):
130132
"""Test successful pipeline creation."""
131133
client = Client()
132134

133-
with patch(
134-
"httpx.Client.request", return_value=mock_success_response
135-
) as mock_request:
135+
with mock_success() as mock_request:
136136
pipeline = client.create_pipeline(valid_config)
137137
mock_request.assert_called_once_with(
138138
"POST", client.ENDPOINT, json=mock_request.call_args[1]["json"]
@@ -150,25 +150,21 @@ def test_client_create_pipeline_already_exists(
150150
with pytest.raises(errors.PipelineAlreadyExistsError):
151151
client.create_pipeline(valid_config)
152152

153-
def test_client_create_pipeline_from_yaml_success(self, mock_success_response):
153+
def test_client_create_pipeline_from_yaml_success(self, mock_success):
154154
"""Test pipeline creation from YAML file."""
155155
client = Client()
156-
with patch(
157-
"httpx.Client.request", return_value=mock_success_response
158-
) as mock_request:
156+
with mock_success() as mock_request:
159157
client.create_pipeline(
160158
pipeline_config_yaml_path="tests/data/valid_pipeline.yaml"
161159
)
162160
mock_request.assert_called_once_with(
163161
"POST", client.ENDPOINT, json=mock_request.call_args[1]["json"]
164162
)
165163

166-
def test_client_create_pipeline_from_json_success(self, mock_success_response):
164+
def test_client_create_pipeline_from_json_success(self, mock_success):
167165
"""Test pipeline creation from JSON file."""
168166
client = Client()
169-
with patch(
170-
"httpx.Client.request", return_value=mock_success_response
171-
) as mock_request:
167+
with mock_success() as mock_request:
172168
client.create_pipeline(
173169
pipeline_config_json_path="tests/data/valid_pipeline.json"
174170
)
@@ -188,14 +184,12 @@ def test_client_create_pipeline_value_error(self, valid_config):
188184
with pytest.raises(ValueError):
189185
client.create_pipeline()
190186

191-
def test_client_delete_pipeline_success(self, mock_success_response):
187+
def test_client_delete_pipeline_success(self, mock_success):
192188
"""Test successful pipeline deletion."""
193189
client = Client()
194190
pipeline_id = "test-pipeline-id"
195191

196-
with patch(
197-
"httpx.Client.request", return_value=mock_success_response
198-
) as mock_delete_request:
192+
with mock_success() as mock_delete_request:
199193
client.delete_pipeline(pipeline_id)
200194
mock_delete_request.assert_called_once_with(
201195
"DELETE", f"{client.ENDPOINT}/{pipeline_id}"
@@ -211,27 +205,23 @@ def test_client_delete_pipeline_not_found(self, mock_not_found_response):
211205
client.delete_pipeline(pipeline_id)
212206
assert "not found" in str(exc_info.value)
213207

214-
def test_client_stop_pipeline_success(self, mock_success_response):
208+
def test_client_stop_pipeline_success(self, mock_success):
215209
"""Test successful pipeline stop."""
216210
client = Client()
217211
pipeline_id = "test-pipeline-id"
218212

219-
with patch(
220-
"httpx.Client.request", return_value=mock_success_response
221-
) as mock_request:
213+
with mock_success() as mock_request:
222214
client.stop_pipeline(pipeline_id)
223215
mock_request.assert_called_once_with(
224216
"POST", f"{client.ENDPOINT}/{pipeline_id}/stop"
225217
)
226218

227-
def test_client_stop_pipeline_terminate_success(self, mock_success_response):
219+
def test_client_stop_pipeline_terminate_success(self, mock_success):
228220
"""Test successful pipeline stop with terminate=True."""
229221
client = Client()
230222
pipeline_id = "test-pipeline-id"
231223

232-
with patch(
233-
"httpx.Client.request", return_value=mock_success_response
234-
) as mock_request:
224+
with mock_success() as mock_request:
235225
client.stop_pipeline(pipeline_id, terminate=True)
236226
mock_request.assert_called_once_with(
237227
"POST", f"{client.ENDPOINT}/{pipeline_id}/terminate"
@@ -256,11 +246,9 @@ def test_pipeline_to_dict(self, valid_config):
256246
assert isinstance(pipeline_dict, dict)
257247
assert pipeline_dict["pipeline_id"] == valid_config["pipeline_id"]
258248

259-
def test_pipeline_delete(self, pipeline_from_id, mock_success_response):
249+
def test_pipeline_delete(self, pipeline_from_id, mock_success):
260250
"""Test Pipeline delete with explicit pipeline_id."""
261-
with patch(
262-
"httpx.Client.request", return_value=mock_success_response
263-
) as mock_request:
251+
with mock_success() as mock_request:
264252
pipeline_from_id.delete()
265253
mock_request.assert_called_once_with(
266254
"DELETE",

tests/test_dlq.py

Lines changed: 17 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,13 @@ def test_dlq_initialization(self, dlq):
1616
assert dlq.http_client.base_url == "http://localhost:8080"
1717
assert dlq.endpoint == "/api/v1/pipeline/test-pipeline/dlq"
1818

19-
def test_consume_success(self, dlq):
19+
def test_consume_success(self, dlq, mock_success):
2020
"""Test successful DLQ consume operation."""
21-
mock_response = mock_responses.create_mock_response_factory()(
22-
status_code=200,
23-
json_data=[
24-
{"id": "msg1", "content": "test message 1"},
25-
{"id": "msg2", "content": "test message 2"},
26-
],
27-
)
28-
29-
with patch("httpx.Client.request", return_value=mock_response) as mock_get:
21+
payload = [
22+
{"id": "msg1", "content": "test message 1"},
23+
{"id": "msg2", "content": "test message 2"},
24+
]
25+
with mock_success(json_payloads=[payload]) as mock_get:
3026
result = dlq.consume(batch_size=50)
3127

3228
mock_get.assert_called_once_with(
@@ -79,18 +75,14 @@ def test_consume_http_error_scenarios(self, dlq, scenario):
7975

8076
assert scenario["error_message"] in str(exc_info.value)
8177

82-
def test_state_success(self, dlq):
78+
def test_state_success(self, dlq, mock_success):
8379
"""Test successful DLQ state operation."""
84-
mock_response = mock_responses.create_mock_response_factory()(
85-
status_code=200,
86-
json_data={
87-
"total_messages": 42,
88-
"pending_messages": 5,
89-
"last_updated": "2023-01-01T00:00:00Z",
90-
},
91-
)
92-
93-
with patch("httpx.Client.request", return_value=mock_response) as mock_get:
80+
state_payload = {
81+
"total_messages": 42,
82+
"pending_messages": 5,
83+
"last_updated": "2023-01-01T00:00:00Z",
84+
}
85+
with mock_success(state_payload) as mock_get:
9486
result = dlq.state()
9587

9688
mock_get.assert_called_once_with("GET", f"{dlq.endpoint}/state")
@@ -133,26 +125,16 @@ def test_pipeline_dlq_property_same_url(self):
133125
assert pipeline.http_client.base_url == custom_url
134126
assert pipeline.dlq.http_client.base_url == custom_url
135127

136-
def test_pipeline_dlq_consume_integration(self, pipeline):
128+
def test_pipeline_dlq_consume_integration(self, pipeline, mock_success):
137129
"""Test Pipeline DLQ consume functionality."""
138-
mock_response = mock_responses.create_mock_response_factory()(
139-
status_code=200,
140-
json_data=[{"id": "msg1", "content": "test"}],
141-
)
142-
143-
with patch("httpx.Client.request", return_value=mock_response):
130+
with mock_success(json_payloads=[[{"id": "msg1", "content": "test"}]]):
144131
result = pipeline.dlq.consume(batch_size=10)
145132

146133
assert result == [{"id": "msg1", "content": "test"}]
147134

148-
def test_pipeline_dlq_state_integration(self, pipeline):
135+
def test_pipeline_dlq_state_integration(self, pipeline, mock_success):
149136
"""Test Pipeline DLQ state functionality."""
150-
mock_response = mock_responses.create_mock_response_factory()(
151-
status_code=200,
152-
json_data={"total_messages": 10},
153-
)
154-
155-
with patch("httpx.Client.request", return_value=mock_response):
137+
with mock_success({"total_messages": 10}):
156138
result = pipeline.dlq.state()
157139

158140
assert result == {"total_messages": 10}

0 commit comments

Comments
 (0)