From 8f420ee227e9e52255910b9772caa5ec86685285 Mon Sep 17 00:00:00 2001 From: Adam Edwards Date: Sat, 5 Dec 2015 19:48:07 -0800 Subject: Unit test for resource_credential mixin --- lib/chef/mixin/resource_credential.rb | 36 ++-- lib/chef/provider/remote_file/network_file.rb | 2 +- spec/unit/mixin/resource_credential_spec.rb | 201 +++++++++++++++++++++ spec/unit/provider/execute_spec.rb | 2 +- .../unit/provider/remote_file/network_file_spec.rb | 4 +- 5 files changed, 229 insertions(+), 16 deletions(-) create mode 100644 spec/unit/mixin/resource_credential_spec.rb diff --git a/lib/chef/mixin/resource_credential.rb b/lib/chef/mixin/resource_credential.rb index f2c2d6d7fa..c3844f82b4 100644 --- a/lib/chef/mixin/resource_credential.rb +++ b/lib/chef/mixin/resource_credential.rb @@ -21,30 +21,38 @@ class Chef module ResourceCredential def validate_credential(specified_user, specified_domain, password) - user = specified_user - domain = specified_domain + validate_credential_platform(specified_user, specified_domain, password) + validate_credential_syntax(specified_user, specified_domain, password) + end - if Chef::Platform.windows? - if ! user.nil? - domain, user = canonicalize_credential(specified_domain, specified_user) + def validate_credential_platform(specified_user, specified_domain, password) + if ! Chef::Platform.windows? + if ! password.nil? || ! specified_domain.nil? + raise Exceptions::UnsupportedPlatform, "The `domain` and `password` properties are only supported on the Windows platform" end - - if ! user.nil? && password.nil? - raise ArgumentError, "No `password` property was specified when the `user` property was specified" + else + if ! specified_user.nil? && password.nil? + raise ArgumentError, "A `password` property must be specified when the `user` property is specified on the Windows platform" end - elsif ! domain.nil? || ! password.nil? - raise Exceptions::UnsupportedPlatform, "The `domain` and `password` properties are only supported on the Windows platform" end + end + + def validate_credential_syntax(specified_user, specified_domain, password) + domain, user = qualify_credential_user(specified_domain, specified_user) if ( ! password.nil? || ! domain.nil? ) && user.nil? raise ArgumentError, "The `password` or `domain` property was specified without specification of the user property" end end - def canonicalize_credential(specified_domain, specified_user) + def qualify_credential_user(specified_domain, specified_user) domain = specified_domain user = specified_user + if specified_user.nil? && ! specified_domain.nil? + raise ArgumentError, "The domain #{specified_domain} was specified, but no user name was given" + end + if ! specified_user.nil? && specified_domain.nil? domain_and_user = user.split('\\') @@ -63,8 +71,10 @@ class Chef [domain, user] end - private(:validate_credential) - private(:canonicalize_credential) + protected(:validate_credential) + protected(:validate_credential_platform) + protected(:validate_credential_syntax) + protected(:qualify_credential_user) end end diff --git a/lib/chef/provider/remote_file/network_file.rb b/lib/chef/provider/remote_file/network_file.rb index 7f837cc4cc..848fb41541 100644 --- a/lib/chef/provider/remote_file/network_file.rb +++ b/lib/chef/provider/remote_file/network_file.rb @@ -45,7 +45,7 @@ class Chef tempfile = Chef::FileContentManagement::Tempfile.new(new_resource).tempfile Chef::Log.debug("#{new_resource} staging #{@source} to #{tempfile.path}") - domain, user = canonicalize_credential( new_resource.remote_user_domain, new_resource.remote_user ) + domain, user = qualify_credential_user( new_resource.remote_user_domain, new_resource.remote_user ) with_user_context(user, domain, new_resource.remote_user_password) do ::File.open(@source, 'rb') do | remote_file | diff --git a/spec/unit/mixin/resource_credential_spec.rb b/spec/unit/mixin/resource_credential_spec.rb new file mode 100644 index 0000000000..8fa04c7494 --- /dev/null +++ b/spec/unit/mixin/resource_credential_spec.rb @@ -0,0 +1,201 @@ +# +# Author:: Adam Edwards () +# Copyright:: Copyright (c) 2015 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/mixin/resource_credential' + +shared_examples_for "it received valid credentials" do + describe "the validation method" do + it "should not raise an error" do + expect {instance_with_credential.validate(username, domain, password)}.not_to raise_error + end + end + + describe "the name qualification method" do + it "should correctly translate the user and domain" do + qualified_user = nil + expect { qualified_user = instance_with_credential.qualify_name(domain, username)}.not_to raise_error + expect(qualified_user[0]).to eq(domain) + expect(qualified_user[1]).to eq(username) + end + end +end + +shared_examples_for "it received invalid credentials" do + describe "the validation method" do + it "should raise an error" do + expect { instance_with_credential.validate(username, domain, password)}.to raise_error(ArgumentError) + end + end +end + +shared_examples_for "it received credentials that are not valid on the platform" do + describe "the validation method" do + it "should raise an error" do + expect { instance_with_credential.validate(username, domain, password)}.to raise_error(Chef::Exceptions::UnsupportedPlatform) + end + end +end + +shared_examples_for "a consumer of the resource_credential mixin" do + context "when running on Windows" do + before do + allow(::Chef::Platform).to receive(:windows?).and_return(true) + end + + context "when no user, domain, or password is specified" do + let(:username) { nil } + let(:domain) { nil } + let(:password) { nil } + it_behaves_like "it received valid credentials" + end + + context "when a valid username is specified" do + let(:username) { 'starchild' } + context "when a valid domain is specified" do + let(:domain) { 'mothership' } + + context "when the password is not specified" do + let(:password) { nil } + it_behaves_like "it received invalid credentials" + end + + context "when the password is specified" do + let(:password) { 'we.funk!' } + it_behaves_like "it received valid credentials" + end + end + + context "when the domain is not specified" do + let(:domain) { nil } + + context "when the password is not specified" do + let(:password) { nil } + it_behaves_like "it received invalid credentials" + end + + context "when the password is specified" do + let(:password) { 'we.funk!' } + it_behaves_like "it received valid credentials" + end + end + end + + context "when the username is not specified" do + let(:username) { nil } + + context "when the password is specified and the domain is not" do + let(:password) { 'we.funk!' } + let(:domain) { nil } + it_behaves_like "it received invalid credentials" + end + + context "when the domain is specified and the password is not" do + let(:domain) { 'mothership' } + let(:password) { nil } + it_behaves_like "it received invalid credentials" + end + + context "when the domain and password are specified" do + let(:domain) { 'mothership' } + let(:password) { 'we.funk!' } + it_behaves_like "it received invalid credentials" + end + end + end + + context "when not running on Windows" do + before do + allow(::Chef::Platform).to receive(:windows?).and_return(false) + end + + context "when no user, domain, or password is specified" do + let(:username) { nil } + let(:domain) { nil } + let(:password) { nil } + it_behaves_like "it received valid credentials" + end + + context "when the user is specified and the domain and password are not" do + let(:username) { 'starchild' } + let(:domain) { nil } + let(:password) { nil } + it_behaves_like "it received valid credentials" + + context "when the password is specified and the domain is not" do + let(:password) { 'we.funk!' } + let(:domain) { nil } + it_behaves_like "it received credentials that are not valid on the platform" + end + + context "when the domain is specified and the password is not" do + let(:domain) { 'mothership' } + let(:password) { nil } + it_behaves_like "it received credentials that are not valid on the platform" + end + + context "when the domain and password are specified" do + let(:domain) { 'mothership' } + let(:password) { 'we.funk!' } + it_behaves_like "it received credentials that are not valid on the platform" + end + end + + context "when the user is not specified" do + let(:username) { nil } + context "when the domain is specified" do + let(:domain) { 'mothership' } + context "when the password is specified" do + let(:password) { 'we.funk!' } + it_behaves_like "it received credentials that are not valid on the platform" + end + + context "when password is not specified" do + let(:password) { nil } + it_behaves_like "it received credentials that are not valid on the platform" + end + end + + context "when the domain is not specified" do + let(:domain) { nil } + context "when the password is specified" do + let(:password) { 'we.funk!' } + it_behaves_like "it received credentials that are not valid on the platform" + end + end + end + end +end + +describe "a class that mixes in resource_credential" do + let(:instance_with_credential) do + class CredentialClass + include ::Chef::Mixin::ResourceCredential + def validate(*args) + validate_credential(*args) + end + + def qualify_name(*args) + qualify_credential_user(*args) + end + end + CredentialClass.new + end + + it_behaves_like "a consumer of the resource_credential mixin" +end diff --git a/spec/unit/provider/execute_spec.rb b/spec/unit/provider/execute_spec.rb index 3d171dfed1..cbcb9373c4 100644 --- a/spec/unit/provider/execute_spec.rb +++ b/spec/unit/provider/execute_spec.rb @@ -237,7 +237,7 @@ describe Chef::Provider::Execute do expect { provider.run_action(:run) }.to raise_error(ArgumentError) end - it "should raise an error if the domain and user are specified" do + it "should raise an error if the domain and password are specified" do expect(new_resource).to receive(:password).at_least(1).times.and_return('we.funk!') expect(new_resource).to receive(:domain).at_least(1).times.and_return('mothership') expect { provider.run_action(:run) }.to raise_error(ArgumentError) diff --git a/spec/unit/provider/remote_file/network_file_spec.rb b/spec/unit/provider/remote_file/network_file_spec.rb index 3666a47468..c39b6d0951 100644 --- a/spec/unit/provider/remote_file/network_file_spec.rb +++ b/spec/unit/provider/remote_file/network_file_spec.rb @@ -1,3 +1,4 @@ + # # Author:: Jay Mundrawala () # Copyright:: Copyright (c) 2015 Chef Software @@ -30,10 +31,11 @@ describe Chef::Provider::RemoteFile::NetworkFile do let(:tempfile) { double("Tempfile", :path => "/tmp/foo/bar/Foo.tar.gz", :close => nil) } let(:chef_tempfile) { double("Chef::FileContentManagement::Tempfile", :tempfile => tempfile) } + let(:source_file) { double("::File", :read => nil) } it "stages the local file to a temporary file" do expect(Chef::FileContentManagement::Tempfile).to receive(:new).with(new_resource).and_return(chef_tempfile) - expect(::FileUtils).to receive(:cp).with(source, tempfile.path) + expect(::File).to receive(:open).with(source, 'rb').and_return(source_file) expect(tempfile).to receive(:close) result = fetcher.fetch -- cgit v1.2.1