Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(PDK-373) Make test unit --list consistent with test unit #216

Merged
merged 3 commits into from
Aug 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 8 additions & 25 deletions lib/pdk/tests/unit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,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))

raise PDK::CLI::FatalError, _('Unit test output did not contain a valid JSON result: %{output}') % { output: result[:stdout] } if json_result.nil? || json_result.empty?

Expand Down Expand Up @@ -148,29 +132,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 @@ -52,6 +52,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 @@ -138,4 +143,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