Create appvayor workers for Windows functional tests. (#3397)

* Add more windows functional tests and create some appvayor workers.
* Fix uuid test for automate

Signed-off-by: Jared Quick <jquick@chef.io>
This commit is contained in:
Jared Quick 2018-11-08 12:00:14 -05:00 committed by GitHub
parent 6859d766df
commit d33d189d93
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 222 additions and 121 deletions

View file

@ -81,19 +81,18 @@ namespace :test do
t.ruby_opts = ['--dev'] if defined?(JRUBY_VERSION)
end
# Functional tests on Windows are a WIP. Currently only some
# functional test files are supported.
# TODO: Ensure all functional tests are ran on Windows
Rake::TestTask.new(:'functional:windows') do |t|
# Functional tests on Windows take a bit to run. This
# optionally takes a env to breake the tests up into 3 workers.
Rake::TestTask.new(:'functional:windows') do |t, args|
files = Dir.glob('test/functional/*_test.rb').sort
if ENV['WORKER_NUMBER']
count = (files.count / 3).abs+1
start = (ENV['WORKER_NUMBER'].to_i - 1) * count
files = files[start..start+count-1]
end
t.libs << 'test'
t.test_files = [
'test/functional/inspec_exec_test.rb',
'test/functional/inspec_exec_json_test.rb',
'test/functional/inspec_detect_test.rb',
'test/functional/inspec_vendor_test.rb',
'test/functional/inspec_check_test.rb',
'test/functional/filter_table_test.rb',
]
t.test_files = files
t.warning = true
t.verbose = true
t.ruby_opts = ['--dev'] if defined?(JRUBY_VERSION)

View file

@ -4,9 +4,18 @@ platform:
environment:
matrix:
- ruby_version: "23"
- ruby_version: "24"
- ruby_version: "25"
- name: unit-tests-ruby-2.3.3
ruby_version: "23"
- name: unit-tests-ruby-2.4.4
ruby_version: "24"
- name: unit-tests-ruby-2.5.1
ruby_version: "25"
- name: functional-tests-1
ruby_version: "25"
- name: functional-tests-2
ruby_version: "25"
- name: functional-tests-3
ruby_version: "25"
clone_folder: c:\projects\inspec
clone_depth: 1
@ -54,9 +63,24 @@ for:
-
matrix:
only:
- ruby_version: "25"
- name: functional-tests-1
test_script:
- SET SPEC_OPTS=--format progress
- bundle exec rake
- SET WORKER_NUMBER=1
- bundle exec rake test:functional:windows
-
matrix:
only:
- name: functional-tests-2
test_script:
- SET SPEC_OPTS=--format progress
- SET WORKER_NUMBER=2
- bundle exec rake test:functional:windows
-
matrix:
only:
- name: functional-tests-3
test_script:
- SET SPEC_OPTS=--format progress
- SET WORKER_NUMBER=3
- bundle exec rake test:functional:windows

View file

@ -238,9 +238,11 @@ module Inspec
# Load local profile dependencies. This is used in inspec shell
# to provide access to local profiles that add resources.
@depends
.map { |x| Inspec::Profile.for_path(x, { profile_context: ctx }) }
.each(&:load_libraries)
@depends.each do |dep|
# support for windows paths
dep = dep.tr('\\', '/')
Inspec::Profile.for_path(dep, { profile_context: ctx }).load_libraries
end
ctx.load(command)
end

View file

@ -18,8 +18,10 @@ describe 'profiles with git-based dependencies' do
Dir.chdir(@git_dep_dir) do
CMD.run_command("git init")
CMD.run_command("git add .")
CMD.run_command("git commit -m 'initial commit' --no-gpg-sign")
CMD.run_command("git commit -m 'another commit' --allow-empty --no-gpg-sign")
CMD.run_command("git config user.name \"test\"")
CMD.run_command("git config user.email \"test@yahoo.com\"")
CMD.run_command("git commit -m \"initial commit\" --no-gpg-sign")
CMD.run_command("git commit -m \"another commit\" --allow-empty --no-gpg-sign")
CMD.run_command("git tag antag")
end

View file

@ -15,7 +15,12 @@ class Module
end
module FunctionalHelper
let(:repo_path) { File.expand_path(File.join( __FILE__, '..', '..', '..')) }
let(:repo_path) do
path = File.expand_path(File.join( __FILE__, '..', '..', '..'))
# fix for vagrant repo pathing
path.gsub!('//vboxsrv', 'C:') if is_windows?
path
end
let(:exec_inspec) { File.join(repo_path, 'bin', 'inspec') }
let(:mock_path) { File.join(repo_path, 'test', 'unit', 'mock') }
let(:profile_path) { File.join(mock_path, 'profiles') }
@ -50,10 +55,14 @@ module FunctionalHelper
text.gsub!("\033[0;1;31m", "\033[38;5;9m")
end
def is_windows?
def self.is_windows?
RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
end
def is_windows?
FunctionalHelper.is_windows?
end
def inspec(commandline, prefix = nil)
if is_windows?
result = CMD.run_command("cmd /C \"#{prefix} bundle exec ruby #{exec_inspec} #{commandline}\"")

View file

@ -7,6 +7,7 @@ require 'tmpdir'
describe 'inspec archive' do
include FunctionalHelper
let(:auto_dst) { File.expand_path(File.join(repo_path, 'profile-1.0.0.tar.gz')) }
it 'archive is successful' do
prepare_examples('profile') do |dir|
@ -21,7 +22,7 @@ describe 'inspec archive' do
prepare_examples('profile') do |dir|
out = inspec('archive ' + dir + ' --output ' + dst.path)
out.stderr.must_equal ''
out.stdout.must_include 'Generate archive '+ dst.path
out.stdout.must_include 'Generate archive ' + dst.path
out.stdout.must_include 'Finished archive generation.'
out.exit_status.must_equal 0
File.exist?(dst.path).must_equal true
@ -30,7 +31,6 @@ describe 'inspec archive' do
it 'auto-archives when no --output is given' do
prepare_examples('profile') do |dir|
auto_dst = File.join(repo_path, 'profile-1.0.0.tar.gz')
out = inspec('archive ' + dir + ' --overwrite')
out.stderr.must_equal ''
out.stdout.must_include 'Generate archive ' + auto_dst
@ -42,7 +42,7 @@ describe 'inspec archive' do
it 'archive on invalid archive' do
Dir.tmpdir do |target_dir|
out = inspec('archive #{target_dir} --output ' + dst.path)
out = inspec("archive #{target_dir} --output " + dst.path)
out.stderr.must_include "Don't understand inspec profile in \"#{target_dir}\""
out.exit_status.must_equal 1
File.exist?(dst.path).must_equal false

View file

@ -0,0 +1,47 @@
# encoding: utf-8
require 'fileutils'
require 'functional/helper'
require 'securerandom'
describe 'inspec exec' do
include FunctionalHelper
it 'can generate keys' do
prepare_examples do |dir|
unique_key_name = SecureRandom.uuid()
out = inspec("artifact generate --keyname #{unique_key_name}", "cd #{dir} && ")
out.exit_status.must_equal 0
stdout = out.stdout.force_encoding(Encoding::UTF_8)
stdout.must_include 'Generating private key'
stdout.must_include 'Generating public key'
end
end
it 'can sign, verify and install a signed profile' do
# The arcive install commands do not currently support windows and
# use specific linux extract tar commands. Since artifact is still
# experimental we are skipping it for now.
return if is_windows?
prepare_examples do |dir|
unique_key_name = SecureRandom.uuid()
install_dir = File.join(dir, SecureRandom.uuid())
profile = File.join(dir, 'profile')
FileUtils.mkdir(install_dir)
out = inspec("artifact generate --keyname #{unique_key_name}", "cd #{dir} &&")
out.exit_status.must_equal 0
out = inspec("artifact sign-profile --profile #{profile} --keyname #{unique_key_name}", "cd #{dir} &&")
out.exit_status.must_equal 0
out = inspec("artifact install-profile --infile profile-1.0.0.iaf --destdir #{install_dir}", "cd #{dir} &&")
out.exit_status.must_equal 0
out.stdout.force_encoding(Encoding::UTF_8).must_include "Installing to #{install_dir}"
Dir.entries(install_dir).join.must_include "inspec.yml"
end
end
end

View file

@ -15,7 +15,8 @@ describe 'inspec exec automate' do
"stdout" : false,
"url" : "https://fake_url_a2.com/data-collector/v0/",
"token" : "faketoken123",
"insecure" : true
"insecure" : true,
"node_uuid" : "test123"
}
}
}

View file

@ -59,7 +59,11 @@ describe 'inspec exec with junit formatter' do
end
it 'should be skipped' do
first_gordon_test.elements.to_a('//skipped').length.must_equal 1
if is_windows?
first_gordon_test.elements.to_a('//skipped').length.must_equal 2
else
first_gordon_test.elements.to_a('//skipped').length.must_equal 1
end
end
end
end

View file

@ -115,16 +115,16 @@ describe 'inspec json' do
describe 'json test for pax header archives' do
let(:profile_tgz) { File.join(Dir.mktmpdir, "pax-profile-test.tar.gz") }
before do
it 'successfully reads a pax-formatted tar file' do
# TODO: this needs updated to also support windows taring
return if is_windows?
files = Dir.glob("#{example_profile}/**/*").delete_if { |x| !File.file?(x) }
relatives = files.map { |e| Pathname.new(e).relative_path_from(Pathname.new(example_profile)).to_s }
cmd = Mixlib::ShellOut.new("tar --format=pax -czf #{profile_tgz} #{relatives.join(' ')}", cwd: example_profile)
cmd.run_command
cmd.error!
end
it 'successfully reads a pax-formatted tar file' do
out = inspec("json #{profile_tgz}")
out.exit_status.must_equal 0
end

View file

@ -8,7 +8,8 @@ describe 'inspec shell tests' do
describe 'cmd' do
def do_shell_c(code, exit_status, json = false, stderr = '')
json_suffix = " --reporter 'json'" if json
out = inspec("shell -c '#{code.tr('\'','\\\'')}'#{json_suffix}")
command = "shell -c '#{code.tr('\'','\\\'')}'#{json_suffix}"
out = inspec(command)
out.stderr.must_equal stderr
out.exit_status.must_equal exit_status
out
@ -47,12 +48,16 @@ describe 'inspec shell tests' do
end
it 'can run arbitrary ruby (json output)' do
# You cannot have a pipe in a windows command line
return if is_windows?
out = do_shell_c('x = [1,2,3].inject(0) {|a,v| a + v*v}; x+10', 0, true)
j = JSON.load(out.stdout)
j.must_equal 24 # 1^2 + 2^2 + 3^2 + 10
end
it 'can run arbitrary ruby' do
# You cannot have a pipe in a windows command line
return if is_windows?
out = do_shell_c('x = [1,2,3].inject(0) {|a,v| a + v*v}; x+10', 0)
out.stdout.must_equal "24\n"
end
@ -131,108 +136,112 @@ describe 'inspec shell tests' do
end
end
describe 'shell' do
def do_shell(code, exit_status = 0, stderr = '')
cmd = "echo '#{code.tr('\'','\\\'')}' | #{exec_inspec} shell"
out = CMD.run_command(cmd)
#out.stderr.must_equal stderr
out.exit_status.must_equal exit_status
out
end
# Pry does not support STDIN from windows currently. Skipping these for now.
unless FunctionalHelper.is_windows?
it 'loads a dependency' do
cmd = "echo 'gordon_config' | #{exec_inspec} shell --depends #{example_profile}"
res = CMD.run_command(cmd)
res.exit_status.must_equal 0
res.stdout.must_include "=> gordon_config"
end
describe 'shell' do
def do_shell(code, exit_status = 0, stderr = '')
cmd = "echo '#{code.tr('\'','\\\'')}' | #{exec_inspec} shell"
out = CMD.run_command(cmd)
#out.stderr.must_equal stderr
out.exit_status.must_equal exit_status
out
end
it 'displays the target device information for the user without requiring the help command' do
out = do_shell('1+1')
out.stdout.must_include 'You are currently running on:'
end
it 'loads a dependency' do
cmd = "echo 'gordon_config' | #{exec_inspec} shell --depends #{example_profile}"
res = CMD.run_command(cmd)
res.exit_status.must_equal 0
res.stdout.must_include "=> gordon_config"
end
it 'provides a help command' do
out = do_shell('help')
out.stdout.must_include 'Available commands:'
out.stdout.must_include 'You are currently running on:'
end
it 'displays the target device information for the user without requiring the help command' do
out = do_shell('1+1')
out.stdout.must_include 'You are currently running on:'
end
it 'provides resource help' do
out = do_shell('help file')
out.stdout.must_include 'Use the file InSpec audit resource'
end
it 'provides a help command' do
out = do_shell('help')
out.stdout.must_include 'Available commands:'
out.stdout.must_include 'You are currently running on:'
end
it 'provides helpful feedback if an invalid resource is provided' do
out = do_shell('help not_a_valid_resource')
out.stdout.must_include 'The resource not_a_valid_resource does not exist.'
end
it 'provides resource help' do
out = do_shell('help file')
out.stdout.must_include 'Use the file InSpec audit resource'
end
it 'provides a list of resources' do
out = do_shell('help resources')
out.stdout.must_include ' - command'
out.stdout.must_include ' - file'
out.stdout.must_include ' - sshd_config'
end
it 'provides helpful feedback if an invalid resource is provided' do
out = do_shell('help not_a_valid_resource')
out.stdout.must_include 'The resource not_a_valid_resource does not exist.'
end
it 'provides matchers help' do
out = do_shell('help matchers')
out.stdout.must_include 'For more examples, see: https://www.inspec.io/docs/reference/matchers/'
end
it 'provides a list of resources' do
out = do_shell('help resources')
out.stdout.must_include ' - command'
out.stdout.must_include ' - file'
out.stdout.must_include ' - sshd_config'
end
it 'provides empty example help' do
out = do_shell('help file')
out.stdout.must_include 'Name'
out.stdout.must_include 'Description'
out.stdout.must_include 'Example'
out.stdout.must_include 'Web Reference'
end
it 'provides matchers help' do
out = do_shell('help matchers')
out.stdout.must_include 'For more examples, see: https://www.inspec.io/docs/reference/matchers/'
end
it 'exposes all resources' do
out = do_shell('os')
out.stdout.must_match(/\=> .*Operating.* .*System.* .*Detection/)
end
it 'provides empty example help' do
out = do_shell('help file')
out.stdout.must_include 'Name'
out.stdout.must_include 'Description'
out.stdout.must_include 'Example'
out.stdout.must_include 'Web Reference'
end
it 'can run ruby expressions' do
x = rand
y = rand
out = do_shell("#{x} + #{y}")
out.stdout.must_include "#{x+y}"
end
it 'exposes all resources' do
out = do_shell('os')
out.stdout.must_match(/\=> .*Operating.* .*System.* .*Detection/)
end
it 'can run arbitrary ruby' do
out = do_shell('x = [1,2,3].inject(0) {|a,v| a + v*v}; x+10')
out.stdout.must_include "24"
end
it 'can run ruby expressions' do
x = rand
y = rand
out = do_shell("#{x} + #{y}")
out.stdout.must_include "#{x+y}"
end
it 'runs anonymous tests that succeed' do
out = do_shell("describe file(\"#{__FILE__}\") do it { should exist } end")
out.stdout.must_include '1 successful'
out.stdout.must_include '0 failures'
end
it 'can run arbitrary ruby' do
out = do_shell('x = [1,2,3].inject(0) {|a,v| a + v*v}; x+10')
out.stdout.must_include "24"
end
it 'runs anonymous tests that fail' do
out = do_shell("describe file(\"foo/bar/baz\") do it { should exist } end")
out.stdout.must_include '0 successful'
out.stdout.must_include '1 failure'
end
it 'runs anonymous tests that succeed' do
out = do_shell("describe file(\"#{__FILE__}\") do it { should exist } end")
out.stdout.must_include '1 successful'
out.stdout.must_include '0 failures'
end
it 'runs controls with tests' do
out = do_shell("control \"test\" do describe file(\"#{__FILE__}\") do it { should exist } end end")
out.stdout.must_include '1 successful'
out.stdout.must_include '0 failures'
end
it 'runs anonymous tests that fail' do
out = do_shell("describe file(\"foo/bar/baz\") do it { should exist } end")
out.stdout.must_include '0 successful'
out.stdout.must_include '1 failure'
end
it 'runs controls with multiple tests' do
out = do_shell("control \"test\" do describe file(\"#{__FILE__}\") do it { should exist } end; describe file(\"foo/bar/baz\") do it { should exist } end end")
out.stdout.must_include '0 successful'
out.stdout.must_include '1 failure'
end
it 'runs controls with tests' do
out = do_shell("control \"test\" do describe file(\"#{__FILE__}\") do it { should exist } end end")
out.stdout.must_include '1 successful'
out.stdout.must_include '0 failures'
end
it 'reruns controls when redefined' do
out = do_shell("control \"test\" do describe file(\"#{__FILE__}\") do it { should exist } end end\ncontrol \"test\" do describe file(\"foo/bar/baz\") do it { should exist } end end")
out.stdout.must_include '1 successful'
out.stdout.must_include '1 failure'
it 'runs controls with multiple tests' do
out = do_shell("control \"test\" do describe file(\"#{__FILE__}\") do it { should exist } end; describe file(\"foo/bar/baz\") do it { should exist } end end")
out.stdout.must_include '0 successful'
out.stdout.must_include '1 failure'
end
it 'reruns controls when redefined' do
out = do_shell("control \"test\" do describe file(\"#{__FILE__}\") do it { should exist } end end\ncontrol \"test\" do describe file(\"foo/bar/baz\") do it { should exist } end end")
out.stdout.must_include '1 successful'
out.stdout.must_include '1 failure'
end
end
end
end

View file

@ -19,7 +19,11 @@ describe 'inspec supermakert' do
end
it 'supermarket exec' do
out = inspec('supermarket exec dev-sec/ssh-baseline')
if is_windows?
out = inspec('supermarket exec dev-sec/windows-patch-baseline')
else
out = inspec('supermarket exec dev-sec/ssh-baseline')
end
out.exit_status.wont_equal 1
out.stderr.must_equal ''
out.stdout.must_include 'Profile Summary'