test_browser.py 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. import os
  2. import subprocess
  3. import sys
  4. import tempfile
  5. import time
  6. import unittest
  7. from pathlib import Path
  8. from unittest.mock import patch
  9. from PIL import Image
  10. import fixtures
  11. class BrowserToolsRegression(unittest.TestCase):
  12. def test_explicit_unusable_browser_fails_authoritatively(self):
  13. module = fixtures.load_script("browser_tools")
  14. with self.assertRaises(FileNotFoundError):
  15. module.find_browser("this-browser-does-not-exist")
  16. if os.name != "nt":
  17. with tempfile.NamedTemporaryFile() as file:
  18. with self.assertRaises(FileNotFoundError):
  19. module.find_browser(file.name)
  20. def test_windows_chrome_edge_discovery(self):
  21. module = fixtures.load_script("browser_tools")
  22. with tempfile.TemporaryDirectory() as directory:
  23. root = Path(directory)
  24. for relative in ("Google/Chrome/Application/chrome.exe", "Microsoft/Edge/Application/msedge.exe"):
  25. browser = root / relative
  26. browser.parent.mkdir(parents=True)
  27. browser.touch()
  28. with patch.object(module.sys, "platform", "win32"), patch.dict(os.environ, {"LOCALAPPDATA": str(root)}, clear=True), patch.object(module.shutil, "which", return_value=None):
  29. self.assertEqual(module.find_browser(None), str(browser.resolve()))
  30. browser.unlink()
  31. with patch.object(module.sys, "platform", "win32"), patch.dict(os.environ, {}, clear=True), patch.object(module.shutil, "which", side_effect=lambda name: "C:/Edge/msedge.exe" if name == "msedge.exe" else None):
  32. self.assertEqual(module.find_browser(None), "C:/Edge/msedge.exe")
  33. def browser(self, module):
  34. browser = module.find_browser(os.environ.get("MOVIE_BROWSER"))
  35. if not browser:
  36. self.skipTest("Chrome/Edge is required")
  37. return browser
  38. def test_render_card_special_path_is_a_real_png(self):
  39. module = fixtures.load_script("browser_tools")
  40. browser = self.browser(module)
  41. with tempfile.TemporaryDirectory() as directory:
  42. work = Path(directory) / "special path O'Brien λ # %"
  43. work.mkdir()
  44. html, png = work / "card page.html", work / "card.png"
  45. html.write_text("<meta charset='utf-8'><style>body{margin:0;background:rgb(255,0,0)}</style><p>λ</p>", encoding="utf-8")
  46. module.render_card(html, png, browser=browser, width=640, height=360)
  47. with Image.open(png) as image:
  48. self.assertEqual(image.size, (640, 360))
  49. self.assertEqual(image.convert("RGB").getpixel((500, 200)), (255, 0, 0))
  50. def test_render_card_timeout_preserves_unrelated_process(self):
  51. module = fixtures.load_script("browser_tools")
  52. browser = self.browser(module)
  53. sentinel = subprocess.Popen([sys.executable, "-c", "import time; time.sleep(60)"])
  54. try:
  55. with tempfile.TemporaryDirectory() as directory:
  56. work = Path(directory)
  57. html = work / "card.html"
  58. html.write_text("<p>timeout</p>", encoding="utf-8")
  59. start = time.monotonic()
  60. with self.assertRaises(TimeoutError):
  61. module.render_card(html, work / "card.png", browser=browser, width=640, height=360, timeout=0)
  62. self.assertLess(time.monotonic() - start, 10)
  63. self.assertIsNone(sentinel.poll())
  64. finally:
  65. sentinel.terminate()
  66. sentinel.wait(timeout=10)