From f23d00af07a0d3006cb5ea225e6a9fa8d2e2544d Mon Sep 17 00:00:00 2001 From: Kenta Murata Date: Wed, 29 May 2024 12:48:32 +0900 Subject: [PATCH 1/8] Introduce PlaywrightManager helper module --- .../backend_helpers/playwright_manager.rb | 71 +++++++++++++++++++ lib/charty/backends/plotly.rb | 60 +++------------- 2 files changed, 80 insertions(+), 51 deletions(-) create mode 100644 lib/charty/backends/backend_helpers/playwright_manager.rb diff --git a/lib/charty/backends/backend_helpers/playwright_manager.rb b/lib/charty/backends/backend_helpers/playwright_manager.rb new file mode 100644 index 00000000..84e695c9 --- /dev/null +++ b/lib/charty/backends/backend_helpers/playwright_manager.rb @@ -0,0 +1,71 @@ +module Charty + module Backends + module BackendHelpers + module PlaywrightManager + @_playwright_exec = nil + @_browser = nil + @_context = nil + + at_exit do + if @_context + @_context.close + @_context = nil + end + if @_browser + @_browser.close + @_browser = nil + end + if @_playwright_exec + @_playwright_exec.stop + @_playwright_exec = nil + end + end + + module_function def playwright + unless @_playwright_exec + load_playwright + path = ENV.fetch("PLAYWRIGHT_CLI_EXECUTABLE_PATH", "npx playwright") + @_playwright_exec = Playwright.create(playwright_cli_executable_path: path) + end + @_playwright_exec.playwright + end + + module_function def launch_browser + playwright.chromium.launch(headless: true) + end + + module_function def default_browser + unless @_browser + @_browser = launch_browser + end + @_browser + end + + module_function def default_context + unless @_context + @_context = default_browser.new_context + end + @_context + end + + module_function def new_page(&block) + page = default_context.new_page + return page unless block + + begin + return block.call(page) + ensure + page.close + end + end + + module_function def load_playwright + require "playwright" + rescue LoadError + $stderr.puts "ERROR: You need to install playwright and playwright-ruby-client before using Plotly renderer" + raise + end + end + end + end +end diff --git a/lib/charty/backends/plotly.rb b/lib/charty/backends/plotly.rb index 06875031..1ad98738 100644 --- a/lib/charty/backends/plotly.rb +++ b/lib/charty/backends/plotly.rb @@ -5,6 +5,7 @@ require_relative "plotly_helpers/html_renderer" require_relative "plotly_helpers/notebook_renderer" require_relative "plotly_helpers/plotly_renderer" +require_relative "backend_helpers/playwright_manager" module Charty module Backends @@ -918,60 +919,17 @@ def self.mathjax_config end end - @playwright_fiber = nil - - def self.ensure_playwright - if @playwright_fiber.nil? - begin - require "playwright" - rescue LoadError - $stderr.puts "ERROR: You need to install playwright and playwright-ruby-client before using Plotly renderer" - raise - end + def self.render_image(input, output, format, element_id, width, height) + BackendHelpers::PlaywrightManager.new_page do |page| + page.set_viewport_size(width: width, height: height) + page.goto("file://#{input}") + element = page.query_selector("\##{element_id}") - @playwright_fiber = Fiber.new do - playwright_cli_executable_path = ENV.fetch("PLAYWRIGHT_CLI_EXECUTABLE_PATH", "npx playwright") - Playwright.create(playwright_cli_executable_path: playwright_cli_executable_path) do |playwright| - playwright.chromium.launch(headless: true) do |browser| - request = Fiber.yield - loop do - result = nil - case request.shift - when :finish - break - when :render - input, output, format, element_id, width, height = request - - page = browser.new_page - page.set_viewport_size(width: width, height: height) - page.goto("file://#{input}") - element = page.query_selector("\##{element_id}") - - kwargs = {type: format} - kwargs[:path] = output unless output.nil? - result = element.screenshot(**kwargs) - end - request = Fiber.yield(result) - end - end - end - end - @playwright_fiber.resume + kwargs = {type: format} + kwargs[:path] = output unless output.nil? + element.screenshot(**kwargs) end end - - def self.terminate_playwright - return if @playwright_fiber.nil? - - @playwright_fiber.resume([:finish]) - end - - at_exit { terminate_playwright } - - def self.render_image(input, output, format, element_id, width, height) - ensure_playwright if @playwright_fiber.nil? - @playwright_fiber.resume([:render, input, output, format.to_s, element_id, width, height]) - end end end end From 72be623725b7d1727981cd45aef03c89b3eef61b Mon Sep 17 00:00:00 2001 From: Kenta Murata Date: Thu, 30 May 2024 11:11:19 +0900 Subject: [PATCH 2/8] Shutdown playwright before test exit --- .../backend_helpers/playwright_manager.rb | 34 +++++++++++-------- test/run.rb | 8 ++++- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/lib/charty/backends/backend_helpers/playwright_manager.rb b/lib/charty/backends/backend_helpers/playwright_manager.rb index 84e695c9..f29c9365 100644 --- a/lib/charty/backends/backend_helpers/playwright_manager.rb +++ b/lib/charty/backends/backend_helpers/playwright_manager.rb @@ -6,21 +6,6 @@ module PlaywrightManager @_browser = nil @_context = nil - at_exit do - if @_context - @_context.close - @_context = nil - end - if @_browser - @_browser.close - @_browser = nil - end - if @_playwright_exec - @_playwright_exec.stop - @_playwright_exec = nil - end - end - module_function def playwright unless @_playwright_exec load_playwright @@ -65,6 +50,25 @@ module PlaywrightManager $stderr.puts "ERROR: You need to install playwright and playwright-ruby-client before using Plotly renderer" raise end + + module_function def shutdown + if @_context + @_context.close + @_context = nil + end + if @_browser + @_browser.close + @_browser = nil + end + if @_playwright_exec + @_playwright_exec.stop + @_playwright_exec = nil + end + end + + at_exit do + shutdown + end end end end diff --git a/test/run.rb b/test/run.rb index fa6a85c1..654b33c7 100755 --- a/test/run.rb +++ b/test/run.rb @@ -16,4 +16,10 @@ require_relative "helper" -exit(Test::Unit::AutoRunner.run(true, test_dir.to_s)) +result = Test::Unit::AutoRunner.run(true, test_dir.to_s) + +if defined? Charty::Backends::BackendHelpers::PlaywrightManager + Charty::Backends::BackendHelpers::PlaywrightManager.shutdown +end + +exit(result) From 38b93df9a2f436605f85ffa18c3cf922924b3ce9 Mon Sep 17 00:00:00 2001 From: Kenta Murata Date: Thu, 30 May 2024 11:25:52 +0900 Subject: [PATCH 3/8] WIP: timeout --- test/run.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/run.rb b/test/run.rb index 654b33c7..029b3deb 100755 --- a/test/run.rb +++ b/test/run.rb @@ -19,7 +19,10 @@ result = Test::Unit::AutoRunner.run(true, test_dir.to_s) if defined? Charty::Backends::BackendHelpers::PlaywrightManager - Charty::Backends::BackendHelpers::PlaywrightManager.shutdown + require "timeout" + Timeout.timeout(60) do + Charty::Backends::BackendHelpers::PlaywrightManager.shutdown + end end exit(result) From 023d23c10f258df609fd694c05158d1354fc161d Mon Sep 17 00:00:00 2001 From: Kenta Murata Date: Thu, 30 May 2024 13:56:54 +0900 Subject: [PATCH 4/8] Simplify PlaywrightManager.shutdown --- .../backend_helpers/playwright_manager.rb | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/lib/charty/backends/backend_helpers/playwright_manager.rb b/lib/charty/backends/backend_helpers/playwright_manager.rb index f29c9365..0a066e7b 100644 --- a/lib/charty/backends/backend_helpers/playwright_manager.rb +++ b/lib/charty/backends/backend_helpers/playwright_manager.rb @@ -52,18 +52,10 @@ module PlaywrightManager end module_function def shutdown - if @_context - @_context.close - @_context = nil - end - if @_browser - @_browser.close - @_browser = nil - end - if @_playwright_exec - @_playwright_exec.stop - @_playwright_exec = nil - end + @_playwright_exec.stop if @_playwright_exec + @_playwright_exec = nil + @_context = nil + @_browser = nil end at_exit do From fdd041a4f0ae68a7c32f5286e888558dc366d923 Mon Sep 17 00:00:00 2001 From: Kenta Murata Date: Fri, 31 May 2024 10:58:38 +0900 Subject: [PATCH 5/8] Stop using at_exit to shutdown playwright The processes of Playwright and headless browser can stop when the ruby process terminates. --- .../backends/backend_helpers/playwright_manager.rb | 4 ---- test/run.rb | 11 +---------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/lib/charty/backends/backend_helpers/playwright_manager.rb b/lib/charty/backends/backend_helpers/playwright_manager.rb index 0a066e7b..edca3f02 100644 --- a/lib/charty/backends/backend_helpers/playwright_manager.rb +++ b/lib/charty/backends/backend_helpers/playwright_manager.rb @@ -57,10 +57,6 @@ module PlaywrightManager @_context = nil @_browser = nil end - - at_exit do - shutdown - end end end end diff --git a/test/run.rb b/test/run.rb index 029b3deb..fa6a85c1 100755 --- a/test/run.rb +++ b/test/run.rb @@ -16,13 +16,4 @@ require_relative "helper" -result = Test::Unit::AutoRunner.run(true, test_dir.to_s) - -if defined? Charty::Backends::BackendHelpers::PlaywrightManager - require "timeout" - Timeout.timeout(60) do - Charty::Backends::BackendHelpers::PlaywrightManager.shutdown - end -end - -exit(result) +exit(Test::Unit::AutoRunner.run(true, test_dir.to_s)) From eb68d140c54026d6384638a4d416c707b81b5d85 Mon Sep 17 00:00:00 2001 From: Kenta Murata Date: Fri, 31 May 2024 17:57:10 +0900 Subject: [PATCH 6/8] Introduce TIMEOUT_SEC on test --- .github/workflows/ci.yml | 2 ++ .github/workflows/nmatrix.yml | 2 ++ .github/workflows/pycall.yml | 1 + test/run.rb | 10 +++++++++- 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9bdc1cb4..f3cfdf4f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -72,6 +72,8 @@ jobs: - run: bundle install --jobs 4 --retry 3 --without "nmatrix python" - run: bundle exec rake + env: + TIMEOUT_SEC: 180 - run: rake build diff --git a/.github/workflows/nmatrix.yml b/.github/workflows/nmatrix.yml index 7b312c46..c0132184 100644 --- a/.github/workflows/nmatrix.yml +++ b/.github/workflows/nmatrix.yml @@ -65,6 +65,8 @@ jobs: - run: bundle install --jobs 4 --retry 3 --without "numo python" - run: bundle exec rake + env: + TIMEOUT_SEC: 180 - run: rake build diff --git a/.github/workflows/pycall.yml b/.github/workflows/pycall.yml index 5c50fe54..98ffddbd 100644 --- a/.github/workflows/pycall.yml +++ b/.github/workflows/pycall.yml @@ -86,4 +86,5 @@ jobs: - run: bundle exec rake env: PYTHON: python + TIMEOUT_SEC: 180 continue-on-error: ${{ matrix.python == '2.x' }} diff --git a/test/run.rb b/test/run.rb index fa6a85c1..6cdeb9ee 100755 --- a/test/run.rb +++ b/test/run.rb @@ -4,6 +4,7 @@ # $VERBOSE = true require "pathname" +require "timeout" base_dir = Pathname(__dir__).parent.expand_path @@ -16,4 +17,11 @@ require_relative "helper" -exit(Test::Unit::AutoRunner.run(true, test_dir.to_s)) +run_test = lambda { Test::Unit::AutoRunner.run(true, test_dir.to_s) } +timeout_sec = ENV.fetch("TIMEOUT_SEC", "0").to_i +status = if timeout_sec > 0 + Timeout.timeout(timeout_sec) { run_test.() } + else + run_test.() + end +exit(status) From 060cb2ef0f7d8e9a5597ee045f9d69f509ab498c Mon Sep 17 00:00:00 2001 From: Kenta Murata Date: Fri, 31 May 2024 18:14:37 +0900 Subject: [PATCH 7/8] CI: Specify verbose flag --- .github/workflows/ci.yml | 2 +- .github/workflows/nmatrix.yml | 2 +- .github/workflows/pycall.yml | 2 +- Rakefile | 4 +++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f3cfdf4f..f8eb6da9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,7 +71,7 @@ jobs: - run: bundle install --jobs 4 --retry 3 --without "nmatrix python" - - run: bundle exec rake + - run: bundle exec rake VERBOSE=1 env: TIMEOUT_SEC: 180 diff --git a/.github/workflows/nmatrix.yml b/.github/workflows/nmatrix.yml index c0132184..f1616777 100644 --- a/.github/workflows/nmatrix.yml +++ b/.github/workflows/nmatrix.yml @@ -64,7 +64,7 @@ jobs: - run: bundle install --jobs 4 --retry 3 --without "numo python" - - run: bundle exec rake + - run: bundle exec rake VERBOSE=1 env: TIMEOUT_SEC: 180 diff --git a/.github/workflows/pycall.yml b/.github/workflows/pycall.yml index 98ffddbd..1dc1e507 100644 --- a/.github/workflows/pycall.yml +++ b/.github/workflows/pycall.yml @@ -83,7 +83,7 @@ jobs: - run: python -V - - run: bundle exec rake + - run: bundle exec rake VERBOSE=1 env: PYTHON: python TIMEOUT_SEC: 180 diff --git a/Rakefile b/Rakefile index 4bb2425a..68699553 100644 --- a/Rakefile +++ b/Rakefile @@ -3,7 +3,9 @@ require "rake/testtask" desc "Run tests" task :test do - ruby("test/run.rb") + verbose = "" + verbose = "-v" if ENV["VERBOSE"].to_i > 0 + ruby("test/run.rb #{verbose}".strip) end task default: :test From a09d0985fbe3e9bd2419432ab439375ed1371f9e Mon Sep 17 00:00:00 2001 From: Kenta Murata Date: Sat, 1 Jun 2024 11:15:41 +0900 Subject: [PATCH 8/8] Set TIMEOUT_SEC=480 --- .github/workflows/ci.yml | 2 +- .github/workflows/nmatrix.yml | 2 +- .github/workflows/pycall.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f8eb6da9..87031eb8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,7 +73,7 @@ jobs: - run: bundle exec rake VERBOSE=1 env: - TIMEOUT_SEC: 180 + TIMEOUT_SEC: 480 - run: rake build diff --git a/.github/workflows/nmatrix.yml b/.github/workflows/nmatrix.yml index f1616777..07937fa1 100644 --- a/.github/workflows/nmatrix.yml +++ b/.github/workflows/nmatrix.yml @@ -66,7 +66,7 @@ jobs: - run: bundle exec rake VERBOSE=1 env: - TIMEOUT_SEC: 180 + TIMEOUT_SEC: 480 - run: rake build diff --git a/.github/workflows/pycall.yml b/.github/workflows/pycall.yml index 1dc1e507..a0bd253e 100644 --- a/.github/workflows/pycall.yml +++ b/.github/workflows/pycall.yml @@ -86,5 +86,5 @@ jobs: - run: bundle exec rake VERBOSE=1 env: PYTHON: python - TIMEOUT_SEC: 180 + TIMEOUT_SEC: 480 continue-on-error: ${{ matrix.python == '2.x' }}