-
Notifications
You must be signed in to change notification settings - Fork 3
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
habitat_package: Add installation_path and dependency_ids properties #32
base: main
Are you sure you want to change the base?
Changes from all commits
35aaa63
d44d7b8
f680a12
5324fee
acf19d1
a5a4903
53f136b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,11 +47,57 @@ def identifier | |
end | ||
|
||
def to_s | ||
"Habitat Service #{identifier}" | ||
"Habitat Package #{identifier}" | ||
end | ||
|
||
def installation_path | ||
return nil unless exists? | ||
|
||
"#{hab_install_root}/#{identifier}" | ||
end | ||
|
||
# Read dependency package IDs from the TDEPs file | ||
def dependency_ids | ||
return [] unless exists? | ||
return @dependency_ids if defined?(@dependency_ids) | ||
|
||
tdeps = inspec.backend.run_command("cat #{installation_path}/TDEPS").stdout | ||
@dependency_ids = tdeps.chomp.split("\n") | ||
end | ||
|
||
def dependency_names | ||
return [] unless exists? | ||
return @dependency_names if defined?(@dependency_names) | ||
|
||
@dependency_names = dependency_ids.map { |id| id.split('/')[0, 2].join('/') } | ||
end | ||
|
||
private | ||
|
||
def hab_install_root | ||
@hab_install_root ||= determine_hab_install_root | ||
end | ||
|
||
# Figure out the hab installation path by looking at the PATH of | ||
# a package known to be installed, and known to have a simple PATH | ||
# - hab itself is perfect for this. | ||
def determine_hab_install_root | ||
list_result = inspec.backend.run_hab_cli('pkg list core/hab') | ||
hab_spec = list_result.stdout.split("\n").first | ||
env_result = inspec.backend.run_hab_cli("pkg env #{hab_spec}") | ||
path_line = env_result.stdout.split("\n").detect { |l| l.include?('PATH') } | ||
path_line.tr!('\\', '/') # Force slashes to be backslashes to match package IDs | ||
# Like export PATH="/hab/pkgs/core/hab/0.81.0/20190507225645/bin" | ||
# Or set PATH="C:\hab\pkgs\core\hab\0.81.0\20190507225645\bin" | ||
match = path_line.match(%r{="(.+)[\\\/]#{hab_spec}}) | ||
unless match | ||
# TODO: Inspec 3174 resource unable handling | ||
raise Inspec::Exceptions::ResourceFailed, 'Cannot determine habitat install root' | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For something this simple, unless the line is long/ugly, I use an unless modifier. ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was getting confused by this code and path_line =~ %r%="(.+)[\\\/]#{hab_spec}%
raise [...] unless $1
$1 I only flipped it to |
||
|
||
match[1] | ||
end | ||
|
||
def perform_existence_check | ||
unless inspec.backend.cli_options_provided? | ||
@exists = false | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
core/acl/2.2.53/20190115012136 | ||
core/apr-util/1.6.1/20190307150947 | ||
core/apr/1.6.5/20190307150747 | ||
core/attr/2.4.48/20190115012129 | ||
core/bash/4.4.19/20190115012619 | ||
core/binutils/2.31.1/20190115003743 | ||
core/bzip2/1.0.6/20190115011950 | ||
core/cacerts/2018.12.05/20190115014206 | ||
core/coreutils/8.30/20190115012313 | ||
core/db/5.3.28/20190115012845 | ||
core/expat/2.2.5/20190115012836 | ||
core/gcc-libs/8.2.0/20190115011926 | ||
core/gdbm/1.17/20190115012826 | ||
core/glibc/2.27/20190115002733 | ||
core/gmp/6.1.2/20190115003943 | ||
core/grep/3.1/20190115012541 | ||
core/less/530/20190115013008 | ||
core/libcap/2.25/20190115012150 | ||
core/libiconv/1.14/20190115155025 | ||
core/linux-headers/4.17.12/20190115002705 | ||
core/ncurses/6.1/20190115012027 | ||
core/openssl-fips/2.0.16/20190115014207 | ||
core/openssl/1.0.2r/20190305210149 | ||
core/pcre/8.42/20190115012526 | ||
core/perl/5.28.0/20190115013014 | ||
core/readline/7.0.3/20190115012607 | ||
core/sed/4.5/20190115012152 | ||
core/zlib/1.2.11/20190115003728 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export PATH="/hab/pkgs/core/hab/0.81.0/20190507225645/bin" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
core/hab/0.81.0/20190507225645 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -173,5 +173,50 @@ | |
end | ||
end | ||
end | ||
|
||
#==========================================================================# | ||
# Properties | ||
#==========================================================================# | ||
|
||
describe 'properties' do | ||
describe 'installation_path' do | ||
it 'should be correct' do | ||
fixture = { | ||
cli: [ | ||
{ cmd: 'pkg list core/hab', stdout_file: 'pkg-list-hab.cli.txt' }, | ||
{ cmd: regexp_matches(%r{pkg env core/hab}), stdout_file: 'pkg-env-hab.cli.txt' }, | ||
{ cmd: 'pkg list core/httpd', stdout_file: 'pkg-list-single.cli.txt' }, | ||
], | ||
} | ||
InspecHabitat::UnitTestHelper.mock_inspec_context_object(self, fixture) | ||
pkg = HabitatPackage.new('core/httpd') | ||
pkg.installation_path.must_equal('/hab/pkgs/core/httpd/2.4.35/20190307151146') | ||
end | ||
end | ||
|
||
describe 'dependency ids and names' do | ||
it 'should be correct' do | ||
fixture = { | ||
cli: [ | ||
{ cmd: 'pkg list core/hab', stdout_file: 'pkg-list-hab.cli.txt' }, | ||
{ cmd: regexp_matches(%r{pkg env core/hab}), stdout_file: 'pkg-env-hab.cli.txt' }, | ||
{ cmd: 'pkg list core/httpd', stdout_file: 'pkg-list-single.cli.txt' }, | ||
], | ||
general_cli: [ | ||
{ cmd: 'cat /hab/pkgs/core/httpd/2.4.35/20190307151146/TDEPS', stdout_file: 'cat-httpd-tdeps.cli.txt' }, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should these magic strings be pulled out into constants or anything? 🤷♀ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably, it references a package version and date, eventually it might not be in the package index. |
||
], | ||
} | ||
InspecHabitat::UnitTestHelper.mock_inspec_context_object(self, fixture) | ||
pkg = HabitatPackage.new('core/httpd') | ||
dep_ids = pkg.dependency_ids | ||
dep_ids.count.must_equal 28 | ||
dep_ids.must_include 'core/glibc/2.27/20190115002733' | ||
|
||
dep_names = pkg.dependency_names | ||
dep_names.count.must_equal dep_ids.count | ||
dep_names.must_include 'core/glibc' | ||
end | ||
end | ||
end | ||
end | ||
# rubocop:enable Metrics/BlockLength |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,6 +36,7 @@ def check_definition(opts) | |
# Pass a fixture Hash to this method as the second arg. | ||
# { | ||
# cli: { # Optional. If present, connection will say that CLI mode is available. | ||
# # This may also be an array of such hashes. | ||
# cmd: 'svc status core/httpd', # This registers the stub, so it will only respond to this command | ||
# stdout_file: 'svc-status-single.cli.txt', # A file under test/unit/fixtures, empty String if this key is absent | ||
# stderr_file: 'some-other-file.cli.txt', # A file under test/unit/fixtures, empty String if this key is absent | ||
|
@@ -45,7 +46,10 @@ def check_definition(opts) | |
# path: '/services', # This registers the stub, so it will only respond to this path | ||
# body_file: 'services-single.api.json', # A file under test/unit/fixtures, empty String if this key is absent | ||
# code: 200 | ||
# } | ||
# }, | ||
# general_cli: [ # Used for general run_command CLI calls. | ||
# { cmd: '', stdout_file: '' }, # As for cli: above | ||
# ], | ||
# } | ||
|
||
# About this method. | ||
|
@@ -57,7 +61,10 @@ def check_definition(opts) | |
# which means we need to be in an `it` block. So... and this is awful ... | ||
# pass the it block (which is `self`, within the it block) as the test | ||
# context and then perform a block-type instance-eval. | ||
def mock_inspec_context_object(test_cxt, fixture) # rubocop:disable Metrics/AbcSize | ||
|
||
# Also, this is really bad, linting-wise; but I'm not sure how to refactor | ||
# this much, in an instance eval.... | ||
def mock_inspec_context_object(test_cxt, fixture) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hah! I love the |
||
test_cxt.instance_eval do | ||
inspec_cxt = mock | ||
hab_cxn = mock | ||
|
@@ -66,15 +73,19 @@ def mock_inspec_context_object(test_cxt, fixture) # rubocop:disable Metrics/AbcS | |
|
||
if fixture.key?(:cli) | ||
hab_cxn.stubs(:cli_options_provided?).returns(true) | ||
run_result = mock | ||
run_result.stubs(:exit_status).returns(fixture[:cli][:exit_status]) | ||
|
||
out = fixture[:cli][:stdout_file] ? File.read(File.join(unit_fixture_path, fixture[:cli][:stdout_file])) : '' | ||
run_result.stubs(:stdout).returns(out) | ||
err = fixture[:cli][:stderr_file] ? File.read(File.join(unit_fixture_path, fixture[:cli][:stderr_file])) : '' | ||
run_result.stubs(:stderr).returns(err) | ||
# Boost this to an Array if it isn't already | ||
(fixture[:cli].is_a?(Array) ? fixture[:cli] : [fixture[:cli]]).each do |cli_fixture| | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
to:
|
||
run_result = mock | ||
run_result.stubs(:exit_status).returns(cli_fixture[:exit_status] || 0) | ||
|
||
out = cli_fixture[:stdout_file] ? File.read(File.join(unit_fixture_path, cli_fixture[:stdout_file])) : '' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Refactor these into a helper method or two. |
||
run_result.stubs(:stdout).returns(out) | ||
err = cli_fixture[:stderr_file] ? File.read(File.join(unit_fixture_path, cli_fixture[:stderr_file])) : '' | ||
run_result.stubs(:stderr).returns(err) | ||
|
||
hab_cxn.stubs(:run_hab_cli).with(fixture[:cli][:cmd]).returns(run_result) | ||
hab_cxn.stubs(:run_hab_cli).with(cli_fixture[:cmd]).returns(run_result) | ||
end | ||
else | ||
hab_cxn.stubs(:cli_options_provided?).returns(false) | ||
end | ||
|
@@ -93,8 +104,23 @@ def mock_inspec_context_object(test_cxt, fixture) # rubocop:disable Metrics/AbcS | |
else | ||
hab_cxn.stubs(:api_options_provided?).returns(false) | ||
end | ||
Inspec::Plugins::Resource.any_instance.stubs(:inspec).returns(inspec_cxt) | ||
|
||
if fixture.key?(:general_cli) | ||
fixture[:general_cli].each do |cli_fixture| | ||
hab_cxn.stubs(:cli_options_provided?).returns(true) | ||
run_result = mock | ||
run_result.stubs(:exit_status).returns(cli_fixture[:exit_status] || 0) | ||
out = cli_fixture[:stdout_file] ? File.read(File.join(unit_fixture_path, cli_fixture[:stdout_file])) : '' | ||
run_result.stubs(:stdout).returns(out) | ||
err = cli_fixture[:stderr_file] ? File.read(File.join(unit_fixture_path, cli_fixture[:stderr_file])) : '' | ||
run_result.stubs(:stderr).returns(err) | ||
hab_cxn.stubs(:run_command).with(cli_fixture[:cmd]).returns(run_result) | ||
end | ||
end | ||
|
||
# Stub at both instance and class level | ||
Inspec::Plugins::Resource.any_instance.stubs(:inspec).returns(inspec_cxt) | ||
Inspec::Plugins::Resource.stubs(:inspec).returns(inspec_cxt) | ||
end | ||
end | ||
module_function :mock_inspec_context_object # rubocop:disable Style/AccessModifierDeclarations | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
stdout.lines.first
is more expressive.