You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

пре 4 година
пре 4 година
пре 4 година
пре 4 година
пре 4 година
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. from pathlib import Path
  2. from contextlib import contextmanager
  3. import json
  4. from http.server import SimpleHTTPRequestHandler, HTTPServer
  5. from typing import NamedTuple, Any, Iterator
  6. from concurrent.futures import ThreadPoolExecutor
  7. from functools import partial
  8. import tempfile
  9. import sys
  10. import subprocess
  11. import pytest
  12. from _pytest.fixtures import FixtureRequest
  13. class DirectoryServingHTTPRequestHandler(SimpleHTTPRequestHandler):
  14. """
  15. A simple HTTP request handler that simply serves files from a directory given to the constructor.
  16. """
  17. def __init__(self, *args: Any, **kwargs: Any) -> None:
  18. self.dir = kwargs.pop('dir')
  19. super().__init__(*args, **kwargs)
  20. def translate_path(self, path: str) -> str:
  21. # Convert the given URL path to a path relative to the directory we are serving
  22. abspath = Path(super().translate_path(path)) # type: ignore
  23. relpath = abspath.relative_to(Path.cwd())
  24. return str(self.dir / relpath)
  25. class ServerInfo(NamedTuple):
  26. """
  27. Information about an HTTP server fixture
  28. """
  29. base_url: str
  30. root: Path
  31. @contextmanager
  32. def run_http_server(dirpath: Path, port: int) -> Iterator[ServerInfo]:
  33. """
  34. Context manager that spawns an HTTP server that serves thegiven directory on
  35. the given TCP port.
  36. """
  37. handler = partial(DirectoryServingHTTPRequestHandler, dir=dirpath)
  38. addr = ('127.0.0.1', port)
  39. pool = ThreadPoolExecutor()
  40. with HTTPServer(addr, handler) as httpd:
  41. pool.submit(lambda: httpd.serve_forever(poll_interval=0.1))
  42. try:
  43. print('Serving at', addr)
  44. yield ServerInfo(f'http://127.0.0.1:{port}', dirpath)
  45. finally:
  46. httpd.shutdown()
  47. @pytest.fixture()
  48. def http_tmp_dir_server(tmp_path: Path, unused_tcp_port: int) -> Iterator[ServerInfo]:
  49. """
  50. Creates an HTTP server that serves the contents of a new
  51. temporary directory.
  52. """
  53. with run_http_server(tmp_path, unused_tcp_port) as s:
  54. yield s
  55. class RepoFixture:
  56. """
  57. A fixture handle to a dds HTTP repository, including a path and URL.
  58. """
  59. def __init__(self, dds_exe: Path, info: ServerInfo, repo_name: str) -> None:
  60. self.repo_name = repo_name
  61. self.server = info
  62. self.url = info.base_url
  63. self.dds_exe = dds_exe
  64. def import_json_data(self, data: Any) -> None:
  65. """
  66. Import some packages into the repo for the given JSON data. Uses
  67. mkrepo.py
  68. """
  69. with tempfile.NamedTemporaryFile(delete=False) as f:
  70. f.write(json.dumps(data).encode())
  71. f.close()
  72. self.import_json_file(Path(f.name))
  73. Path(f.name).unlink()
  74. def import_json_file(self, fpath: Path) -> None:
  75. """
  76. Import some package into the repo for the given JSON file. Uses mkrepo.py
  77. """
  78. subprocess.check_call([
  79. sys.executable,
  80. str(Path.cwd() / 'tools/mkrepo.py'),
  81. f'--dds-exe={self.dds_exe}',
  82. f'--dir={self.server.root}',
  83. f'--spec={fpath}',
  84. ])
  85. @pytest.fixture()
  86. def http_repo(dds_exe: Path, http_tmp_dir_server: ServerInfo, request: FixtureRequest) -> Iterator[RepoFixture]:
  87. """
  88. Fixture that creates a new empty dds repository and an HTTP server to serve
  89. it.
  90. """
  91. name = f'test-repo-{request.function.__name__}'
  92. subprocess.check_call([str(dds_exe), 'repoman', 'init', str(http_tmp_dir_server.root), f'--name={name}'])
  93. yield RepoFixture(dds_exe, http_tmp_dir_server, repo_name=name)