mirror of
https://github.com/discourse/discourse.git
synced 2024-12-01 09:53:43 +08:00
30990006a9
This reduces chances of errors where consumers of strings mutate inputs and reduces memory usage of the app. Test suite passes now, but there may be some stuff left, so we will run a few sites on a branch prior to merging
192 lines
4.5 KiB
Ruby
192 lines
4.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "demon/rails_autospec"
|
|
|
|
module Autospec
|
|
|
|
class QunitRunner < BaseRunner
|
|
|
|
WATCHERS = {}
|
|
def self.watch(pattern, &blk)
|
|
WATCHERS[pattern] = blk
|
|
end
|
|
def watchers
|
|
WATCHERS
|
|
end
|
|
|
|
# Discourse specific
|
|
watch(%r{^app/assets/javascripts/discourse/(.+)\.js.es6$}) { |m| "test/javascripts/#{m[1]}-test.js.es6" }
|
|
watch(%r{^app/assets/javascripts/admin/(.+)\.js.es6$}) { |m| "test/javascripts/admin/#{m[1]}-test.js.es6" }
|
|
watch(%r{^test/javascripts/.+\.js.es6$})
|
|
|
|
RELOADERS = Set.new
|
|
def self.reload(pattern)
|
|
RELOADERS << pattern
|
|
end
|
|
def reloaders
|
|
RELOADERS
|
|
end
|
|
|
|
# Discourse specific
|
|
reload(%r{^test/javascripts/fixtures/.+_fixtures\.js(\.es6)?$})
|
|
reload(%r{^test/javascripts/(helpers|mixins)/.+\.js(\.es6)?$})
|
|
reload("test/javascripts/test_helper.js")
|
|
|
|
watch(%r{^plugins/.*/test/.+\.js.es6$})
|
|
|
|
require "socket"
|
|
|
|
class ChromeNotInstalled < StandardError; end
|
|
|
|
def initialize
|
|
ensure_chrome_is_installed
|
|
end
|
|
|
|
def start
|
|
# ensure we can launch the rails server
|
|
unless port_available?(port)
|
|
puts "Port #{port} is not available"
|
|
puts "Either kill the process using that port or use the `TEST_SERVER_PORT` environment variable"
|
|
return
|
|
end
|
|
|
|
# start rails
|
|
start_rails_server
|
|
@running = true
|
|
end
|
|
|
|
def running?
|
|
@running
|
|
end
|
|
|
|
def run(specs)
|
|
puts "Running Qunit: #{specs}"
|
|
Demon::RailsAutospec.ensure_running
|
|
|
|
abort
|
|
|
|
qunit_url = "http://localhost:#{port}/qunit"
|
|
|
|
if specs != "spec"
|
|
module_or_filename, test_id, _name = specs.strip.split(":::")
|
|
module_name = module_or_filename
|
|
if !test_id
|
|
module_name = try_to_find_module_name(module_or_filename)
|
|
qunit_url << "?module=#{module_name}" if module_name
|
|
else
|
|
qunit_url << "?testId=#{test_id}"
|
|
end
|
|
end
|
|
|
|
cmd = "node #{Rails.root}/test/run-qunit.js \"#{qunit_url}\" 3000000 ./tmp/qunit_result"
|
|
|
|
@pid = Process.spawn(cmd)
|
|
_, status = Process.wait2(@pid)
|
|
|
|
status.exitstatus
|
|
end
|
|
|
|
def reload
|
|
stop_rails_server
|
|
sleep 1
|
|
start_rails_server
|
|
end
|
|
|
|
def abort
|
|
if @pid
|
|
children_processes(@pid).each { |pid| kill_process(pid) }
|
|
kill_process(@pid)
|
|
@pid = nil
|
|
end
|
|
end
|
|
|
|
def failed_specs
|
|
specs = []
|
|
path = './tmp/qunit_result'
|
|
specs = File.readlines(path) if File.exist?(path)
|
|
specs
|
|
end
|
|
|
|
def stop
|
|
abort
|
|
stop_rails_server
|
|
@running = false
|
|
end
|
|
|
|
private
|
|
|
|
def ensure_chrome_is_installed
|
|
|
|
binary = "google-chrome-stable" if system("command -v google-chrome-stable >/dev/null;")
|
|
binary ||= "google-chrome" if system("command -v google-chrome >/dev/null;")
|
|
|
|
raise ChromeNotInstalled.new if !binary
|
|
|
|
if Gem::Version.new(`#{binary} --version`.match(/[\d\.]+/)[0]) < Gem::Version.new("59")
|
|
raise "Chrome 59 or higher is required"
|
|
end
|
|
end
|
|
|
|
def port_available?(port)
|
|
TCPServer.open(port).close
|
|
true
|
|
rescue Errno::EADDRINUSE
|
|
false
|
|
end
|
|
|
|
def port
|
|
@port ||= ENV["TEST_SERVER_PORT"] || 60099
|
|
end
|
|
|
|
def start_rails_server
|
|
Demon::RailsAutospec.start(1)
|
|
end
|
|
|
|
def stop_rails_server
|
|
Demon::RailsAutospec.stop
|
|
end
|
|
|
|
def children_processes(base = Process.pid)
|
|
process_tree = Hash.new { |hash, key| hash[key] = [key] }
|
|
Hash[*`ps -eo pid,ppid`.scan(/\d+/).map(&:to_i)].each do |pid, ppid|
|
|
process_tree[ppid] << process_tree[pid]
|
|
end
|
|
process_tree[base].flatten - [base]
|
|
end
|
|
|
|
def kill_process(pid)
|
|
return unless pid
|
|
Process.kill("INT", pid) rescue nil
|
|
while (Process.getpgid(pid) rescue nil)
|
|
sleep 0.001
|
|
end
|
|
end
|
|
|
|
def try_to_find_module_name(file)
|
|
file, _ = file.split(/:\d+$/)
|
|
return unless File.exists?(file)
|
|
File.open(file, "r").each_line do |line|
|
|
if m = /module\(['"]([^'"]+)/i.match(line)
|
|
return m[1]
|
|
end
|
|
if m = /moduleForWidget\(['"]([^"']+)/i.match(line)
|
|
return "widget:#{m[1]}"
|
|
end
|
|
if m = /acceptance\(['"]([^"']+)/i.match(line)
|
|
return "Acceptance: #{m[1]}"
|
|
end
|
|
if m = /moduleFor\(['"]([^'"]+)/i.match(line)
|
|
return m[1]
|
|
end
|
|
if m = /moduleForComponent\(['"]([^"']+)/i.match(line)
|
|
return m[1]
|
|
end
|
|
end
|
|
|
|
nil
|
|
end
|
|
|
|
end
|
|
|
|
end
|