berkshelf 1.4.6 → 2.0.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/CHANGELOG.md +1 -5
- data/CONTRIBUTING.md +3 -1
- data/Gemfile +11 -1
- data/README.md +16 -0
- data/Thorfile +3 -1
- data/berkshelf.gemspec +26 -38
- data/features/apply_command.feature +32 -0
- data/features/configure_command.feature +31 -0
- data/features/contingent_command.feature +5 -5
- data/features/default_locations.feature +2 -2
- data/features/groups_install.feature +19 -20
- data/features/info_command.feature +13 -13
- data/features/install_command.feature +86 -83
- data/features/json_formatter.feature +60 -23
- data/features/list_command.feature +5 -11
- data/features/lockfile.feature +286 -6
- data/features/open_command.feature +8 -4
- data/features/outdated_command.feature +8 -15
- data/features/package_command.feature +39 -0
- data/features/show_command.feature +8 -9
- data/features/step_definitions/chef_server_steps.rb +20 -2
- data/features/step_definitions/cli_steps.rb +10 -2
- data/features/step_definitions/configure_cli_steps.rb +7 -0
- data/features/step_definitions/filesystem_steps.rb +19 -14
- data/features/step_definitions/json_steps.rb +22 -5
- data/features/step_definitions/utility_steps.rb +13 -1
- data/features/support/env.rb +10 -23
- data/features/update_command.feature +105 -24
- data/features/upload_command.feature +0 -14
- data/features/vendor_install.feature +3 -3
- data/generator_files/Vagrantfile.erb +11 -11
- data/lib/berkshelf.rb +6 -5
- data/lib/berkshelf/berksfile.rb +267 -99
- data/lib/berkshelf/cli.rb +70 -34
- data/lib/berkshelf/cli_commands/test_command.rb +11 -0
- data/lib/berkshelf/community_rest.rb +1 -1
- data/lib/berkshelf/config.rb +19 -2
- data/lib/berkshelf/cookbook_source.rb +41 -12
- data/lib/berkshelf/cookbook_store.rb +8 -4
- data/lib/berkshelf/errors.rb +61 -29
- data/lib/berkshelf/formatters.rb +13 -19
- data/lib/berkshelf/formatters/human_readable.rb +8 -0
- data/lib/berkshelf/formatters/json.rb +12 -1
- data/lib/berkshelf/formatters/null.rb +23 -0
- data/lib/berkshelf/init_generator.rb +22 -11
- data/lib/berkshelf/location.rb +8 -10
- data/lib/berkshelf/locations/chef_api_location.rb +4 -5
- data/lib/berkshelf/locations/git_location.rb +14 -12
- data/lib/berkshelf/locations/path_location.rb +16 -1
- data/lib/berkshelf/locations/site_location.rb +1 -3
- data/lib/berkshelf/lockfile.rb +230 -33
- data/lib/berkshelf/resolver.rb +2 -1
- data/lib/berkshelf/ui.rb +4 -8
- data/lib/berkshelf/version.rb +1 -1
- data/lib/thor/monkies/shell.rb +2 -5
- data/spec/fixtures/cassettes/Berkshelf_Resolver/{ClassMethods/_initialize → _initialize}/adds_the_dependencies_of_the_source_as_sources.yml +0 -0
- data/spec/fixtures/cookbooks/example_cookbook/.gitignore +2 -0
- data/spec/fixtures/cookbooks/example_cookbook/.kitchen.yml +26 -0
- data/spec/fixtures/cookbooks/example_cookbook/Berksfile.lock +5 -0
- data/spec/fixtures/lockfiles/default.lock +11 -0
- data/spec/{config/knife.rb → knife.rb.sample} +2 -2
- data/spec/spec_helper.rb +15 -3
- data/spec/support/chef_api.rb +19 -5
- data/spec/support/chef_server.rb +4 -3
- data/spec/support/knife.rb +18 -0
- data/spec/unit/berkshelf/berksfile_spec.rb +332 -235
- data/spec/unit/berkshelf/cached_cookbook_spec.rb +40 -42
- data/spec/unit/berkshelf/chef/cookbook/chefignore_spec.rb +11 -15
- data/spec/unit/berkshelf/community_rest_spec.rb +16 -14
- data/spec/unit/berkshelf/config_spec.rb +36 -20
- data/spec/unit/berkshelf/cookbook_generator_spec.rb +6 -10
- data/spec/unit/berkshelf/cookbook_source_spec.rb +244 -183
- data/spec/unit/berkshelf/cookbook_store_spec.rb +72 -76
- data/spec/unit/berkshelf/core_ext/file_utils_spec.rb +2 -2
- data/spec/unit/berkshelf/downloader_spec.rb +137 -157
- data/spec/unit/berkshelf/errors_spec.rb +1 -1
- data/spec/unit/berkshelf/formatters/null_spec.rb +17 -0
- data/spec/unit/berkshelf/formatters_spec.rb +83 -90
- data/spec/unit/berkshelf/git_spec.rb +219 -207
- data/spec/unit/berkshelf/init_generator_spec.rb +73 -73
- data/spec/unit/berkshelf/location_spec.rb +143 -162
- data/spec/unit/berkshelf/locations/chef_api_location_spec.rb +94 -89
- data/spec/unit/berkshelf/locations/git_location_spec.rb +75 -59
- data/spec/unit/berkshelf/locations/path_location_spec.rb +46 -30
- data/spec/unit/berkshelf/locations/site_location_spec.rb +4 -4
- data/spec/unit/berkshelf/lockfile_spec.rb +185 -1
- data/spec/unit/berkshelf/logger_spec.rb +6 -24
- data/spec/unit/berkshelf/mixin/logging_spec.rb +6 -8
- data/spec/unit/berkshelf/resolver_spec.rb +36 -38
- data/spec/unit/berkshelf/ui_spec.rb +9 -10
- data/spec/unit/berkshelf_spec.rb +41 -40
- data/spec/unit/chef/config_spec.rb +9 -11
- metadata +55 -203
- data/spec/config/berkshelf.pem +0 -27
- data/spec/config/validator.pem +0 -27
data/lib/berkshelf/resolver.rb
CHANGED
@@ -5,6 +5,7 @@ module Berkshelf
|
|
5
5
|
|
6
6
|
# @return [Berkshelf::Berksfile]
|
7
7
|
attr_reader :berksfile
|
8
|
+
|
8
9
|
# @return [Solve::Graph]
|
9
10
|
attr_reader :graph
|
10
11
|
|
@@ -14,7 +15,7 @@ module Berkshelf
|
|
14
15
|
# @option options [Array<CookbookSource>, CookbookSource] sources
|
15
16
|
def initialize(berksfile, options = {})
|
16
17
|
@berksfile = berksfile
|
17
|
-
@downloader =
|
18
|
+
@downloader = berksfile.downloader
|
18
19
|
@graph = Solve::Graph.new
|
19
20
|
@sources = Hash.new
|
20
21
|
|
data/lib/berkshelf/ui.rb
CHANGED
@@ -10,16 +10,12 @@ module Berkshelf
|
|
10
10
|
@mute = false
|
11
11
|
end
|
12
12
|
|
13
|
-
def say(message =
|
13
|
+
def say(message = "", color = nil, force_new_line = nil)
|
14
14
|
return if quiet?
|
15
15
|
|
16
|
-
super(message, color
|
17
|
-
end
|
18
|
-
|
19
|
-
# @see {say}
|
20
|
-
def info(message = '', color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/))
|
21
|
-
say(message, color, force_new_line)
|
16
|
+
super(message, color)
|
22
17
|
end
|
18
|
+
alias_method :info, :say
|
23
19
|
|
24
20
|
def say_status(status, message, log_status = true)
|
25
21
|
return if quiet?
|
@@ -29,7 +25,7 @@ module Berkshelf
|
|
29
25
|
|
30
26
|
def warn(message, color = :yellow)
|
31
27
|
return if quiet?
|
32
|
-
|
28
|
+
|
33
29
|
say(message, color)
|
34
30
|
end
|
35
31
|
|
data/lib/berkshelf/version.rb
CHANGED
data/lib/thor/monkies/shell.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
require 'berkshelf/ui'
|
2
2
|
|
3
3
|
# @author Seth Vargo <sethvargo@gmail.com>
|
4
|
-
|
5
|
-
|
6
|
-
# Vagrant and Berkshelf UI
|
7
|
-
include ::Berkshelf::UI
|
8
|
-
end
|
4
|
+
# Include the Berkshelf UI methods - this is used by both Vagrant and Berkshelf
|
5
|
+
Thor::Base.shell.send(:include, Berkshelf::UI)
|
File without changes
|
@@ -0,0 +1,26 @@
|
|
1
|
+
---
|
2
|
+
driver_plugin: vagrant
|
3
|
+
|
4
|
+
platforms:
|
5
|
+
- name: ubuntu-12.04
|
6
|
+
driver_config:
|
7
|
+
box: canonical-ubuntu-12.04
|
8
|
+
box_url: http://cloud-images.ubuntu.com/vagrant/precise/current/precise-server-cloudimg-amd64-vagrant-disk1.box
|
9
|
+
require_chef_omnibus: true
|
10
|
+
- name: ubuntu-10.04
|
11
|
+
driver_config:
|
12
|
+
box: opscode-ubuntu-10.04
|
13
|
+
box_url: http://opscode-vm.s3.amazonaws.com/vagrant/opscode_ubuntu-10.04_chef-11.2.0.box
|
14
|
+
- name: centos-6.3
|
15
|
+
driver_config:
|
16
|
+
box: opscode-centos-6.3
|
17
|
+
box_url: http://opscode-vm.s3.amazonaws.com/vagrant/opscode_centos-6.3_chef-11.2.0.box
|
18
|
+
- name: centos-5.8
|
19
|
+
driver_config:
|
20
|
+
box: opscode-centos-5.8
|
21
|
+
box_url: http://opscode-vm.s3.amazonaws.com/vagrant/opscode_centos-5.8_chef-11.2.0.box
|
22
|
+
|
23
|
+
suites:
|
24
|
+
- name: default
|
25
|
+
run_list: []
|
26
|
+
attributes: {}
|
@@ -4,8 +4,8 @@ log_level :info
|
|
4
4
|
log_location STDOUT
|
5
5
|
node_name "berkshelf"
|
6
6
|
client_key "#{current_dir}/berkshelf.pem"
|
7
|
-
validation_client_name "validator"
|
8
|
-
validation_key "#{current_dir}/validator.pem"
|
7
|
+
validation_client_name "chef-validator"
|
8
|
+
validation_key "#{current_dir}/chef-validator.pem"
|
9
9
|
chef_server_url "http://localhost:4000"
|
10
10
|
cache_type 'BasicFile'
|
11
11
|
cache_options( :path => "#{ENV['HOME']}/.chef/checksums" )
|
data/spec/spec_helper.rb
CHANGED
@@ -15,7 +15,7 @@ Spork.prefork do
|
|
15
15
|
|
16
16
|
APP_ROOT = File.expand_path('../../', __FILE__)
|
17
17
|
ENV["BERKSHELF_PATH"] = File.join(APP_ROOT, "spec", "tmp", "berkshelf")
|
18
|
-
ENV["BERKSHELF_CHEF_CONFIG"] = File.join(APP_ROOT, "spec", "
|
18
|
+
ENV["BERKSHELF_CHEF_CONFIG"] = File.join(APP_ROOT, "spec", "knife.rb")
|
19
19
|
|
20
20
|
Dir[File.join(APP_ROOT, "spec/support/**/*.rb")].each {|f| require f}
|
21
21
|
|
@@ -24,30 +24,40 @@ Spork.prefork do
|
|
24
24
|
config.cassette_library_dir = 'spec/fixtures/cassettes'
|
25
25
|
config.hook_into :webmock
|
26
26
|
config.default_cassette_options = { record: :new_episodes }
|
27
|
+
config.ignore_localhost = true
|
27
28
|
end
|
28
29
|
|
29
30
|
RSpec.configure do |config|
|
30
31
|
config.include Berkshelf::RSpec::FileSystemMatchers
|
31
32
|
config.include JsonSpec::Helpers
|
32
33
|
config.include Berkshelf::RSpec::ChefAPI
|
34
|
+
config.include Berkshelf::RSpec::ChefServer
|
35
|
+
|
36
|
+
# Disallow should syntax
|
37
|
+
config.expect_with :rspec do |c|
|
38
|
+
c.syntax = :expect
|
39
|
+
end
|
33
40
|
|
34
41
|
config.mock_with :rspec
|
35
42
|
config.treat_symbols_as_metadata_keys_with_true_values = true
|
36
43
|
config.filter_run focus: true
|
37
44
|
config.run_all_when_everything_filtered = true
|
38
45
|
|
39
|
-
config.before(:
|
46
|
+
config.before(:all) do
|
40
47
|
Berkshelf::RSpec::ChefServer.start
|
41
48
|
WebMock.disable_net_connect!(allow_localhost: true, net_http_connect_on_start: true)
|
42
49
|
end
|
43
50
|
|
44
|
-
config.after(:
|
51
|
+
config.after(:all) do
|
45
52
|
Berkshelf::RSpec::ChefServer.stop
|
46
53
|
end
|
47
54
|
|
48
55
|
config.before(:each) do
|
56
|
+
Celluloid.shutdown
|
57
|
+
Celluloid.boot
|
49
58
|
clean_tmp_path
|
50
59
|
Berkshelf.cookbook_store = Berkshelf::CookbookStore.new(tmp_path.join("downloader_tmp"))
|
60
|
+
Berkshelf.set_format(:null)
|
51
61
|
Berkshelf.ui.mute!
|
52
62
|
end
|
53
63
|
|
@@ -164,6 +174,8 @@ Spork.prefork do
|
|
164
174
|
def run(cmd)
|
165
175
|
`#{cmd}`
|
166
176
|
end
|
177
|
+
|
178
|
+
Berkshelf::RSpec::Knife.load_knife_config(File.join(APP_ROOT, 'spec/knife.rb'))
|
167
179
|
end
|
168
180
|
|
169
181
|
Spork.each_run do
|
data/spec/support/chef_api.rb
CHANGED
@@ -24,8 +24,7 @@ module Berkshelf
|
|
24
24
|
else
|
25
25
|
ridley.cookbook.delete(name, version)
|
26
26
|
end
|
27
|
-
rescue Ridley::Errors::HTTPNotFound
|
28
|
-
Ridley::Errors::ResourceNotFound
|
27
|
+
rescue Ridley::Errors::HTTPNotFound
|
29
28
|
true
|
30
29
|
end
|
31
30
|
|
@@ -37,8 +36,7 @@ module Berkshelf
|
|
37
36
|
else
|
38
37
|
!versions.find { |ver| ver == version }.nil?
|
39
38
|
end
|
40
|
-
rescue Ridley::Errors::HTTPNotFound
|
41
|
-
Ridley::Errors::ResourceNotFound
|
39
|
+
rescue Ridley::Errors::HTTPNotFound
|
42
40
|
false
|
43
41
|
end
|
44
42
|
|
@@ -89,10 +87,26 @@ EOF
|
|
89
87
|
File.open(cookbook_path.join("metadata.rb"), 'w+') do |f|
|
90
88
|
f.write metadata
|
91
89
|
end
|
92
|
-
|
90
|
+
|
93
91
|
cookbook_path
|
94
92
|
end
|
95
93
|
|
94
|
+
def create_environment(environment_name)
|
95
|
+
ridley.environment.create(name: environment_name)
|
96
|
+
end
|
97
|
+
|
98
|
+
def delete_environment(environment_name)
|
99
|
+
ridley.environment.delete(environment_name)
|
100
|
+
end
|
101
|
+
|
102
|
+
def environment(environment_name)
|
103
|
+
ridley.environment.find(environment_name)
|
104
|
+
end
|
105
|
+
|
106
|
+
def environment_exists?(environment_name)
|
107
|
+
!environment(environment_name).nil?
|
108
|
+
end
|
109
|
+
|
96
110
|
private
|
97
111
|
|
98
112
|
def ridley
|
data/spec/support/chef_server.rb
CHANGED
@@ -14,14 +14,15 @@ module Berkshelf::RSpec
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def server
|
17
|
-
@server ||= ChefZero::Server.new(port: PORT,
|
17
|
+
@server ||= ChefZero::Server.new(port: PORT, signals: false, log_requests: true)
|
18
18
|
end
|
19
19
|
|
20
20
|
def server_url
|
21
|
-
|
21
|
+
"http://localhost:#{PORT}"
|
22
22
|
end
|
23
23
|
|
24
24
|
def start
|
25
|
+
Thin::Logging.silent = true
|
25
26
|
server.start_background
|
26
27
|
server.on_response do |request, response|
|
27
28
|
request_log << [ request, response ]
|
@@ -32,7 +33,7 @@ module Berkshelf::RSpec
|
|
32
33
|
end
|
33
34
|
|
34
35
|
def stop
|
35
|
-
@server.stop if
|
36
|
+
@server.stop if @server
|
36
37
|
end
|
37
38
|
|
38
39
|
def running?
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'berkshelf/chef'
|
2
|
+
|
3
|
+
module Berkshelf
|
4
|
+
module RSpec
|
5
|
+
module Knife
|
6
|
+
class << self
|
7
|
+
def load_knife_config(path)
|
8
|
+
if File.exist?(path)
|
9
|
+
Berkshelf::Chef::Config.from_file(path)
|
10
|
+
ENV["CHEF_CONFIG"] = path
|
11
|
+
else
|
12
|
+
raise "Cannot continue; '#{path}' must exist and have testing credentials." unless ENV['CI']
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,174 +1,162 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Berkshelf::Berksfile do
|
4
|
-
|
5
|
-
|
6
|
-
cookbook 'ntp', '<= 1.0.0'
|
7
|
-
cookbook 'mysql'
|
8
|
-
cookbook 'nginx', '< 0.101.2'
|
9
|
-
cookbook 'ssh_known_hosts2', :git => 'https://github.com/erikh/chef-ssh_known_hosts2.git'
|
10
|
-
EOF
|
11
|
-
end
|
4
|
+
describe '.from_file' do
|
5
|
+
let(:cookbook_file) { fixtures_path.join('lockfile_spec', 'with_lock', 'Berksfile') }
|
12
6
|
|
13
|
-
|
14
|
-
|
7
|
+
it 'reads a Berksfile and returns an instance Berksfile' do
|
8
|
+
expect(Berkshelf::Berksfile.from_file(cookbook_file)).to be_a(Berkshelf::Berksfile)
|
9
|
+
end
|
15
10
|
|
16
|
-
|
17
|
-
let(:
|
11
|
+
context 'when Berksfile does not exist at given path' do
|
12
|
+
let(:bad_path) { tmp_path.join('thisdoesnotexist') }
|
18
13
|
|
19
|
-
it
|
20
|
-
|
14
|
+
it 'raises BerksfileNotFound' do
|
15
|
+
expect {
|
16
|
+
Berkshelf::Berksfile.from_file(bad_path)
|
17
|
+
}.to raise_error(Berkshelf::BerksfileNotFound)
|
21
18
|
end
|
19
|
+
end
|
20
|
+
end
|
22
21
|
|
23
|
-
|
24
|
-
|
22
|
+
describe '.vendor' do
|
23
|
+
let(:cached_cookbooks) { [] }
|
24
|
+
let(:tmpdir) { Dir.mktmpdir(nil, tmp_path) }
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
subject.from_file(bad_path)
|
29
|
-
}.should raise_error(Berkshelf::BerksfileNotFound)
|
30
|
-
end
|
31
|
-
end
|
26
|
+
it 'returns the expanded filepath of the vendor directory' do
|
27
|
+
expect(Berkshelf::Berksfile.vendor(cached_cookbooks, tmpdir)).to eql(tmpdir)
|
32
28
|
end
|
33
29
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
it "returns the expanded filepath of the vendor directory" do
|
39
|
-
subject.vendor(cached_cookbooks, tmpdir).should eql(tmpdir)
|
30
|
+
context 'with a chefignore' do
|
31
|
+
before do
|
32
|
+
File.stub(:exists?).and_return(true)
|
33
|
+
Berkshelf::Chef::Cookbook::Chefignore.any_instance.stub(:remove_ignores_from).and_return(['metadata.rb'])
|
40
34
|
end
|
41
35
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
36
|
+
it 'finds a chefignore file' do
|
37
|
+
Berkshelf::Chef::Cookbook::Chefignore.should_receive(:new).with(File.expand_path('chefignore'))
|
38
|
+
Berkshelf::Berksfile.vendor(cached_cookbooks, tmpdir)
|
39
|
+
end
|
47
40
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
41
|
+
it 'removes files in chefignore' do
|
42
|
+
cached_cookbooks = [ Berkshelf::CachedCookbook.from_path(fixtures_path.join('cookbooks/example_cookbook')) ]
|
43
|
+
FileUtils.should_receive(:cp_r).with(['metadata.rb'], anything()).exactly(1).times
|
44
|
+
FileUtils.should_receive(:cp_r).with(anything(), anything(), anything()).once
|
45
|
+
Berkshelf::Berksfile.vendor(cached_cookbooks, tmpdir)
|
53
46
|
end
|
54
47
|
end
|
55
48
|
end
|
56
49
|
|
57
|
-
let(:source_one) { double('source_one', name: "nginx") }
|
58
|
-
let(:source_two) { double('source_two', name: "mysql") }
|
59
50
|
|
60
|
-
subject { described_class.new(tmp_path.join("Berksfile")) }
|
61
51
|
|
62
|
-
|
63
|
-
|
52
|
+
let(:source_one) { double('source_one', name: 'nginx') }
|
53
|
+
let(:source_two) { double('source_two', name: 'mysql') }
|
54
|
+
|
55
|
+
subject do
|
56
|
+
berksfile_path = tmp_path.join('Berksfile').to_s
|
57
|
+
FileUtils.touch(berksfile_path)
|
58
|
+
Berkshelf::Berksfile.new(berksfile_path)
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#cookbook' do
|
62
|
+
let(:name) { 'artifact' }
|
64
63
|
let(:constraint) { double('constraint') }
|
65
64
|
let(:default_options) { { group: [] } }
|
66
65
|
|
67
|
-
it
|
66
|
+
it 'sends the add_source message with the name, constraint, and options to the instance of the includer' do
|
68
67
|
subject.should_receive(:add_source).with(name, constraint, default_options)
|
69
|
-
|
70
|
-
subject.cookbook name, constraint, default_options
|
68
|
+
subject.cookbook(name, constraint, default_options)
|
71
69
|
end
|
72
70
|
|
73
|
-
it
|
74
|
-
subject.should_receive(:add_source).with(name, constraint, path:
|
75
|
-
|
76
|
-
subject.cookbook name, constraint, path: "/Users/reset"
|
71
|
+
it 'merges the default options into specified options' do
|
72
|
+
subject.should_receive(:add_source).with(name, constraint, path: '/Users/reset', group: [])
|
73
|
+
subject.cookbook(name, constraint, path: '/Users/reset')
|
77
74
|
end
|
78
75
|
|
79
|
-
it
|
76
|
+
it 'converts a single specified group option into an array of groups' do
|
80
77
|
subject.should_receive(:add_source).with(name, constraint, group: [:production])
|
81
|
-
|
82
|
-
subject.cookbook name, constraint, group: :production
|
78
|
+
subject.cookbook(name, constraint, group: :production)
|
83
79
|
end
|
84
80
|
|
85
|
-
context
|
86
|
-
it
|
81
|
+
context 'when no constraint specified' do
|
82
|
+
it 'sends the add_source message with a nil value for constraint' do
|
87
83
|
subject.should_receive(:add_source).with(name, nil, default_options)
|
88
|
-
|
89
|
-
subject.cookbook name, default_options
|
84
|
+
subject.cookbook(name, default_options)
|
90
85
|
end
|
91
86
|
end
|
92
87
|
|
93
|
-
context
|
94
|
-
it
|
88
|
+
context 'when no options specified' do
|
89
|
+
it 'sends the add_source message with an empty Hash for the value of options' do
|
95
90
|
subject.should_receive(:add_source).with(name, constraint, default_options)
|
96
|
-
|
97
|
-
subject.cookbook name, constraint
|
91
|
+
subject.cookbook(name, constraint)
|
98
92
|
end
|
99
93
|
end
|
100
94
|
end
|
101
95
|
|
102
96
|
describe '#group' do
|
103
|
-
let(:name) {
|
104
|
-
let(:group) {
|
97
|
+
let(:name) { 'artifact' }
|
98
|
+
let(:group) { 'production' }
|
105
99
|
|
106
|
-
it
|
100
|
+
it 'sends the add_source message with an array of groups determined by the parameter passed to the group block' do
|
107
101
|
subject.should_receive(:add_source).with(name, nil, group: [group])
|
108
102
|
|
109
|
-
subject.group
|
110
|
-
subject.cookbook
|
103
|
+
subject.group(group) do
|
104
|
+
subject.cookbook(name)
|
111
105
|
end
|
112
106
|
end
|
113
107
|
end
|
114
108
|
|
115
|
-
describe
|
116
|
-
let(:
|
117
|
-
subject {
|
109
|
+
describe '#metadata' do
|
110
|
+
let(:path) { fixtures_path.join('cookbooks/example_cookbook') }
|
111
|
+
subject { Berkshelf::Berksfile.new(path.join('Berksfile')) }
|
118
112
|
|
119
|
-
before
|
120
|
-
|
121
|
-
it "sends the add_source message with an explicit version constraint and the path to the cookbook" do
|
122
|
-
subject.should_receive(:add_source).with("example_cookbook", "= 0.5.0", path: cb_path.to_s)
|
113
|
+
before { Dir.chdir(path) }
|
123
114
|
|
115
|
+
it 'sends the add_source message with an explicit version constraint and the path to the cookbook' do
|
116
|
+
subject.should_receive(:add_source).with('example_cookbook', '= 0.5.0', path: path.to_s)
|
124
117
|
subject.metadata
|
125
118
|
end
|
126
119
|
end
|
127
120
|
|
128
|
-
describe
|
129
|
-
let(:uri) {
|
121
|
+
describe '#site' do
|
122
|
+
let(:uri) { 'http://opscode/v1' }
|
130
123
|
|
131
|
-
it
|
124
|
+
it 'sends the add_location to the instance of the implementing class with a SiteLocation' do
|
132
125
|
subject.should_receive(:add_location).with(:site, uri)
|
133
|
-
|
134
126
|
subject.site(uri)
|
135
127
|
end
|
136
128
|
|
137
|
-
context
|
138
|
-
it
|
129
|
+
context 'given the symbol :opscode' do
|
130
|
+
it 'sends an add_location message with the default Opscode Community API as the first parameter' do
|
139
131
|
subject.should_receive(:add_location).with(:site, :opscode)
|
140
|
-
|
141
132
|
subject.site(:opscode)
|
142
133
|
end
|
143
134
|
end
|
144
135
|
end
|
145
136
|
|
146
|
-
describe
|
147
|
-
let(:uri) {
|
137
|
+
describe '#chef_api' do
|
138
|
+
let(:uri) { 'http://chef:8080/' }
|
148
139
|
|
149
|
-
it
|
140
|
+
it 'sends and add_location message with the type :chef_api and the given URI' do
|
150
141
|
subject.should_receive(:add_location).with(:chef_api, uri, {})
|
151
|
-
|
152
142
|
subject.chef_api(uri)
|
153
143
|
end
|
154
144
|
|
155
|
-
it
|
156
|
-
options = { node_name:
|
145
|
+
it 'also sends any options passed' do
|
146
|
+
options = { node_name: 'reset', client_key: '/Users/reset/.chef/reset.pem' }
|
157
147
|
subject.should_receive(:add_location).with(:chef_api, uri, options)
|
158
|
-
|
159
148
|
subject.chef_api(uri, options)
|
160
149
|
end
|
161
150
|
|
162
|
-
context
|
163
|
-
it
|
151
|
+
context 'given the symbol :config' do
|
152
|
+
it 'sends an add_location message with the the type :chef_api and the URI :config' do
|
164
153
|
subject.should_receive(:add_location).with(:chef_api, :config, {})
|
165
|
-
|
166
154
|
subject.chef_api(:config)
|
167
155
|
end
|
168
156
|
end
|
169
157
|
end
|
170
158
|
|
171
|
-
describe
|
159
|
+
describe '#sources' do
|
172
160
|
let(:groups) do
|
173
161
|
[
|
174
162
|
:nautilus,
|
@@ -176,146 +164,146 @@ EOF
|
|
176
164
|
]
|
177
165
|
end
|
178
166
|
|
179
|
-
it
|
167
|
+
it 'returns all CookbookSources added to the instance of Berksfile' do
|
180
168
|
subject.add_source(source_one.name)
|
181
169
|
subject.add_source(source_two.name)
|
182
170
|
|
183
|
-
subject.sources.
|
184
|
-
subject.
|
185
|
-
subject.
|
171
|
+
expect(subject.sources).to have(2).items
|
172
|
+
expect(subject).to have_source(source_one.name)
|
173
|
+
expect(subject).to have_source(source_two.name)
|
186
174
|
end
|
187
175
|
|
188
|
-
context
|
189
|
-
before
|
176
|
+
context 'given the option :except' do
|
177
|
+
before do
|
190
178
|
source_one.stub(:groups) { [:default, :skarner] }
|
191
179
|
source_two.stub(:groups) { [:default, :nautilus] }
|
192
180
|
end
|
193
181
|
|
194
|
-
it
|
182
|
+
it 'returns all of the sources except the ones in the given groups' do
|
195
183
|
subject.add_source(source_one.name, nil, group: [:default, :skarner])
|
196
184
|
subject.add_source(source_two.name, nil, group: [:default, :nautilus])
|
197
185
|
filtered = subject.sources(except: :nautilus)
|
198
186
|
|
199
|
-
filtered.
|
200
|
-
filtered.first.name.
|
187
|
+
expect(filtered).to have(1).item
|
188
|
+
expect(filtered.first.name).to eq(source_one.name)
|
201
189
|
end
|
202
190
|
end
|
203
191
|
|
204
|
-
context
|
205
|
-
before
|
192
|
+
context 'given the option :only' do
|
193
|
+
before do
|
206
194
|
source_one.stub(:groups) { [:default, :skarner] }
|
207
195
|
source_two.stub(:groups) { [:default, :nautilus] }
|
208
196
|
end
|
209
197
|
|
210
|
-
it
|
198
|
+
it 'returns only the sources in the givne groups' do
|
211
199
|
subject.add_source(source_one.name, nil, group: [:default, :skarner])
|
212
200
|
subject.add_source(source_two.name, nil, group: [:default, :nautilus])
|
213
201
|
filtered = subject.sources(only: :nautilus)
|
214
202
|
|
215
|
-
filtered.
|
216
|
-
filtered.first.name.
|
203
|
+
expect(filtered).to have(1).item
|
204
|
+
expect(filtered.first.name).to eq(source_two.name)
|
217
205
|
end
|
218
206
|
end
|
219
207
|
|
220
|
-
context
|
221
|
-
it
|
222
|
-
|
208
|
+
context 'when a value for :only and :except is given' do
|
209
|
+
it 'raises an ArgumentError' do
|
210
|
+
expect {
|
223
211
|
subject.sources(only: [:default], except: [:other])
|
224
|
-
}.
|
212
|
+
}.to raise_error(Berkshelf::ArgumentError, "Cannot specify both :except and :only")
|
225
213
|
end
|
226
214
|
end
|
227
215
|
end
|
228
216
|
|
229
|
-
describe
|
230
|
-
before
|
217
|
+
describe '#groups' do
|
218
|
+
before do
|
231
219
|
subject.stub(:sources) { [source_one, source_two] }
|
232
220
|
source_one.stub(:groups) { [:nautilus, :skarner] }
|
233
221
|
source_two.stub(:groups) { [:nautilus, :riven] }
|
234
222
|
end
|
235
223
|
|
236
|
-
it
|
237
|
-
subject.groups.keys.
|
238
|
-
subject.groups.
|
239
|
-
subject.groups.
|
240
|
-
subject.groups.
|
224
|
+
it 'returns a hash containing keys for every group a source is a member of' do
|
225
|
+
expect(subject.groups.keys).to have(3).items
|
226
|
+
expect(subject.groups).to have_key(:nautilus)
|
227
|
+
expect(subject.groups).to have_key(:skarner)
|
228
|
+
expect(subject.groups).to have_key(:riven)
|
241
229
|
end
|
242
230
|
|
243
|
-
it
|
244
|
-
subject.groups[:nautilus].
|
245
|
-
subject.groups[:riven].
|
231
|
+
it 'returns an Array of CookbookSources who are members of the group for value' do
|
232
|
+
expect(subject.groups[:nautilus]).to have(2).items
|
233
|
+
expect(subject.groups[:riven]).to have(1).item
|
246
234
|
end
|
247
235
|
end
|
248
236
|
|
249
|
-
describe
|
237
|
+
describe '#resolve' do
|
250
238
|
let(:resolver) { double('resolver') }
|
251
|
-
|
239
|
+
let(:sources) { [source_one, source_two] }
|
240
|
+
let(:cached) { [double('cached_one'), double('cached_two')] }
|
241
|
+
|
242
|
+
before do
|
243
|
+
Berkshelf::Resolver.stub(:new).and_return(resolver)
|
244
|
+
end
|
245
|
+
|
246
|
+
it 'resolves the Berksfile' do
|
247
|
+
resolver.should_receive(:resolve).and_return(cached)
|
248
|
+
resolver.should_receive(:sources).and_return(sources)
|
252
249
|
|
253
|
-
|
254
|
-
resolver.should_receive(:resolve).and_return([double('cached_cookbook_one'), double('cached_cookbook_two')])
|
255
|
-
solution = subject.resolve
|
256
|
-
solution.should have(2).items
|
250
|
+
expect(subject.resolve).to eq({ solution: cached, sources: sources })
|
257
251
|
end
|
258
252
|
end
|
259
253
|
|
260
|
-
describe
|
254
|
+
describe '#install' do
|
261
255
|
let(:resolver) { double('resolver') }
|
262
|
-
|
256
|
+
let(:lockfile) { double('lockfile') }
|
263
257
|
|
264
|
-
|
265
|
-
|
266
|
-
subject.should_receive(:lockfile_present?).and_return(false)
|
267
|
-
resolver.should_receive(:sources).and_return([])
|
268
|
-
end
|
258
|
+
let(:cached_cookbooks) { [double('cached_one'), double('cached_two')] }
|
259
|
+
let(:sources) { [source_one, source_two] }
|
269
260
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
double('cached_two')
|
274
|
-
]
|
275
|
-
end
|
261
|
+
before do
|
262
|
+
Berkshelf::Resolver.stub(:new).and_return(resolver)
|
263
|
+
Berkshelf::Lockfile.stub(:new).and_return(lockfile)
|
276
264
|
|
277
|
-
|
278
|
-
resolver.should_receive(:resolve).and_return(cached_cookbooks)
|
265
|
+
subject.stub(:sha).and_return('abc123')
|
279
266
|
|
280
|
-
|
267
|
+
lockfile.stub(:sources).and_return([])
|
268
|
+
lockfile.stub(:sha).and_return('xyz456')
|
269
|
+
|
270
|
+
resolver.stub(:sources).and_return([])
|
271
|
+
lockfile.stub(:update)
|
272
|
+
end
|
273
|
+
|
274
|
+
context 'when a lockfile is not present' do
|
275
|
+
it 'returns the result from sending the message resolve to resolver' do
|
276
|
+
resolver.should_receive(:resolve).and_return(cached_cookbooks)
|
277
|
+
expect(subject.install).to eql(cached_cookbooks)
|
281
278
|
end
|
282
279
|
|
283
|
-
it
|
280
|
+
it 'sets a value for self.cached_cookbooks equivalent to the return value' do
|
284
281
|
resolver.should_receive(:resolve).and_return(cached_cookbooks)
|
285
282
|
subject.install
|
286
283
|
|
287
|
-
subject.cached_cookbooks.
|
284
|
+
expect(subject.cached_cookbooks).to eql(cached_cookbooks)
|
288
285
|
end
|
289
286
|
|
290
|
-
it
|
287
|
+
it 'creates a new resolver and finds a solution by calling resolve on the resolver' do
|
291
288
|
resolver.should_receive(:resolve)
|
292
|
-
|
293
289
|
subject.install
|
294
290
|
end
|
295
291
|
|
296
|
-
it
|
292
|
+
it 'writes a lockfile with the resolvers sources' do
|
297
293
|
resolver.should_receive(:resolve)
|
298
|
-
|
294
|
+
lockfile.should_receive(:update).with([], sha: 'abc123')
|
299
295
|
|
300
296
|
subject.install
|
301
297
|
end
|
302
298
|
end
|
303
299
|
|
304
|
-
context
|
305
|
-
before
|
306
|
-
|
307
|
-
it "does not write a new lock file" do
|
300
|
+
context 'when a value for :path is given' do
|
301
|
+
before do
|
308
302
|
resolver.should_receive(:resolve)
|
309
|
-
|
310
|
-
|
311
|
-
subject.install
|
303
|
+
resolver.should_receive(:sources).and_return([])
|
312
304
|
end
|
313
|
-
end
|
314
|
-
|
315
|
-
context "when a value for :path is given" do
|
316
|
-
before(:each) { resolver.should_receive(:resolve) }
|
317
305
|
|
318
|
-
it
|
306
|
+
it 'sends the message :vendor to Berksfile with the value for :path' do
|
319
307
|
path = double('path')
|
320
308
|
subject.class.should_receive(:vendor).with(subject.cached_cookbooks, path)
|
321
309
|
|
@@ -323,99 +311,113 @@ EOF
|
|
323
311
|
end
|
324
312
|
end
|
325
313
|
|
326
|
-
context
|
327
|
-
before
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
subject.
|
332
|
-
|
314
|
+
context 'when a value for :except is given' do
|
315
|
+
before do
|
316
|
+
resolver.should_receive(:resolve)
|
317
|
+
resolver.should_receive(:sources).and_return([])
|
318
|
+
subject.stub(:sources).and_return(sources)
|
319
|
+
subject.stub(:apply_lockfile).and_return(sources)
|
320
|
+
end
|
333
321
|
|
322
|
+
it 'filters the sources and gives the results to the Resolver initializer' do
|
323
|
+
subject.should_receive(:sources).with(except: [:skip_me]).and_return(sources)
|
334
324
|
subject.install(except: [:skip_me])
|
335
325
|
end
|
336
326
|
end
|
337
327
|
|
338
|
-
context
|
339
|
-
before
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
subject.
|
328
|
+
context 'when a value for :only is given' do
|
329
|
+
before do
|
330
|
+
resolver.should_receive(:resolve)
|
331
|
+
resolver.should_receive(:sources).and_return([])
|
332
|
+
subject.stub(:sources).and_return(sources)
|
333
|
+
subject.stub(:apply_lockfile).and_return(sources)
|
334
|
+
end
|
344
335
|
|
336
|
+
it 'filters the sources and gives the results to the Resolver initializer' do
|
337
|
+
subject.should_receive(:sources).with(only: [:skip_me]).and_return(sources)
|
345
338
|
subject.install(only: [:skip_me])
|
346
339
|
end
|
347
340
|
end
|
348
341
|
end
|
349
342
|
|
350
|
-
describe
|
351
|
-
|
343
|
+
describe '#load' do
|
344
|
+
let(:content) do
|
345
|
+
<<-EOF.strip
|
346
|
+
cookbook 'ntp', '<= 1.0.0'
|
347
|
+
cookbook 'mysql'
|
348
|
+
cookbook 'nginx', '< 0.101.2'
|
349
|
+
cookbook 'ssh_known_hosts2', :git => 'https://github.com/erikh/chef-ssh_known_hosts2.git'
|
350
|
+
EOF
|
351
|
+
end
|
352
|
+
|
353
|
+
it 'reads the content of a Berksfile and adds the sources to the Shelf' do
|
352
354
|
subject.load(content)
|
353
355
|
|
354
|
-
|
355
|
-
subject.
|
356
|
+
%w(ntp mysql nginx ssh_known_hosts2).each do |name|
|
357
|
+
expect(subject).to have_source(name)
|
356
358
|
end
|
357
359
|
end
|
358
360
|
|
359
|
-
it
|
360
|
-
subject.load(content).
|
361
|
+
it 'returns an instance of Berksfile' do
|
362
|
+
expect(subject.load(content)).to be_a(Berkshelf::Berksfile)
|
361
363
|
end
|
362
364
|
end
|
363
365
|
|
364
|
-
describe
|
365
|
-
let(:name) {
|
366
|
-
let(:constraint) {
|
367
|
-
let(:location) { { site:
|
366
|
+
describe '#add_source' do
|
367
|
+
let(:name) { 'cookbook_one' }
|
368
|
+
let(:constraint) { '= 1.2.0' }
|
369
|
+
let(:location) { { site: 'http://site' } }
|
368
370
|
|
369
371
|
before(:each) do
|
370
372
|
subject.add_source(name, constraint, location)
|
371
373
|
end
|
372
374
|
|
373
|
-
it
|
374
|
-
subject.sources.
|
375
|
+
it 'adds new cookbook source to the list of sources' do
|
376
|
+
expect(subject.sources).to have(1).source
|
375
377
|
end
|
376
378
|
|
377
379
|
it "adds a cookbook source with a 'name' of the given name" do
|
378
|
-
subject.sources.first.name.
|
380
|
+
expect(subject.sources.first.name).to eq(name)
|
379
381
|
end
|
380
382
|
|
381
383
|
it "adds a cookbook source with a 'version_constraint' of the given constraint" do
|
382
|
-
subject.sources.first.version_constraint.to_s.
|
384
|
+
expect(subject.sources.first.version_constraint.to_s).to eq(constraint)
|
383
385
|
end
|
384
386
|
|
385
|
-
it
|
386
|
-
|
387
|
+
it 'raises DuplicateSourceDefined if multiple sources of the same name are found' do
|
388
|
+
expect {
|
387
389
|
subject.add_source(name)
|
388
|
-
}.
|
390
|
+
}.to raise_error(Berkshelf::DuplicateSourceDefined)
|
389
391
|
end
|
390
392
|
end
|
391
393
|
|
392
|
-
describe
|
394
|
+
describe '#add_location' do
|
393
395
|
let(:type) { :site }
|
394
396
|
let(:value) { double('value') }
|
395
397
|
let(:options) { double('options') }
|
396
398
|
|
397
|
-
it
|
399
|
+
it 'delegates :add_location to the downloader' do
|
398
400
|
subject.downloader.should_receive(:add_location).with(type, value, options)
|
399
|
-
|
400
401
|
subject.add_location(type, value, options)
|
401
402
|
end
|
402
403
|
end
|
403
404
|
|
404
|
-
describe
|
405
|
+
describe '#upload' do
|
405
406
|
let(:upload) { subject.upload(options) }
|
406
407
|
let(:options) { Hash.new }
|
407
408
|
let(:ssl) { double('ssl', verify: true) }
|
408
409
|
let(:chef) {
|
409
410
|
double('chef',
|
410
|
-
node_name:
|
411
|
-
client_key:
|
412
|
-
chef_server_url:
|
411
|
+
node_name: 'fake-client',
|
412
|
+
client_key: 'client-key',
|
413
|
+
chef_server_url: 'http://configured-chef-server/'
|
414
|
+
)
|
413
415
|
}
|
414
416
|
let(:berkshelf_config) { double('berks', ssl: ssl, chef: chef) }
|
415
417
|
let(:default_ridley_options) {
|
416
418
|
{
|
417
|
-
client_name:
|
418
|
-
client_key:
|
419
|
+
client_name: 'fake-client',
|
420
|
+
client_key: 'client-key',
|
419
421
|
ssl: {
|
420
422
|
verify: true
|
421
423
|
}
|
@@ -424,82 +426,177 @@ EOF
|
|
424
426
|
|
425
427
|
before do
|
426
428
|
Berkshelf::Config.stub(:instance).and_return(berkshelf_config)
|
427
|
-
subject.stub(:resolve).and_return([])
|
429
|
+
subject.stub(:resolve).and_return(solution: [], sources: [])
|
428
430
|
end
|
429
431
|
|
430
|
-
context
|
431
|
-
let(:chef)
|
432
|
+
context 'when there is no :server_url' do
|
433
|
+
let(:chef) do
|
432
434
|
double('chef',
|
433
|
-
node_name:
|
434
|
-
client_key:
|
435
|
-
chef_server_url: nil
|
436
|
-
|
437
|
-
|
435
|
+
node_name: 'fake-client',
|
436
|
+
client_key: 'client-key',
|
437
|
+
chef_server_url: nil
|
438
|
+
)
|
439
|
+
end
|
440
|
+
let(:message) { 'Missing required attribute in your Berkshelf configuration: chef.server_url' }
|
438
441
|
|
439
|
-
it
|
442
|
+
it 'raises an error' do
|
440
443
|
expect {
|
441
444
|
upload
|
442
|
-
}.to raise_error(Berkshelf::
|
445
|
+
}.to raise_error(Berkshelf::ChefConnectionError, message)
|
443
446
|
end
|
444
447
|
end
|
445
448
|
|
446
|
-
context
|
447
|
-
let(:chef)
|
449
|
+
context 'when there is no :client_name' do
|
450
|
+
let(:chef) do
|
448
451
|
double('chef',
|
449
452
|
node_name: nil,
|
450
|
-
client_key:
|
451
|
-
chef_server_url:
|
452
|
-
|
453
|
-
|
453
|
+
client_key: 'client-key',
|
454
|
+
chef_server_url: 'http://configured-chef-server/'
|
455
|
+
)
|
456
|
+
end
|
457
|
+
let(:message) { 'Missing required attribute in your Berkshelf configuration: chef.node_name' }
|
454
458
|
|
455
|
-
it
|
459
|
+
it 'raises an error' do
|
456
460
|
expect {
|
457
461
|
upload
|
458
|
-
}.to raise_error(Berkshelf::
|
462
|
+
}.to raise_error(Berkshelf::ChefConnectionError, message)
|
459
463
|
end
|
460
464
|
end
|
461
465
|
|
462
|
-
context
|
463
|
-
let(:chef)
|
466
|
+
context 'when there is no :client_key' do
|
467
|
+
let(:chef) do
|
464
468
|
double('chef',
|
465
|
-
node_name:
|
469
|
+
node_name: 'fake-client',
|
466
470
|
client_key: nil,
|
467
|
-
chef_server_url:
|
468
|
-
|
469
|
-
|
471
|
+
chef_server_url: 'http://configured-chef-server/'
|
472
|
+
)
|
473
|
+
end
|
474
|
+
let(:message) { 'Missing required attribute in your Berkshelf configuration: chef.client_key' }
|
470
475
|
|
471
|
-
it
|
476
|
+
it 'raises an error' do
|
472
477
|
expect {
|
473
478
|
upload
|
474
|
-
}.to raise_error(Berkshelf::
|
479
|
+
}.to raise_error(Berkshelf::ChefConnectionError, message)
|
475
480
|
end
|
476
481
|
end
|
477
482
|
|
478
|
-
context
|
483
|
+
context 'when a Chef Server url is not passed as an option' do
|
479
484
|
let(:ridley_options) do
|
480
|
-
{server_url:
|
485
|
+
{ server_url: 'http://configured-chef-server/' }.merge(default_ridley_options)
|
481
486
|
end
|
482
487
|
|
483
|
-
it
|
488
|
+
it 'uses Berkshelf::Config configured server_url' do
|
484
489
|
Ridley.should_receive(:new).with(ridley_options)
|
485
490
|
upload
|
486
491
|
end
|
487
492
|
end
|
488
493
|
|
489
|
-
context
|
490
|
-
let(:options)
|
494
|
+
context 'when a Chef Server url is passed as an option' do
|
495
|
+
let(:options) do
|
491
496
|
{
|
492
|
-
server_url:
|
497
|
+
server_url: 'http://fake-chef-server.com/'
|
493
498
|
}
|
494
|
-
|
495
|
-
let(:ridley_options)
|
496
|
-
{server_url:
|
497
|
-
|
499
|
+
end
|
500
|
+
let(:ridley_options) do
|
501
|
+
{ server_url: 'http://fake-chef-server.com/'}.merge(default_ridley_options)
|
502
|
+
end
|
498
503
|
|
499
|
-
it
|
504
|
+
it 'uses the passed in :server_url' do
|
500
505
|
Ridley.should_receive(:new).with(ridley_options)
|
501
506
|
upload
|
502
507
|
end
|
503
508
|
end
|
504
509
|
end
|
510
|
+
|
511
|
+
describe '#apply' do
|
512
|
+
let(:env_name) { 'berkshelf-test' }
|
513
|
+
let(:server_url) { Berkshelf::RSpec::ChefServer.server_url }
|
514
|
+
let(:client_name) { 'reset' }
|
515
|
+
let(:client_key) { fixtures_path.join('reset.pem').to_s }
|
516
|
+
let(:ridley) { Ridley.new(server_url: server_url, client_name: client_name, client_key: client_key) }
|
517
|
+
|
518
|
+
before do
|
519
|
+
subject.stub(:ridley_connection).and_return(ridley)
|
520
|
+
subject.add_source('nginx', '>= 0.1.2', chef_api: server_url, node_name: client_name, client_key: client_key)
|
521
|
+
subject.stub(install: nil)
|
522
|
+
end
|
523
|
+
|
524
|
+
context 'when the chef environment exists' do
|
525
|
+
let(:sources) do
|
526
|
+
[
|
527
|
+
double(name: 'nginx', locked_version: '1.2.3'),
|
528
|
+
double(name: 'artifact', locked_version: '1.4.0')
|
529
|
+
]
|
530
|
+
end
|
531
|
+
|
532
|
+
before do
|
533
|
+
chef_environment('berkshelf')
|
534
|
+
subject.lockfile.stub(:sources).and_return(sources)
|
535
|
+
end
|
536
|
+
|
537
|
+
it 'installs the Berksfile' do
|
538
|
+
subject.should_receive(:install)
|
539
|
+
subject.apply('berkshelf')
|
540
|
+
end
|
541
|
+
|
542
|
+
it 'applys the locked_versions of the Lockfile sources to the given Chef environment' do
|
543
|
+
subject.apply('berkshelf')
|
544
|
+
|
545
|
+
environment = ::JSON.parse(chef_server.data['environments']['berkshelf'])
|
546
|
+
expect(environment['cookbook_versions']).to have(2).items
|
547
|
+
expect(environment['cookbook_versions']['nginx']).to eq('1.2.3')
|
548
|
+
expect(environment['cookbook_versions']['artifact']).to eq('1.4.0')
|
549
|
+
end
|
550
|
+
end
|
551
|
+
|
552
|
+
context 'when the environment does not exist' do
|
553
|
+
it 'raises an EnvironmentNotFound error' do
|
554
|
+
expect {
|
555
|
+
subject.apply(env_name)
|
556
|
+
}.to raise_error(Berkshelf::EnvironmentNotFound)
|
557
|
+
end
|
558
|
+
end
|
559
|
+
|
560
|
+
context 'when Ridley throw an exception' do
|
561
|
+
before { ridley.stub_chain(:environment, :find).and_raise(Ridley::Errors::RidleyError) }
|
562
|
+
|
563
|
+
it 'raises a ChefConnectionError' do
|
564
|
+
expect {
|
565
|
+
subject.apply(env_name)
|
566
|
+
}.to raise_error(Berkshelf::ChefConnectionError)
|
567
|
+
end
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
describe '#package' do
|
572
|
+
context 'when the source does not exist' do
|
573
|
+
it 'raises a CookbookNotFound exception' do
|
574
|
+
expect {
|
575
|
+
subject.package('non-existent', output: '/tmp')
|
576
|
+
}.to raise_error(Berkshelf::CookbookNotFound)
|
577
|
+
end
|
578
|
+
end
|
579
|
+
|
580
|
+
context 'when the source exists' do
|
581
|
+
let(:source) { double('source') }
|
582
|
+
let(:cached) { double('cached', path: '/foo/bar', cookbook_name: 'cookbook') }
|
583
|
+
let(:options) { { output: '/tmp' } }
|
584
|
+
|
585
|
+
before do
|
586
|
+
FileUtils.stub(:cp_r)
|
587
|
+
FileUtils.stub(:mkdir_p)
|
588
|
+
subject.stub(:find).with('non-existent').and_return(source)
|
589
|
+
subject.stub(:resolve).with(source, options).and_return({ solution: [cached], sources: [source] })
|
590
|
+
end
|
591
|
+
|
592
|
+
it 'resolves the sources' do
|
593
|
+
subject.should_receive(:resolve).with(source, options)
|
594
|
+
subject.package('non-existent', options)
|
595
|
+
end
|
596
|
+
|
597
|
+
it 'returns the output path' do
|
598
|
+
expect(subject.package('non-existent', options)).to eq('/tmp/non-existent.tar.gz')
|
599
|
+
end
|
600
|
+
end
|
601
|
+
end
|
505
602
|
end
|