From 5b90d09398021b0c6f6dac2081c1d884c8270f51 Mon Sep 17 00:00:00 2001 From: Tim Smith Date: Fri, 13 Jul 2018 13:12:25 -0700 Subject: Move all plugin logic into knife supermarket We want to deprecate knife cookbook site. This moves all the logic into the knife supermarket plugins and has the legacy knife cookbook site plugins inherit from that. Signed-off-by: Tim Smith --- spec/unit/knife/cookbook_site_download_spec.rb | 150 ------------------ spec/unit/knife/cookbook_site_install_spec.rb | 200 ----------------------- spec/unit/knife/cookbook_site_share_spec.rb | 209 ------------------------- spec/unit/knife/cookbook_site_unshare_spec.rb | 77 --------- spec/unit/knife/supermarket_download_spec.rb | 152 ++++++++++++++++++ spec/unit/knife/supermarket_install_spec.rb | 201 ++++++++++++++++++++++++ spec/unit/knife/supermarket_share_spec.rb | 209 +++++++++++++++++++++++++ spec/unit/knife/supermarket_unshare_spec.rb | 78 +++++++++ 8 files changed, 640 insertions(+), 636 deletions(-) delete mode 100644 spec/unit/knife/cookbook_site_download_spec.rb delete mode 100644 spec/unit/knife/cookbook_site_install_spec.rb delete mode 100644 spec/unit/knife/cookbook_site_share_spec.rb delete mode 100644 spec/unit/knife/cookbook_site_unshare_spec.rb create mode 100644 spec/unit/knife/supermarket_download_spec.rb create mode 100644 spec/unit/knife/supermarket_install_spec.rb create mode 100644 spec/unit/knife/supermarket_share_spec.rb create mode 100644 spec/unit/knife/supermarket_unshare_spec.rb (limited to 'spec/unit') diff --git a/spec/unit/knife/cookbook_site_download_spec.rb b/spec/unit/knife/cookbook_site_download_spec.rb deleted file mode 100644 index 9bf10859c0..0000000000 --- a/spec/unit/knife/cookbook_site_download_spec.rb +++ /dev/null @@ -1,150 +0,0 @@ -# -# Author:: Thomas Bishop () -# Copyright:: Copyright 2012-2016, Thomas Bishop -# 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 File.expand_path(File.dirname(__FILE__) + "/../../spec_helper") - -describe Chef::Knife::CookbookSiteDownload do - - describe "run" do - before do - @knife = Chef::Knife::CookbookSiteDownload.new - @knife.name_args = ["apache2"] - @noauth_rest = double("no auth rest") - @stderr = StringIO.new - @cookbook_api_url = "https://supermarket.chef.io/api/v1/cookbooks" - @version = "1.0.2" - @version_us = @version.tr ".", "_" - @current_data = { "deprecated" => false, - "latest_version" => "#{@cookbook_api_url}/apache2/versions/#{@version_us}", - "replacement" => "other_apache2" } - - allow(@knife.ui).to receive(:stderr).and_return(@stderr) - allow(@knife).to receive(:noauth_rest).and_return(@noauth_rest) - expect(@noauth_rest).to receive(:get) - .with("#{@cookbook_api_url}/apache2") - .and_return(@current_data) - @knife.configure_chef - end - - context "when the cookbook is deprecated and not forced" do - before do - @current_data["deprecated"] = true - end - - it "should warn with info about the replacement" do - expect(@knife.ui).to receive(:warn) - .with(/.+deprecated.+replaced by other_apache2.+/i) - expect(@knife.ui).to receive(:warn) - .with(/use --force.+download.+/i) - @knife.run - end - end - - context "when" do - before do - @cookbook_data = { "version" => @version, - "file" => "http://example.com/apache2_#{@version_us}.tgz" } - @temp_file = double( path: "/tmp/apache2_#{@version_us}.tgz" ) - @file = File.join(Dir.pwd, "apache2-#{@version}.tar.gz") - end - - context "downloading the latest version" do - before do - expect(@noauth_rest).to receive(:get) - .with(@current_data["latest_version"]) - .and_return(@cookbook_data) - expect(@noauth_rest).to receive(:streaming_request) - .with(@cookbook_data["file"]) - .and_return(@temp_file) - end - - context "and it is deprecated and with --force" do - before do - @current_data["deprecated"] = true - @knife.config[:force] = true - end - - it "should download the latest version" do - expect(@knife.ui).to receive(:warn) - .with(/.+deprecated.+replaced by other_apache2.+/i) - expect(FileUtils).to receive(:cp).with(@temp_file.path, @file) - @knife.run - expect(@stderr.string).to match /downloading apache2.+version.+#{Regexp.escape(@version)}/i - expect(@stderr.string).to match /cookbook save.+#{Regexp.escape(@file)}/i - end - - end - - it "should download the latest version" do - expect(FileUtils).to receive(:cp).with(@temp_file.path, @file) - @knife.run - expect(@stderr.string).to match /downloading apache2.+version.+#{Regexp.escape(@version)}/i - expect(@stderr.string).to match /cookbook save.+#{Regexp.escape(@file)}/i - end - - context "with -f or --file" do - before do - @file = "/opt/chef/cookbooks/apache2.tar.gz" - @knife.config[:file] = @file - expect(FileUtils).to receive(:cp).with(@temp_file.path, @file) - end - - it "should download the cookbook to the desired file" do - @knife.run - expect(@stderr.string).to match /downloading apache2.+version.+#{Regexp.escape(@version)}/i - expect(@stderr.string).to match /cookbook save.+#{Regexp.escape(@file)}/i - end - end - - it "should provide an accessor to the version" do - allow(FileUtils).to receive(:cp).and_return(true) - expect(@knife.version).to eq(@version) - @knife.run - end - end - - context "downloading a cookbook of a specific version" do - before do - @version = "1.0.1" - @version_us = @version.tr ".", "_" - @cookbook_data = { "version" => @version, - "file" => "http://example.com/apache2_#{@version_us}.tgz" } - @temp_file = double(path: "/tmp/apache2_#{@version_us}.tgz") - @file = File.join(Dir.pwd, "apache2-#{@version}.tar.gz") - @knife.name_args << @version - end - - it "should download the desired version" do - expect(@noauth_rest).to receive(:get) - .with("#{@cookbook_api_url}/apache2/versions/#{@version_us}") - .and_return(@cookbook_data) - expect(@noauth_rest).to receive(:streaming_request) - .with(@cookbook_data["file"]) - .and_return(@temp_file) - expect(FileUtils).to receive(:cp).with(@temp_file.path, @file) - @knife.run - expect(@stderr.string).to match /downloading apache2.+version.+#{Regexp.escape(@version)}/i - expect(@stderr.string).to match /cookbook save.+#{Regexp.escape(@file)}/i - end - end - - end - - end - -end diff --git a/spec/unit/knife/cookbook_site_install_spec.rb b/spec/unit/knife/cookbook_site_install_spec.rb deleted file mode 100644 index 4e9c7b6265..0000000000 --- a/spec/unit/knife/cookbook_site_install_spec.rb +++ /dev/null @@ -1,200 +0,0 @@ -# -# Author:: Steven Danna () -# Copyright:: Copyright 2011-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 File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper")) - -describe Chef::Knife::CookbookSiteInstall do - let(:knife) { Chef::Knife::CookbookSiteInstall.new } - let(:stdout) { StringIO.new } - let(:stderr) { StringIO.new } - let(:downloader) { Hash.new } - let(:archive) { double(Mixlib::Archive, extract: true) } - let(:repo) do - double(sanity_check: true, reset_to_default_state: true, - prepare_to_import: true, finalize_updates_to: true, - merge_updates_from: true) end - let(:install_path) do - if Chef::Platform.windows? - "C:/tmp/chef" - else - "/var/tmp/chef" - end - end - - before(:each) do - require "chef/knife/core/cookbook_scm_repo" - - allow(knife.ui).to receive(:stdout).and_return(stdout) - knife.config = {} - knife.config[:cookbook_path] = [ install_path ] - - allow(knife).to receive(:stderr).and_return(stderr) - allow(knife).to receive(:stdout).and_return(stdout) - - # Assume all external commands would have succeed. :( - allow(File).to receive(:unlink) - allow(File).to receive(:rmtree) - allow(knife).to receive(:shell_out!).and_return(true) - allow(Mixlib::Archive).to receive(:new).and_return(archive) - - # CookbookSiteDownload Stup - allow(knife).to receive(:download_cookbook_to).and_return(downloader) - allow(downloader).to receive(:version) do - if knife.name_args.size == 2 - knife.name_args[1] - else - "0.3.0" - end - end - - # Stubs for CookbookSCMRepo - allow(Chef::Knife::CookbookSCMRepo).to receive(:new).and_return(repo) - end - - describe "run" do - it "raises an error if a cookbook name is not provided" do - knife.name_args = [] - expect(knife.ui).to receive(:error).with("Please specify a cookbook to download and install.") - expect { knife.run }.to raise_error(SystemExit) - end - - it "raises an error if more than two arguments are given" do - knife.name_args = %w{foo bar baz} - expect(knife.ui).to receive(:error).with("Installing multiple cookbooks at once is not supported.") - expect { knife.run }.to raise_error(SystemExit) - end - - it "raises an error if the second argument is not a version" do - knife.name_args = ["getting-started", "1pass"] - expect(knife.ui).to receive(:error).with("Installing multiple cookbooks at once is not supported.") - expect { knife.run }.to raise_error(SystemExit) - end - - it "raises an error if the second argument is a four-digit version" do - knife.name_args = ["getting-started", "0.0.0.1"] - expect(knife.ui).to receive(:error).with("Installing multiple cookbooks at once is not supported.") - expect { knife.run }.to raise_error(SystemExit) - end - - it "raises an error if the second argument is a one-digit version" do - knife.name_args = ["getting-started", "1"] - expect(knife.ui).to receive(:error).with("Installing multiple cookbooks at once is not supported.") - expect { knife.run }.to raise_error(SystemExit) - end - - it "installs the specified version if second argument is a three-digit version" do - knife.name_args = ["getting-started", "0.1.0"] - knife.config[:no_deps] = true - upstream_file = File.join(install_path, "getting-started.tar.gz") - expect(knife).to receive(:download_cookbook_to).with(upstream_file) - expect(knife).to receive(:extract_cookbook).with(upstream_file, "0.1.0") - expect(knife).to receive(:clear_existing_files).with(File.join(install_path, "getting-started")) - expect(repo).to receive(:merge_updates_from).with("getting-started", "0.1.0") - knife.run - end - - it "installs the specified version if second argument is a two-digit version" do - knife.name_args = ["getting-started", "0.1"] - knife.config[:no_deps] = true - upstream_file = File.join(install_path, "getting-started.tar.gz") - expect(knife).to receive(:download_cookbook_to).with(upstream_file) - expect(knife).to receive(:extract_cookbook).with(upstream_file, "0.1") - expect(knife).to receive(:clear_existing_files).with(File.join(install_path, "getting-started")) - expect(repo).to receive(:merge_updates_from).with("getting-started", "0.1") - knife.run - end - - it "installs the latest version if only a cookbook name is given" do - knife.name_args = ["getting-started"] - knife.config[:no_deps] = true - upstream_file = File.join(install_path, "getting-started.tar.gz") - expect(knife).to receive(:download_cookbook_to).with(upstream_file) - expect(knife).to receive(:extract_cookbook).with(upstream_file, "0.3.0") - expect(knife).to receive(:clear_existing_files).with(File.join(install_path, "getting-started")) - expect(repo).to receive(:merge_updates_from).with("getting-started", "0.3.0") - knife.run - end - - it "does not create/reset git branches if use_current_branch is set" do - knife.name_args = ["getting-started"] - knife.config[:use_current_branch] = true - knife.config[:no_deps] = true - upstream_file = File.join(install_path, "getting-started.tar.gz") - expect(repo).not_to receive(:prepare_to_import) - expect(repo).not_to receive(:reset_to_default_state) - knife.run - end - - it "does not raise an error if cookbook_path is a string" do - knife.config[:cookbook_path] = install_path - knife.config[:no_deps] = true - knife.name_args = ["getting-started"] - upstream_file = File.join(install_path, "getting-started.tar.gz") - expect(knife).to receive(:download_cookbook_to).with(upstream_file) - expect(knife).to receive(:extract_cookbook).with(upstream_file, "0.3.0") - expect(knife).to receive(:clear_existing_files).with(File.join(install_path, "getting-started")) - expect(repo).to receive(:merge_updates_from).with("getting-started", "0.3.0") - expect { knife.run }.not_to raise_error - end - end # end of run - - let(:metadata) { Chef::Cookbook::Metadata.new } - let(:rb_metadata_path) { File.join(install_path, "post-punk-kitchen", "metadata.rb") } - let(:json_metadata_path) { File.join(install_path, "post-punk-kitchen", "metadata.json") } - - describe "preferred_metadata" do - before do - allow(Chef::Cookbook::Metadata).to receive(:new).and_return(metadata) - allow(File).to receive(:exist?).and_return(false) - knife.instance_variable_set(:@cookbook_name, "post-punk-kitchen") - knife.instance_variable_set(:@install_path, install_path) - end - - it "returns a populated Metadata object if metadata.rb exists" do - allow(File).to receive(:exist?).with(rb_metadata_path).and_return(true) - expect(metadata).to receive(:from_file).with(rb_metadata_path) - knife.preferred_metadata - end - - it "returns a populated Metadata object if metadata.json exists" do - allow(File).to receive(:exist?).with(json_metadata_path).and_return(true) - # expect(IO).to receive(:read).with(json_metadata_path) - allow(IO).to receive(:read) - expect(metadata).to receive(:from_json) - knife.preferred_metadata - end - - it "prefers metadata.rb over metadata.json" do - allow(File).to receive(:exist?).with(rb_metadata_path).and_return(true) - allow(File).to receive(:exist?).with(json_metadata_path).and_return(true) - allow(IO).to receive(:read) - expect(metadata).to receive(:from_file).with(rb_metadata_path) - expect(metadata).not_to receive(:from_json) - knife.preferred_metadata - end - - it "rasies an error if it finds no metadata file" do - expect { knife.preferred_metadata }.to raise_error { |error| - expect(error).to be_a(Chef::Exceptions::MetadataNotFound) - expect(error.cookbook_name).to eq("post-punk-kitchen") - expect(error.install_path).to eq(install_path) - } - end - - end -end diff --git a/spec/unit/knife/cookbook_site_share_spec.rb b/spec/unit/knife/cookbook_site_share_spec.rb deleted file mode 100644 index 773c1a78c3..0000000000 --- a/spec/unit/knife/cookbook_site_share_spec.rb +++ /dev/null @@ -1,209 +0,0 @@ -# -# Author:: Stephen Delano () -# Copyright:: Copyright 2010-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 "chef/cookbook_uploader" -require "chef/cookbook_site_streaming_uploader" - -describe Chef::Knife::CookbookSiteShare do - - before(:each) do - @knife = Chef::Knife::CookbookSiteShare.new - # Merge default settings in. - @knife.merge_configs - @knife.name_args = %w{cookbook_name AwesomeSausage} - - @cookbook = Chef::CookbookVersion.new("cookbook_name") - - @cookbook_loader = double("Chef::CookbookLoader") - allow(@cookbook_loader).to receive(:cookbook_exists?).and_return(true) - allow(@cookbook_loader).to receive(:[]).and_return(@cookbook) - allow(Chef::CookbookLoader).to receive(:new).and_return(@cookbook_loader) - - @noauth_rest = double(Chef::ServerAPI) - allow(@knife).to receive(:noauth_rest).and_return(@noauth_rest) - - @cookbook_uploader = Chef::CookbookUploader.new("herpderp", rest: "norest") - allow(Chef::CookbookUploader).to receive(:new).and_return(@cookbook_uploader) - allow(@cookbook_uploader).to receive(:validate_cookbooks).and_return(true) - allow(Chef::CookbookSiteStreamingUploader).to receive(:create_build_dir).and_return(Dir.mktmpdir) - - allow(@knife).to receive(:shell_out!).and_return(true) - @stdout = StringIO.new - allow(@knife.ui).to receive(:stdout).and_return(@stdout) - end - - describe "run" do - - before(:each) do - allow(@knife).to receive(:do_upload).and_return(true) - @category_response = { - "name" => "cookbook_name", - "category" => "Testing Category", - } - @bad_category_response = { - "error_code" => "NOT_FOUND", - "error_messages" => [ - "Resource does not exist.", - ], - } - end - - it "should set true to config[:dry_run] as default" do - expect(@knife.config[:dry_run]).to be_falsey - end - - it "should should print usage and exit when given no arguments" do - @knife.name_args = [] - expect(@knife).to receive(:show_usage) - expect(@knife.ui).to receive(:fatal) - expect { @knife.run }.to raise_error(SystemExit) - end - - it "should not fail when given only 1 argument and can determine category" do - @knife.name_args = ["cookbook_name"] - expect(@noauth_rest).to receive(:get).with("https://supermarket.chef.io/api/v1/cookbooks/cookbook_name").and_return(@category_response) - expect(@knife).to receive(:do_upload) - @knife.run - end - - it "should use a default category when given only 1 argument and cannot determine category" do - @knife.name_args = ["cookbook_name"] - expect(@noauth_rest).to receive(:get).with("https://supermarket.chef.io/api/v1/cookbooks/cookbook_name") { raise Net::HTTPServerException.new("404 Not Found", OpenStruct.new(code: "404")) } - expect(@knife).to receive(:do_upload) - expect { @knife.run }.to_not raise_error - end - - it "should print error and exit when given only 1 argument and Chef::ServerAPI throws an exception" do - @knife.name_args = ["cookbook_name"] - expect(@noauth_rest).to receive(:get).with("https://supermarket.chef.io/api/v1/cookbooks/cookbook_name") { raise Errno::ECONNREFUSED, "Connection refused" } - expect(@knife.ui).to receive(:fatal) - expect { @knife.run }.to raise_error(SystemExit) - end - - it "should check if the cookbook exists" do - expect(@cookbook_loader).to receive(:cookbook_exists?) - @knife.run - end - - it "should exit and log to error if the cookbook doesn't exist" do - allow(@cookbook_loader).to receive(:cookbook_exists?).and_return(false) - expect(@knife.ui).to receive(:error) - expect { @knife.run }.to raise_error(SystemExit) - end - - if File.exists?("/usr/bin/gnutar") || File.exists?("/bin/gnutar") - it "should use gnutar to make a tarball of the cookbook" do - expect(@knife).to receive(:shell_out!) do |args| - expect(args.to_s).to match(/gnutar -czf/) - end - @knife.run - end - else - it "should make a tarball of the cookbook" do - expect(@knife).to receive(:shell_out!) do |args| - expect(args.to_s).to match(/tar -czf/) - end - @knife.run - end - end - - it "should exit and log to error when the tarball creation fails" do - allow(@knife).to receive(:shell_out!).and_raise(Chef::Exceptions::Exec) - expect(@knife.ui).to receive(:error) - expect { @knife.run }.to raise_error(SystemExit) - end - - it "should upload the cookbook and clean up the tarball" do - expect(@knife).to receive(:do_upload) - expect(FileUtils).to receive(:rm_rf) - @knife.run - end - - context "when the --dry-run flag is specified" do - before do - allow(Chef::CookbookSiteStreamingUploader).to receive(:create_build_dir).and_return("/var/tmp/dummy") - @knife.config = { dry_run: true } - allow(@knife).to receive_message_chain(:shell_out!, :stdout).and_return("file") - end - - it "should list files in the tarball" do - allow(@knife).to receive(:tar_cmd).and_return("footar") - expect(@knife).to receive(:shell_out!).with("footar -czf #{@cookbook.name}.tgz #{@cookbook.name}", { cwd: "/var/tmp/dummy" }) - expect(@knife).to receive(:shell_out!).with("footar -tzf #{@cookbook.name}.tgz", { cwd: "/var/tmp/dummy" }) - @knife.run - end - - it "does not upload the cookbook" do - allow(@knife).to receive(:shell_out!).and_return(true) - expect(@knife).not_to receive(:do_upload) - @knife.run - end - end - end - - describe "do_upload" do - - before(:each) do - @upload_response = double("Net::HTTPResponse") - allow(Chef::CookbookSiteStreamingUploader).to receive(:post).and_return(@upload_response) - - @stdout = StringIO.new - @stderr = StringIO.new - allow(@knife.ui).to receive(:stdout).and_return(@stdout) - allow(@knife.ui).to receive(:stderr).and_return(@stderr) - allow(File).to receive(:open).and_return(true) - end - - it 'should post the cookbook to "https://supermarket.chef.io"' do - response_text = Chef::JSONCompat.to_json({ uri: "https://supermarket.chef.io/cookbooks/cookbook_name" }) - allow(@upload_response).to receive(:body).and_return(response_text) - allow(@upload_response).to receive(:code).and_return(201) - expect(Chef::CookbookSiteStreamingUploader).to receive(:post).with(/supermarket\.chef\.io/, anything(), anything(), anything()) - @knife.run - end - - it "should alert the user when a version already exists" do - response_text = Chef::JSONCompat.to_json({ error_messages: ["Version already exists"] }) - allow(@upload_response).to receive(:body).and_return(response_text) - allow(@upload_response).to receive(:code).and_return(409) - expect { @knife.run }.to raise_error(SystemExit) - expect(@stderr.string).to match(/ERROR(.+)cookbook already exists/) - end - - it "should pass any errors on to the user" do - response_text = Chef::JSONCompat.to_json({ error_messages: ["You're holding it wrong"] }) - allow(@upload_response).to receive(:body).and_return(response_text) - allow(@upload_response).to receive(:code).and_return(403) - expect { @knife.run }.to raise_error(SystemExit) - expect(@stderr.string).to match("ERROR(.*)You're holding it wrong") - end - - it "should print the body if no errors are exposed on failure" do - response_text = Chef::JSONCompat.to_json({ system_error: "Your call was dropped", reason: "There's a map for that" }) - allow(@upload_response).to receive(:body).and_return(response_text) - allow(@upload_response).to receive(:code).and_return(500) - expect(@knife.ui).to receive(:error).with(/#{Regexp.escape(response_text)}/) # .ordered - expect(@knife.ui).to receive(:error).with(/Unknown error/) # .ordered - expect { @knife.run }.to raise_error(SystemExit) - end - - end - -end diff --git a/spec/unit/knife/cookbook_site_unshare_spec.rb b/spec/unit/knife/cookbook_site_unshare_spec.rb deleted file mode 100644 index 7797fdb3f8..0000000000 --- a/spec/unit/knife/cookbook_site_unshare_spec.rb +++ /dev/null @@ -1,77 +0,0 @@ -# -# Author:: Stephen Delano () -# Author:: Tim Hinderliter () -# Copyright:: Copyright 2010-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" - -describe Chef::Knife::CookbookSiteUnshare do - - before(:each) do - @knife = Chef::Knife::CookbookSiteUnshare.new - @knife.name_args = ["cookbook_name"] - allow(@knife).to receive(:confirm).and_return(true) - - @rest = double("Chef::ServerAPI") - allow(@rest).to receive(:delete).and_return(true) - allow(@knife).to receive(:rest).and_return(@rest) - @stdout = StringIO.new - allow(@knife.ui).to receive(:stdout).and_return(@stdout) - end - - describe "run" do - - describe "with no cookbook argument" do - it "should print the usage and exit" do - @knife.name_args = [] - expect(@knife.ui).to receive(:fatal) - expect(@knife).to receive(:show_usage) - expect { @knife.run }.to raise_error(SystemExit) - end - end - - it "should confirm you want to unshare the cookbook" do - expect(@knife).to receive(:confirm) - @knife.run - end - - it "should send a delete request to the cookbook site" do - expect(@rest).to receive(:delete) - @knife.run - end - - it "should log an error and exit when forbidden" do - exception = double('403 "Forbidden"', code: "403") - allow(@rest).to receive(:delete).and_raise(Net::HTTPServerException.new('403 "Forbidden"', exception)) - expect(@knife.ui).to receive(:error) - expect { @knife.run }.to raise_error(SystemExit) - end - - it "should re-raise any non-forbidden errors on delete" do - exception = double('500 "Application Error"', code: "500") - allow(@rest).to receive(:delete).and_raise(Net::HTTPServerException.new('500 "Application Error"', exception)) - expect { @knife.run }.to raise_error(Net::HTTPServerException) - end - - it "should log a success message" do - expect(@knife.ui).to receive(:info) - @knife.run - end - - end - -end diff --git a/spec/unit/knife/supermarket_download_spec.rb b/spec/unit/knife/supermarket_download_spec.rb new file mode 100644 index 0000000000..0332bd4390 --- /dev/null +++ b/spec/unit/knife/supermarket_download_spec.rb @@ -0,0 +1,152 @@ +# +# Author:: Thomas Bishop () +# Copyright:: Copyright 2012-2016, Thomas Bishop +# Copyright:: Copyright 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 "chef/knife/supermarket_download" +require "spec_helper" + +describe Chef::Knife::SupermarketDownload do + + describe "run" do + before do + @knife = Chef::Knife::SupermarketDownload.new + @knife.name_args = ["apache2"] + @noauth_rest = double("no auth rest") + @stderr = StringIO.new + @cookbook_api_url = "https://supermarket.chef.io/api/v1/cookbooks" + @version = "1.0.2" + @version_us = @version.tr ".", "_" + @current_data = { "deprecated" => false, + "latest_version" => "#{@cookbook_api_url}/apache2/versions/#{@version_us}", + "replacement" => "other_apache2" } + + allow(@knife.ui).to receive(:stderr).and_return(@stderr) + allow(@knife).to receive(:noauth_rest).and_return(@noauth_rest) + expect(@noauth_rest).to receive(:get) + .with("#{@cookbook_api_url}/apache2") + .and_return(@current_data) + @knife.configure_chef + end + + context "when the cookbook is deprecated and not forced" do + before do + @current_data["deprecated"] = true + end + + it "should warn with info about the replacement" do + expect(@knife.ui).to receive(:warn) + .with(/.+deprecated.+replaced by other_apache2.+/i) + expect(@knife.ui).to receive(:warn) + .with(/use --force.+download.+/i) + @knife.run + end + end + + context "when" do + before do + @cookbook_data = { "version" => @version, + "file" => "http://example.com/apache2_#{@version_us}.tgz" } + @temp_file = double( path: "/tmp/apache2_#{@version_us}.tgz" ) + @file = File.join(Dir.pwd, "apache2-#{@version}.tar.gz") + end + + context "downloading the latest version" do + before do + expect(@noauth_rest).to receive(:get) + .with(@current_data["latest_version"]) + .and_return(@cookbook_data) + expect(@noauth_rest).to receive(:streaming_request) + .with(@cookbook_data["file"]) + .and_return(@temp_file) + end + + context "and it is deprecated and with --force" do + before do + @current_data["deprecated"] = true + @knife.config[:force] = true + end + + it "should download the latest version" do + expect(@knife.ui).to receive(:warn) + .with(/.+deprecated.+replaced by other_apache2.+/i) + expect(FileUtils).to receive(:cp).with(@temp_file.path, @file) + @knife.run + expect(@stderr.string).to match /downloading apache2.+version.+#{Regexp.escape(@version)}/i + expect(@stderr.string).to match /cookbook save.+#{Regexp.escape(@file)}/i + end + + end + + it "should download the latest version" do + expect(FileUtils).to receive(:cp).with(@temp_file.path, @file) + @knife.run + expect(@stderr.string).to match /downloading apache2.+version.+#{Regexp.escape(@version)}/i + expect(@stderr.string).to match /cookbook save.+#{Regexp.escape(@file)}/i + end + + context "with -f or --file" do + before do + @file = "/opt/chef/cookbooks/apache2.tar.gz" + @knife.config[:file] = @file + expect(FileUtils).to receive(:cp).with(@temp_file.path, @file) + end + + it "should download the cookbook to the desired file" do + @knife.run + expect(@stderr.string).to match /downloading apache2.+version.+#{Regexp.escape(@version)}/i + expect(@stderr.string).to match /cookbook save.+#{Regexp.escape(@file)}/i + end + end + + it "should provide an accessor to the version" do + allow(FileUtils).to receive(:cp).and_return(true) + expect(@knife.version).to eq(@version) + @knife.run + end + end + + context "downloading a cookbook of a specific version" do + before do + @version = "1.0.1" + @version_us = @version.tr ".", "_" + @cookbook_data = { "version" => @version, + "file" => "http://example.com/apache2_#{@version_us}.tgz" } + @temp_file = double(path: "/tmp/apache2_#{@version_us}.tgz") + @file = File.join(Dir.pwd, "apache2-#{@version}.tar.gz") + @knife.name_args << @version + end + + it "should download the desired version" do + expect(@noauth_rest).to receive(:get) + .with("#{@cookbook_api_url}/apache2/versions/#{@version_us}") + .and_return(@cookbook_data) + expect(@noauth_rest).to receive(:streaming_request) + .with(@cookbook_data["file"]) + .and_return(@temp_file) + expect(FileUtils).to receive(:cp).with(@temp_file.path, @file) + @knife.run + expect(@stderr.string).to match /downloading apache2.+version.+#{Regexp.escape(@version)}/i + expect(@stderr.string).to match /cookbook save.+#{Regexp.escape(@file)}/i + end + end + + end + + end + +end diff --git a/spec/unit/knife/supermarket_install_spec.rb b/spec/unit/knife/supermarket_install_spec.rb new file mode 100644 index 0000000000..68c8af1028 --- /dev/null +++ b/spec/unit/knife/supermarket_install_spec.rb @@ -0,0 +1,201 @@ +# +# Author:: Steven Danna () +# Copyright:: Copyright 2011-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 "chef/knife/supermarket_install" + +describe Chef::Knife::SupermarketInstall do + let(:knife) { Chef::Knife::SupermarketInstall.new } + let(:stdout) { StringIO.new } + let(:stderr) { StringIO.new } + let(:downloader) { Hash.new } + let(:archive) { double(Mixlib::Archive, extract: true) } + let(:repo) do + double(sanity_check: true, reset_to_default_state: true, + prepare_to_import: true, finalize_updates_to: true, + merge_updates_from: true) end + let(:install_path) do + if Chef::Platform.windows? + "C:/tmp/chef" + else + "/var/tmp/chef" + end + end + + before(:each) do + require "chef/knife/core/cookbook_scm_repo" + + allow(knife.ui).to receive(:stdout).and_return(stdout) + knife.config = {} + knife.config[:cookbook_path] = [ install_path ] + + allow(knife).to receive(:stderr).and_return(stderr) + allow(knife).to receive(:stdout).and_return(stdout) + + # Assume all external commands would have succeed. :( + allow(File).to receive(:unlink) + allow(File).to receive(:rmtree) + allow(knife).to receive(:shell_out!).and_return(true) + allow(Mixlib::Archive).to receive(:new).and_return(archive) + + # SupermarketDownload Setup + allow(knife).to receive(:download_cookbook_to).and_return(downloader) + allow(downloader).to receive(:version) do + if knife.name_args.size == 2 + knife.name_args[1] + else + "0.3.0" + end + end + + # Stubs for CookbookSCMRepo + allow(Chef::Knife::CookbookSCMRepo).to receive(:new).and_return(repo) + end + + describe "run" do + it "raises an error if a cookbook name is not provided" do + knife.name_args = [] + expect(knife.ui).to receive(:error).with("Please specify a cookbook to download and install.") + expect { knife.run }.to raise_error(SystemExit) + end + + it "raises an error if more than two arguments are given" do + knife.name_args = %w{foo bar baz} + expect(knife.ui).to receive(:error).with("Installing multiple cookbooks at once is not supported.") + expect { knife.run }.to raise_error(SystemExit) + end + + it "raises an error if the second argument is not a version" do + knife.name_args = ["getting-started", "1pass"] + expect(knife.ui).to receive(:error).with("Installing multiple cookbooks at once is not supported.") + expect { knife.run }.to raise_error(SystemExit) + end + + it "raises an error if the second argument is a four-digit version" do + knife.name_args = ["getting-started", "0.0.0.1"] + expect(knife.ui).to receive(:error).with("Installing multiple cookbooks at once is not supported.") + expect { knife.run }.to raise_error(SystemExit) + end + + it "raises an error if the second argument is a one-digit version" do + knife.name_args = ["getting-started", "1"] + expect(knife.ui).to receive(:error).with("Installing multiple cookbooks at once is not supported.") + expect { knife.run }.to raise_error(SystemExit) + end + + it "installs the specified version if second argument is a three-digit version" do + knife.name_args = ["getting-started", "0.1.0"] + knife.config[:no_deps] = true + upstream_file = File.join(install_path, "getting-started.tar.gz") + expect(knife).to receive(:download_cookbook_to).with(upstream_file) + expect(knife).to receive(:extract_cookbook).with(upstream_file, "0.1.0") + expect(knife).to receive(:clear_existing_files).with(File.join(install_path, "getting-started")) + expect(repo).to receive(:merge_updates_from).with("getting-started", "0.1.0") + knife.run + end + + it "installs the specified version if second argument is a two-digit version" do + knife.name_args = ["getting-started", "0.1"] + knife.config[:no_deps] = true + upstream_file = File.join(install_path, "getting-started.tar.gz") + expect(knife).to receive(:download_cookbook_to).with(upstream_file) + expect(knife).to receive(:extract_cookbook).with(upstream_file, "0.1") + expect(knife).to receive(:clear_existing_files).with(File.join(install_path, "getting-started")) + expect(repo).to receive(:merge_updates_from).with("getting-started", "0.1") + knife.run + end + + it "installs the latest version if only a cookbook name is given" do + knife.name_args = ["getting-started"] + knife.config[:no_deps] = true + upstream_file = File.join(install_path, "getting-started.tar.gz") + expect(knife).to receive(:download_cookbook_to).with(upstream_file) + expect(knife).to receive(:extract_cookbook).with(upstream_file, "0.3.0") + expect(knife).to receive(:clear_existing_files).with(File.join(install_path, "getting-started")) + expect(repo).to receive(:merge_updates_from).with("getting-started", "0.3.0") + knife.run + end + + it "does not create/reset git branches if use_current_branch is set" do + knife.name_args = ["getting-started"] + knife.config[:use_current_branch] = true + knife.config[:no_deps] = true + upstream_file = File.join(install_path, "getting-started.tar.gz") + expect(repo).not_to receive(:prepare_to_import) + expect(repo).not_to receive(:reset_to_default_state) + knife.run + end + + it "does not raise an error if cookbook_path is a string" do + knife.config[:cookbook_path] = install_path + knife.config[:no_deps] = true + knife.name_args = ["getting-started"] + upstream_file = File.join(install_path, "getting-started.tar.gz") + expect(knife).to receive(:download_cookbook_to).with(upstream_file) + expect(knife).to receive(:extract_cookbook).with(upstream_file, "0.3.0") + expect(knife).to receive(:clear_existing_files).with(File.join(install_path, "getting-started")) + expect(repo).to receive(:merge_updates_from).with("getting-started", "0.3.0") + expect { knife.run }.not_to raise_error + end + end # end of run + + let(:metadata) { Chef::Cookbook::Metadata.new } + let(:rb_metadata_path) { File.join(install_path, "post-punk-kitchen", "metadata.rb") } + let(:json_metadata_path) { File.join(install_path, "post-punk-kitchen", "metadata.json") } + + describe "preferred_metadata" do + before do + allow(Chef::Cookbook::Metadata).to receive(:new).and_return(metadata) + allow(File).to receive(:exist?).and_return(false) + knife.instance_variable_set(:@cookbook_name, "post-punk-kitchen") + knife.instance_variable_set(:@install_path, install_path) + end + + it "returns a populated Metadata object if metadata.rb exists" do + allow(File).to receive(:exist?).with(rb_metadata_path).and_return(true) + expect(metadata).to receive(:from_file).with(rb_metadata_path) + knife.preferred_metadata + end + + it "returns a populated Metadata object if metadata.json exists" do + allow(File).to receive(:exist?).with(json_metadata_path).and_return(true) + # expect(IO).to receive(:read).with(json_metadata_path) + allow(IO).to receive(:read) + expect(metadata).to receive(:from_json) + knife.preferred_metadata + end + + it "prefers metadata.rb over metadata.json" do + allow(File).to receive(:exist?).with(rb_metadata_path).and_return(true) + allow(File).to receive(:exist?).with(json_metadata_path).and_return(true) + allow(IO).to receive(:read) + expect(metadata).to receive(:from_file).with(rb_metadata_path) + expect(metadata).not_to receive(:from_json) + knife.preferred_metadata + end + + it "rasies an error if it finds no metadata file" do + expect { knife.preferred_metadata }.to raise_error { |error| + expect(error).to be_a(Chef::Exceptions::MetadataNotFound) + expect(error.cookbook_name).to eq("post-punk-kitchen") + expect(error.install_path).to eq(install_path) + } + end + + end +end diff --git a/spec/unit/knife/supermarket_share_spec.rb b/spec/unit/knife/supermarket_share_spec.rb new file mode 100644 index 0000000000..dde58775f4 --- /dev/null +++ b/spec/unit/knife/supermarket_share_spec.rb @@ -0,0 +1,209 @@ +# +# Author:: Stephen Delano () +# Copyright:: Copyright 2010-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 "chef/knife/supermarket_share" +require "chef/cookbook_uploader" +require "chef/cookbook_site_streaming_uploader" + +describe Chef::Knife::SupermarketShare do + + before(:each) do + @knife = Chef::Knife::SupermarketShare.new + # Merge default settings in. + @knife.merge_configs + @knife.name_args = %w{cookbook_name AwesomeSausage} + + @cookbook = Chef::CookbookVersion.new("cookbook_name") + + @cookbook_loader = double("Chef::CookbookLoader") + allow(@cookbook_loader).to receive(:cookbook_exists?).and_return(true) + allow(@cookbook_loader).to receive(:[]).and_return(@cookbook) + allow(Chef::CookbookLoader).to receive(:new).and_return(@cookbook_loader) + + @noauth_rest = double(Chef::ServerAPI) + allow(@knife).to receive(:noauth_rest).and_return(@noauth_rest) + + @cookbook_uploader = Chef::CookbookUploader.new("herpderp", rest: "norest") + allow(Chef::CookbookUploader).to receive(:new).and_return(@cookbook_uploader) + allow(@cookbook_uploader).to receive(:validate_cookbooks).and_return(true) + allow(Chef::CookbookSiteStreamingUploader).to receive(:create_build_dir).and_return(Dir.mktmpdir) + + allow(@knife).to receive(:shell_out!).and_return(true) + @stdout = StringIO.new + allow(@knife.ui).to receive(:stdout).and_return(@stdout) + end + + describe "run" do + + before(:each) do + allow(@knife).to receive(:do_upload).and_return(true) + @category_response = { + "name" => "cookbook_name", + "category" => "Testing Category", + } + @bad_category_response = { + "error_code" => "NOT_FOUND", + "error_messages" => [ + "Resource does not exist.", + ], + } + end + + it "should set true to config[:dry_run] as default" do + expect(@knife.config[:dry_run]).to be_falsey + end + + it "should should print usage and exit when given no arguments" do + @knife.name_args = [] + expect(@knife).to receive(:show_usage) + expect(@knife.ui).to receive(:fatal) + expect { @knife.run }.to raise_error(SystemExit) + end + + it "should not fail when given only 1 argument and can determine category" do + @knife.name_args = ["cookbook_name"] + expect(@noauth_rest).to receive(:get).with("https://supermarket.chef.io/api/v1/cookbooks/cookbook_name").and_return(@category_response) + expect(@knife).to receive(:do_upload) + @knife.run + end + + it "should use a default category when given only 1 argument and cannot determine category" do + @knife.name_args = ["cookbook_name"] + expect(@noauth_rest).to receive(:get).with("https://supermarket.chef.io/api/v1/cookbooks/cookbook_name") { raise Net::HTTPServerException.new("404 Not Found", OpenStruct.new(code: "404")) } + expect(@knife).to receive(:do_upload) + expect { @knife.run }.to_not raise_error + end + + it "should print error and exit when given only 1 argument and Chef::ServerAPI throws an exception" do + @knife.name_args = ["cookbook_name"] + expect(@noauth_rest).to receive(:get).with("https://supermarket.chef.io/api/v1/cookbooks/cookbook_name") { raise Errno::ECONNREFUSED, "Connection refused" } + expect(@knife.ui).to receive(:fatal) + expect { @knife.run }.to raise_error(SystemExit) + end + + it "should check if the cookbook exists" do + expect(@cookbook_loader).to receive(:cookbook_exists?) + @knife.run + end + + it "should exit and log to error if the cookbook doesn't exist" do + allow(@cookbook_loader).to receive(:cookbook_exists?).and_return(false) + expect(@knife.ui).to receive(:error) + expect { @knife.run }.to raise_error(SystemExit) + end + + if File.exists?("/usr/bin/gnutar") || File.exists?("/bin/gnutar") + it "should use gnutar to make a tarball of the cookbook" do + expect(@knife).to receive(:shell_out!) do |args| + expect(args.to_s).to match(/gnutar -czf/) + end + @knife.run + end + else + it "should make a tarball of the cookbook" do + expect(@knife).to receive(:shell_out!) do |args| + expect(args.to_s).to match(/tar -czf/) + end + @knife.run + end + end + + it "should exit and log to error when the tarball creation fails" do + allow(@knife).to receive(:shell_out!).and_raise(Chef::Exceptions::Exec) + expect(@knife.ui).to receive(:error) + expect { @knife.run }.to raise_error(SystemExit) + end + + it "should upload the cookbook and clean up the tarball" do + expect(@knife).to receive(:do_upload) + expect(FileUtils).to receive(:rm_rf) + @knife.run + end + + context "when the --dry-run flag is specified" do + before do + allow(Chef::CookbookSiteStreamingUploader).to receive(:create_build_dir).and_return("/var/tmp/dummy") + @knife.config = { dry_run: true } + allow(@knife).to receive_message_chain(:shell_out!, :stdout).and_return("file") + end + + it "should list files in the tarball" do + allow(@knife).to receive(:tar_cmd).and_return("footar") + expect(@knife).to receive(:shell_out!).with("footar -czf #{@cookbook.name}.tgz #{@cookbook.name}", { cwd: "/var/tmp/dummy" }) + expect(@knife).to receive(:shell_out!).with("footar -tzf #{@cookbook.name}.tgz", { cwd: "/var/tmp/dummy" }) + @knife.run + end + + it "does not upload the cookbook" do + allow(@knife).to receive(:shell_out!).and_return(true) + expect(@knife).not_to receive(:do_upload) + @knife.run + end + end + end + + describe "do_upload" do + + before(:each) do + @upload_response = double("Net::HTTPResponse") + allow(Chef::CookbookSiteStreamingUploader).to receive(:post).and_return(@upload_response) + + @stdout = StringIO.new + @stderr = StringIO.new + allow(@knife.ui).to receive(:stdout).and_return(@stdout) + allow(@knife.ui).to receive(:stderr).and_return(@stderr) + allow(File).to receive(:open).and_return(true) + end + + it 'should post the cookbook to "https://supermarket.chef.io"' do + response_text = Chef::JSONCompat.to_json({ uri: "https://supermarket.chef.io/cookbooks/cookbook_name" }) + allow(@upload_response).to receive(:body).and_return(response_text) + allow(@upload_response).to receive(:code).and_return(201) + expect(Chef::CookbookSiteStreamingUploader).to receive(:post).with(/supermarket\.chef\.io/, anything(), anything(), anything()) + @knife.run + end + + it "should alert the user when a version already exists" do + response_text = Chef::JSONCompat.to_json({ error_messages: ["Version already exists"] }) + allow(@upload_response).to receive(:body).and_return(response_text) + allow(@upload_response).to receive(:code).and_return(409) + expect { @knife.run }.to raise_error(SystemExit) + expect(@stderr.string).to match(/ERROR(.+)cookbook already exists/) + end + + it "should pass any errors on to the user" do + response_text = Chef::JSONCompat.to_json({ error_messages: ["You're holding it wrong"] }) + allow(@upload_response).to receive(:body).and_return(response_text) + allow(@upload_response).to receive(:code).and_return(403) + expect { @knife.run }.to raise_error(SystemExit) + expect(@stderr.string).to match("ERROR(.*)You're holding it wrong") + end + + it "should print the body if no errors are exposed on failure" do + response_text = Chef::JSONCompat.to_json({ system_error: "Your call was dropped", reason: "There's a map for that" }) + allow(@upload_response).to receive(:body).and_return(response_text) + allow(@upload_response).to receive(:code).and_return(500) + expect(@knife.ui).to receive(:error).with(/#{Regexp.escape(response_text)}/) # .ordered + expect(@knife.ui).to receive(:error).with(/Unknown error/) # .ordered + expect { @knife.run }.to raise_error(SystemExit) + end + + end + +end diff --git a/spec/unit/knife/supermarket_unshare_spec.rb b/spec/unit/knife/supermarket_unshare_spec.rb new file mode 100644 index 0000000000..206717e211 --- /dev/null +++ b/spec/unit/knife/supermarket_unshare_spec.rb @@ -0,0 +1,78 @@ +# +# Author:: Stephen Delano () +# Author:: Tim Hinderliter () +# Copyright:: Copyright 2010-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 "chef/knife/supermarket_unshare" + +describe Chef::Knife::SupermarketUnshare do + + before(:each) do + @knife = Chef::Knife::SupermarketUnshare.new + @knife.name_args = ["cookbook_name"] + allow(@knife).to receive(:confirm).and_return(true) + + @rest = double("Chef::ServerAPI") + allow(@rest).to receive(:delete).and_return(true) + allow(@knife).to receive(:rest).and_return(@rest) + @stdout = StringIO.new + allow(@knife.ui).to receive(:stdout).and_return(@stdout) + end + + describe "run" do + + describe "with no cookbook argument" do + it "should print the usage and exit" do + @knife.name_args = [] + expect(@knife.ui).to receive(:fatal) + expect(@knife).to receive(:show_usage) + expect { @knife.run }.to raise_error(SystemExit) + end + end + + it "should confirm you want to unshare the cookbook" do + expect(@knife).to receive(:confirm) + @knife.run + end + + it "should send a delete request to the cookbook site" do + expect(@rest).to receive(:delete) + @knife.run + end + + it "should log an error and exit when forbidden" do + exception = double('403 "Forbidden"', code: "403") + allow(@rest).to receive(:delete).and_raise(Net::HTTPServerException.new('403 "Forbidden"', exception)) + expect(@knife.ui).to receive(:error) + expect { @knife.run }.to raise_error(SystemExit) + end + + it "should re-raise any non-forbidden errors on delete" do + exception = double('500 "Application Error"', code: "500") + allow(@rest).to receive(:delete).and_raise(Net::HTTPServerException.new('500 "Application Error"', exception)) + expect { @knife.run }.to raise_error(Net::HTTPServerException) + end + + it "should log a success message" do + expect(@knife.ui).to receive(:info) + @knife.run + end + + end + +end -- cgit v1.2.1