machines 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. data/.gitignore +11 -0
  2. data/EXAMPLES.md +18 -0
  3. data/Gemfile +4 -0
  4. data/Guardfile +14 -0
  5. data/INSTALL.md +25 -0
  6. data/LICENSE +23 -0
  7. data/README.md +271 -0
  8. data/Rakefile +60 -0
  9. data/TODO.md +92 -0
  10. data/bin/machines +6 -0
  11. data/lib/machines/app_settings.rb +54 -0
  12. data/lib/machines/base.rb +13 -0
  13. data/lib/machines/checks.rb +63 -0
  14. data/lib/machines/cloud_machine.rb +33 -0
  15. data/lib/machines/command.rb +86 -0
  16. data/lib/machines/commandline.rb +148 -0
  17. data/lib/machines/configuration.rb +49 -0
  18. data/lib/machines/core.rb +117 -0
  19. data/lib/machines/database.rb +17 -0
  20. data/lib/machines/file_operations.rb +104 -0
  21. data/lib/machines/help.rb +30 -0
  22. data/lib/machines/installation.rb +151 -0
  23. data/lib/machines/log_command.rb +22 -0
  24. data/lib/machines/logger.rb +65 -0
  25. data/lib/machines/machinesfile.rb +25 -0
  26. data/lib/machines/named_buffer.rb +9 -0
  27. data/lib/machines/questions.rb +15 -0
  28. data/lib/machines/services.rb +24 -0
  29. data/lib/machines/upload.rb +29 -0
  30. data/lib/machines/version.rb +4 -0
  31. data/lib/machines.rb +19 -0
  32. data/lib/packages/abiword.rb +11 -0
  33. data/lib/packages/amazon_mp3.rb +4 -0
  34. data/lib/packages/awstats.rb +16 -0
  35. data/lib/packages/base.rb +14 -0
  36. data/lib/packages/chrome.rb +12 -0
  37. data/lib/packages/cruisecontrol.rb +22 -0
  38. data/lib/packages/dependencies.rb +10 -0
  39. data/lib/packages/docky.rb +36 -0
  40. data/lib/packages/dotfiles.rb +26 -0
  41. data/lib/packages/file_roller.rb +12 -0
  42. data/lib/packages/finalise.rb +4 -0
  43. data/lib/packages/firefox.rb +4 -0
  44. data/lib/packages/gedit.rb +11 -0
  45. data/lib/packages/git.rb +4 -0
  46. data/lib/packages/gmate.rb +33 -0
  47. data/lib/packages/gnome.rb +10 -0
  48. data/lib/packages/gnumeric.rb +11 -0
  49. data/lib/packages/hosts.rb +13 -0
  50. data/lib/packages/load_machines.rb +38 -0
  51. data/lib/packages/monit.rb +10 -0
  52. data/lib/packages/mysql.rb +46 -0
  53. data/lib/packages/nginx.rb +22 -0
  54. data/lib/packages/nginx_logrotate.rb +26 -0
  55. data/lib/packages/openbox.rb +35 -0
  56. data/lib/packages/passenger.rb +14 -0
  57. data/lib/packages/passenger_nginx.rb +8 -0
  58. data/lib/packages/postfix.rb +10 -0
  59. data/lib/packages/questions.rb +5 -0
  60. data/lib/packages/rbenv.rb +27 -0
  61. data/lib/packages/rvm.rb +20 -0
  62. data/lib/packages/save_machines.rb +4 -0
  63. data/lib/packages/slim.rb +6 -0
  64. data/lib/packages/sqlserver.rb +5 -0
  65. data/lib/packages/subtle.rb +29 -0
  66. data/lib/packages/sudo_mods.rb +6 -0
  67. data/lib/packages/time.rb +6 -0
  68. data/lib/packages/time_daily.rb +5 -0
  69. data/lib/packages/timezone.rb +10 -0
  70. data/lib/packages/unison.rb +5 -0
  71. data/lib/packages/virtualbox.rb +11 -0
  72. data/lib/packages/virtualbox_guest.rb +7 -0
  73. data/lib/packages/webapps.rb +36 -0
  74. data/lib/template/Machinesfile +48 -0
  75. data/lib/template/certificates/example.com.crt +0 -0
  76. data/lib/template/certificates/example.com.key +0 -0
  77. data/lib/template/certificates/selfsigned.crt +14 -0
  78. data/lib/template/certificates/selfsigned.key +16 -0
  79. data/lib/template/config.yml +98 -0
  80. data/lib/template/logrotate/app.erb +10 -0
  81. data/lib/template/logrotate/nginx.erb +12 -0
  82. data/lib/template/machines.yml +179 -0
  83. data/lib/template/misc/awstats.conf.erb +7 -0
  84. data/lib/template/misc/ntp.conf +7 -0
  85. data/lib/template/monit/conf.d/delayed_job.erb +11 -0
  86. data/lib/template/monit/conf.d/mysql.erb +7 -0
  87. data/lib/template/monit/conf.d/nginx +5 -0
  88. data/lib/template/monit/conf.d/postfix +7 -0
  89. data/lib/template/monit/conf.d/ssh +6 -0
  90. data/lib/template/monit/conf.d/system.erb +14 -0
  91. data/lib/template/monit/monitrc.erb +10 -0
  92. data/lib/template/monit/upstart.conf +16 -0
  93. data/lib/template/mysql/dbmaster.cnf +7 -0
  94. data/lib/template/mysql/dbslave.cnf +3 -0
  95. data/lib/template/nginx/app_server.conf.erb +87 -0
  96. data/lib/template/nginx/nginx.conf.erb +46 -0
  97. data/lib/template/nginx/upstart.conf.erb +21 -0
  98. data/lib/template/packages/custom.rb +17 -0
  99. data/lib/template/packages/productivity.rb +18 -0
  100. data/lib/template/slim/themes/dark/background.jpg +0 -0
  101. data/lib/template/slim/themes/dark/panel.png +0 -0
  102. data/lib/template/slim/themes/dark/slim.theme +39 -0
  103. data/lib/template/users/phil/dotfiles/bash_aliases +45 -0
  104. data/lib/template/users/phil/dotfiles/config/Trolltech.conf +4 -0
  105. data/lib/template/users/phil/dotfiles/config/gtk-3.0/settings.ini +9 -0
  106. data/lib/template/users/phil/dotfiles/config/openbox/autostart.sh +14 -0
  107. data/lib/template/users/phil/dotfiles/config/openbox/rc.xml +482 -0
  108. data/lib/template/users/phil/dotfiles/config/terminator/config +10 -0
  109. data/lib/template/users/phil/dotfiles/fonts.conf +15 -0
  110. data/lib/template/users/phil/dotfiles/gitconfig +27 -0
  111. data/lib/template/users/phil/dotfiles/gtkrc-2.0 +16 -0
  112. data/lib/template/users/phil/dotfiles/local/share/applications/mimeapps.list +4 -0
  113. data/lib/template/users/phil/dotfiles/unison/default.prf +33 -0
  114. data/lib/template/users/www/authorized_keys +0 -0
  115. data/lib/template/users/www/dotfiles/bash_aliases +40 -0
  116. data/lib/template/webapps.yml +75 -0
  117. data/machines.gemspec +44 -0
  118. data/spec/acceptance/dev_machine_spec.rb +22 -0
  119. data/spec/lib/machines/app_settings_spec.rb +106 -0
  120. data/spec/lib/machines/checks_spec.rb +105 -0
  121. data/spec/lib/machines/cloud_machine_spec.rb +36 -0
  122. data/spec/lib/machines/command_spec.rb +184 -0
  123. data/spec/lib/machines/commandline_spec.rb +299 -0
  124. data/spec/lib/machines/configuration_spec.rb +61 -0
  125. data/spec/lib/machines/core_spec.rb +299 -0
  126. data/spec/lib/machines/database_spec.rb +51 -0
  127. data/spec/lib/machines/file_operations_spec.rb +124 -0
  128. data/spec/lib/machines/help_spec.rb +22 -0
  129. data/spec/lib/machines/installation_spec.rb +176 -0
  130. data/spec/lib/machines/log_command_spec.rb +16 -0
  131. data/spec/lib/machines/logger_spec.rb +70 -0
  132. data/spec/lib/machines/machinesfile_spec.rb +34 -0
  133. data/spec/lib/machines/questions_spec.rb +73 -0
  134. data/spec/lib/machines/services_spec.rb +26 -0
  135. data/spec/lib/machines/upload_spec.rb +86 -0
  136. data/spec/lib/packages/abiword_spec.rb +20 -0
  137. data/spec/lib/packages/amazon_mp3_spec.rb +17 -0
  138. data/spec/lib/packages/awstats_spec.rb +26 -0
  139. data/spec/lib/packages/base_spec.rb +21 -0
  140. data/spec/lib/packages/chrome_spec.rb +30 -0
  141. data/spec/lib/packages/cruisecontrol_spec.rb +33 -0
  142. data/spec/lib/packages/dependencies_spec.rb +20 -0
  143. data/spec/lib/packages/docky_spec.rb +32 -0
  144. data/spec/lib/packages/dotfiles_spec.rb +44 -0
  145. data/spec/lib/packages/file_roller_spec.rb +69 -0
  146. data/spec/lib/packages/firefox_spec.rb +16 -0
  147. data/spec/lib/packages/gedit_spec.rb +20 -0
  148. data/spec/lib/packages/git_spec.rb +16 -0
  149. data/spec/lib/packages/gmate_spec.rb +39 -0
  150. data/spec/lib/packages/gnome_spec.rb +22 -0
  151. data/spec/lib/packages/gnumeric_spec.rb +21 -0
  152. data/spec/lib/packages/hosts_spec.rb +41 -0
  153. data/spec/lib/packages/load_machines_spec.rb +118 -0
  154. data/spec/lib/packages/monit_spec.rb +34 -0
  155. data/spec/lib/packages/mysql_spec.rb +69 -0
  156. data/spec/lib/packages/nginx_logrotate_spec.rb +80 -0
  157. data/spec/lib/packages/nginx_spec.rb +46 -0
  158. data/spec/lib/packages/openbox_spec.rb +41 -0
  159. data/spec/lib/packages/passenger_nginx_spec.rb +20 -0
  160. data/spec/lib/packages/passenger_spec.rb +26 -0
  161. data/spec/lib/packages/postfix_spec.rb +19 -0
  162. data/spec/lib/packages/questions_spec.rb +29 -0
  163. data/spec/lib/packages/rbenv_spec.rb +32 -0
  164. data/spec/lib/packages/rvm_spec.rb +31 -0
  165. data/spec/lib/packages/save_machines_spec.rb +51 -0
  166. data/spec/lib/packages/slim_spec.rb +22 -0
  167. data/spec/lib/packages/sqlserver_spec.rb +17 -0
  168. data/spec/lib/packages/timezone_spec.rb +27 -0
  169. data/spec/lib/packages/unison_spec.rb +17 -0
  170. data/spec/lib/packages/virtualbox_guest_spec.rb +25 -0
  171. data/spec/lib/packages/virtualbox_spec.rb +23 -0
  172. data/spec/lib/packages/webapps_spec.rb +70 -0
  173. data/spec/spec_helper.rb +103 -0
  174. data/spec/support/coverage.rb +8 -0
  175. data/spec/support/fake_out.rb +22 -0
  176. data/spec/support/fakefs_additions.rb +10 -0
  177. data/spec/support/minitest.rb +69 -0
  178. data/spec/support/vm_control.rb +54 -0
  179. data/tmp/.gitkeep +0 -0
  180. metadata +581 -0
@@ -0,0 +1,299 @@
1
+ require 'spec_helper'
2
+
3
+ describe Machines::Commandline do
4
+ include Machines::Core
5
+ include Machines::Commandline
6
+ include Machines::Questions
7
+
8
+ before(:each) do
9
+ $conf.log_only = false
10
+ File.open('config.yml', 'w') { |f| f.puts "timezone: GB" }
11
+ FileUtils.mkdir_p 'log'
12
+ end
13
+
14
+ describe 'build' do
15
+ before(:each) do
16
+ stubs(:init)
17
+ FileUtils.touch('Machinesfile')
18
+ $conf.machine = AppConf.new
19
+ $conf.machine.address = 'target'
20
+ $conf.machine.user = 'username'
21
+ $conf.password = 'userpass'
22
+ Net::SCP.stubs(:new)
23
+ @ssh_stub = stub('Net::SSH', :close => nil, :exec! => nil)
24
+ Net::SSH.stubs(:start).returns @ssh_stub
25
+ end
26
+
27
+ it 'sets machine_name' do
28
+ build ['machine']
29
+ $conf.machine_name.must_equal 'machine'
30
+ end
31
+
32
+ it 'starts an SCP session using password authentication' do
33
+ Net::SSH.expects(:start).with('target', 'username', :paranoid => false, :password => 'userpass').returns @ssh_stub
34
+ build []
35
+ end
36
+
37
+ it 'starts an SCP session using key based authentication' do
38
+ $conf.machine.cloud = AppConf.new
39
+ $conf.machine.cloud.private_key_path = 'path/to/private_key'
40
+ $conf.machine.cloud.username = 'ubuntu'
41
+ Net::SSH.expects(:start).with('target', 'ubuntu', :paranoid => false, :keys => ['path/to/private_key']).returns @ssh_stub
42
+
43
+ build []
44
+ end
45
+
46
+ it 'runs each command' do
47
+ mock_command = mock 'Machines::Command'
48
+ $conf.commands = [mock_command]
49
+
50
+ mock_command.expects(:run)
51
+
52
+ build []
53
+ end
54
+
55
+ it 'flushes log file after running command' do
56
+ $conf.log_only = false
57
+ command_stub = stub('Machines::Command', :run => nil)
58
+ $conf.commands = [command_stub]
59
+
60
+ Machines::Command.file.expects(:flush)
61
+ build []
62
+ end
63
+
64
+ it 'replaces commands with the single task when supplied' do
65
+ command_will_run = Machines::Command.new '', ''
66
+ command_wont_run = Machines::Command.new '', ''
67
+ $conf.tasks = { :task => {:block => Proc.new { run command_will_run }} }
68
+
69
+ build ['machine', 'task']
70
+
71
+ $conf.commands.must_equal [command_will_run]
72
+ end
73
+
74
+ it 'logs instead of SSHing and running commands' do
75
+ Net::SCP.expects(:start).never
76
+ $conf.commands = [mock('Machines::Command')]
77
+ $conf.commands.first.expects(:run)
78
+ $conf.log_only = true
79
+ build []
80
+ end
81
+
82
+ describe 'interrupts' do
83
+ before(:each) do
84
+ mock_command = mock 'Machines::Command'
85
+ $conf.commands = [mock_command]
86
+
87
+ mock_command.stubs(:run)
88
+ $exit_requested = false
89
+ end
90
+
91
+ it 'handles CTRL+C and calls handler' do
92
+ expects(:prepare_to_exit)
93
+ Kernel.expects(:trap).with('INT').yields
94
+ build []
95
+ end
96
+
97
+
98
+ it 'sets exit flag and displays message' do
99
+ prepare_to_exit
100
+ $exit_requested.must_equal true
101
+ $console.next.must_equal colored("\nEXITING after current command completes...\n", :warning)
102
+ end
103
+
104
+ it 'second request to exit exits immediately' do
105
+ $exit_requested = true
106
+ expects(:exit)
107
+ prepare_to_exit
108
+ end
109
+
110
+ it 'exits when exit requested' do
111
+ $exit_requested = true
112
+ expects(:exit)
113
+
114
+ build []
115
+ end
116
+ end
117
+ end
118
+
119
+ describe 'dryrun' do
120
+ it 'asks build to only log commands' do
121
+ options = []
122
+ expects(:build).with options
123
+ dryrun options
124
+ $conf.log_only.must_equal true
125
+ end
126
+ end
127
+
128
+ describe 'execute' do
129
+ it 'calls specified action' do
130
+ Machines::Help.new.actions.reject{|a| a == 'new'}.each do |action|
131
+ expects action
132
+ execute [action]
133
+ end
134
+ end
135
+
136
+ it 'calls generate with folder' do
137
+ expects(:generate).with(['dir'])
138
+ execute ['new', 'dir']
139
+ end
140
+
141
+ it 'calls generate without folder' do
142
+ expects(:generate).with([])
143
+ execute ['new']
144
+ end
145
+
146
+ it 'calls help when no matching command' do
147
+ lambda { execute ['anything'] }.must_output Machines::Help.new.syntax
148
+ end
149
+ end
150
+
151
+ describe 'generate' do
152
+ it 'copies the template within ./' do
153
+ expects(:ask).with("Overwrite './' (y/n)? ").returns 'y'
154
+ FileUtils.expects(:cp_r).with("#{$conf.application_dir}/template/.", './')
155
+ FileUtils.expects(:mkdir_p).with('./packages')
156
+ generate []
157
+ end
158
+
159
+ it 'copies the template within dir' do
160
+ FileUtils.expects(:cp_r).with("#{$conf.application_dir}/template/.", 'dir')
161
+ FileUtils.expects(:mkdir_p).with(File.join('dir', 'packages'))
162
+ expects(:say).with('Project created at dir/')
163
+ generate ['dir']
164
+ end
165
+
166
+ describe 'when folder exists' do
167
+ before(:each) do
168
+ FileUtils.mkdir_p('dir')
169
+ end
170
+
171
+ it 'is overwritten after user confirmation' do
172
+ expects(:ask).with("Overwrite 'dir' (y/n)? ").returns 'y'
173
+ FileUtils.expects(:cp_r).with("#{$conf.application_dir}/template/.", 'dir')
174
+ FileUtils.expects(:mkdir_p).with(File.join('dir', 'packages'))
175
+ generate ['dir']
176
+ end
177
+
178
+ it 'generation is aborted at user request' do
179
+ expects(:ask).with("Overwrite 'dir' (y/n)? ").returns 'n'
180
+ FileUtils.expects(:cp_r).never
181
+ FileUtils.expects(:mkdir_p).never
182
+ generate ['dir']
183
+ end
184
+ end
185
+ end
186
+
187
+ describe 'htpasswd' do
188
+ it 'htpasswd is generated and saved' do
189
+ $conf.webserver = 'server'
190
+ $input.string = "user\npass\npass\n"
191
+ htpasswd nil
192
+ File.read('server/conf/htpasswd').must_match /user:.{13}/
193
+ end
194
+ end
195
+
196
+ describe 'init' do
197
+ it 'initializes some $conf settings and loads configs' do
198
+ Machines::Command.file = nil
199
+ Machines::Command.console = nil
200
+ Machines::Command.debug = nil
201
+ init
202
+ $conf.passwords.must_equal []
203
+ $conf.commands.must_equal []
204
+ $conf.tasks.must_equal({})
205
+ $conf.timezone.must_equal 'GB'
206
+ File.exists?('log/output.log').must_equal true
207
+ Machines::Command.file.must_be_instance_of Machines::Logger
208
+ Machines::Command.console.must_be_instance_of Machines::Logger
209
+ Machines::Command.debug.must_be_instance_of Machines::Logger
210
+ end
211
+ end
212
+
213
+ describe 'load_machinesfile' do
214
+ it 'raises LoadError with custom message when no Machinesfile' do
215
+ File.expects(:read).with("Machinesfile").raises LoadError.new('Machinesfile not found')
216
+
217
+ begin
218
+ load_machinesfile
219
+ rescue LoadError => e
220
+ e.message.must_equal 'Machinesfile does not exist. Use `machines new <DIR>` to create a template.'
221
+ end
222
+ end
223
+
224
+ it 'raises normal LoadError on other files' do
225
+ File.expects(:read).with("Machinesfile").raises LoadError
226
+
227
+ begin
228
+ load_machinesfile
229
+ rescue LoadError => e
230
+ e.message.must_equal 'LoadError'
231
+ end
232
+ end
233
+ end
234
+
235
+ describe 'override' do
236
+ before(:each) do
237
+ FileUtils.mkdir_p File.join($conf.application_dir, 'packages')
238
+ FileUtils.mkdir_p 'packages'
239
+ FileUtils.touch File.join($conf.application_dir, 'packages', 'base.rb')
240
+ end
241
+
242
+ it 'copies package to project folder' do
243
+ override ['base']
244
+ File.exists?('packages/base.rb').must_equal true
245
+ end
246
+
247
+ describe 'when copying over existing package' do
248
+ before(:each) do
249
+ FileUtils.touch 'packages/base.rb'
250
+ end
251
+
252
+ it 'terminates when user answer no' do
253
+ $input.string = "n\n"
254
+ lambda { override ['base'] }.must_output 'Project package already exists. Overwrite? (y/n)
255
+ Aborted.
256
+ '
257
+ end
258
+
259
+ it 'overwrites project package with default package' do
260
+ $input.string = "y\n"
261
+ lambda { override ['base'] }.must_output 'Project package already exists. Overwrite? (y/n)
262
+ Package copied to packages/base.rb
263
+ '
264
+ end
265
+ end
266
+ end
267
+
268
+ describe 'packages' do
269
+ it 'displays a list of default and project packages' do
270
+ FileUtils.mkdir_p File.join($conf.application_dir, 'packages')
271
+ FileUtils.mkdir_p 'packages'
272
+ FileUtils.touch File.join($conf.application_dir, 'packages', 'base.rb')
273
+ FileUtils.touch File.join('packages', 'apps.rb')
274
+ lambda { packages nil }.must_output 'Default packages
275
+ * base
276
+ Project packages
277
+ * apps
278
+ '
279
+ end
280
+ end
281
+
282
+ describe 'tasks' do
283
+ it 'displays a list of tasks' do
284
+ expects(:init)
285
+ expects(:load_machinesfile)
286
+ $conf.tasks = {
287
+ :task1 => {:description => 'description 1'},
288
+ :task2 => {:description => 'description 2'},
289
+ :task3 => {:description => 'description 3'}
290
+ }
291
+ lambda { tasks }.must_output 'Tasks
292
+ task1 description 1
293
+ task2 description 2
294
+ task3 description 3
295
+ '
296
+ end
297
+ end
298
+ end
299
+
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Configuration' do
4
+ include Machines::Core
5
+ include Machines::Configuration
6
+
7
+ describe 'add_user' do
8
+ it do
9
+ command = add_user 'login'
10
+ command.command.must_equal 'useradd -s /bin/bash -d /home/login -m login'
11
+ command.check.must_equal "test -d /home/login #{echo_result}"
12
+ end
13
+
14
+ it do
15
+ command = add_user 'a_user', :password => 'password', :admin => true
16
+ command.command.must_match /useradd -s \/bin\/bash -d \/home\/a_user -m -p .* -G admin a_user/
17
+ command.check.must_equal "test -d /home/a_user #{echo_result}"
18
+ end
19
+ end
20
+
21
+ describe 'add' do
22
+ it 'add an existing user to a group' do
23
+ command = add :user => 'phil', :to => 'group'
24
+ command.command.must_equal 'usermod -a -G group phil'
25
+ end
26
+ end
27
+
28
+ describe 'configure' do
29
+ before(:each) do
30
+ @options = {:string => 'str', :number => 123, :t => true, :f => false, :float => 1.1, :array => ['item 1', 'item 2']}
31
+ end
32
+
33
+ it 'supports different types' do
34
+ commands = configure @options
35
+ commands.map(&:command).must_equal [
36
+ 'gconftool-2 --set "string" --type string "str"',
37
+ 'gconftool-2 --set "number" --type int 123',
38
+ 'gconftool-2 --set "t" --type bool true',
39
+ 'gconftool-2 --set "f" --type bool false',
40
+ 'gconftool-2 --set "float" --type float 1.1',
41
+ 'gconftool-2 --set "array" --type list --list-type=string ["item 1","item 2"]'
42
+ ]
43
+ end
44
+
45
+ it 'checks value has been set' do
46
+ command = configure 'key' => 'value'
47
+ command.first.check.must_equal 'gconftool-2 --get "key" | grep "value" ' + echo_result
48
+ end
49
+
50
+ it { lambda{ configure(:invalid_type => Object.new) }.must_raise RuntimeError }
51
+ end
52
+
53
+ describe 'del_user' do
54
+ it 'calls deluser with remove-all-files option' do
55
+ subject = del_user 'login'
56
+ subject.command.must_equal 'deluser login --remove-home -q'
57
+ subject.check.must_equal "test ! -s /home/login #{echo_result}"
58
+ end
59
+ end
60
+ end
61
+
@@ -0,0 +1,299 @@
1
+ require 'spec_helper'
2
+
3
+ describe Machines::Core do
4
+ include Machines::Core
5
+ include Machines::FileOperations
6
+
7
+ before do
8
+ @command1 = Machines::Command.new('command 1', 'check 1')
9
+ @command2 = Machines::Command.new('command 2', 'check 2')
10
+ end
11
+
12
+ describe 'generate_password' do
13
+ it 'generates a random password' do
14
+ WEBrick::Utils.stubs(:random_string).with(20).returns '01234567890123456789'
15
+ generate_password.must_equal '01234567890123456789'
16
+ end
17
+ end
18
+
19
+ describe 'task' do
20
+ it 'yields' do
21
+ yielded = false
22
+ task :name do
23
+ yielded = true
24
+ end
25
+ yielded.must_equal true
26
+ end
27
+
28
+ it 'logs the task' do
29
+ task :name, 'description' do
30
+ end
31
+ $conf.commands.first.info.must_equal "TASK name - description"
32
+ end
33
+
34
+ it 'stores task' do
35
+ block = Proc.new {}
36
+ task :name, 'description', &block
37
+ $conf.tasks.must_equal :name => {:description => 'description', :block => block}
38
+ end
39
+
40
+ it 'sets commands to only run those from the specified task' do
41
+ block_ran = false
42
+ block = Proc.new { block_ran = true }
43
+ $conf.tasks[:name] = {:block => block}
44
+ task :name, nil
45
+ block_ran.must_equal true
46
+ end
47
+
48
+ describe 'when dependent task' do
49
+ before(:each) do
50
+ @yielded = false
51
+ @block = Proc.new { @yielded = true }
52
+ end
53
+
54
+ describe 'exists' do
55
+ before(:each) do
56
+ store_task :dependent_task, nil
57
+ task :name, nil, :if => :dependent_task, &@block
58
+ end
59
+
60
+ it { @yielded.must_equal true }
61
+ it 'task stored' do
62
+ $conf.tasks.must_include :name
63
+ end
64
+ end
65
+
66
+ describe 'does not exist' do
67
+ before(:each) { task :name, nil, :if => :dependent_task, &@block }
68
+ it { @yielded.must_equal false }
69
+ it 'task not stored' do
70
+ $conf.tasks.wont_include :name
71
+ end
72
+ end
73
+ end
74
+
75
+ describe 'when multiple dependent tasks' do
76
+ before(:each) do
77
+ @yielded = false
78
+ @block = Proc.new { @yielded = true }
79
+ end
80
+
81
+ describe 'all exist' do
82
+ before(:each) do
83
+ store_task :dependent_task, nil
84
+ store_task :another_dependent, nil
85
+ task :name, nil, :if => [:dependent_task, :another_dependent], &@block
86
+ end
87
+
88
+ it { @yielded.must_equal true }
89
+ it 'task stored' do
90
+ $conf.tasks.must_include :name
91
+ end
92
+ end
93
+
94
+ describe 'all but one exist' do
95
+ before(:each) do
96
+ store_task :another_dependent, nil
97
+ task :name, nil, :if => [:dependent_task, :another_dependent], &@block
98
+ end
99
+
100
+ it { @yielded.must_equal false }
101
+ it 'task not stored' do
102
+ $conf.tasks.wont_include :name
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ describe 'list_tasks' do
109
+ it 'displays a list of tasks' do
110
+ task :name, 'description', &Proc.new {}
111
+ task :another, 'another description', &Proc.new {}
112
+ lambda { list_tasks }.must_output ' name description
113
+ another another description
114
+ '
115
+ end
116
+ end
117
+
118
+ describe 'only' do
119
+ it 'yields when matched' do
120
+ expects(:matched).with('options').returns true
121
+ yielded = false
122
+ only 'options' do
123
+ yielded = true
124
+ end
125
+ yielded.must_equal true
126
+ end
127
+
128
+ it 'does not yield when not matched' do
129
+ expects(:matched).with('options').returns false
130
+ yielded = false
131
+ only 'options' do
132
+ yielded = true
133
+ end
134
+ yielded.must_equal false
135
+ end
136
+
137
+ it 'yields when symbol matches string' do
138
+ $conf.environment = 'development'
139
+ yielded = false
140
+ only :environment => :development do
141
+ yielded = true
142
+ end
143
+ yielded.must_equal true
144
+ end
145
+ end
146
+
147
+ describe 'except' do
148
+ it 'does not yield when matched' do
149
+ expects(:matched).with('options').returns true
150
+ yielded = false
151
+ except 'options' do
152
+ yielded = true
153
+ end
154
+ yielded.must_equal false
155
+ end
156
+
157
+ it 'yields when not matched' do
158
+ expects(:matched).with('options').returns false
159
+ yielded = false
160
+ except 'options' do
161
+ yielded = true
162
+ end
163
+ yielded.must_equal true
164
+ end
165
+ end
166
+
167
+ describe 'matched' do
168
+ describe '$conf values are strings' do
169
+ before do
170
+ $conf.string_param = 'matched'
171
+ end
172
+
173
+ it { matched(:string_param => :matched).must_equal true }
174
+ it { matched(:string_param => 'matched').must_equal true }
175
+ it { matched(:string_param => :unmatched).wont_equal true }
176
+ end
177
+
178
+ describe '$conf values are arrays' do
179
+ before do
180
+ $conf.params_array = [:matched, :another]
181
+ end
182
+
183
+ describe 'options values are arrays of symbols' do
184
+ it { matched({:params_array => [:matched]}).must_equal true }
185
+ it { matched({:params_array => [:unmatched]}).wont_equal true }
186
+ end
187
+
188
+ describe 'options values are arrays of strings' do
189
+ it { matched({'params_array' => ['matched']}).must_equal true }
190
+ it { matched({'params_array' => ['unmatched']}).wont_equal true }
191
+ end
192
+
193
+ describe 'options values are symbols' do
194
+ it { matched({:params_array => :matched}).must_equal true }
195
+ it { matched({:params_array => :unmatched}).wont_equal true }
196
+ end
197
+
198
+ describe 'options values are strings' do
199
+ it { matched({:params_array => 'matched'}).must_equal true }
200
+ it { matched({:params_array => 'unmatched'}).wont_equal true }
201
+ end
202
+ end
203
+
204
+ describe '$conf values are symbols' do
205
+ before do
206
+ $conf.single_param = :matched
207
+ end
208
+
209
+ describe 'options values are arrays' do
210
+ it { matched({:single_param => [:matched]}).must_equal true }
211
+ it { matched({:single_param => [:unmatched]}).wont_equal true }
212
+ end
213
+
214
+ describe 'options values are symbols' do
215
+ it { matched({:single_param => :matched}).must_equal true }
216
+ it { matched({:single_param => :unmatched}).wont_equal true }
217
+ end
218
+ end
219
+ end
220
+
221
+ describe 'run' do
222
+ it 'adds a command to the commands array' do
223
+ run @command1
224
+ $conf.commands.must_equal [@command1]
225
+ end
226
+
227
+ it 'appends several commands' do
228
+ run @command1
229
+ run @command2
230
+ $conf.commands.must_equal [@command1, @command2]
231
+ end
232
+
233
+ it 'appends several commands in a single call' do
234
+ run @command1, @command2
235
+ $conf.commands.must_equal [@command1, @command2]
236
+ end
237
+
238
+ describe 'when commands are two strings' do
239
+ it 'creates a Command' do
240
+ run 'command', 'check'
241
+ $conf.commands.first.command.must_equal 'command'
242
+ $conf.commands.first.check.must_equal 'check'
243
+ end
244
+ end
245
+ end
246
+
247
+ describe 'sudo' do
248
+ it 'wraps a command in a sudo with password call' do
249
+ $conf.password = 'password'
250
+ @command1.expects(:use_sudo)
251
+ sudo @command1
252
+ end
253
+
254
+ describe 'when commands are two strings' do
255
+ it 'creates a Command' do
256
+ sudo 'command', 'check'
257
+ $conf.commands.first.command.must_equal 'command'
258
+ $conf.commands.first.check.must_equal 'check'
259
+ end
260
+ end
261
+ end
262
+
263
+ describe 'upload' do
264
+ subject { upload 'source', 'dest' }
265
+ it { subject.local.must_equal 'source' }
266
+ it { subject.remote.must_equal 'dest' }
267
+ end
268
+
269
+ describe 'sudo upload' do
270
+ it 'modifies Upload to send it to a temp file and sudos to copy it to destination' do
271
+ File.stubs(:directory?).returns false
272
+ sudo upload 'source', 'dest'
273
+
274
+ $conf.commands.map(&:command).must_equal [nil, "cp -rf /tmp/dest dest", "rm -rf /tmp/dest"]
275
+ $conf.commands.map(&:check).must_equal [
276
+ "test -s /tmp/dest && echo CHECK PASSED || echo CHECK FAILED",
277
+ "test -s dest && echo CHECK PASSED || echo CHECK FAILED",
278
+ "test ! -s /tmp/dest && echo CHECK PASSED || echo CHECK FAILED"
279
+ ]
280
+ end
281
+
282
+ it 'adds /. to the end of folder paths' do
283
+ File.stubs(:directory?).with('source').returns true
284
+ sudo upload 'source', 'dest'
285
+ $conf.commands.map(&:command).must_equal [nil, "cp -rf /tmp/dest/. dest", "rm -rf /tmp/dest"]
286
+ end
287
+ end
288
+
289
+ describe 'required_options' do
290
+ it 'does not raise when option exists' do
291
+ required_options({:required => :option}, [:required])
292
+ end
293
+
294
+ it 'raises when option does not exist' do
295
+ lambda{required_options({}, [:required])}.must_raise(ArgumentError)
296
+ end
297
+ end
298
+ end
299
+
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Database' do
4
+ include Machines::Core
5
+ include Machines::Configuration
6
+ include Machines::Database
7
+ include Machines::AppSettings
8
+ include Machines::FileOperations
9
+
10
+ describe 'write_database_yml' do
11
+ before do
12
+ $conf.environment = 'staging'
13
+ $conf.db_server = AppConf.new
14
+ $conf.db_server.address = 'dbhost'
15
+ end
16
+
17
+ it 'supplies correct parameters' do
18
+ file = write_database_yml AppBuilder.new(:name => 'app', :password => 'password', :path => 'path')
19
+ file.local.read.must_equal <<-EOF
20
+ ---
21
+ staging:
22
+ adapter: mysql
23
+ database: app
24
+ username: app
25
+ password: password
26
+ host: dbhost
27
+ encoding: utf8
28
+ EOF
29
+ end
30
+
31
+ it 'writes file to specified path' do
32
+ file = write_database_yml AppBuilder.new(:name => 'app', :password => 'password', :path => 'path')
33
+ file.remote.must_equal 'path/shared/config/database.yml'
34
+ end
35
+
36
+ it 'overrides database name when supplied' do
37
+ file = write_database_yml AppBuilder.new(:name => 'app', :password => 'password', :username => 'phil', :database => 'myapp', :path => 'path')
38
+ file.local.read.must_equal <<-EOF
39
+ ---
40
+ staging:
41
+ adapter: mysql
42
+ database: myapp
43
+ username: phil
44
+ password: password
45
+ host: dbhost
46
+ encoding: utf8
47
+ EOF
48
+ end
49
+ end
50
+ end
51
+