From 40a38c47d48577cba076820a52a5abfd53410c4c Mon Sep 17 00:00:00 2001 From: Lamont Granquist Date: Fri, 2 Feb 2018 11:54:51 -0800 Subject: Use apt_package instead of package, and rename file this really only tests apt_package, but was written before Chef 12. Signed-off-by: Lamont Granquist --- spec/functional/resource/apt_package_spec.rb | 386 +++++++++++++++++++++++++++ spec/functional/resource/package_spec.rb | 386 --------------------------- 2 files changed, 386 insertions(+), 386 deletions(-) create mode 100644 spec/functional/resource/apt_package_spec.rb delete mode 100644 spec/functional/resource/package_spec.rb diff --git a/spec/functional/resource/apt_package_spec.rb b/spec/functional/resource/apt_package_spec.rb new file mode 100644 index 0000000000..7c58937ee2 --- /dev/null +++ b/spec/functional/resource/apt_package_spec.rb @@ -0,0 +1,386 @@ +# encoding: UTF-8 +# +# Author:: Daniel DeLeo () +# Copyright:: Copyright 2013-2018, Chef Software Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require "spec_helper" +require "webrick" + +module AptServer + def enable_testing_apt_source + File.open("/etc/apt/sources.list.d/chef-integration-test.list", "w+") do |f| + f.puts "deb http://localhost:9000/ sid main" + end + # Magic to update apt cache for only our repo + shell_out!("apt-get update " + + '-o Dir::Etc::sourcelist="sources.list.d/chef-integration-test.list" ' + + '-o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0"') + end + + def disable_testing_apt_source + FileUtils.rm("/etc/apt/sources.list.d/chef-integration-test.list") + rescue Errno::ENOENT + puts("Attempted to remove integration test from /etc/apt/sources.list.d but it didn't exist") + end + + def tcp_test_port(hostname, port) + tcp_socket = TCPSocket.new(hostname, port) + true + rescue Errno::ETIMEDOUT + false + rescue Errno::ECONNREFUSED + false + ensure + tcp_socket && tcp_socket.close + end + + def apt_server + @apt_server ||= WEBrick::HTTPServer.new( + :Port => 9000, + :DocumentRoot => apt_data_dir + "/var/www/apt", + # Make WEBrick quiet, comment out for debug. + :Logger => Logger.new(StringIO.new), + :AccessLog => [ StringIO.new, WEBrick::AccessLog::COMMON_LOG_FORMAT ] + ) + end + + def run_apt_server + apt_server.start + end + + def start_apt_server + @apt_server_thread = Thread.new do + run_apt_server + end + until tcp_test_port("localhost", 9000) + if @apt_server_thread.alive? + sleep 1 + else + @apt_server_thread.join + raise "apt server failed to start" + end + end + end + + def stop_apt_server + apt_server.shutdown + @apt_server_thread.join + end + + def apt_data_dir + File.join(CHEF_SPEC_DATA, "apt") + end +end + +metadata = { :unix_only => true, + :requires_root => true, + :provider => { :package => Chef::Provider::Package::Apt }, + :arch => "x86_64" # test packages are 64bit +} + +describe Chef::Resource::AptPackage, metadata do + include Chef::Mixin::ShellOut + + context "with a remote package source" do + + include AptServer + + before(:all) do + # Disable mixlib-shellout live streams + Chef::Log.level = :warn + start_apt_server + enable_testing_apt_source + end + + after(:all) do + stop_apt_server + disable_testing_apt_source + shell_out!("apt-get clean") + end + + after do + shell_out!("dpkg -r chef-integration-test") + shell_out("dpkg --clear-avail") + shell_out!("apt-get clean") + end + + let(:node) do + n = Chef::Node.new + n.consume_external_attrs(OHAI_SYSTEM.data.dup, {}) + n + end + + let(:events) do + Chef::EventDispatch::Dispatcher.new + end + + # TODO: lots of duplication from client.rb; + # All of this must be setup for preseed files to get found + let(:cookbook_collection) do + cookbook_path = File.join(CHEF_SPEC_DATA, "cookbooks") + cl = Chef::CookbookLoader.new(cookbook_path) + cl.load_cookbooks + Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_path) + Chef::CookbookCollection.new(cl) + end + + let(:run_context) do + Chef::RunContext.new(node, cookbook_collection, events) + end + + def base_resource + r = Chef::Resource::AptPackage.new("chef-integration-test", run_context) + # The apt repository in the spec data is not gpg signed, so we need to + # force apt to accept the package: + r.options("--force-yes") + r + end + + let(:package_resource) do + base_resource + end + + context "when the package is not yet installed" do + it "installs the package with action :install" do + package_resource.run_action(:install) + shell_out!("dpkg -l chef-integration-test") + expect(package_resource).to be_updated_by_last_action + end + + it "installs the package for action :upgrade" do + package_resource.run_action(:upgrade) + shell_out!("dpkg -l chef-integration-test") + expect(package_resource).to be_updated_by_last_action + end + + it "does nothing for action :remove" do + package_resource.run_action(:remove) + shell_out!("dpkg -l chef-integration-test", :returns => [1]) + expect(package_resource).not_to be_updated_by_last_action + end + + it "does nothing for action :purge" do + package_resource.run_action(:purge) + shell_out!("dpkg -l chef-integration-test", :returns => [1]) + expect(package_resource).not_to be_updated_by_last_action + end + + context "and a not-available package version is specified" do + let(:package_resource) do + r = base_resource + r.version("2.0") + r + end + + it "raises a reasonable error for action :install" do + expect do + package_resource.run_action(:install) + end.to raise_error(Mixlib::ShellOut::ShellCommandFailed) + end + + end + + describe "when preseeding the install" do + + let(:file_cache_path) { Dir.mktmpdir } + + before do + Chef::Config[:file_cache_path] = file_cache_path + debconf_reset = 'chef-integration-test chef-integration-test/sample-var string "INVALID"' + shell_out!("echo #{debconf_reset} |debconf-set-selections") + end + + after do + FileUtils.rm_rf(file_cache_path) + end + + context "with a preseed file" do + + let(:package_resource) do + r = base_resource + r.cookbook_name = "preseed" + r.response_file("preseed-file.seed") + r + end + + it "preseeds the package, then installs it" do + package_resource.run_action(:install) + cmd = shell_out!("debconf-show chef-integration-test") + expect(cmd.stdout).to include('chef-integration-test/sample-var: "hello world"') + expect(package_resource).to be_updated_by_last_action + end + + context "and the preseed file exists and is up-to-date" do + + before do + # Code here is duplicated from the implementation. Not great, but + # it should at least fail if the code gets out of sync. + source = File.join(CHEF_SPEC_DATA, "cookbooks/preseed/files/default/preseed-file.seed") + file_cache_dir = Chef::FileCache.create_cache_path("preseed/preseed") + dest = "#{file_cache_dir}/chef-integration-test-1.1-1.seed" + FileUtils.cp(source, dest) + end + + it "does not update the package configuration" do + package_resource.run_action(:install) + cmd = shell_out!("debconf-show chef-integration-test") + expect(cmd.stdout).to include("chef-integration-test/sample-var: INVALID") + expect(package_resource).to be_updated_by_last_action + end + + end + + end + + context "with a preseed template" do + + # NOTE: in the fixtures, there is also a cookbook_file named + # "preseed-template.seed". This implicitly tests that templates are + # preferred over cookbook_files when both are present. + + let(:package_resource) do + r = base_resource + r.cookbook_name = "preseed" + r.response_file("preseed-template.seed") + r + end + + before do + node.normal[:preseed_value] = "FROM TEMPLATE" + end + + it "preseeds the package, then installs it" do + package_resource.run_action(:install) + cmd = shell_out!("debconf-show chef-integration-test") + expect(cmd.stdout).to include('chef-integration-test/sample-var: "FROM TEMPLATE"') + expect(package_resource).to be_updated_by_last_action + end + + context "with variables" do + let(:package_resource) do + r = base_resource + r.cookbook_name = "preseed" + r.response_file("preseed-template-variables.seed") + r.response_file_variables({ :template_variable => "SUPPORTS VARIABLES" }) + r + end + + it "preseeds the package, then installs it" do + package_resource.run_action(:install) + cmd = shell_out!("debconf-show chef-integration-test") + expect(cmd.stdout).to include('chef-integration-test/sample-var: "SUPPORTS VARIABLES"') + expect(package_resource).to be_updated_by_last_action + end + end + + end + end # installing w/ preseed + end # when package not installed + + context "and the desired version of the package is installed" do + + before do + v_1_1_package = File.expand_path("apt/chef-integration-test_1.1-1_amd64.deb", CHEF_SPEC_DATA) + shell_out!("dpkg -i #{v_1_1_package}") + end + + it "does nothing for action :install" do + package_resource.run_action(:install) + shell_out!("dpkg -l chef-integration-test", :returns => [0]) + expect(package_resource).not_to be_updated_by_last_action + end + + it "does nothing for action :upgrade" do + package_resource.run_action(:upgrade) + shell_out!("dpkg -l chef-integration-test", :returns => [0]) + expect(package_resource).not_to be_updated_by_last_action + end + + # Verify that the package is removed by running `dpkg -l PACKAGE` + # On Ubuntu 12.10 and newer, the command exits 1. + # + # On Ubuntu 12.04 and older, the `dpkg -l` command will exit 0 and + # display a package status message like this: + # + # Desired=Unknown/Install/Remove/Purge/Hold + # | Status=Not/Inst/Cfg-files/Unpacked/Failed-cfg/Half-inst/trig-aWait/Trig-pend + # |/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad) + # ||/ Name Version Description + # +++-=================================-=========================================-============================================ + # un chef-integration-test (no description available) + def pkg_should_be_removed + # will raise if exit code != 0,1 + pkg_check = shell_out!("dpkg -l chef-integration-test", :returns => [0, 1]) + + if pkg_check.exitstatus == 0 + expect(pkg_check.stdout).to match(/un[\s]+chef-integration-test/) + end + end + + it "removes the package for action :remove" do + package_resource.run_action(:remove) + pkg_should_be_removed + expect(package_resource).to be_updated_by_last_action + end + + it "removes the package for action :purge" do + package_resource.run_action(:purge) + pkg_should_be_removed + expect(package_resource).to be_updated_by_last_action + end + + end + + context "and an older version of the package is installed" do + before do + v_1_0_package = File.expand_path("apt/chef-integration-test_1.0-1_amd64.deb", CHEF_SPEC_DATA) + shell_out!("dpkg -i #{v_1_0_package}") + end + + it "does nothing for action :install" do + package_resource.run_action(:install) + shell_out!("dpkg -l chef-integration-test", :returns => [0]) + expect(package_resource).not_to be_updated_by_last_action + end + + it "upgrades the package for action :upgrade" do + package_resource.run_action(:upgrade) + dpkg_l = shell_out!("dpkg -l chef-integration-test", :returns => [0]) + expect(dpkg_l.stdout).to match(/chef\-integration\-test[\s]+1\.1\-1/) + expect(package_resource).to be_updated_by_last_action + end + + context "and the resource specifies the new version" do + let(:package_resource) do + r = base_resource + r.version("1.1-1") + r + end + + it "upgrades the package for action :install" do + package_resource.run_action(:install) + dpkg_l = shell_out!("dpkg -l chef-integration-test", :returns => [0]) + expect(dpkg_l.stdout).to match(/chef\-integration\-test[\s]+1\.1\-1/) + expect(package_resource).to be_updated_by_last_action + end + end + + end + + end + +end diff --git a/spec/functional/resource/package_spec.rb b/spec/functional/resource/package_spec.rb deleted file mode 100644 index 0f01a751ec..0000000000 --- a/spec/functional/resource/package_spec.rb +++ /dev/null @@ -1,386 +0,0 @@ -# encoding: UTF-8 -# -# Author:: Daniel DeLeo () -# Copyright:: Copyright 2013-2016, Chef Software, Inc. -# License:: Apache License, Version 2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -require "spec_helper" -require "webrick" - -module AptServer - def enable_testing_apt_source - File.open("/etc/apt/sources.list.d/chef-integration-test.list", "w+") do |f| - f.puts "deb http://localhost:9000/ sid main" - end - # Magic to update apt cache for only our repo - shell_out!("apt-get update " + - '-o Dir::Etc::sourcelist="sources.list.d/chef-integration-test.list" ' + - '-o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0"') - end - - def disable_testing_apt_source - FileUtils.rm("/etc/apt/sources.list.d/chef-integration-test.list") - rescue Errno::ENOENT - puts("Attempted to remove integration test from /etc/apt/sources.list.d but it didn't exist") - end - - def tcp_test_port(hostname, port) - tcp_socket = TCPSocket.new(hostname, port) - true - rescue Errno::ETIMEDOUT - false - rescue Errno::ECONNREFUSED - false - ensure - tcp_socket && tcp_socket.close - end - - def apt_server - @apt_server ||= WEBrick::HTTPServer.new( - :Port => 9000, - :DocumentRoot => apt_data_dir + "/var/www/apt", - # Make WEBrick quiet, comment out for debug. - :Logger => Logger.new(StringIO.new), - :AccessLog => [ StringIO.new, WEBrick::AccessLog::COMMON_LOG_FORMAT ] - ) - end - - def run_apt_server - apt_server.start - end - - def start_apt_server - @apt_server_thread = Thread.new do - run_apt_server - end - until tcp_test_port("localhost", 9000) - if @apt_server_thread.alive? - sleep 1 - else - @apt_server_thread.join - raise "apt server failed to start" - end - end - end - - def stop_apt_server - apt_server.shutdown - @apt_server_thread.join - end - - def apt_data_dir - File.join(CHEF_SPEC_DATA, "apt") - end -end - -metadata = { :unix_only => true, - :requires_root => true, - :provider => { :package => Chef::Provider::Package::Apt }, - :arch => "x86_64" # test packages are 64bit -} - -describe Chef::Resource::Package, metadata do - include Chef::Mixin::ShellOut - - context "with a remote package source" do - - include AptServer - - before(:all) do - # Disable mixlib-shellout live streams - Chef::Log.level = :warn - start_apt_server - enable_testing_apt_source - end - - after(:all) do - stop_apt_server - disable_testing_apt_source - shell_out!("apt-get clean") - end - - after do - shell_out!("dpkg -r chef-integration-test") - shell_out("dpkg --clear-avail") - shell_out!("apt-get clean") - end - - let(:node) do - n = Chef::Node.new - n.consume_external_attrs(OHAI_SYSTEM.data.dup, {}) - n - end - - let(:events) do - Chef::EventDispatch::Dispatcher.new - end - - # TODO: lots of duplication from client.rb; - # All of this must be setup for preseed files to get found - let(:cookbook_collection) do - cookbook_path = File.join(CHEF_SPEC_DATA, "cookbooks") - cl = Chef::CookbookLoader.new(cookbook_path) - cl.load_cookbooks - Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_path) - Chef::CookbookCollection.new(cl) - end - - let(:run_context) do - Chef::RunContext.new(node, cookbook_collection, events) - end - - def base_resource - r = Chef::Resource::Package.new("chef-integration-test", run_context) - # The apt repository in the spec data is not gpg signed, so we need to - # force apt to accept the package: - r.options("--force-yes") - r - end - - let(:package_resource) do - base_resource - end - - context "when the package is not yet installed" do - it "installs the package with action :install" do - package_resource.run_action(:install) - shell_out!("dpkg -l chef-integration-test") - expect(package_resource).to be_updated_by_last_action - end - - it "installs the package for action :upgrade" do - package_resource.run_action(:upgrade) - shell_out!("dpkg -l chef-integration-test") - expect(package_resource).to be_updated_by_last_action - end - - it "does nothing for action :remove" do - package_resource.run_action(:remove) - shell_out!("dpkg -l chef-integration-test", :returns => [1]) - expect(package_resource).not_to be_updated_by_last_action - end - - it "does nothing for action :purge" do - package_resource.run_action(:purge) - shell_out!("dpkg -l chef-integration-test", :returns => [1]) - expect(package_resource).not_to be_updated_by_last_action - end - - context "and a not-available package version is specified" do - let(:package_resource) do - r = base_resource - r.version("2.0") - r - end - - it "raises a reasonable error for action :install" do - expect do - package_resource.run_action(:install) - end.to raise_error(Mixlib::ShellOut::ShellCommandFailed) - end - - end - - describe "when preseeding the install" do - - let(:file_cache_path) { Dir.mktmpdir } - - before do - Chef::Config[:file_cache_path] = file_cache_path - debconf_reset = 'chef-integration-test chef-integration-test/sample-var string "INVALID"' - shell_out!("echo #{debconf_reset} |debconf-set-selections") - end - - after do - FileUtils.rm_rf(file_cache_path) - end - - context "with a preseed file" do - - let(:package_resource) do - r = base_resource - r.cookbook_name = "preseed" - r.response_file("preseed-file.seed") - r - end - - it "preseeds the package, then installs it" do - package_resource.run_action(:install) - cmd = shell_out!("debconf-show chef-integration-test") - expect(cmd.stdout).to include('chef-integration-test/sample-var: "hello world"') - expect(package_resource).to be_updated_by_last_action - end - - context "and the preseed file exists and is up-to-date" do - - before do - # Code here is duplicated from the implementation. Not great, but - # it should at least fail if the code gets out of sync. - source = File.join(CHEF_SPEC_DATA, "cookbooks/preseed/files/default/preseed-file.seed") - file_cache_dir = Chef::FileCache.create_cache_path("preseed/preseed") - dest = "#{file_cache_dir}/chef-integration-test-1.1-1.seed" - FileUtils.cp(source, dest) - end - - it "does not update the package configuration" do - package_resource.run_action(:install) - cmd = shell_out!("debconf-show chef-integration-test") - expect(cmd.stdout).to include("chef-integration-test/sample-var: INVALID") - expect(package_resource).to be_updated_by_last_action - end - - end - - end - - context "with a preseed template" do - - # NOTE: in the fixtures, there is also a cookbook_file named - # "preseed-template.seed". This implicitly tests that templates are - # preferred over cookbook_files when both are present. - - let(:package_resource) do - r = base_resource - r.cookbook_name = "preseed" - r.response_file("preseed-template.seed") - r - end - - before do - node.normal[:preseed_value] = "FROM TEMPLATE" - end - - it "preseeds the package, then installs it" do - package_resource.run_action(:install) - cmd = shell_out!("debconf-show chef-integration-test") - expect(cmd.stdout).to include('chef-integration-test/sample-var: "FROM TEMPLATE"') - expect(package_resource).to be_updated_by_last_action - end - - context "with variables" do - let(:package_resource) do - r = base_resource - r.cookbook_name = "preseed" - r.response_file("preseed-template-variables.seed") - r.response_file_variables({ :template_variable => "SUPPORTS VARIABLES" }) - r - end - - it "preseeds the package, then installs it" do - package_resource.run_action(:install) - cmd = shell_out!("debconf-show chef-integration-test") - expect(cmd.stdout).to include('chef-integration-test/sample-var: "SUPPORTS VARIABLES"') - expect(package_resource).to be_updated_by_last_action - end - end - - end - end # installing w/ preseed - end # when package not installed - - context "and the desired version of the package is installed" do - - before do - v_1_1_package = File.expand_path("apt/chef-integration-test_1.1-1_amd64.deb", CHEF_SPEC_DATA) - shell_out!("dpkg -i #{v_1_1_package}") - end - - it "does nothing for action :install" do - package_resource.run_action(:install) - shell_out!("dpkg -l chef-integration-test", :returns => [0]) - expect(package_resource).not_to be_updated_by_last_action - end - - it "does nothing for action :upgrade" do - package_resource.run_action(:upgrade) - shell_out!("dpkg -l chef-integration-test", :returns => [0]) - expect(package_resource).not_to be_updated_by_last_action - end - - # Verify that the package is removed by running `dpkg -l PACKAGE` - # On Ubuntu 12.10 and newer, the command exits 1. - # - # On Ubuntu 12.04 and older, the `dpkg -l` command will exit 0 and - # display a package status message like this: - # - # Desired=Unknown/Install/Remove/Purge/Hold - # | Status=Not/Inst/Cfg-files/Unpacked/Failed-cfg/Half-inst/trig-aWait/Trig-pend - # |/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad) - # ||/ Name Version Description - # +++-=================================-=========================================-============================================ - # un chef-integration-test (no description available) - def pkg_should_be_removed - # will raise if exit code != 0,1 - pkg_check = shell_out!("dpkg -l chef-integration-test", :returns => [0, 1]) - - if pkg_check.exitstatus == 0 - expect(pkg_check.stdout).to match(/un[\s]+chef-integration-test/) - end - end - - it "removes the package for action :remove" do - package_resource.run_action(:remove) - pkg_should_be_removed - expect(package_resource).to be_updated_by_last_action - end - - it "removes the package for action :purge" do - package_resource.run_action(:purge) - pkg_should_be_removed - expect(package_resource).to be_updated_by_last_action - end - - end - - context "and an older version of the package is installed" do - before do - v_1_0_package = File.expand_path("apt/chef-integration-test_1.0-1_amd64.deb", CHEF_SPEC_DATA) - shell_out!("dpkg -i #{v_1_0_package}") - end - - it "does nothing for action :install" do - package_resource.run_action(:install) - shell_out!("dpkg -l chef-integration-test", :returns => [0]) - expect(package_resource).not_to be_updated_by_last_action - end - - it "upgrades the package for action :upgrade" do - package_resource.run_action(:upgrade) - dpkg_l = shell_out!("dpkg -l chef-integration-test", :returns => [0]) - expect(dpkg_l.stdout).to match(/chef\-integration\-test[\s]+1\.1\-1/) - expect(package_resource).to be_updated_by_last_action - end - - context "and the resource specifies the new version" do - let(:package_resource) do - r = base_resource - r.version("1.1-1") - r - end - - it "upgrades the package for action :install" do - package_resource.run_action(:install) - dpkg_l = shell_out!("dpkg -l chef-integration-test", :returns => [0]) - expect(dpkg_l.stdout).to match(/chef\-integration\-test[\s]+1\.1\-1/) - expect(package_resource).to be_updated_by_last_action - end - end - - end - - end - -end -- cgit v1.2.1