Skip to content

Commit eac2d6c

Browse files
committed
tests: integration: fix http server response overrides
Signed-off-by: Eduardo Silva <eduardo@chronosphere.io>
1 parent 26f53b0 commit eac2d6c

2 files changed

Lines changed: 130 additions & 31 deletions

File tree

tests/integration/scenarios/out_http/tests/test_out_http_001.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import json
22
import logging
33
import os
4+
import socket
5+
import time
46

57
import requests
68

@@ -15,6 +17,30 @@
1517
logger = logging.getLogger(__name__)
1618

1719

20+
def _find_free_port():
21+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
22+
sock.bind(("127.0.0.1", 0))
23+
port = sock.getsockname()[1]
24+
sock.close()
25+
return port
26+
27+
28+
def _wait_for_http_server(port, timeout=5):
29+
deadline = time.time() + timeout
30+
31+
while time.time() < deadline:
32+
try:
33+
response = requests.get(f"http://127.0.0.1:{port}/ping", timeout=1)
34+
if response.status_code == 200:
35+
return
36+
except requests.RequestException:
37+
pass
38+
39+
time.sleep(0.1)
40+
41+
raise TimeoutError(f"Timed out waiting for HTTP server on port {port}")
42+
43+
1844
class Service:
1945
def __init__(self, config_file, *, response_setup=None, use_tls=False):
2046
self.config_file = os.path.abspath(os.path.join(os.path.dirname(__file__), "../config", config_file))
@@ -281,3 +307,66 @@ def test_out_http_tls_read_idle_timeout_retries_partial_response():
281307

282308
assert len(requests_seen) >= 2
283309
assert "read idle timeout reached" in log_text
310+
311+
312+
def test_http_server_configure_helpers_allow_clearing_nullable_fields():
313+
port = _find_free_port()
314+
http_server_run(port, reset_state=True)
315+
_wait_for_http_server(port)
316+
317+
try:
318+
configure_http_response(
319+
stream_fragments=["part"],
320+
hang_after_fragment_index=0,
321+
)
322+
configure_http_response(
323+
stream_fragments=None,
324+
hang_after_fragment_index=None,
325+
)
326+
327+
response = requests.post(
328+
f"http://127.0.0.1:{port}/data",
329+
json={"test": "clear"},
330+
timeout=5,
331+
)
332+
333+
assert response.status_code == 200
334+
assert response.json() == {"status": "received"}
335+
finally:
336+
try:
337+
requests.post(f"http://127.0.0.1:{port}/shutdown", timeout=2)
338+
except requests.RequestException:
339+
pass
340+
341+
342+
def test_http_server_oauth_token_honors_explicit_content_type_and_raw_body():
343+
port = _find_free_port()
344+
http_server_run(port, reset_state=True)
345+
_wait_for_http_server(port)
346+
347+
try:
348+
configure_oauth_token_response(
349+
stream_fragments=["partial-token"],
350+
hang_after_fragment_index=0,
351+
)
352+
configure_oauth_token_response(
353+
body="not-json",
354+
content_type="text/plain",
355+
stream_fragments=None,
356+
hang_after_fragment_index=None,
357+
)
358+
359+
response = requests.post(
360+
f"http://127.0.0.1:{port}/oauth/token",
361+
data="grant_type=client_credentials",
362+
timeout=5,
363+
)
364+
365+
assert response.status_code == 200
366+
assert response.text == "not-json"
367+
assert response.headers["Content-Type"].startswith("text/plain")
368+
finally:
369+
try:
370+
requests.post(f"http://127.0.0.1:{port}/shutdown", timeout=2)
371+
except requests.RequestException:
372+
pass

tests/integration/src/server/http_server.py

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
server_thread = None
6464
server_instances = []
6565
shutdown_event = threading.Event()
66+
UNSET = object()
6667

6768

6869
def _sleep_interruptible(seconds):
@@ -115,51 +116,51 @@ def reset_http_server_state():
115116
)
116117

117118

118-
def configure_http_response(*, status_code=None, body=None, content_type=None,
119-
delay_seconds=None, stream_fragments=None,
120-
fragment_delay_seconds=None,
121-
hang_before_response=None,
122-
hang_after_fragment_index=None):
123-
if status_code is not None:
119+
def configure_http_response(*, status_code=UNSET, body=UNSET, content_type=UNSET,
120+
delay_seconds=UNSET, stream_fragments=UNSET,
121+
fragment_delay_seconds=UNSET,
122+
hang_before_response=UNSET,
123+
hang_after_fragment_index=UNSET):
124+
if status_code is not UNSET:
124125
response_config["status_code"] = status_code
125-
if body is not None:
126+
if body is not UNSET:
126127
response_config["body"] = body
127-
if content_type is not None:
128+
if content_type is not UNSET:
128129
response_config["content_type"] = content_type
129-
if delay_seconds is not None:
130+
if delay_seconds is not UNSET:
130131
response_config["delay_seconds"] = delay_seconds
131-
if stream_fragments is not None:
132-
response_config["stream_fragments"] = list(stream_fragments)
133-
if fragment_delay_seconds is not None:
132+
if stream_fragments is not UNSET:
133+
response_config["stream_fragments"] = None if stream_fragments is None else list(stream_fragments)
134+
if fragment_delay_seconds is not UNSET:
134135
response_config["fragment_delay_seconds"] = fragment_delay_seconds
135-
if hang_before_response is not None:
136+
if hang_before_response is not UNSET:
136137
response_config["hang_before_response"] = hang_before_response
137-
if hang_after_fragment_index is not None:
138+
if hang_after_fragment_index is not UNSET:
138139
response_config["hang_after_fragment_index"] = hang_after_fragment_index
139140

140141

141-
def configure_oauth_token_response(*, status_code=None, body=None,
142-
content_type=None,
143-
delay_seconds=None,
144-
hang_before_response=None,
145-
stream_fragments=None,
146-
fragment_delay_seconds=None,
147-
hang_after_fragment_index=None):
148-
if status_code is not None:
142+
def configure_oauth_token_response(*, status_code=UNSET, body=UNSET,
143+
content_type=UNSET,
144+
delay_seconds=UNSET,
145+
hang_before_response=UNSET,
146+
stream_fragments=UNSET,
147+
fragment_delay_seconds=UNSET,
148+
hang_after_fragment_index=UNSET):
149+
if status_code is not UNSET:
149150
oauth_token_response["status_code"] = status_code
150-
if body is not None:
151+
if body is not UNSET:
151152
oauth_token_response["body"] = body
152-
if content_type is not None:
153+
if content_type is not UNSET:
153154
oauth_token_response["content_type"] = content_type
154-
if delay_seconds is not None:
155+
if delay_seconds is not UNSET:
155156
oauth_token_response["delay_seconds"] = delay_seconds
156-
if hang_before_response is not None:
157+
if hang_before_response is not UNSET:
157158
oauth_token_response["hang_before_response"] = hang_before_response
158-
if stream_fragments is not None:
159-
oauth_token_response["stream_fragments"] = list(stream_fragments)
160-
if fragment_delay_seconds is not None:
159+
if stream_fragments is not UNSET:
160+
oauth_token_response["stream_fragments"] = None if stream_fragments is None else list(stream_fragments)
161+
if fragment_delay_seconds is not UNSET:
161162
oauth_token_response["fragment_delay_seconds"] = fragment_delay_seconds
162-
if hang_after_fragment_index is not None:
163+
if hang_after_fragment_index is not UNSET:
163164
oauth_token_response["hang_after_fragment_index"] = hang_after_fragment_index
164165

165166

@@ -284,7 +285,16 @@ def oauth_token():
284285
return Response(status=503)
285286
if oauth_token_response["stream_fragments"] is not None:
286287
return _build_streaming_response(oauth_token_response)
287-
return jsonify(oauth_token_response["body"]), oauth_token_response["status_code"]
288+
289+
body = oauth_token_response["body"]
290+
if isinstance(body, (dict, list)) and oauth_token_response["content_type"] is None:
291+
return jsonify(body), oauth_token_response["status_code"]
292+
293+
return Response(
294+
body,
295+
status=oauth_token_response["status_code"],
296+
content_type=oauth_token_response.get("content_type"),
297+
)
288298

289299

290300
@app.route('/ping', methods=['GET'])

0 commit comments

Comments
 (0)