soloist-rvm 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ def make_story_channel(&block)
2
+ story do |session|
3
+ channel = session.opens_channel
4
+ block.call(channel)
5
+ channel.gets_close
6
+ channel.sends_close
7
+ end
8
+ end
@@ -0,0 +1,38 @@
1
+ require "net/ssh/test"
2
+
3
+ class Net::SSH::Test::Packet
4
+ alias :original_types :types
5
+ def types
6
+ @types ||= case @type
7
+ when CHANNEL_EXTENDED_DATA then [:long, :long, :string]
8
+ else original_types
9
+ end
10
+ end
11
+ end
12
+
13
+ class Net::SSH::Test::Script
14
+ def gets_channel_extended_data(channel, data)
15
+ events << Net::SSH::Test::RemotePacket.new(:channel_extended_data, channel.local_id, 1, data)
16
+ end
17
+ end
18
+
19
+ class Net::SSH::Test::Channel
20
+ def gets_extended_data(data)
21
+ script.gets_channel_extended_data(self, data)
22
+ end
23
+ end
24
+
25
+ class Net::SSH::Test::Kex
26
+ def exchange_keys
27
+ result = Net::SSH::Buffer.from(:byte, NEWKEYS)
28
+ @connection.send_message(result)
29
+
30
+ buffer = @connection.next_message
31
+ raise Net::SSH::Exception, "expected NEWKEYS" unless buffer.type == NEWKEYS
32
+
33
+ { :session_id => "abc-xyz",
34
+ :server_key => OpenSSL::PKey::RSA.new(512),
35
+ :shared_secret => OpenSSL::BN.new("1234567890", 10),
36
+ :hashing_algorithm => OpenSSL::Digest::SHA1 }
37
+ end
38
+ end
@@ -0,0 +1,171 @@
1
+ require "spec_helper"
2
+
3
+ describe Soloist::CLI do
4
+ let(:cli) { Soloist::CLI.new }
5
+ let(:base_path) { RSpec.configuration.tempdir }
6
+ let(:soloistrc_path) { File.expand_path("soloistrc", base_path) }
7
+
8
+ before do
9
+ FileUtils.mkdir_p(base_path)
10
+ Soloist::Config.any_instance.stub(:exec)
11
+ end
12
+
13
+ describe "#chef" do
14
+ it "receives the outside environment" do
15
+ FileUtils.touch(soloistrc_path)
16
+ Dir.chdir(base_path) do
17
+ ENV["AUTREYISM"] = "pathological-yodeling"
18
+ cli.soloist_config.should_receive(:exec) do |chef_solo|
19
+ `#{chef_solo}`.chomp.should == "pathological-yodeling"
20
+ end
21
+ cli.soloist_config.stub(:chef_solo).and_return('echo $AUTREYISM')
22
+ cli.chef
23
+ end
24
+ end
25
+
26
+ context "when the soloistrc file does not exist" do
27
+ it "raises an error" do
28
+ expect do
29
+ begin
30
+ Dir.chdir(base_path) { cli.chef }
31
+ rescue Soloist::NotFound => e
32
+ e.message.should == "Could not find soloistrc or .soloistrc"
33
+ raise
34
+ end
35
+ end.to raise_error(Soloist::NotFound)
36
+ end
37
+ end
38
+
39
+ context "when the soloistrc file exists" do
40
+ before do
41
+ File.open(soloistrc_path, "w") do |file|
42
+ file.write(YAML.dump("recipes" => ["stinky::feet"]))
43
+ end
44
+ cli.soloist_config = nil
45
+ Dir.chdir(base_path) { cli.soloist_config.stub(:exec) }
46
+ end
47
+
48
+ it "runs the proper recipes" do
49
+ cli.chef
50
+ cli.soloist_config.royal_crown.recipes.should =~ ["stinky::feet"]
51
+ end
52
+
53
+ context "when a soloistrc_local file exists" do
54
+ let(:soloistrc_local_path) { File.expand_path("soloistrc_local", base_path) }
55
+
56
+ before do
57
+ File.open(soloistrc_local_path, "w") do |file|
58
+ file.write(YAML.dump("recipes" => ["stinky::socks"]))
59
+ end
60
+ cli.soloist_config = nil
61
+ Dir.chdir(base_path) { cli.soloist_config.stub(:exec) }
62
+ end
63
+
64
+ it "installs the proper recipes" do
65
+ cli.chef
66
+ cli.soloist_config.royal_crown.recipes.should =~ ["stinky::feet", "stinky::socks"]
67
+ end
68
+ end
69
+
70
+ context "when the Cheffile does not exist" do
71
+ it "runs chef" do
72
+ cli.soloist_config.should_receive(:exec)
73
+ cli.chef
74
+ end
75
+
76
+ it "does not run librarian" do
77
+ Librarian::Chef::Cli.should_not_receive(:with_environment)
78
+ cli.chef
79
+ end
80
+ end
81
+
82
+ context "when the Cheffile exists" do
83
+ let(:cli_instance) { double(:cli_instance) }
84
+
85
+ before { FileUtils.touch(File.expand_path("Cheffile", base_path)) }
86
+
87
+ it "runs librarian" do
88
+ Librarian::Chef::Cli.should_receive(:with_environment).and_yield
89
+ Librarian::Chef::Cli.should_receive(:new).and_return(cli_instance)
90
+ cli_instance.should_receive(:install)
91
+ cli.chef
92
+ end
93
+
94
+ context "when the user is not root" do
95
+ context "when rvm is not present" do
96
+ before do
97
+ cli.soloist_config.stub(:rvm?).and_return(false)
98
+ end
99
+ it "creates the cache path using sudo" do
100
+ cli.soloist_config.should_receive(:exec) do |command|
101
+ command.should =~ /^sudo -E/
102
+ end
103
+ cli.chef
104
+ end
105
+ end
106
+
107
+ context "when rvm is present" do
108
+ before do
109
+ cli.soloist_config.stub(:rvm?).and_return(true)
110
+ end
111
+ it "creates the cache path using rvmsudo" do
112
+ cli.soloist_config.should_receive(:exec) do |command|
113
+ command.should =~ /rvmsudo -E/
114
+ end
115
+ cli.chef
116
+ end
117
+ end
118
+ end
119
+
120
+ context "when the user is root" do
121
+ before { Process.stub(:uid => 0) }
122
+
123
+ it "creates the cache path" do
124
+ cli.soloist_config.should_receive(:exec) do |command|
125
+ command.should_not =~ /^sudo -E/
126
+ end
127
+ cli.chef
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+ describe "#run_recipe" do
135
+ context "when the soloistrc does not exist" do
136
+ it "raises an error" do
137
+ expect do
138
+ Dir.chdir(base_path) { cli.run_recipe("pineapple::wut") }
139
+ end.to raise_error(Soloist::NotFound)
140
+ end
141
+ end
142
+
143
+ context "when the soloistrc file exists" do
144
+ before do
145
+ File.open(soloistrc_path, "w") do |file|
146
+ file.write(YAML.dump("recipes" => ["pineapple::wutcake"]))
147
+ end
148
+ end
149
+
150
+ it "sets a recipe to run" do
151
+ Dir.chdir(base_path) do
152
+ cli.should_receive(:chef)
153
+ cli.run_recipe("angst::teenage", "ennui::default")
154
+ cli.soloist_config.royal_crown.recipes.should =~ ["angst::teenage", "ennui::default"]
155
+ end
156
+ end
157
+ end
158
+ end
159
+
160
+ describe "#config" do
161
+ let(:royal_crown) { Soloist::RoyalCrown.new(:node_attributes => {"a" => "b"}) }
162
+ let(:config) { Soloist::Config.new(royal_crown) }
163
+
164
+ before { cli.stub(:soloist_config => config) }
165
+
166
+ it "prints the hash render of the RoyalCrown" do
167
+ Kernel.should_receive(:ap).with({"recipes"=>[], "a" => "b"})
168
+ cli.config
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,196 @@
1
+ require "spec_helper"
2
+
3
+ describe Soloist::Config do
4
+ let(:soloist_rc_path) { File.expand_path("soloistrc", RSpec.configuration.tempdir) }
5
+ let(:soloist_rc) { Soloist::RoyalCrown.new(:path => soloist_rc_path) }
6
+ let(:config) { Soloist::Config.new(soloist_rc) }
7
+ let(:cookbook_path) { File.expand_path("cookbooks", RSpec.configuration.tempdir) }
8
+ let(:nested_cookbook_path) { File.expand_path("whoa/cookbooks", RSpec.configuration.tempdir) }
9
+
10
+ describe "#as_solo_rb" do
11
+ subject { config.as_solo_rb }
12
+
13
+ it { should include 'file_cache_path "/var/chef/cache"' }
14
+ it { should include %(json_attribs "#{config.node_json_path}") }
15
+ end
16
+
17
+ describe "#cookbook_paths" do
18
+ subject { config.cookbook_paths }
19
+
20
+ context "when the default cookbook path does not exist" do
21
+ it { should have(0).paths }
22
+ end
23
+
24
+ context "when the default cookbook path exists" do
25
+ before { FileUtils.mkdir_p(cookbook_path) }
26
+
27
+ it { should have(1).path }
28
+ it { should =~ [cookbook_path] }
29
+
30
+ context "when the default cookbook path is specified" do
31
+ before { soloist_rc.cookbook_paths = [cookbook_path] }
32
+
33
+ it { should have(1).path }
34
+ it { should =~ [cookbook_path] }
35
+ end
36
+
37
+ context "with a specified cookbook path" do
38
+ before { soloist_rc.cookbook_paths = [nested_cookbook_path] }
39
+
40
+ context "when the specified path exists" do
41
+ before { FileUtils.mkdir_p(nested_cookbook_path) }
42
+
43
+ it { should have(2).paths }
44
+ it { should =~ [cookbook_path, nested_cookbook_path] }
45
+
46
+ context "with duplicate cookbook paths" do
47
+ before { soloist_rc.cookbook_paths = [nested_cookbook_path, nested_cookbook_path] }
48
+
49
+ it { should have(2).paths }
50
+ it { should =~ [cookbook_path, nested_cookbook_path] }
51
+ end
52
+ end
53
+
54
+ context "when the specified path does not exist" do
55
+ it { should have(1).path }
56
+ it { should =~ [cookbook_path] }
57
+ end
58
+ end
59
+ end
60
+
61
+ context "with relative paths" do
62
+ before do
63
+ soloist_rc.cookbook_paths = ["./whoa/cookbooks"]
64
+ FileUtils.mkdir_p(nested_cookbook_path)
65
+ end
66
+
67
+ it { should have(1).path }
68
+ it { should =~ [nested_cookbook_path] }
69
+ end
70
+
71
+ context "with unixisms in the cookbook path" do
72
+ let(:home) { File.expand_path("~") }
73
+
74
+ before { soloist_rc.cookbook_paths = ["~"] }
75
+
76
+ it { should have(1).path }
77
+ it { should =~ [home] }
78
+ end
79
+ end
80
+
81
+ describe "#as_node_json" do
82
+ let(:soloist_rc) do
83
+ Soloist::RoyalCrown.new(
84
+ :path => soloist_rc_path,
85
+ :recipes => ["waffles"],
86
+ :node_attributes => { "gargling" => "cool", "birds" => {"nested" => "cheep"} }
87
+ )
88
+ end
89
+
90
+ describe "node_attributes" do
91
+ subject { config.as_node_json }
92
+
93
+ it { should include "gargling" => "cool" }
94
+ it { should include "birds" => { "nested" => "cheep" } }
95
+ end
96
+
97
+ describe "recipes" do
98
+ subject { config.as_node_json["recipes"] }
99
+
100
+ it { should have(1).recipe }
101
+ it { should =~ ["waffles"] }
102
+ end
103
+ end
104
+
105
+ describe "#compiled" do
106
+ let(:nested) { {} }
107
+ let(:switch) do
108
+ {
109
+ "TONGUES" => {
110
+ "FINE" => {
111
+ "recipes" => ["hobo_fist"],
112
+ "env_variable_switches" => nested
113
+ }
114
+ }
115
+ }
116
+ end
117
+
118
+ before { config.royal_crown.env_variable_switches = switch }
119
+
120
+ context "when the switch is inactive" do
121
+ before { ENV.stub(:[]).and_return("LOLWUT") }
122
+
123
+ it "does not merge the attribute" do
124
+ config.compiled["recipes"].should be_empty
125
+ end
126
+ end
127
+
128
+ context "when a switch is active" do
129
+ before { ENV.stub(:[]).and_return("FINE") }
130
+
131
+ it "merges the attributes" do
132
+ config.compiled.recipes.should =~ ["hobo_fist"]
133
+ end
134
+
135
+ context "when an inactive switch is nested" do
136
+ let(:nested) { {"BEANS" => {"EW" => {"recipes" => ["slammin"]}}} }
137
+
138
+ it "does not merge the attributes" do
139
+ config.compiled.recipes.should =~ ["hobo_fist"]
140
+ end
141
+ end
142
+
143
+ context "when an active switch is nested" do
144
+ let(:nested) { {"BEANS" => {"FINE" => {"recipes" => ["slammin"]}}} }
145
+
146
+ it "merges the attributes" do
147
+ config.compiled.recipes.should =~ ["slammin"]
148
+ end
149
+ end
150
+ end
151
+ end
152
+
153
+ describe "#merge!" do
154
+ let(:soloist_rc) { Soloist::RoyalCrown.new(:recipes => ["guts"], :node_attributes => {:reliable => "maybe"}) }
155
+ let(:other_rc) { Soloist::RoyalCrown.new(:recipes => ["chum"], :node_attributes => {:tasty => "maybe"}) }
156
+ let(:other_config) { Soloist::Config.new(other_rc) }
157
+
158
+ it "merges another config into the current one" do
159
+ config.merge!(other_config)
160
+ config.royal_crown.recipes.should =~ ["guts", "chum"]
161
+ config.royal_crown.node_attributes.keys.should =~ [:reliable, :tasty]
162
+ end
163
+
164
+ it "does not trample the other config" do
165
+ config.merge!(other_config)
166
+ other_config.royal_crown.recipes.should =~ ["chum"]
167
+ other_config.royal_crown.node_attributes.should == {:tasty => "maybe"}
168
+ end
169
+ end
170
+
171
+ describe "#log_level" do
172
+ subject { config.log_level }
173
+
174
+ context "when LOG_LEVEL is not set" do
175
+ it { should == "info" }
176
+ end
177
+
178
+ context "when LOG_LEVEL is set" do
179
+ before { ENV.stub(:[] => "BEANS") }
180
+ it { should == "BEANS" }
181
+ end
182
+ end
183
+
184
+ describe "#debug?" do
185
+ subject { config.debug? }
186
+
187
+ context "when log_level is not debug" do
188
+ it { should_not be }
189
+ end
190
+
191
+ context "when log_level is debug" do
192
+ before { config.stub(:log_level => "debug") }
193
+ it { should be }
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,84 @@
1
+ require "spec_helper"
2
+
3
+ describe Soloist::RemoteConfig do
4
+ let(:royal_crown_path) { File.expand_path("soloistrc", RSpec.configuration.tempdir) }
5
+ let(:royal_crown) { Soloist::RoyalCrown.new(:path => royal_crown_path) }
6
+ let(:remote) { Soloist::Remote.new("user", "host", "key") }
7
+ let(:remote_config) { Soloist::RemoteConfig.new(royal_crown, remote) }
8
+
9
+ before { remote.stub(:backtick => "", :system => 0) }
10
+
11
+ def commands_for(method)
12
+ [].tap do |commands|
13
+ remote.stub(:system) { |c| commands << c; 0 }
14
+ remote.stub(:backtick) { |c| commands << c; "" }
15
+ remote_config.send(method)
16
+ end
17
+ end
18
+
19
+ describe "#run_chef" do
20
+ it "runs chef" do
21
+ commands_for(:run_chef).last.should include "chef-solo"
22
+ end
23
+ end
24
+
25
+ describe "#solo_rb_path" do
26
+ it "sets the path to /etc/chef/solo.rb" do
27
+ remote_config.solo_rb_path.should == "/etc/chef/solo.rb"
28
+ end
29
+
30
+ it "sets up solo.rb remotely" do
31
+ commands_for(:solo_rb_path).last.should =~ /sudo -E tee \/etc\/chef\/solo\.rb$/
32
+ end
33
+ end
34
+
35
+ describe "#node_json_path" do
36
+ it "sets the path" do
37
+ remote_config.node_json_path.should == "/etc/chef/node.json"
38
+ end
39
+
40
+ it "sets up node.json remotely" do
41
+ commands_for(:node_json_path).last.should =~ /sudo -E tee \/etc\/chef\/node\.json$/
42
+ end
43
+ end
44
+
45
+ describe "#chef_config_path" do
46
+ it "sets the path" do
47
+ remote_config.chef_config_path.should == "/etc/chef"
48
+ end
49
+
50
+ it "creates the path remotely" do
51
+ commands_for(:chef_config_path).tap do |commands|
52
+ commands.should have(1).command
53
+ commands.first.should =~ /mkdir .*? -p \/etc\/chef$/
54
+ end
55
+ end
56
+ end
57
+
58
+ describe "#chef_cache_path" do
59
+ it "sets the path" do
60
+ remote_config.chef_cache_path.should == "/var/chef/cache"
61
+ end
62
+
63
+ it "creates the path remotely" do
64
+ commands_for(:chef_cache_path).tap do |commands|
65
+ commands.should have(1).command
66
+ commands.first.should =~ /mkdir .*? -p \/var\/chef\/cache$/
67
+ end
68
+ end
69
+ end
70
+
71
+ describe "#cookbook_paths" do
72
+ it "sets the path" do
73
+ remote_config.cookbook_paths.should have(1).path
74
+ remote_config.cookbook_paths.should =~ ["/var/chef/cookbooks"]
75
+ end
76
+
77
+ it "creates the path remotely" do
78
+ commands_for(:cookbook_paths).tap do |commands|
79
+ commands.should have(1).command
80
+ commands.first.should =~ /mkdir .*? -p \/var\/chef\/cookbooks$/
81
+ end
82
+ end
83
+ end
84
+ end