chef 11.12.0.alpha.1 → 11.12.0.rc.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/chef/api_client/registration.rb +46 -9
- data/lib/chef/application.rb +1 -0
- data/lib/chef/application/client.rb +25 -24
- data/lib/chef/client.rb +34 -0
- data/lib/chef/config.rb +11 -0
- data/lib/chef/cookbook/chefignore.rb +10 -2
- data/lib/chef/cookbook/metadata.rb +31 -3
- data/lib/chef/cookbook/synchronizer.rb +2 -2
- data/lib/chef/cookbook/syntax_check.rb +4 -4
- data/lib/chef/encrypted_data_bag_item.rb +37 -1
- data/lib/chef/exceptions.rb +1 -0
- data/lib/chef/guard_interpreter/default_guard_interpreter.rb +42 -0
- data/lib/chef/guard_interpreter/resource_guard_interpreter.rb +122 -0
- data/lib/chef/http.rb +0 -1
- data/lib/chef/http/decompressor.rb +7 -4
- data/lib/chef/http/simple.rb +5 -0
- data/lib/chef/http/validate_content_length.rb +28 -12
- data/lib/chef/knife.rb +1 -0
- data/lib/chef/knife/client_bulk_delete.rb +48 -9
- data/lib/chef/knife/client_delete.rb +4 -4
- data/lib/chef/knife/cookbook_bulk_delete.rb +1 -1
- data/lib/chef/knife/cookbook_upload.rb +17 -7
- data/lib/chef/knife/core/bootstrap_context.rb +1 -1
- data/lib/chef/knife/core/ui.rb +42 -5
- data/lib/chef/knife/node_run_list_add.rb +31 -2
- data/lib/chef/knife/ssh.rb +44 -31
- data/lib/chef/knife/ssl_check.rb +213 -0
- data/lib/chef/knife/ssl_fetch.rb +145 -0
- data/lib/chef/mixin/deep_merge.rb +13 -5
- data/lib/chef/mixin/shell_out.rb +9 -3
- data/lib/chef/node.rb +23 -4
- data/lib/chef/node/immutable_collections.rb +32 -0
- data/lib/chef/platform/provider_mapping.rb +21 -18
- data/lib/chef/platform/query_helpers.rb +10 -2
- data/lib/chef/policy_builder/expand_node_object.rb +3 -6
- data/lib/chef/provider/cron.rb +25 -3
- data/lib/chef/provider/mount/mount.rb +1 -1
- data/lib/chef/provider/package/dpkg.rb +2 -1
- data/lib/chef/provider/package/windows.rb +80 -0
- data/lib/chef/provider/package/windows/msi.rb +69 -0
- data/lib/chef/provider/powershell_script.rb +19 -6
- data/lib/chef/provider/service/solaris.rb +11 -7
- data/lib/chef/resource.rb +18 -5
- data/lib/chef/resource/conditional.rb +20 -7
- data/lib/chef/resource/cron.rb +18 -2
- data/lib/chef/resource/execute.rb +0 -2
- data/lib/chef/resource/powershell_script.rb +23 -1
- data/lib/chef/resource/script.rb +25 -0
- data/lib/chef/resource/subversion.rb +4 -0
- data/lib/chef/resource/windows_package.rb +79 -0
- data/lib/chef/resource/windows_script.rb +0 -5
- data/lib/chef/resources.rb +1 -0
- data/lib/chef/rest.rb +6 -1
- data/lib/chef/run_context.rb +22 -2
- data/lib/chef/run_context/cookbook_compiler.rb +12 -0
- data/lib/chef/util/editor.rb +92 -0
- data/lib/chef/util/file_edit.rb +22 -54
- data/lib/chef/version.rb +2 -2
- data/lib/chef/win32/api/installer.rb +166 -0
- data/lib/chef/win32/version.rb +8 -0
- data/spec/data/standalone_cookbook/Gemfile +1 -0
- data/spec/data/standalone_cookbook/chefignore +9 -0
- data/spec/data/standalone_cookbook/recipes/default.rb +3 -0
- data/spec/data/standalone_cookbook/vendor/bundle/ruby/2.0.0/gems/multi_json-1.9.0/lib/multi_json.rb +1 -0
- data/spec/functional/resource/powershell_spec.rb +262 -1
- data/spec/functional/win32/versions_spec.rb +3 -3
- data/spec/integration/knife/chefignore_spec.rb +1 -2
- data/spec/integration/knife/raw_spec.rb +8 -13
- data/spec/integration/knife/redirection_spec.rb +6 -14
- data/spec/integration/solo/solo_spec.rb +19 -0
- data/spec/support/shared/functional/windows_script.rb +1 -1
- data/spec/support/shared/integration/app_server_support.rb +42 -0
- data/spec/support/shared/integration/integration_helper.rb +1 -0
- data/spec/support/shared/unit/script_resource.rb +38 -0
- data/spec/unit/api_client/registration_spec.rb +109 -38
- data/spec/unit/application/client_spec.rb +48 -1
- data/spec/unit/cookbook/chefignore_spec.rb +10 -0
- data/spec/unit/cookbook/metadata_spec.rb +45 -1
- data/spec/unit/cookbook/syntax_check_spec.rb +28 -0
- data/spec/unit/cookbook_spec.rb +0 -10
- data/spec/unit/guard_interpreter/resource_guard_interpreter_spec.rb +56 -0
- data/spec/unit/http/simple_spec.rb +32 -0
- data/spec/unit/http/validate_content_length_spec.rb +187 -0
- data/spec/unit/knife/bootstrap_spec.rb +13 -4
- data/spec/unit/knife/client_bulk_delete_spec.rb +123 -38
- data/spec/unit/knife/client_delete_spec.rb +4 -4
- data/spec/unit/knife/cookbook_upload_spec.rb +181 -88
- data/spec/unit/knife/core/bootstrap_context_spec.rb +11 -1
- data/spec/unit/knife/core/ui_spec.rb +109 -38
- data/spec/unit/knife/node_run_list_add_spec.rb +24 -1
- data/spec/unit/knife/ssh_spec.rb +17 -6
- data/spec/unit/knife/ssl_check_spec.rb +187 -0
- data/spec/unit/knife/ssl_fetch_spec.rb +151 -0
- data/spec/unit/mixin/deep_merge_spec.rb +17 -0
- data/spec/unit/node/immutable_collections_spec.rb +55 -0
- data/spec/unit/node_spec.rb +9 -0
- data/spec/unit/platform/query_helpers_spec.rb +32 -0
- data/spec/unit/platform_spec.rb +193 -175
- data/spec/unit/policy_builder/expand_node_object_spec.rb +1 -1
- data/spec/unit/provider/cron_spec.rb +175 -1
- data/spec/unit/provider/mount/mount_spec.rb +33 -3
- data/spec/unit/provider/package/dpkg_spec.rb +4 -0
- data/spec/unit/provider/package/windows/msi_spec.rb +60 -0
- data/spec/unit/provider/package/windows_spec.rb +80 -0
- data/spec/unit/provider/service/macosx_spec.rb +3 -3
- data/spec/unit/provider/service/solaris_smf_service_spec.rb +35 -10
- data/spec/unit/pure_application_spec.rb +32 -0
- data/spec/unit/recipe_spec.rb +4 -0
- data/spec/unit/resource/conditional_spec.rb +13 -12
- data/spec/unit/resource/cron_spec.rb +7 -2
- data/spec/unit/resource/powershell_spec.rb +85 -2
- data/spec/unit/resource/subversion_spec.rb +5 -0
- data/spec/unit/resource/windows_package_spec.rb +74 -0
- data/spec/unit/resource_spec.rb +23 -1
- data/spec/unit/rest_spec.rb +15 -0
- data/spec/unit/run_context/cookbook_compiler_spec.rb +12 -0
- data/spec/unit/run_context_spec.rb +7 -0
- data/spec/unit/util/editor_spec.rb +152 -0
- data/spec/unit/util/file_edit_spec.rb +37 -1
- metadata +41 -30
@@ -124,12 +124,21 @@ describe Chef::Knife::Bootstrap do
|
|
124
124
|
end
|
125
125
|
|
126
126
|
describe "specifying no_proxy with various entries" do
|
127
|
-
subject(:knife)
|
128
|
-
|
127
|
+
subject(:knife) do
|
128
|
+
k = described_class.new
|
129
|
+
k.instance_variable_set("@template_file", template_file)
|
130
|
+
k.parse_options(options)
|
131
|
+
k.merge_configs
|
132
|
+
k
|
133
|
+
end
|
134
|
+
|
135
|
+
# Include a data bag secret in the options to prevent Bootstrap from
|
136
|
+
# attempting to access /etc/chef/encrypted_data_bag_secret, which
|
137
|
+
# can fail when the file exists but can't be accessed by the user
|
138
|
+
# running the tests.
|
139
|
+
let(:options){ ["--bootstrap-no-proxy", setting, "-s", "foo"] }
|
129
140
|
let(:template_file) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "no_proxy.erb")) }
|
130
141
|
let(:rendered_template) do
|
131
|
-
knife.instance_variable_set("@template_file", template_file)
|
132
|
-
knife.parse_options(options)
|
133
142
|
template_string = knife.read_template
|
134
143
|
knife.render_template(template_string)
|
135
144
|
end
|
@@ -19,60 +19,145 @@
|
|
19
19
|
require 'spec_helper'
|
20
20
|
|
21
21
|
describe Chef::Knife::ClientBulkDelete do
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
22
|
+
let(:stdout_io) { StringIO.new }
|
23
|
+
let(:stdout) {stdout_io.string}
|
24
|
+
|
25
|
+
let(:knife) {
|
26
|
+
k = Chef::Knife::ClientBulkDelete.new
|
27
|
+
k.name_args = name_args
|
28
|
+
k.config = option_args
|
29
|
+
k.ui.stub(:stdout).and_return(stdout_io)
|
30
|
+
k.ui.stub(:confirm).and_return(knife_confirm)
|
31
|
+
k.ui.stub(:confirm_without_exit).and_return(knife_confirm)
|
32
|
+
k
|
33
|
+
}
|
34
|
+
|
35
|
+
let(:name_args) { [ "." ] }
|
36
|
+
let(:option_args) { {} }
|
37
|
+
|
38
|
+
let(:knife_confirm) { true }
|
39
|
+
|
40
|
+
let(:nonvalidator_client_names) { %w{tim dan stephen} }
|
41
|
+
let(:nonvalidator_clients) {
|
42
|
+
clients = Hash.new
|
43
|
+
|
44
|
+
nonvalidator_client_names.each do |client_name|
|
33
45
|
client = Chef::ApiClient.new()
|
34
46
|
client.name(client_name)
|
35
47
|
client.stub(:destroy).and_return(true)
|
36
|
-
|
48
|
+
clients[client_name] = client
|
49
|
+
end
|
50
|
+
|
51
|
+
clients
|
52
|
+
}
|
53
|
+
|
54
|
+
let(:validator_client_names) { %w{myorg-validator} }
|
55
|
+
let(:validator_clients) {
|
56
|
+
clients = Hash.new
|
57
|
+
|
58
|
+
validator_client_names.each do |validator_client_name|
|
59
|
+
validator_client = Chef::ApiClient.new()
|
60
|
+
validator_client.name(validator_client_name)
|
61
|
+
validator_client.stub(:validator).and_return(true)
|
62
|
+
validator_client.stub(:destroy).and_return(true)
|
63
|
+
clients[validator_client_name] = validator_client
|
37
64
|
end
|
38
|
-
|
65
|
+
|
66
|
+
clients
|
67
|
+
}
|
68
|
+
|
69
|
+
let(:client_names) { nonvalidator_client_names + validator_client_names}
|
70
|
+
let(:clients) {
|
71
|
+
nonvalidator_clients.merge(validator_clients)
|
72
|
+
}
|
73
|
+
|
74
|
+
before(:each) do
|
75
|
+
Chef::ApiClient.stub(:list).and_return(clients)
|
39
76
|
end
|
40
77
|
|
41
78
|
describe "run" do
|
79
|
+
describe "without a regex" do
|
80
|
+
let(:name_args) { [ ] }
|
42
81
|
|
43
|
-
|
44
|
-
|
45
|
-
|
82
|
+
it "should exit if the regex is not provided" do
|
83
|
+
lambda { knife.run }.should raise_error(SystemExit)
|
84
|
+
end
|
46
85
|
end
|
47
86
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
87
|
+
describe "with any clients" do
|
88
|
+
it "should get the list of the clients" do
|
89
|
+
Chef::ApiClient.should_receive(:list)
|
90
|
+
knife.run
|
91
|
+
end
|
52
92
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
93
|
+
it "should print the name of the clients" do
|
94
|
+
knife.run
|
95
|
+
client_names.each do |client_name|
|
96
|
+
stdout.should include(client_name)
|
97
|
+
end
|
98
|
+
end
|
57
99
|
|
58
|
-
|
59
|
-
|
60
|
-
|
100
|
+
it "should confirm you really want to delete them" do
|
101
|
+
knife.ui.should_receive(:confirm)
|
102
|
+
knife.run
|
61
103
|
end
|
62
|
-
@knife.run
|
63
|
-
end
|
64
104
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
105
|
+
describe "without --delete-validators" do
|
106
|
+
it "should mention that validator clients wont be deleted" do
|
107
|
+
knife.run
|
108
|
+
stdout.should include("Following clients are validators and will not be deleted.")
|
109
|
+
info = stdout.index "Following clients are validators and will not be deleted."
|
110
|
+
val = stdout.index "myorg-validator"
|
111
|
+
(val > info).should be_true
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should only delete nonvalidator clients" do
|
115
|
+
nonvalidator_clients.each_value do |c|
|
116
|
+
c.should_receive(:destroy)
|
117
|
+
end
|
118
|
+
|
119
|
+
validator_clients.each_value do |c|
|
120
|
+
c.should_not_receive(:destroy)
|
121
|
+
end
|
122
|
+
|
123
|
+
knife.run
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe "with --delete-validators" do
|
128
|
+
let(:option_args) { {:delete_validators => true} }
|
129
|
+
|
130
|
+
it "should mention that validator clients will be deleted" do
|
131
|
+
knife.run
|
132
|
+
stdout.should include("The following validators will be deleted")
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should confirm twice" do
|
136
|
+
knife.ui.should_receive(:confirm).once
|
137
|
+
knife.ui.should_receive(:confirm_without_exit).once
|
138
|
+
knife.run
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should delete all clients" do
|
142
|
+
clients.each_value do |c|
|
143
|
+
c.should_receive(:destroy)
|
144
|
+
end
|
145
|
+
|
146
|
+
knife.run
|
147
|
+
end
|
148
|
+
end
|
71
149
|
end
|
72
150
|
|
73
|
-
|
74
|
-
|
75
|
-
|
151
|
+
describe "with some clients" do
|
152
|
+
let(:name_args) { [ "^ti" ] }
|
153
|
+
|
154
|
+
it "should only delete clients that match the regex" do
|
155
|
+
clients["tim"].should_receive(:destroy)
|
156
|
+
clients["stephen"].should_not_receive(:destroy)
|
157
|
+
clients["dan"].should_not_receive(:destroy)
|
158
|
+
clients["myorg-validator"].should_not_receive(:destroy)
|
159
|
+
knife.run
|
160
|
+
end
|
76
161
|
end
|
77
162
|
end
|
78
163
|
end
|
@@ -23,7 +23,7 @@ describe Chef::Knife::ClientDelete do
|
|
23
23
|
@knife = Chef::Knife::ClientDelete.new
|
24
24
|
# defaults
|
25
25
|
@knife.config = {
|
26
|
-
:
|
26
|
+
:delete_validators => false
|
27
27
|
}
|
28
28
|
@knife.name_args = [ 'adam' ]
|
29
29
|
end
|
@@ -51,7 +51,7 @@ describe Chef::Knife::ClientDelete do
|
|
51
51
|
end
|
52
52
|
|
53
53
|
it 'should delete non-validator client if --force is not set' do
|
54
|
-
@knife.config[:
|
54
|
+
@knife.config[:delete_validators] = false
|
55
55
|
@client.should_receive(:destroy).and_return(@client)
|
56
56
|
@knife.should_receive(:msg)
|
57
57
|
|
@@ -59,7 +59,7 @@ describe Chef::Knife::ClientDelete do
|
|
59
59
|
end
|
60
60
|
|
61
61
|
it 'should delete non-validator client if --force is set' do
|
62
|
-
@knife.config[:
|
62
|
+
@knife.config[:delete_validators] = true
|
63
63
|
@client.should_receive(:destroy).and_return(@client)
|
64
64
|
@knife.should_receive(:msg)
|
65
65
|
|
@@ -73,7 +73,7 @@ describe Chef::Knife::ClientDelete do
|
|
73
73
|
end
|
74
74
|
|
75
75
|
it 'should delete validator client if --force is set' do
|
76
|
-
@knife.config[:
|
76
|
+
@knife.config[:delete_validators] = true
|
77
77
|
@client.should_receive(:destroy).and_return(@client)
|
78
78
|
@knife.should_receive(:msg)
|
79
79
|
|
@@ -23,178 +23,271 @@ require 'chef/cookbook_uploader'
|
|
23
23
|
require 'timeout'
|
24
24
|
|
25
25
|
describe Chef::Knife::CookbookUpload do
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
let(:cookbook) { Chef::CookbookVersion.new('test_cookbook') }
|
27
|
+
|
28
|
+
let(:cookbooks_by_name) do
|
29
|
+
{cookbook.name => cookbook}
|
30
|
+
end
|
29
31
|
|
30
|
-
|
32
|
+
let(:cookbook_loader) do
|
33
|
+
cookbook_loader = cookbooks_by_name.dup
|
34
|
+
cookbook_loader.stub(:merged_cookbooks).and_return([])
|
35
|
+
cookbook_loader.stub(:load_cookbooks).and_return(cookbook_loader)
|
36
|
+
cookbook_loader
|
37
|
+
end
|
38
|
+
|
39
|
+
let(:cookbook_uploader) { double(:upload_cookbooks => nil) }
|
31
40
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
@cookbook_loader.stub(:load_cookbooks).and_return(@cookbook_loader)
|
36
|
-
Chef::CookbookLoader.stub(:new).and_return(@cookbook_loader)
|
41
|
+
let(:output) { StringIO.new }
|
42
|
+
|
43
|
+
let(:name_args) { ['test_cookbook'] }
|
37
44
|
|
38
|
-
|
39
|
-
|
40
|
-
|
45
|
+
let(:knife) do
|
46
|
+
k = Chef::Knife::CookbookUpload.new
|
47
|
+
k.name_args = name_args
|
48
|
+
k.ui.stub(:stdout).and_return(output)
|
49
|
+
k.ui.stub(:stderr).and_return(output)
|
50
|
+
k
|
51
|
+
end
|
52
|
+
|
53
|
+
before(:each) do
|
54
|
+
Chef::CookbookLoader.stub(:new).and_return(cookbook_loader)
|
41
55
|
end
|
42
56
|
|
43
57
|
describe 'with --concurrency' do
|
44
58
|
it 'should upload cookbooks with predefined concurrency' do
|
45
|
-
@cookbook_uploader = double(:upload_cookbooks => nil)
|
46
59
|
Chef::CookbookVersion.stub(:list_all_versions).and_return({})
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
60
|
+
knife.config[:concurrency] = 3
|
61
|
+
test_cookbook = Chef::CookbookVersion.new('test_cookbook')
|
62
|
+
cookbook_loader.stub(:each).and_yield("test_cookbook", test_cookbook)
|
63
|
+
cookbook_loader.stub(:cookbook_names).and_return(["test_cookbook"])
|
51
64
|
Chef::CookbookUploader.should_receive(:new).with( kind_of(Array), kind_of(Array),
|
52
65
|
{:force=>nil, :concurrency => 3}).and_return(double("Chef::CookbookUploader", :upload_cookbooks=> true))
|
53
|
-
|
66
|
+
knife.run
|
54
67
|
end
|
55
68
|
end
|
56
69
|
|
57
70
|
describe 'run' do
|
58
71
|
before(:each) do
|
59
|
-
|
60
|
-
Chef::CookbookUploader.stub(:new => @cookbook_uploader)
|
72
|
+
Chef::CookbookUploader.stub(:new => cookbook_uploader)
|
61
73
|
Chef::CookbookVersion.stub(:list_all_versions).and_return({})
|
62
74
|
end
|
63
75
|
|
64
76
|
it 'should print usage and exit when a cookbook name is not provided' do
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
lambda {
|
77
|
+
knife.name_args = []
|
78
|
+
knife.should_receive(:show_usage)
|
79
|
+
knife.ui.should_receive(:fatal)
|
80
|
+
lambda { knife.run }.should raise_error(SystemExit)
|
69
81
|
end
|
70
82
|
|
71
83
|
describe 'when specifying a cookbook name' do
|
72
84
|
it 'should upload the cookbook' do
|
73
|
-
|
74
|
-
|
85
|
+
knife.should_receive(:upload).once
|
86
|
+
knife.run
|
75
87
|
end
|
76
88
|
|
77
89
|
it 'should report on success' do
|
78
|
-
|
79
|
-
|
80
|
-
|
90
|
+
knife.should_receive(:upload).once
|
91
|
+
knife.ui.should_receive(:info).with(/Uploaded 1 cookbook/)
|
92
|
+
knife.run
|
81
93
|
end
|
82
94
|
end
|
83
95
|
|
84
96
|
describe 'when specifying the same cookbook name twice' do
|
85
97
|
it 'should upload the cookbook only once' do
|
86
|
-
|
87
|
-
|
88
|
-
|
98
|
+
knife.name_args = ['test_cookbook', 'test_cookbook']
|
99
|
+
knife.should_receive(:upload).once
|
100
|
+
knife.run
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context "when uploading a cookbook that uses deprecated overlays" do
|
105
|
+
|
106
|
+
before do
|
107
|
+
cookbook_loader.stub(:merged_cookbooks).and_return(['test_cookbook'])
|
108
|
+
cookbook_loader.stub(:merged_cookbook_paths).
|
109
|
+
and_return({'test_cookbook' => %w{/path/one/test_cookbook /path/two/test_cookbook}})
|
110
|
+
end
|
111
|
+
|
112
|
+
it "emits a warning" do
|
113
|
+
knife.run
|
114
|
+
expected_message=<<-E
|
115
|
+
WARNING: The cookbooks: test_cookbook exist in multiple places in your cookbook_path.
|
116
|
+
A composite version of these cookbooks has been compiled for uploading.
|
117
|
+
|
118
|
+
IMPORTANT: In a future version of Chef, this behavior will be removed and you will no longer
|
119
|
+
be able to have the same version of a cookbook in multiple places in your cookbook_path.
|
120
|
+
WARNING: The affected cookbooks are located:
|
121
|
+
test_cookbook:
|
122
|
+
/path/one/test_cookbook
|
123
|
+
/path/two/test_cookbook
|
124
|
+
E
|
125
|
+
output.string.should include(expected_message)
|
89
126
|
end
|
90
127
|
end
|
91
128
|
|
92
129
|
describe 'when specifying a cookbook name among many' do
|
93
|
-
|
94
|
-
|
95
|
-
|
130
|
+
let(:name_args) { ['test_cookbook1'] }
|
131
|
+
|
132
|
+
let(:cookbooks_by_name) do
|
133
|
+
{
|
96
134
|
'test_cookbook1' => Chef::CookbookVersion.new('test_cookbook1'),
|
97
135
|
'test_cookbook2' => Chef::CookbookVersion.new('test_cookbook2'),
|
98
136
|
'test_cookbook3' => Chef::CookbookVersion.new('test_cookbook3')
|
99
137
|
}
|
100
|
-
@cookbook_loader = {}
|
101
|
-
@cookbook_loader.stub(:merged_cookbooks).and_return([])
|
102
|
-
@cookbook_loader.stub(:[]) { |ckbk| @cookbooks[ckbk] }
|
103
|
-
Chef::CookbookLoader.stub(:new).and_return(@cookbook_loader)
|
104
138
|
end
|
105
139
|
|
106
140
|
it "should read only one cookbook" do
|
107
|
-
|
108
|
-
|
141
|
+
cookbook_loader.should_receive(:[]).once.with('test_cookbook1').and_call_original
|
142
|
+
knife.run
|
109
143
|
end
|
110
144
|
|
111
145
|
it "should not read all cookbooks" do
|
112
|
-
|
113
|
-
|
146
|
+
cookbook_loader.should_not_receive(:load_cookbooks)
|
147
|
+
knife.run
|
114
148
|
end
|
115
149
|
|
116
150
|
it "should upload only one cookbook" do
|
117
|
-
|
118
|
-
|
151
|
+
knife.should_receive(:upload).exactly(1).times
|
152
|
+
knife.run
|
119
153
|
end
|
120
154
|
end
|
121
155
|
|
122
156
|
# This is testing too much. We should break it up.
|
123
157
|
describe 'when specifying a cookbook name with dependencies' do
|
158
|
+
let(:name_args) { ["test_cookbook2"] }
|
159
|
+
|
160
|
+
let(:cookbooks_by_name) do
|
161
|
+
{ "test_cookbook1" => test_cookbook1,
|
162
|
+
"test_cookbook2" => test_cookbook2,
|
163
|
+
"test_cookbook3" => test_cookbook3 }
|
164
|
+
end
|
165
|
+
|
166
|
+
let(:test_cookbook1) { Chef::CookbookVersion.new('test_cookbook1') }
|
167
|
+
|
168
|
+
let(:test_cookbook2) do
|
169
|
+
c = Chef::CookbookVersion.new('test_cookbook2')
|
170
|
+
c.metadata.depends("test_cookbook3")
|
171
|
+
c
|
172
|
+
end
|
173
|
+
|
174
|
+
let(:test_cookbook3) do
|
175
|
+
c = Chef::CookbookVersion.new('test_cookbook3')
|
176
|
+
c.metadata.depends("test_cookbook1")
|
177
|
+
c.metadata.depends("test_cookbook2")
|
178
|
+
c
|
179
|
+
end
|
180
|
+
|
124
181
|
it "should upload all dependencies once" do
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
@test_cookbook3.metadata.depends("test_cookbook2")
|
133
|
-
@cookbook_loader.stub(:[]) do |ckbk|
|
134
|
-
{ "test_cookbook1" => @test_cookbook1,
|
135
|
-
"test_cookbook2" => @test_cookbook2,
|
136
|
-
"test_cookbook3" => @test_cookbook3 }[ckbk]
|
137
|
-
end
|
138
|
-
@knife.stub(:cookbook_names).and_return(["test_cookbook1", "test_cookbook2", "test_cookbook3"])
|
139
|
-
@knife.should_receive(:upload).exactly(3).times
|
140
|
-
Timeout::timeout(5) do
|
141
|
-
@knife.run
|
182
|
+
knife.config[:depends] = true
|
183
|
+
knife.stub(:cookbook_names).and_return(["test_cookbook1", "test_cookbook2", "test_cookbook3"])
|
184
|
+
knife.should_receive(:upload).exactly(3).times
|
185
|
+
lambda do
|
186
|
+
Timeout::timeout(5) do
|
187
|
+
knife.run
|
188
|
+
end
|
142
189
|
end.should_not raise_error
|
143
190
|
end
|
144
191
|
end
|
145
192
|
|
193
|
+
describe 'when specifying a cookbook name with missing dependencies' do
|
194
|
+
let(:cookbook_dependency) { Chef::CookbookVersion.new('dependency') }
|
195
|
+
|
196
|
+
before(:each) do
|
197
|
+
cookbook.metadata.depends("dependency")
|
198
|
+
cookbook_loader.stub(:[]) do |ckbk|
|
199
|
+
{ "test_cookbook" => cookbook,
|
200
|
+
"dependency" => cookbook_dependency}[ckbk]
|
201
|
+
end
|
202
|
+
knife.stub(:cookbook_names).and_return(["cookbook_dependency", "test_cookbook"])
|
203
|
+
@stdout, @stderr, @stdin = StringIO.new, StringIO.new, StringIO.new
|
204
|
+
knife.ui = Chef::Knife::UI.new(@stdout, @stderr, @stdin, {})
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'should exit and not upload the cookbook' do
|
208
|
+
cookbook_loader.should_receive(:[]).once.with('test_cookbook')
|
209
|
+
cookbook_loader.should_not_receive(:load_cookbooks)
|
210
|
+
cookbook_uploader.should_not_receive(:upload_cookbooks)
|
211
|
+
expect {knife.run}.to raise_error(SystemExit)
|
212
|
+
end
|
213
|
+
|
214
|
+
it 'should output a message for a single missing dependency' do
|
215
|
+
expect {knife.run}.to raise_error(SystemExit)
|
216
|
+
@stderr.string.should include('Cookbook test_cookbook depends on cookbooks which are not currently')
|
217
|
+
@stderr.string.should include('being uploaded and cannot be found on the server.')
|
218
|
+
@stderr.string.should include("The missing cookbook(s) are: 'dependency' version '>= 0.0.0'")
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'should output a message for a multiple missing dependencies which are concatenated' do
|
222
|
+
cookbook_dependency2 = Chef::CookbookVersion.new('dependency2')
|
223
|
+
cookbook.metadata.depends("dependency2")
|
224
|
+
cookbook_loader.stub(:[]) do |ckbk|
|
225
|
+
{ "test_cookbook" => cookbook,
|
226
|
+
"dependency" => cookbook_dependency,
|
227
|
+
"dependency2" => cookbook_dependency2}[ckbk]
|
228
|
+
end
|
229
|
+
knife.stub(:cookbook_names).and_return(["dependency", "dependency2", "test_cookbook"])
|
230
|
+
expect {knife.run}.to raise_error(SystemExit)
|
231
|
+
@stderr.string.should include('Cookbook test_cookbook depends on cookbooks which are not currently')
|
232
|
+
@stderr.string.should include('being uploaded and cannot be found on the server.')
|
233
|
+
@stderr.string.should include("The missing cookbook(s) are:")
|
234
|
+
@stderr.string.should include("'dependency' version '>= 0.0.0'")
|
235
|
+
@stderr.string.should include("'dependency2' version '>= 0.0.0'")
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
146
239
|
it "should freeze the version of the cookbooks if --freeze is specified" do
|
147
|
-
|
148
|
-
|
149
|
-
|
240
|
+
knife.config[:freeze] = true
|
241
|
+
cookbook.should_receive(:freeze_version).once
|
242
|
+
knife.run
|
150
243
|
end
|
151
244
|
|
152
245
|
describe 'with -a or --all' do
|
153
246
|
before(:each) do
|
154
|
-
|
247
|
+
knife.config[:all] = true
|
155
248
|
@test_cookbook1 = Chef::CookbookVersion.new('test_cookbook1')
|
156
249
|
@test_cookbook2 = Chef::CookbookVersion.new('test_cookbook2')
|
157
|
-
|
158
|
-
|
250
|
+
cookbook_loader.stub(:each).and_yield("test_cookbook1", @test_cookbook1).and_yield("test_cookbook2", @test_cookbook2)
|
251
|
+
cookbook_loader.stub(:cookbook_names).and_return(["test_cookbook1", "test_cookbook2"])
|
159
252
|
end
|
160
253
|
|
161
254
|
it 'should upload all cookbooks' do
|
162
|
-
|
163
|
-
|
255
|
+
knife.should_receive(:upload).once
|
256
|
+
knife.run
|
164
257
|
end
|
165
258
|
|
166
259
|
it 'should report on success' do
|
167
|
-
|
168
|
-
|
169
|
-
|
260
|
+
knife.should_receive(:upload).once
|
261
|
+
knife.ui.should_receive(:info).with(/Uploaded all cookbooks/)
|
262
|
+
knife.run
|
170
263
|
end
|
171
264
|
|
172
265
|
it 'should update the version constraints for an environment' do
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
266
|
+
knife.stub(:assert_environment_valid!).and_return(true)
|
267
|
+
knife.config[:environment] = "production"
|
268
|
+
knife.should_receive(:update_version_constraints).once
|
269
|
+
knife.run
|
177
270
|
end
|
178
271
|
end
|
179
272
|
|
180
273
|
describe 'when a frozen cookbook exists on the server' do
|
181
274
|
it 'should fail to replace it' do
|
182
275
|
exception = Chef::Exceptions::CookbookFrozen.new
|
183
|
-
|
276
|
+
cookbook_uploader.should_receive(:upload_cookbooks).
|
184
277
|
and_raise(exception)
|
185
|
-
|
186
|
-
|
187
|
-
lambda {
|
278
|
+
knife.ui.stub(:error)
|
279
|
+
knife.ui.should_receive(:error).with(exception)
|
280
|
+
lambda { knife.run }.should raise_error(SystemExit)
|
188
281
|
end
|
189
282
|
|
190
283
|
it 'should not update the version constraints for an environment' do
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
lambda {
|
284
|
+
knife.stub(:assert_environment_valid!).and_return(true)
|
285
|
+
knife.config[:environment] = "production"
|
286
|
+
knife.stub(:upload).and_raise(Chef::Exceptions::CookbookFrozen)
|
287
|
+
knife.ui.should_receive(:error).with(/Failed to upload 1 cookbook/)
|
288
|
+
knife.ui.should_receive(:warn).with(/Not updating version constraints/)
|
289
|
+
knife.should_not_receive(:update_version_constraints)
|
290
|
+
lambda { knife.run }.should raise_error(SystemExit)
|
198
291
|
end
|
199
292
|
end
|
200
293
|
end # run
|