Skip to content

Commit

Permalink
Merge pull request #216 from james-stocks/PDK-373
Browse files Browse the repository at this point in the history
(PDK-373) Make test unit --list consistent with test unit
  • Loading branch information
scotje committed Aug 2, 2017
2 parents ac63f51 + 2f65a99 commit a1d5353
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 25 deletions.
33 changes: 8 additions & 25 deletions lib/pdk/tests/unit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,7 @@ def self.invoke(report, options = {})

result = command.execute!

# TODO: cleanup rspec and/or beaker output
# Iterate through possible JSON documents until we find one that is valid.
json_result = nil
json_result = [] if options.key?(:parallel)

result[:stdout].scan(%r{\{(?:[^{}]|(?:\g<0>))*\}}x) do |str|
begin
if options.key?(:parallel)
json_result.push(JSON.parse(str))
else
json_result = JSON.parse(str)
break
end
rescue JSON::ParserError
next
end
end
json_result = PDK::Util.find_valid_json_in(result[:stdout], break_on_first: !options.key?(:parallel))

if parallel_with_no_tests?(options.key?(:parallel), json_result, result)
json_result = [{ 'messages' => ['No examples found.'] }]
Expand Down Expand Up @@ -159,29 +143,28 @@ def self.merge_json_results(json_data, duration)
# @return array of { :id, :full_description }
def self.list
PDK::Util::Bundler.ensure_bundle!
PDK::Util::Bundler.ensure_binstubs!('rspec-core')
PDK::Util::Bundler.ensure_binstubs!('rake')

command_argv = [File.join(PDK::Util.module_root, 'bin', 'rspec'), '--dry-run', '--format', 'json']
command_argv = [File.join(PDK::Util.module_root, 'bin', 'rake'), 'spec_list_json']
command_argv.unshift('ruby') if Gem.win_platform?
list_command = PDK::CLI::Exec::Command.new(*command_argv)
list_command.context = :module
output = list_command.execute!

rspec_json_output = JSON.parse(output[:stdout])
if rspec_json_output['examples'].empty?
rspec_message = rspec_json_output['messages'][0]
rspec_json = PDK::Util.find_valid_json_in(output[:stdout])
raise PDK::CLI::FatalError, _('Failed to find valid JSON in output from rspec: %{output}' % { output: output[:stdout] }) unless rspec_json
if rspec_json['examples'].empty?
rspec_message = rspec_json['messages'][0]
return [] if rspec_message == 'No examples found.'

raise PDK::CLI::FatalError, _('Unable to enumerate examples. rspec reported: %{message}' % { message: rspec_message })
else
examples = []
rspec_json_output['examples'].each do |example|
rspec_json['examples'].each do |example|
examples << { id: example['id'], full_description: example['full_description'] }
end
examples
end
rescue JSON::ParserError => e
raise PDK::CLI::FatalError, _('Failed to parse output from rspec: %{message}' % { message: e.message })
end
end
end
Expand Down
31 changes: 31 additions & 0 deletions lib/pdk/util.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,36 @@ def module_root
end
end
module_function :module_root

# Iterate through possible JSON documents until we find one that is valid.
#
# @param [String] text the text in which to find a JSON document
# @param [Hash] opts options
# @option opts [Boolean] :break_on_first Whether or not to break after valid JSON is found, defaults to true
#
# @return [Hash, Array<Hash>, nil] subset of text as Hash of first valid JSON found, array of all valid JSON found, or nil if no valid
# JSON found in the text
def find_valid_json_in(text, opts = {})
break_on_first = opts.key?(:break_on_first) ? opts[:break_on_first] : true

json_result = break_on_first ? nil : []

text.scan(%r{\{(?:[^{}]|(?:\g<0>))*\}}x) do |str|
begin
if break_on_first
json_result = JSON.parse(str)
break
else
json_result.push(JSON.parse(str))
end
rescue JSON::ParserError
next
end
end

return nil if json_result.nil? || json_result.empty?
json_result
end
module_function :find_valid_json_in
end
end
54 changes: 54 additions & 0 deletions spec/acceptance/test_unit_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@
its(:exit_status) { is_expected.to eq(0) }
its(:stderr) { is_expected.to match(%r{running unit tests.*3 tests.*0 failures}im) }
end

describe command('pdk test unit --parallel') do
its(:exit_status) { is_expected.to eq(0) }
its(:stderr) { is_expected.to match(%r{running unit tests in parallel.*3 tests.*0 failures}im) }
end
end

context 'with failing tests' do
Expand Down Expand Up @@ -145,4 +150,53 @@
its(:stderr) { is_expected.to match(%r{SyntaxError}) }
end
end

context 'multiple files with passing tests' do
include_context 'in a new module', 'unit_test_module_multiple_pass'

before(:all) do
FileUtils.mkdir_p('spec/unit')
# FIXME: facterversion pin and facterdb issues
File.open('spec/unit/passing_one_spec.rb', 'w') do |f|
f.puts <<-EOF
require 'spec_helper'
RSpec.describe 'passing test' do
on_supported_os(:facterversion => '2.4.6').each do |os, facts|
context "On OS \#{os}" do
it 'should pass' do
expect(true).to eq(true)
end
end
end
end
EOF
end
File.open('spec/unit/passing_two_spec.rb', 'w') do |f|
f.puts <<-EOF
require 'spec_helper'
RSpec.describe 'passing test' do
on_supported_os(:facterversion => '2.4.6').each do |os, facts|
context "On OS \#{os}" do
it 'should pass' do
expect(true).to eq(true)
end
end
end
end
EOF
end
end

describe command('pdk test unit') do
its(:exit_status) { is_expected.to eq(0) }
its(:stderr) { is_expected.to match(%r{running unit tests.*6 tests.*0 failures}im) }
end

describe command('pdk test unit --parallel') do
its(:exit_status) { is_expected.to eq(0) }
its(:stderr) { is_expected.to match(%r{running unit tests in parallel.*6 tests.*0 failures}im) }
end
end
end
54 changes: 54 additions & 0 deletions spec/unit/pdk/util_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -239,4 +239,58 @@
it { is_expected.to be_nil }
end
end

# TODO: These expect a string rather than actual JSON. Primarily they expect the non-JSON string to be removed
describe '.find_valid_json_in' do
it 'returns JSON from start of a string' do
text = '{"version":"3.6.0", "examples":[]}bar'
expected = { 'version' => '3.6.0', 'examples' => [] }

expect(described_class.find_valid_json_in(text)).to eq(expected)
end

it 'returns JSON from the end of a string' do
text = 'foo{"version":"3.6.0", "examples":[]}'
expected = { 'version' => '3.6.0', 'examples' => [] }

expect(described_class.find_valid_json_in(text)).to eq(expected)
end

it 'returns JSON from the middle of a string' do
text = 'foo{"version":"3.6.0", "examples":[]}bar'
expected = { 'version' => '3.6.0', 'examples' => [] }

expect(described_class.find_valid_json_in(text)).to eq(expected)
end

it 'returns nil for invalid JSON in a string' do
text = 'foo{"version"":"3.6.0", "examples":[]}bar'

expect(described_class.find_valid_json_in(text)).to be_nil
end

it 'returns nil for no JSON in a string' do
text = 'foosomethingbar'

expect(described_class.find_valid_json_in(text)).to be_nil
end

it 'returns first JSON document from string with multiple valid docs' do
text = '{"version": "3.6.0", "examples": []}{"version": "4.6.0", "examples": []}'
expected = { 'version' => '3.6.0', 'examples' => [] }

expect(described_class.find_valid_json_in(text)).to eq(expected)
end

context 'when break_on_first option is set to false' do
let(:opts) { { break_on_first: false } }

it 'returns array of JSON documents from string with multiple valid docs' do
text = '{"version": "3.6.0", "examples": []}{"version": "4.6.0", "examples": []}'
expected = [{ 'version' => '3.6.0', 'examples' => [] }, { 'version' => '4.6.0', 'examples' => [] }]

expect(described_class.find_valid_json_in(text, opts)).to contain_exactly(*expected)
end
end
end
end

0 comments on commit a1d5353

Please sign in to comment.