sj26 / rspec_junit_formatter

RSpec results that your CI can read
http://rubygems.org/gems/rspec_junit_formatter
MIT License
302 stars 122 forks source link

Regression of #57 (Encoding::UndefinedConversionError) in versions >= 0.4.0 #67

Closed jayhendren closed 4 years ago

jayhendren commented 6 years ago

Looks like #57 was fixed in 0.3.0, but regressed in 0.4.0.

The following code generates the following error in versions >= 0.4.0, but not 0.3.0. So far I have only been able to reproduce the error when using Serverspec; I haven't yet figured out how to reproduce in plain RSpec.

RSpec.configure do |c|
  c.add_formatter('RspecJunitFormatter', '/tmp/foo.xml')
end

describe 'foo' do
  describe command('echo oøps') do
    its(:stdout) { is_expected.to contain('o') }
  end
end
       foo
         Command "echo oøps"
           stdout
             should contain "o"

       Finished in 0.02209 seconds (files took 0.26107 seconds to load)
       1 example, 0 failures

       Traceback (most recent call last):
        25: from /opt/chef/embedded/bin/rspec:23:in `<main>'
        24: from /opt/chef/embedded/bin/rspec:23:in `load'
        23: from /tmp/verifier/gems/gems/rspec-core-3.8.0/exe/rspec:4:in `<top (required)>'
        22: from /tmp/verifier/gems/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:45:in `invoke'
        21: from /tmp/verifier/gems/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:71:in `run'
        20: from /tmp/verifier/gems/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:87:in `run'
        19: from /tmp/verifier/gems/gems/rspec-core-3.8.0/lib/rspec/core/runner.rb:110:in `run_specs'
        18: from /tmp/verifier/gems/gems/rspec-core-3.8.0/lib/rspec/core/reporter.rb:76:in `report'
        17: from /tmp/verifier/gems/gems/rspec-core-3.8.0/lib/rspec/core/reporter.rb:166:in `finish'
        16: from /tmp/verifier/gems/gems/rspec-core-3.8.0/lib/rspec/core/reporter.rb:186:in `close_after'
        15: from /tmp/verifier/gems/gems/rspec-core-3.8.0/lib/rspec/core/reporter.rb:177:in `block in finish'
        14: from /tmp/verifier/gems/gems/rspec-core-3.8.0/lib/rspec/core/reporter.rb:200:in `notify'
        13: from /tmp/verifier/gems/gems/rspec-core-3.8.0/lib/rspec/core/reporter.rb:200:in `each'
        12: from /tmp/verifier/gems/gems/rspec-core-3.8.0/lib/rspec/core/reporter.rb:201:in `block in notify'
        11: from /tmp/verifier/gems/gems/rspec_junit_formatter-0.4.0/lib/rspec_junit_formatter/rspec3.rb:19:in `dump_summary'
        10: from /tmp/verifier/gems/gems/rspec_junit_formatter-0.4.0/lib/rspec_junit_formatter/rspec3.rb:113:in `without_color'
         9: from /tmp/verifier/gems/gems/rspec_junit_formatter-0.4.0/lib/rspec_junit_formatter/rspec3.rb:100:in `swap_rspec_configuration'
         8: from /tmp/verifier/gems/gems/rspec_junit_formatter-0.4.0/lib/rspec_junit_formatter/rspec3.rb:19:in `block in dump_summary'
         7: from /tmp/verifier/gems/gems/rspec_junit_formatter-0.4.0/lib/rspec_junit_formatter.rb:32:in `xml_dump'
         6: from /tmp/verifier/gems/gems/rspec_junit_formatter-0.4.0/lib/rspec_junit_formatter.rb:37:in `xml_dump_examples'
         5: from /tmp/verifier/gems/gems/rspec_junit_formatter-0.4.0/lib/rspec_junit_formatter.rb:37:in `each'
         4: from /tmp/verifier/gems/gems/rspec_junit_formatter-0.4.0/lib/rspec_junit_formatter.rb:44:in `block in xml_dump_examples'
         3: from /tmp/verifier/gems/gems/rspec_junit_formatter-0.4.0/lib/rspec_junit_formatter.rb:74:in `xml_dump_example'
         2: from /tmp/verifier/gems/gems/rspec_junit_formatter-0.4.0/lib/rspec_junit_formatter.rb:81:in `xml_dump_output'
         1: from /tmp/verifier/gems/gems/rspec_junit_formatter-0.4.0/lib/rspec_junit_formatter.rb:165:in `escape'
       /tmp/verifier/gems/gems/rspec_junit_formatter-0.4.0/lib/rspec_junit_formatter.rb:165:in `encode': "\xC3" from ASCII-8BIT to UTF-8 (Encoding::UndefinedConversionError)

There are no errors if I remove the ø character:

describe 'foo' do
  describe command('echo oops') do
    its(:stdout) { is_expected.to contain('o') }
  end
end
sj26 commented 6 years ago

Sounds to me like serverspec is interfering with encodings? Can you reproduce in plain rspec?

jayhendren commented 6 years ago

I wouldn't be surprised if ServerSpec is doing something funky. However, considering that the bug appeared when changing nothing except upgrading rspec_junit_formatter from 0.3.0 to 0.4.0 and that rspec_junit_formatter is the only thing besides rspec in the stack trace, this smells like an issue with rspec_junit_formatter to me.

I'm working on reproducing without ServerSpec. I'm having a bit of trouble but I feel like I'm getting close.

jayhendren commented 6 years ago

Ok, so I'm starting to get this one figured out. There's a few different puzzle pieces here. It's still not clear to me exactly where the issue lies, though I'm starting to suspect Serverspec is doing something wrong.

First, starting in version 0.4.0, rspec_junit_formatter starting processing :stdout and :stderr in example metadata. This is why I'm only seeing the issue with versions >= 0.4.0.

Second, Serverspec always saves stdout to example metadata (this does not appear to be configurable behavior in Serverspec, otherwise I would simply disable it and close this issue and move on).

Finally, Serverspec uses a very low-level way to read command output involving reading from pipes 4096 bytes at a time using IO.select and looping over IO#read_nonblock(4096). As far as I can tell, this often results in an output string (incorrectly?) labeled with ASCII-8BIT encoding. If I override this method to use something a bit more abstract, like IO.read(), then the output usually is UTF-8 encoding and I don't have any encoding issues.

I'm not really sure where the ASCII-8BIT encoding is ultimately coming from. That's what I'm looking into right now.

There are a couple things I wish existed that would allow for workarounds:

thomasbilk commented 4 years ago

@Poohblah did you find anything? I seem to have the same issue.

Wisdom of the Ancients

jayhendren commented 4 years ago

I just pinned to version 0.3.x of this gem and moved on.

IIRC, I considered opening a PR against Serverspec, but that was a lot more work than just pinning one gem version. I barely use the junit output at all, so it simply wasn't worth my time investment.

thomasbilk commented 4 years ago

Thank you for the update. That is what I ended up doing as well. So I guess this issue can be closed.

sj26 commented 4 years ago

Sorry folks, encodings are hard!