Skip to content

Commit 0d98b95

Browse files
committed
split the testing infrastructure across multiple files
1 parent daf7a41 commit 0d98b95

File tree

4 files changed

+143
-48
lines changed

4 files changed

+143
-48
lines changed

tests/support/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,11 @@
6767

6868
from tests.support.assertover import AssertOver
6969
from tests.support.configsupp import FakeConfiguration
70+
from tests.support.htmlsupp import HtmlAssertMixin
7071
from tests.support.loggersupp import FakeLogger
7172
from tests.support.serversupp import make_wrapped_server
73+
from tests.support.wsgisupp import create_wsgi_environ, \
74+
ServerAssertMixin, FakeStartResponse
7275

7376

7477
# Basic global logging configuration for testing

tests/support/htmlsupp.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
#
4+
# --- BEGIN_HEADER ---
5+
#
6+
# htmlsupp - test support library for HTML
7+
# Copyright (C) 2003-2024 The MiG Project by the Science HPC Center at UCPH
8+
#
9+
# This file is part of MiG.
10+
#
11+
# MiG is free software: you can redistribute it and/or modify
12+
# it under the terms of the GNU General Public License as published by
13+
# the Free Software Foundation; either version 2 of the License, or
14+
# (at your option) any later version.
15+
#
16+
# MiG is distributed in the hope that it will be useful,
17+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
# GNU General Public License for more details.
20+
#
21+
# You should have received a copy of the GNU General Public License
22+
# along with this program; if not, write to the Free Software
23+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24+
#
25+
# -- END_HEADER ---
26+
#
27+
28+
"""Test support library for HTML."""
29+
30+
31+
class HtmlAssertMixin:
32+
"""Custom assertions for HTML containing strings."""
33+
34+
def assertHtmlElementTextContent(self, value, tag_name, expected_text, trim_newlines=True):
35+
"""Locate the first occurrence of a tag within an HTML input string
36+
and assert that any contained string equals what was supplied.
37+
"""
38+
39+
self.assertIsValidHtmlDocument(value)
40+
41+
# TODO: this is a definitively stop-gap way of finding a tag within the HTML
42+
# and is used purely to keep this initial change to a reasonable size.
43+
44+
tag_open = ''.join(['<', tag_name, '>'])
45+
tag_open_index = value.index(tag_open)
46+
tag_open_index_after = tag_open_index + len(tag_open)
47+
48+
tag_close = ''.join(['</', tag_name, '>'])
49+
tag_close_index = value.index(tag_close, tag_open_index_after)
50+
51+
actual_text = value[tag_open_index_after:tag_close_index]
52+
if trim_newlines:
53+
actual_text = actual_text.strip('\n')
54+
self.assertEqual(actual_text, expected_text)
55+
56+
def assertIsValidHtmlDocument(self, value):
57+
"""Check that the input string contains a valid HTML document.
58+
"""
59+
60+
assert isinstance(value, type(u""))
61+
62+
error = None
63+
try:
64+
assert value.startswith("<!DOCTYPE html")
65+
end_html_tag_idx = value.rfind('</html>')
66+
maybe_document_end = value[end_html_tag_idx:].rstrip()
67+
self.assertEqual(maybe_document_end, '</html>')
68+
except Exception as exc:
69+
error = exc
70+
if error:
71+
raise AssertionError("failed to verify input string as HTML: %s", str(exc))

tests/support/wsgisupp.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
#
4+
# --- BEGIN_HEADER ---
5+
#
6+
# htmlsupp - test support library for WSGI
7+
# Copyright (C) 2003-2024 The MiG Project by the Science HPC Center at UCPH
8+
#
9+
# This file is part of MiG.
10+
#
11+
# MiG is free software: you can redistribute it and/or modify
12+
# it under the terms of the GNU General Public License as published by
13+
# the Free Software Foundation; either version 2 of the License, or
14+
# (at your option) any later version.
15+
#
16+
# MiG is distributed in the hope that it will be useful,
17+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
# GNU General Public License for more details.
20+
#
21+
# You should have received a copy of the GNU General Public License
22+
# along with this program; if not, write to the Free Software
23+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24+
#
25+
# -- END_HEADER ---
26+
#
27+
28+
"""Test support library for WSGI."""
29+
30+
31+
def create_wsgi_environ(config_file, wsgi_variables):
32+
environ = {}
33+
environ['wsgi.input'] = ()
34+
environ['MIG_CONF'] = config_file
35+
environ['HTTP_HOST'] = wsgi_variables.get('http_host')
36+
environ['PATH_INFO'] = wsgi_variables.get('path_info')
37+
environ['SCRIPT_URI'] = ''.join(('http://', environ['HTTP_HOST'], environ['PATH_INFO']))
38+
return environ
39+
40+
41+
class FakeStartResponse:
42+
def __init__(self):
43+
self.calls = []
44+
45+
def __call__(self, status, headers, exc=None):
46+
self.calls.append((status, headers, exc))
47+
48+
49+
class ServerAssertMixin:
50+
"""Custom assertions for verifying server code executed under test."""
51+
52+
def assertWsgiResponseStatus(self, fake_start_response, expected_status_code):
53+
assert isinstance(fake_start_response, FakeStartResponse)
54+
55+
def called_once(fake):
56+
assert hasattr(fake, 'calls')
57+
return len(fake.calls) == 1
58+
59+
self.assertTrue(called_once(fake_start_response))
60+
thecall = fake_start_response.calls[0]
61+
wsgi_status = thecall[0]
62+
actual_status_code = int(wsgi_status[0:3])
63+
self.assertEqual(actual_status_code, expected_status_code)

tests/test_mig_wsgi-bin_migwsgi.py

Lines changed: 6 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@
3838
import mig.shared.returnvalues as returnvalues
3939

4040

41-
from tests.support import PY2, is_path_within
41+
from tests.support import PY2, is_path_within, \
42+
create_wsgi_environ, ServerAssertMixin, FakeStartResponse, HtmlAssertMixin
4243
from mig.shared.base import client_id_dir, client_dir_id, get_short_id, \
4344
invisible_path, allow_script, brief_list
4445

@@ -179,21 +180,11 @@ def _instrumented_retrieve_handler(*args):
179180
return _instrumented_retrieve_handler
180181

181182

182-
def create_wsgi_environ(config_file, wsgi_variables):
183-
environ = {}
184-
environ['wsgi.input'] = ()
185-
environ['MIG_CONF'] = config_file
186-
environ['HTTP_HOST'] = wsgi_variables.get('http_host')
187-
environ['PATH_INFO'] = wsgi_variables.get('path_info')
188-
environ['SCRIPT_URI'] = ''.join(('http://', environ['HTTP_HOST'], environ['PATH_INFO']))
189-
return environ
190-
191-
192183
def noop(*args):
193184
pass
194185

195186

196-
class MigWsgi_binMigwsgi(MigTestCase):
187+
class MigWsgi_binMigwsgi(MigTestCase, ServerAssertMixin, HtmlAssertMixin):
197188
def assertInstrumentation(self):
198189
simulated_action = self.instrumented_retrieve_handler.simulated
199190
self.assertIsNotNone(simulated_action.returning, "no response programmed")
@@ -205,44 +196,11 @@ def was_called(fake):
205196
self.assertTrue(was_called(self.instrumented_format_output), "no output generated")
206197
self.assertTrue(was_called(self.instrumented_retrieve_handler), "no output generated")
207198

208-
def assertResponseStatus(self, expected_status_code):
209-
def called_once(fake):
210-
assert hasattr(fake, 'calls')
211-
return len(fake.calls) == 1
212-
213-
self.assertTrue(called_once(self.fake_start_response))
214-
thecall = self.fake_start_response.calls[0]
215-
wsgi_status = thecall[0]
216-
actual_status_code = int(wsgi_status[0:3])
217-
self.assertEqual(actual_status_code, expected_status_code)
218-
219-
def assertHtmlElementTextContent(self, output, tag_name, expected_text, trim_newlines=True):
220-
# TODO: this is a definitively stop-gap way of finding a tag within the HTML
221-
# and is used purely to keep this initial change to a reasonable size.
222-
tag_open = ''.join(['<', tag_name, '>'])
223-
tag_open_index = output.index(tag_open)
224-
tag_close = ''.join(['</', tag_name, '>'])
225-
tag_close_index = output.index(tag_close)
226-
actual_text = output[tag_open_index+len(tag_open):tag_close_index]
227-
if trim_newlines:
228-
actual_text = actual_text.strip('\n')
229-
self.assertEqual(actual_text, expected_text)
230-
231-
def assertIsValidHtmlDocument(self, value):
232-
assert isinstance(value, type(u""))
233-
assert value.startswith("<!DOCTYPE")
234-
end_html_tag_idx = value.rfind('</html>')
235-
maybe_document_end = value[end_html_tag_idx:].rstrip()
236-
self.assertEqual(maybe_document_end, '</html>')
237-
238199
def before_each(self):
239200
config = _assert_local_config()
240201
config_global_values = _assert_local_config_global_values(config)
241202

242-
def fake_start_response(status, headers, exc=None):
243-
fake_start_response.calls.append((status, headers, exc))
244-
fake_start_response.calls = []
245-
self.fake_start_response = fake_start_response
203+
self.fake_start_response = FakeStartResponse()
246204

247205
def fake_set_environ(value):
248206
fake_set_environ.calls.append((value))
@@ -257,7 +215,7 @@ def fake_set_environ(value):
257215
self.instrumented_format_output = create_instrumented_format_output()
258216
self.instrumented_retrieve_handler = create_instrumented_retrieve_handler()
259217

260-
self.application_args = (fake_wsgi_environ, fake_start_response,)
218+
self.application_args = (fake_wsgi_environ, self.fake_start_response,)
261219
self.application_kwargs = dict(
262220
_format_output=self.instrumented_format_output,
263221
_retrieve_handler=self.instrumented_retrieve_handler,
@@ -278,7 +236,7 @@ def test_return_value_ok_returns_status_200(self):
278236
_trigger_and_unpack_result(application_result)
279237

280238
self.assertInstrumentation()
281-
self.assertResponseStatus(200)
239+
self.assertWsgiResponseStatus(self.fake_start_response, 200)
282240

283241
def test_return_value_ok_returns_valid_html_page(self):
284242
self.instrumented_retrieve_handler.program([], returnvalues.OK)

0 commit comments

Comments
 (0)