edq-utils 0.0.5__py3-none-any.whl → 0.0.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of edq-utils might be problematic. Click here for more details.

Files changed (62) hide show
  1. edq/__init__.py +1 -1
  2. edq/cli/config/__init__.py +3 -0
  3. edq/cli/config/list.py +69 -0
  4. edq/cli/http/__init__.py +3 -0
  5. edq/cli/http/exchange-server.py +71 -0
  6. edq/cli/http/send-exchange.py +45 -0
  7. edq/cli/http/verify-exchanges.py +38 -0
  8. edq/cli/testing/__init__.py +3 -0
  9. edq/cli/testing/cli-test.py +8 -5
  10. edq/cli/version.py +2 -1
  11. edq/core/argparser.py +28 -3
  12. edq/core/config.py +268 -0
  13. edq/core/config_test.py +1038 -0
  14. edq/procedure/__init__.py +0 -0
  15. edq/procedure/verify_exchanges.py +85 -0
  16. edq/testing/asserts.py +0 -1
  17. edq/testing/cli.py +17 -1
  18. edq/testing/httpserver.py +553 -0
  19. edq/testing/httpserver_test.py +424 -0
  20. edq/testing/run.py +40 -10
  21. edq/testing/testdata/cli/data/configs/empty/edq-config.json +1 -0
  22. edq/testing/testdata/cli/data/configs/simple-1/edq-config.json +4 -0
  23. edq/testing/testdata/cli/data/configs/simple-2/edq-config.json +3 -0
  24. edq/testing/testdata/cli/data/configs/value-number/edq-config.json +3 -0
  25. edq/testing/testdata/cli/tests/config/list/config_list_base.txt +16 -0
  26. edq/testing/testdata/cli/tests/config/list/config_list_config_value_number.txt +10 -0
  27. edq/testing/testdata/cli/tests/config/list/config_list_ignore_config.txt +14 -0
  28. edq/testing/testdata/cli/tests/config/list/config_list_no_config.txt +8 -0
  29. edq/testing/testdata/cli/tests/config/list/config_list_show_origin.txt +13 -0
  30. edq/testing/testdata/cli/tests/config/list/config_list_skip_header.txt +10 -0
  31. edq/testing/testdata/http/exchanges/simple.httpex.json +5 -0
  32. edq/testing/testdata/http/exchanges/simple_anchor.httpex.json +5 -0
  33. edq/testing/testdata/http/exchanges/simple_file.httpex.json +10 -0
  34. edq/testing/testdata/http/exchanges/simple_file_binary.httpex.json +10 -0
  35. edq/testing/testdata/http/exchanges/simple_file_get_params.httpex.json +14 -0
  36. edq/testing/testdata/http/exchanges/simple_file_multiple.httpex.json +13 -0
  37. edq/testing/testdata/http/exchanges/simple_file_name.httpex.json +11 -0
  38. edq/testing/testdata/http/exchanges/simple_file_post_multiple.httpex.json +13 -0
  39. edq/testing/testdata/http/exchanges/simple_file_post_params.httpex.json +14 -0
  40. edq/testing/testdata/http/exchanges/simple_headers.httpex.json +8 -0
  41. edq/testing/testdata/http/exchanges/simple_jsonresponse_dict.httpex.json +7 -0
  42. edq/testing/testdata/http/exchanges/simple_jsonresponse_list.httpex.json +9 -0
  43. edq/testing/testdata/http/exchanges/simple_params.httpex.json +9 -0
  44. edq/testing/testdata/http/exchanges/simple_post.httpex.json +5 -0
  45. edq/testing/testdata/http/exchanges/simple_post_params.httpex.json +9 -0
  46. edq/testing/testdata/http/exchanges/simple_post_urlparams.httpex.json +5 -0
  47. edq/testing/testdata/http/exchanges/simple_urlparams.httpex.json +5 -0
  48. edq/testing/testdata/http/exchanges/specialcase_listparams_explicit.httpex.json +8 -0
  49. edq/testing/testdata/http/exchanges/specialcase_listparams_url.httpex.json +5 -0
  50. edq/testing/testdata/http/files/a.txt +1 -0
  51. edq/testing/testdata/http/files/tiny.png +0 -0
  52. edq/testing/unittest.py +12 -7
  53. edq/util/dirent.py +2 -0
  54. edq/util/json.py +21 -4
  55. edq/util/net.py +894 -0
  56. edq_utils-0.0.6.dist-info/METADATA +156 -0
  57. edq_utils-0.0.6.dist-info/RECORD +78 -0
  58. edq_utils-0.0.5.dist-info/METADATA +0 -63
  59. edq_utils-0.0.5.dist-info/RECORD +0 -34
  60. {edq_utils-0.0.5.dist-info → edq_utils-0.0.6.dist-info}/WHEEL +0 -0
  61. {edq_utils-0.0.5.dist-info → edq_utils-0.0.6.dist-info}/licenses/LICENSE +0 -0
  62. {edq_utils-0.0.5.dist-info → edq_utils-0.0.6.dist-info}/top_level.txt +0 -0
File without changes
@@ -0,0 +1,85 @@
1
+ """
2
+ Verify that exchanges sent to a given server have the same response.
3
+ """
4
+
5
+ import glob
6
+ import logging
7
+ import os
8
+ import typing
9
+ import unittest
10
+
11
+ import edq.testing.unittest
12
+ import edq.util.net
13
+
14
+ class ExchangeVerification(edq.testing.unittest.BaseTest):
15
+ """ Verify that exchanges match their content. """
16
+
17
+ def run(paths: typing.List[str], server: str) -> int:
18
+ """ Run exchange verification. """
19
+
20
+ exchange_paths = _collect_exchange_paths(paths)
21
+
22
+ _attach_tests(exchange_paths, server)
23
+
24
+ runner = unittest.TextTestRunner(verbosity = 2)
25
+ tests = unittest.defaultTestLoader.loadTestsFromTestCase(ExchangeVerification)
26
+ results = runner.run(tests)
27
+
28
+ return len(results.errors) + len(results.failures)
29
+
30
+ def _attach_tests(
31
+ paths: typing.List[str],
32
+ server: str,
33
+ extension: str = edq.util.net.DEFAULT_HTTP_EXCHANGE_EXTENSION,
34
+ ) -> None:
35
+ """ Create tests for each path and attach them to the ExchangeVerification class. """
36
+
37
+ common_prefix = os.path.commonprefix(paths)
38
+
39
+ for path in paths:
40
+ name = path.replace(common_prefix, '').replace(extension, '')
41
+ test_name = f"test_verify_exchange__{name}"
42
+
43
+ setattr(ExchangeVerification, test_name, _get_test_method(path, server))
44
+
45
+ def _get_test_method(path: str, server: str,
46
+ match_options: typing.Union[typing.Dict[str, typing.Any], None] = None,
47
+ ) -> typing.Callable:
48
+ """ Create a test method for the given path. """
49
+
50
+ if (match_options is None):
51
+ match_options = {}
52
+
53
+ def __method(self: edq.testing.unittest.BaseTest) -> None:
54
+ exchange = edq.util.net.HTTPExchange.from_path(path)
55
+ response, body = exchange.make_request(server, raise_for_status = False, **match_options)
56
+
57
+ match, hint = exchange.match_response(response, override_body = body, **match_options)
58
+ if (not match):
59
+ raise AssertionError(f"Exchange does not match: '{hint}'.")
60
+
61
+ return __method
62
+
63
+ def _collect_exchange_paths(
64
+ paths: typing.List[str],
65
+ extension: str = edq.util.net.DEFAULT_HTTP_EXCHANGE_EXTENSION,
66
+ ) -> typing.List[str]:
67
+ """ Collect exchange files by matching extensions and descending dirs. """
68
+
69
+ final_paths = []
70
+
71
+ for path in paths:
72
+ path = os.path.abspath(path)
73
+
74
+ if (os.path.isfile(path)):
75
+ if (path.endswith(extension)):
76
+ final_paths.append(path)
77
+ else:
78
+ logging.warning("Path does not look like an exchange file: '%s'.", path)
79
+ else:
80
+ dirent_paths = glob.glob(os.path.join(path, "**", f"*{extension}"), recursive = True)
81
+ for dirent_path in dirent_paths:
82
+ final_paths.append(dirent_path)
83
+
84
+ final_paths.sort()
85
+ return final_paths
edq/testing/asserts.py CHANGED
@@ -37,7 +37,6 @@ class StringComparisonAssertion(typing.Protocol):
37
37
  Perform an assertion between expected and actual data.
38
38
  """
39
39
 
40
-
41
40
  def content_equals_raw(test: edq.testing.unittest.BaseTest, expected: str, actual: str, **kwargs: typing.Any) -> None:
42
41
  """ Check for equality using a simple string comparison. """
43
42
 
edq/testing/cli.py CHANGED
@@ -9,6 +9,12 @@ and a second part which is the expected text output (stdout).
9
9
  For the keys of the JSON section, see the defaulted arguments to CLITestInfo.
10
10
  The options JSON will be splatted into CLITestInfo's constructor.
11
11
 
12
+ If a test class implements a method with the signature `modify_cli_test_info(self, test_info: CLITestInfo) -> None`,
13
+ then this method will be called with the test info right after the test info is read from disk.
14
+
15
+ If a test class implements a class method with the signature `get_test_basename(cls, path: str) -> str`,
16
+ then this method will be called to create the base name for the test case at the given path.
17
+
12
18
  The expected output or any argument can reference the test's current temp or data dirs with `__TEMP_DIR__()` or `__DATA_DIR__()`, respectively.
13
19
  An optional slash-separated path can be used as an argument to reference a path within those base directories.
14
20
  For example, `__DATA_DIR__(foo/bar.txt)` references `bar.txt` inside the `foo` directory inside the data directory.
@@ -30,6 +36,7 @@ import edq.util.pyimport
30
36
 
31
37
  TEST_CASE_SEP: str = '---'
32
38
  DATA_DIR_ID: str = '__DATA_DIR__'
39
+ ABS_DATA_DIR_ID: str = '__ABS_DATA_DIR__'
33
40
  TEMP_DIR_ID: str = '__TEMP_DIR__'
34
41
  BASE_DIR_ID: str = '__BASE_DIR__'
35
42
 
@@ -175,6 +182,7 @@ class CLITestInfo:
175
182
  (DATA_DIR_ID, self.data_dir),
176
183
  (TEMP_DIR_ID, self.temp_dir),
177
184
  (BASE_DIR_ID, self.base_dir),
185
+ (ABS_DATA_DIR_ID, os.path.abspath(self.data_dir)),
178
186
  ]
179
187
 
180
188
  for (key, target_dir) in replacements:
@@ -251,6 +259,10 @@ def _get_test_method(test_name: str, path: str, data_dir: str) -> typing.Callabl
251
259
  def __method(self: edq.testing.unittest.BaseTest) -> None:
252
260
  test_info = CLITestInfo.load_path(path, test_name, getattr(self, BASE_TEMP_DIR_ATTR), data_dir)
253
261
 
262
+ # Allow the test class a chance to modify the test info before the test runs.
263
+ if (hasattr(self, 'modify_cli_test_info')):
264
+ self.modify_cli_test_info(test_info)
265
+
254
266
  if (test_info.should_skip()):
255
267
  self.skipTest(test_info.skip_message())
256
268
 
@@ -301,7 +313,11 @@ def add_test_paths(target_class: type, data_dir: str, paths: typing.List[str]) -
301
313
  setattr(target_class, BASE_TEMP_DIR_ATTR, edq.util.dirent.get_temp_path('edq_cli_test_'))
302
314
 
303
315
  for path in sorted(paths):
304
- test_name = 'test_cli__' + os.path.splitext(os.path.basename(path))[0]
316
+ basename = os.path.splitext(os.path.basename(path))[0]
317
+ if (hasattr(target_class, 'get_test_basename')):
318
+ basename = getattr(target_class, 'get_test_basename')(path)
319
+
320
+ test_name = 'test_cli__' + basename
305
321
 
306
322
  try:
307
323
  setattr(target_class, test_name, _get_test_method(test_name, path, data_dir))