[前][次][番号順一覧][スレッド一覧]

ruby-changes:52631

From: eregon <ko1@a...>
Date: Wed, 26 Sep 2018 03:47:22 +0900 (JST)
Subject: [ruby-changes:52631] eregon:r64843 (trunk): Update to ruby/mspec@2bca8cb

eregon	2018-09-26 03:47:17 +0900 (Wed, 26 Sep 2018)

  New Revision: 64843

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=64843

  Log:
    Update to ruby/mspec@2bca8cb

  Added files:
    trunk/spec/mspec/lib/mspec/runner/parallel.rb
    trunk/spec/mspec/spec/fixtures/chatty_spec.rb
    trunk/spec/mspec/spec/fixtures/die_spec.rb
  Modified files:
    trunk/spec/mspec/lib/mspec/commands/mspec.rb
    trunk/spec/mspec/lib/mspec/runner/formatters/multi.rb
    trunk/spec/mspec/lib/mspec/runner/mspec.rb
    trunk/spec/mspec/spec/integration/run_spec.rb
    trunk/spec/mspec/spec/runner/formatters/multi_spec.rb
Index: spec/mspec/spec/fixtures/chatty_spec.rb
===================================================================
--- spec/mspec/spec/fixtures/chatty_spec.rb	(nonexistent)
+++ spec/mspec/spec/fixtures/chatty_spec.rb	(revision 64843)
@@ -0,0 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/spec/mspec/spec/fixtures/chatty_spec.rb#L1
+unless defined?(RSpec)
+  describe "Chatty#spec" do
+    it "prints too much" do
+      STDOUT.puts "Hello\nIt's me!"
+      1.should == 1
+    end
+  end
+end
Index: spec/mspec/spec/fixtures/die_spec.rb
===================================================================
--- spec/mspec/spec/fixtures/die_spec.rb	(nonexistent)
+++ spec/mspec/spec/fixtures/die_spec.rb	(revision 64843)
@@ -0,0 +1,7 @@ https://github.com/ruby/ruby/blob/trunk/spec/mspec/spec/fixtures/die_spec.rb#L1
+unless defined?(RSpec)
+  describe "Deadly#spec" do
+    it "dies" do
+      abort "DEAD"
+    end
+  end
+end
Index: spec/mspec/spec/runner/formatters/multi_spec.rb
===================================================================
--- spec/mspec/spec/runner/formatters/multi_spec.rb	(revision 64842)
+++ spec/mspec/spec/runner/formatters/multi_spec.rb	(revision 64843)
@@ -9,10 +9,10 @@ describe MultiFormatter, "#aggregate_res https://github.com/ruby/ruby/blob/trunk/spec/mspec/spec/runner/formatters/multi_spec.rb#L9
     @file = double("file").as_null_object
 
     File.stub(:delete)
-    YAML.stub(:load)
+    File.stub(:read)
 
     @hash = { "files"=>1, "examples"=>1, "expectations"=>2, "failures"=>0, "errors"=>0 }
-    File.stub(:open).and_yield(@file).and_return(@hash)
+    YAML.stub(:load).and_return(@hash)
 
     @formatter = MultiFormatter.new
     @formatter.timer.stub(:format).and_return("Finished in 42 seconds")
Index: spec/mspec/spec/integration/run_spec.rb
===================================================================
--- spec/mspec/spec/integration/run_spec.rb	(revision 64842)
+++ spec/mspec/spec/integration/run_spec.rb	(revision 64843)
@@ -24,23 +24,21 @@ EOS https://github.com/ruby/ruby/blob/trunk/spec/mspec/spec/integration/run_spec.rb#L24
 
   a_stats = "1 file, 3 examples, 2 expectations, 1 failure, 1 error, 0 tagged\n"
   ab_stats = "2 files, 4 examples, 3 expectations, 1 failure, 1 error, 0 tagged\n"
+  fixtures = "spec/fixtures"
 
   it "runs the specs" do
-    fixtures = "spec/fixtures"
     out, ret = run_mspec("run", "#{fixtures}/a_spec.rb")
     out.should == "RUBY_DESCRIPTION\n.FE\n#{a_spec_output}\n#{a_stats}"
     ret.success?.should == false
   end
 
   it "directly with mspec-run runs the specs" do
-    fixtures = "spec/fixtures"
     out, ret = run_mspec("-run", "#{fixtures}/a_spec.rb")
     out.should == "RUBY_DESCRIPTION\n.FE\n#{a_spec_output}\n#{a_stats}"
     ret.success?.should == false
   end
 
   it "runs the specs in parallel with -j" do
-    fixtures = "spec/fixtures"
     out, ret = run_mspec("run", "-j #{fixtures}/a_spec.rb #{fixtures}/b_spec.rb")
     progress_bar =
       "\r[/ |                   0%                     | 00:00:00] \e[0;32m     0F \e[0;32m     0E\e[0m " +
@@ -49,4 +47,22 @@ EOS https://github.com/ruby/ruby/blob/trunk/spec/mspec/spec/integration/run_spec.rb#L47
     out.should == "RUBY_DESCRIPTION\n#{progress_bar}\n#{a_spec_output}\n#{ab_stats}"
     ret.success?.should == false
   end
+
+  it "gives a useful error message when a subprocess dies in parallel mode" do
+    out, ret = run_mspec("run", "-j #{fixtures}/b_spec.rb #{fixtures}/die_spec.rb")
+    lines = out.lines
+    lines.should include "A child mspec-run process died unexpectedly while running CWD/spec/fixtures/die_spec.rb\n"
+    lines.should include "Finished in D.DDDDDD seconds\n"
+    lines.last.should =~ /^\d files?, \d examples?, \d expectations?, 0 failures, 0 errors, 0 tagged$/
+    ret.success?.should == false
+  end
+
+  it "gives a useful error message when a subprocess prints unexpected output on STDOUT in parallel mode" do
+    out, ret = run_mspec("run", "-j #{fixtures}/b_spec.rb #{fixtures}/chatty_spec.rb")
+    lines = out.lines
+    lines.should include "A child mspec-run process printed unexpected output on STDOUT: #{'"Hello\nIt\'s me!\n"'} while running CWD/spec/fixtures/chatty_spec.rb\n"
+    lines.should include "Finished in D.DDDDDD seconds\n"
+    lines.last.should == "2 files, 2 examples, 2 expectations, 0 failures, 0 errors, 0 tagged\n"
+    ret.success?.should == false
+  end
 end
Index: spec/mspec/lib/mspec/commands/mspec.rb
===================================================================
--- spec/mspec/lib/mspec/commands/mspec.rb	(revision 64842)
+++ spec/mspec/lib/mspec/commands/mspec.rb	(revision 64843)
@@ -89,72 +89,13 @@ class MSpecMain < MSpecScript https://github.com/ruby/ruby/blob/trunk/spec/mspec/lib/mspec/commands/mspec.rb#L89
   def register; end
 
   def multi_exec(argv)
-    MSpec.register_files @files
-
     require 'mspec/runner/formatters/multi'
     formatter = MultiFormatter.new
-    if config[:formatter]
-      warn "formatter options is ignored due to multi option"
-    end
+    warn "formatter options is ignored due to multi option" if config[:formatter]
 
-    output_files = []
+    require 'mspec/runner/parallel'
     processes = cores(@files.size)
-    children = processes.times.map { |i|
-      name = tmp "mspec-multi-#{i}"
-      output_files << name
-
-      env = {
-        "SPEC_TEMP_DIR" => "rubyspec_temp_#{i}",
-        "MSPEC_MULTI" => i.to_s
-      }
-      command = argv + ["-fy", "-o", name]
-      $stderr.puts "$ #{command.join(' ')}" if $MSPEC_DEBUG
-      IO.popen([env, *command, close_others: false], "rb+")
-    }
-
-    puts children.map { |child| child.gets }.uniq
-    formatter.start
-    last_files = {}
-
-    until @files.empty?
-      IO.select(children)[0].each { |io|
-        reply = io.read(1)
-        case reply
-        when '.'
-          formatter.unload
-        when nil
-          raise "Worker died!"
-        else
-          while chunk = (io.read_nonblock(4096) rescue nil)
-            reply += chunk
-          end
-          reply.chomp!('.')
-          msg = "A child mspec-run process printed unexpected output on STDOUT"
-          if last_file = last_files[io]
-            msg += " while running #{last_file}"
-          end
-          abort "\n#{msg}: #{reply.inspect}"
-        end
-
-        unless @files.empty?
-          file = @files.shift
-          last_files[io] = file
-          io.puts file
-        end
-      }
-    end
-
-    success = true
-    children.each { |child|
-      child.puts "QUIT"
-      _pid, status = Process.wait2(child.pid)
-      success &&= status.success?
-      child.close
-    }
-
-    formatter.aggregate_results(output_files)
-    formatter.finish
-    success
+    ParallelRunner.new(@files, processes, formatter, argv).run
   end
 
   def run
Index: spec/mspec/lib/mspec/runner/formatters/multi.rb
===================================================================
--- spec/mspec/lib/mspec/runner/formatters/multi.rb	(revision 64842)
+++ spec/mspec/lib/mspec/runner/formatters/multi.rb	(revision 64843)
@@ -15,15 +15,18 @@ class MultiFormatter < SpinnerFormatter https://github.com/ruby/ruby/blob/trunk/spec/mspec/lib/mspec/runner/formatters/multi.rb#L15
     @exceptions = []
 
     files.each do |file|
-      d = File.open(file, "r") { |f| YAML.load f }
+      contents = File.read(file)
+      d = YAML.load(contents)
       File.delete file
 
-      @exceptions += Array(d['exceptions'])
-      @tally.files!        d['files']
-      @tally.examples!     d['examples']
-      @tally.expectations! d['expectations']
-      @tally.errors!       d['errors']
-      @tally.failures!     d['failures']
+      if d # The file might be empty if the child process died
+        @exceptions += Array(d['exceptions'])
+        @tally.files!        d['files']
+        @tally.examples!     d['examples']
+        @tally.expectations! d['expectations']
+        @tally.errors!       d['errors']
+        @tally.failures!     d['failures']
+      end
     end
   end
 
Index: spec/mspec/lib/mspec/runner/mspec.rb
===================================================================
--- spec/mspec/lib/mspec/runner/mspec.rb	(revision 64842)
+++ spec/mspec/lib/mspec/runner/mspec.rb	(revision 64843)
@@ -50,6 +50,7 @@ module MSpec https://github.com/ruby/ruby/blob/trunk/spec/mspec/lib/mspec/runner/mspec.rb#L50
 
   def self.process
     STDOUT.puts RUBY_DESCRIPTION
+    STDOUT.flush
 
     actions :start
     files
@@ -58,9 +59,8 @@ module MSpec https://github.com/ruby/ruby/blob/trunk/spec/mspec/lib/mspec/runner/mspec.rb#L59
 
   def self.each_file(&block)
     if ENV["MSPEC_MULTI"]
-      STDOUT.print "."
-      STDOUT.flush
-      while file = STDIN.gets and file = file.chomp
+      while file = STDIN.gets
+        file = file.chomp
         return if file == "QUIT"
         yield file
         begin
Index: spec/mspec/lib/mspec/runner/parallel.rb
===================================================================
--- spec/mspec/lib/mspec/runner/parallel.rb	(nonexistent)
+++ spec/mspec/lib/mspec/runner/parallel.rb	(revision 64843)
@@ -0,0 +1,98 @@ https://github.com/ruby/ruby/blob/trunk/spec/mspec/lib/mspec/runner/parallel.rb#L1
+class ParallelRunner
+  def initialize(files, processes, formatter, argv)
+    @files = files
+    @processes = processes
+    @formatter = formatter
+    @argv = argv
+    @last_files = {}
+    @output_files = []
+    @success = true
+  end
+
+  def launch_children
+    @children = @processes.times.map { |i|
+      name = tmp "mspec-multi-#{i}"
+      @output_files << name
+
+      env = {
+        "SPEC_TEMP_DIR" => "rubyspec_temp_#{i}",
+        "MSPEC_MULTI" => i.to_s
+      }
+      command = @argv + ["-fy", "-o", name]
+      $stderr.puts "$ #{command.join(' ')}" if $MSPEC_DEBUG
+      IO.popen([env, *command, close_others: false], "rb+")
+    }
+  end
+
+  def handle(child, message)
+    case message
+    when '.'
+      @formatter.unload
+      send_new_file_or_quit(child)
+    else
+      if message == nil
+        msg = "A child mspec-run process died unexpectedly"
+      else
+        msg = "A child mspec-run process printed unexpected output on STDOUT"
+        while chunk = (child.read_nonblock(4096) rescue nil)
+          message += chunk
+        end
+        message.chomp!('.')
+        msg += ": #{message.inspect}"
+      end
+
+      if last_file = @last_files[child]
+        msg += " while running #{last_file}"
+      end
+
+      @success = false
+      quit(child)
+      abort "\n#{msg}"
+    end
+  end
+
+  def quit(child)
+    begin
+      child.puts "QUIT"
+    rescue Errno::EPIPE
+      # The child process already died
+    end
+    _pid, status = Process.wait2(child.pid)
+    @success &&= status.success?
+    child.close
+    @children.delete(child)
+  end
+
+  def send_new_file_or_quit(child)
+    if @files.empty?
+      quit(child)
+    else
+      file = @files.shift
+      @last_files[child] = file
+      child.puts file
+    end
+  end
+
+  def run
+    MSpec.register_files @files
+    launch_children
+
+    puts @children.map { |child| child.gets }.uniq
+    @formatter.start
+    begin
+      @children.each { |child| send_new_file_or_quit(child) }
+
+      until @children.empty?
+        IO.select(@children)[0].each { |child|
+          handle(child, child.read(1))
+        }
+      end
+    ensure
+      @children.dup.each { |child| quit(child) }
+      @formatter.aggregate_results(@output_files)
+      @formatter.finish
+    end
+
+    @success
+  end
+end

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]